File size: 6,407 Bytes
2ffc08a
4cb7b30
8cf1897
 
 
5f5a54f
 
97b090b
8dd9d51
 
764678f
8dd9d51
 
5e1a30a
8dd9d51
 
 
 
 
 
 
 
5e1a30a
d58c03f
8dd9d51
d58c03f
5e1a30a
 
8dd9d51
5e1a30a
d570fcf
4874b7c
 
5e1a30a
38d8ad7
 
5e1a30a
 
38d8ad7
 
 
5e1a30a
 
38d8ad7
5e1a30a
 
 
 
 
 
 
38d8ad7
5e1a30a
 
9400a0f
5e1a30a
 
 
 
4874b7c
5e1a30a
9400a0f
d570fcf
5e1a30a
 
d58c03f
8dd9d51
5e1a30a
 
 
8dd9d51
5e1a30a
5f5a54f
5e1a30a
d58c03f
 
 
5e1a30a
d58c03f
5e1a30a
d58c03f
5e1a30a
d58c03f
5e1a30a
d58c03f
 
5e1a30a
d58c03f
8dd9d51
97b090b
8cf1897
97b090b
 
 
 
5e1a30a
 
d58c03f
5e1a30a
 
8cf1897
9ec48a7
8dd9d51
b3ec31c
 
5e1a30a
b3ec31c
97b090b
 
b3ec31c
 
 
 
 
 
 
 
 
5e1a30a
b3ec31c
 
5e1a30a
b3ec31c
8cf1897
5e1a30a
8cf1897
5e1a30a
4cb7b30
 
 
 
 
 
 
5e1a30a
8cf1897
 
5f5a54f
9ec48a7
8cf1897
d58c03f
 
 
 
5f5a54f
 
5e1a30a
 
5f5a54f
 
 
8cf1897
b3ec31c
 
 
 
97b090b
 
 
b3ec31c
5f5a54f
97b090b
5e1a30a
5f5a54f
8dd9d51
5f5a54f
 
 
9ec48a7
5e1a30a
 
 
 
 
 
5f5a54f
b3ec31c
 
5f5a54f
97b090b
2ffc08a
ead1974
8cf1897
2ffc08a
b5f490a
5e1a30a
 
 
b5f490a
 
5e1a30a
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
import os
import socket
import gradio as gr
import cadquery as cq
from cadquery import exporters
import trimesh
from io import BytesIO
import json
import atexit
import glob

# Cleanup function to remove temporary files
def cleanup_temp_files():
    temp_files = glob.glob("*.stl") + glob.glob("*.inp")
    for temp_file in temp_files:
        try:
            os.remove(temp_file)
        except OSError:
            pass

atexit.register(cleanup_temp_files)

# Define 2D and 3D view generation functions with error handling
def generate_2d_view(file):
    try:
        model = process_cad_file(file)
        two_d_image = model.toSvg()
        return two_d_image
    except Exception as e:
        return f"Error generating 2D view: {str(e)}"

def generate_3d_view(file):
    try:
        # Import CAD file and create a Workplane object
        model = cq.importers.importStep(file.name)

        # Extract solids from the Workplane object
        solids = model.vals() if hasattr(model, 'vals') else model.solids()
        if not solids:
            raise ValueError("No solids found in the CAD model.")

        # Convert solids into trimesh-compatible meshes
        meshes = []
        for solid in solids:
            vertices = []
            faces = []
            for face in solid.tessellate():
                vertices.extend(face[0])  # Extract vertices (x, y, z)
                faces.extend([[face[1][i], face[1][i + 1], face[1][i + 2]] for i in range(0, len(face[1]), 3)])  # Triangular faces
            mesh = trimesh.Trimesh(vertices=vertices, faces=faces)
            meshes.append(mesh)

        # Combine all meshes into a single trimesh object if multiple solids exist
        combined_mesh = trimesh.util.concatenate(meshes) if len(meshes) > 1 else meshes[0]

        # Visualize the mesh
        combined_mesh.show()

        return "3D view generated successfully."
    except Exception as e:
        return f"Error generating 3D view: {str(e)}"


      
# Wrapper function to generate views
def generate_views(file):
    try:
        two_d_view = generate_2d_view(file)
        three_d_view = generate_3d_view(file)
        return two_d_view, three_d_view
    except Exception as e:
        return f"Error: {str(e)}", None

# Function to process different CAD file formats
def process_cad_file(file):
    file_extension = os.path.splitext(file.name)[-1].lower()
    if file_extension in [".stp", ".step"]:
        model = cq.importers.importStep(file.name)
    elif file_extension in [".iges", ".igs"]:
        model = cq.importers.importStep(file.name)  # Same as STEP for cadquery
    elif file_extension == ".sldprt":
        raise NotImplementedError("SLDPRT support is not yet implemented.")
    elif file_extension == ".dwg":
        raise NotImplementedError("DWG support is not yet implemented.")
    else:
        raise ValueError(f"Unsupported file format: {file_extension}")
    return model

# APDL script generation
def generate_apdl_script(file, press_force, material_json):
    try:
        material = json.loads(material_json)
        elastic_modulus = material.get("elastic_modulus", 2e11)
        poisson = material.get("poisson", 0.3)

        # Use temporary file path for processing
        step_file_path = file.name
        model = process_cad_file(file)

        stl_file = step_file_path.replace(".stp", ".stl")
        exporters.export(model, stl_file)

        apdl_script = f"""\n
/PREP7
! Importing Geometry
/import, '{step_file_path}', geom, STEP
! Material Properties
MP, EX, 1, {elastic_modulus}
MP, PRXY, 1, {poisson}
! Load and Boundary Conditions
F, NODE, ALL, FX, {press_force}
! Solve
/SOLU
SOLVE
/POST1
*GET, stress, NODE, 0, S, MAX
/EXIT, SAVE
"""
        apdl_file_path = step_file_path.replace(".stp", ".inp")
        with open(apdl_file_path, "w") as apdl_file:
            apdl_file.write(apdl_script)

        return apdl_script, apdl_file_path
    except Exception as e:
        return f"Error: {str(e)}", None

# Function to find a free port in a range
def find_free_port(start_port, end_port):
    for port in range(start_port, end_port + 1):
        with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
            if sock.connect_ex(('localhost', port)) != 0:  # Port is free
                return port
    raise OSError(f"No available ports in range {start_port}-{end_port}")

# Gradio App
def main():
    with gr.Blocks() as app:
        gr.Markdown("# Press Tool Design and APDL Script Generator")

        with gr.Row():
            step_input = gr.File(
                label="Upload CAD File",
                file_types=[".stp", ".step", ".iges", ".igs", ".sldprt", ".dwg"]
            )

        with gr.Row():
            two_d_output = gr.Textbox(label="2D View/Error Message", interactive=False)
            three_d_output = gr.Textbox(label="3D View/Error Message", interactive=False)
            generate_views_btn = gr.Button("Generate 2D & 3D Views")

        with gr.Row():
            force_input = gr.Number(label="Press Force (N)", value=1000)
            material_input = gr.Textbox(
                label="Material Properties (JSON)",
                value='{"elastic_modulus": 2e11, "poisson": 0.3}'
            )

        with gr.Row():
            script_output = gr.Textbox(label="Generated APDL Script", interactive=False)
            download_button = gr.File(label="Download Script")
            generate_apdl_btn = gr.Button("Generate APDL Script")

        # Events for Visualization
        generate_views_btn.click(
            fn=generate_views,
            inputs=step_input,
            outputs=[two_d_output, three_d_output]
        )

        # Events for APDL Script
        def handle_download(apdl_script, apdl_file_path):
            if apdl_file_path and os.path.exists(apdl_file_path):
                return apdl_file_path
            return None

        generate_apdl_btn.click(
            fn=generate_apdl_script,
            inputs=[step_input, force_input, material_input],
            outputs=[script_output, download_button]
        )
    return app

if __name__ == "__main__":
    app = main()
    try:
        # Dynamically find a free port in range 7860-7870
        port = find_free_port(7860, 7870)
        print(f"Launching on port: {port}")
        app.launch(server_port=port, debug=True)
    except Exception as e:
        print(f"Failed to launch: {str(e)}")