APDL_STPL / app.py
jithenderchoudary's picture
Update app.py
5e1a30a verified
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)}")