Skip to main content
Glama
quellant

OpenSCAD MCP Server

by quellant
render_all_views.py6.93 kB
#!/usr/bin/env python3 """ Comprehensive rendering script for all parts Generates 6 views for each part: top, left, right, bottom, iso-left, iso-right """ import os import subprocess from pathlib import Path # Define parts directory PARTS_DIR = Path("/home/coop/projects/dealer/poc/dealing_mechanism/parts") RENDERS_DIR = PARTS_DIR / "comprehensive_renders" RENDERS_DIR.mkdir(exist_ok=True) # Define standard camera positions for each view VIEWS = { "top": {"camera": "0,0,200,0,0,0,200", "desc": "Top view"}, "bottom": {"camera": "0,0,-200,0,0,0,200", "desc": "Bottom view"}, "left": {"camera": "-200,0,0,0,0,0,200", "desc": "Left side view"}, "right": {"camera": "200,0,0,0,0,0,200", "desc": "Right side view"}, "iso_left": {"camera": "-150,-150,150,0,0,0,300", "desc": "Isometric left"}, "iso_right": {"camera": "150,-150,150,0,0,0,300", "desc": "Isometric right"}, } # Parts to render with their SCAD files and module calls PARTS = { "part1_scanner_base": { "file": "part_1_scanner_base.scad", "module": "scanner_base()", "center": "0,0,20" }, "part2_card_chamber": { "file": "part_2_card_chamber.scad", "module": "card_chamber()", "center": "0,0,40" }, "part3a_roller_housing": { "file": "part_3a_roller_housing.scad", "module": "roller_housing()", "center": "0,0,10" }, "part3b_motor_mount": { "file": "part_3b_motor_mount.scad", "module": "motor_mount()", "center": "0,0,12" }, "part3c_separator_wedge": { "file": "part_3c_separator_wedge.scad", "module": "separator_wedge()", "center": "0,0,0" }, "part3d_roller": { "file": "part_3d_roller.scad", "module": "roller_assembly()", "center": "0,0,0" }, "part4_pressure_plate": { "file": "part_4_pressure_plate.scad", "module": "pressure_plate()", "center": "0,0,0" } } def render_view(scad_file, output_file, camera_pos, center, module_call): """Render a single view of a part""" # Update camera position with proper center cam_parts = camera_pos.split(',') center_parts = center.split(',') camera = f"{cam_parts[0]},{cam_parts[1]},{cam_parts[2]},{center_parts[0]},{center_parts[1]},{center_parts[2]},{cam_parts[6]}" cmd = [ "openscad", "-o", str(output_file), "--camera", camera, "--imgsize", "1024,768", "--colorscheme", "Tomorrow Night", "--autocenter", "--viewall", "-D", "$fn=60", "-D", module_call, str(scad_file) ] try: result = subprocess.run(cmd, capture_output=True, text=True, cwd=str(PARTS_DIR)) if result.returncode == 0: print(f" ✓ {output_file.name}") else: print(f" ✗ {output_file.name}: {result.stderr[:100]}") except Exception as e: print(f" ✗ {output_file.name}: {str(e)}") def render_all_views_for_part(part_name, part_info): """Render all 6 views for a single part""" print(f"\n{'='*60}") print(f"Rendering {part_name}") print(f"{'='*60}") scad_file = PARTS_DIR / part_info["file"] if not scad_file.exists(): print(f" ✗ File not found: {scad_file}") return part_dir = RENDERS_DIR / part_name part_dir.mkdir(exist_ok=True) for view_name, view_info in VIEWS.items(): output_file = part_dir / f"{view_name}.png" render_view( scad_file, output_file, view_info["camera"], part_info["center"], part_info["module"] ) def render_assembly(): """Render all views of the complete assembly""" print(f"\n{'='*60}") print(f"Rendering Full Assembly") print(f"{'='*60}") # Create assembly test file assembly_file = PARTS_DIR / "full_assembly_test.scad" assembly_content = """ // Full assembly test $fn = 60; use <part_1_scanner_base.scad> use <part_2_card_chamber.scad> use <part_3a_roller_housing.scad> use <part_3b_motor_mount.scad> use <part_3c_separator_wedge.scad> use <part_3d_roller.scad> use <part_4_pressure_plate.scad> // Assembly color("Gray") scanner_base(); translate([0, 0, 40]) color("Blue") card_chamber(); translate([0, 30, 50]) color("Orange") roller_housing(); translate([-50, 30, 50]) color("DarkGray") motor_mount(); translate([0, 25, 48]) color("Red") separator_wedge(); translate([0, 30, 50]) rotate([90, 0, 0]) color("Orange", 0.8) roller_assembly(); translate([0, 0, 115]) color("Green") pressure_plate(); """ with open(assembly_file, 'w') as f: f.write(assembly_content) assembly_dir = RENDERS_DIR / "full_assembly" assembly_dir.mkdir(exist_ok=True) # Assembly has different camera distances assembly_views = { "top": {"camera": "0,0,400,0,0,60,500", "desc": "Top view"}, "bottom": {"camera": "0,0,-400,0,0,60,500", "desc": "Bottom view"}, "left": {"camera": "-400,0,60,0,0,60,500", "desc": "Left side view"}, "right": {"camera": "400,0,60,0,0,60,500", "desc": "Right side view"}, "iso_left": {"camera": "-300,-300,250,0,0,60,500", "desc": "Isometric left"}, "iso_right": {"camera": "300,-300,250,0,0,60,500", "desc": "Isometric right"}, } for view_name, view_info in assembly_views.items(): output_file = assembly_dir / f"{view_name}.png" cmd = [ "openscad", "-o", str(output_file), "--camera", view_info["camera"], "--imgsize", "1024,768", "--colorscheme", "Tomorrow Night", "--autocenter", "--viewall", str(assembly_file) ] try: result = subprocess.run(cmd, capture_output=True, text=True, cwd=str(PARTS_DIR)) if result.returncode == 0: print(f" ✓ {output_file.name}") else: print(f" ✗ {output_file.name}") except Exception as e: print(f" ✗ {output_file.name}: {str(e)}") def main(): print("Starting comprehensive render generation...") print(f"Output directory: {RENDERS_DIR}") # Render all individual parts for part_name, part_info in PARTS.items(): render_all_views_for_part(part_name, part_info) # Render assembly render_assembly() print(f"\n{'='*60}") print("Rendering complete!") print(f"All renders saved to: {RENDERS_DIR}") # List all generated files total_files = 0 for part_dir in RENDERS_DIR.iterdir(): if part_dir.is_dir(): files = list(part_dir.glob("*.png")) print(f"\n{part_dir.name}: {len(files)} renders") total_files += len(files) print(f"\nTotal renders generated: {total_files}") if __name__ == "__main__": main()

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/quellant/openscad-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server