Spaces:
Sleeping
Sleeping
| 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)}") |