@@ -377,99 +377,80 @@ def generate_part_renders(part_code, scad_module_name, temp_dir, part=None):
377377 Generate orthogonal and diagonal views of a part
378378
379379 Args:
380- part_code: Part code (A1, A2, etc.)
380+ part_code: Part code (A1, A2, T1, etc.)
381381 scad_module_name: Name of OpenSCAD module to render
382382 temp_dir: Temporary directory for outputs
383383 part: StructuralPart object with dimensions and hole data
384384
385385 Returns:
386386 Dict with paths to rendered images, or None if rendering failed
387387 """
388- # Create temporary SCAD file that calls the module
389- scad_path = os .path .join (temp_dir , f'{ part_code } .scad' )
388+ # Map part codes to their dedicated SCAD files
389+ scad_file_map = {
390+ 'A1' : '../openscad/parts/platform_angle_arm.scad' ,
391+ 'A2' : '../openscad/parts/structural/angle_iron_a2_frame_mount.scad' ,
392+ 'A3' : '../openscad/parts/structural/angle_iron_a3_loader_mount.scad' ,
393+ 'A4' : '../openscad/parts/structural/angle_iron_a4_side_panel_vertical.scad' ,
394+ 'A5' : '../openscad/parts/structural/angle_iron_a5_bottom_plate_horizontal.scad' ,
395+ 'T1' : '../openscad/parts/structural/frame_tube_t1_front.scad' ,
396+ 'T2' : '../openscad/parts/structural/frame_tube_t2_rear.scad' ,
397+ }
390398
391- # Get part dimensions for camera positioning
392- if part :
393- length = part .length_mm
394- leg = 50.8 # 2" angle iron leg size
395- else :
396- length = 425.0 # default
397- leg = 50.8
399+ # Get the SCAD file path
400+ scad_file_rel = scad_file_map .get (part_code )
401+ if not scad_file_rel :
402+ print (f" ⚠️ No SCAD file defined for part { part_code } " )
403+ return None
404+
405+ # Create absolute path from temp directory
406+ scad_path = os .path .join (temp_dir , f'{ part_code } .scad' )
398407
399- # For now, create angle iron visualization with holes
408+ # Create a wrapper SCAD file that includes the part file
400409 with open (scad_path , 'w' ) as f :
401410 if part_code == 'A1' :
402- # Use the actual platform_angle_arm module which has holes
403- f .write ('''
404- include <../openscad/lifetrac_v25_params.scad>
411+ f .write ('''include <../openscad/lifetrac_v25_params.scad>
405412use <../openscad/parts/platform_angle_arm.scad>
406413
407- // Render with holes visible
408414platform_angle_arm(show_holes=true);
409415''' )
410- else :
411- # Generic angle iron with holes for other parts
412- if not part :
413- return None
414-
415- # Generate angle iron with holes
416- f .write (f'''
417- $fn = 32;
416+ elif part_code .startswith ('A' ):
417+ # Angle iron parts
418+ module_name = scad_file_rel .split ('/' )[- 1 ].replace ('.scad' , '' )
419+ f .write (f'''use <{ scad_file_rel } >
418420
419- // Angle iron visualization with holes
420- module angle_iron_with_holes() {{
421- leg = 50.8; // 2" angle iron
422- thick = 6.35; // 1/4" thickness
423- length = { length } ;
424-
425- difference() {{
426- // Main angle iron shape
427- color("Gray")
428- rotate([90, 0, 0])
429- linear_extrude(height=length)
430- polygon([
431- [0, 0],
432- [leg, 0],
433- [leg, thick],
434- [thick, thick],
435- [thick, leg],
436- [0, leg]
437- ]);
438-
439- // Drill holes
440- ''' )
441-
442- # Add holes based on part data
443- if part and part .holes :
444- for hole in part .holes :
445- hole_pos = hole ['position_mm' ]
446- hole_dia = hole ['diameter_mm' ]
447- # Determine which leg the hole goes through
448- if 'vertical leg' in hole .get ('description' , '' ).lower ():
449- # Hole through vertical leg (X direction)
450- f .write (f''' // { hole ['description' ]}
451- translate([leg/2, -{ hole_pos } , leg/2])
452- rotate([0, 90, 0])
453- cylinder(d={ hole_dia } , h=leg+2, center=true, $fn=24);
454- ''' )
455- else :
456- # Hole through horizontal leg (Z direction) or default
457- f .write (f''' // { hole ['description' ]}
458- translate([leg/2, -{ hole_pos } , thick/2])
459- cylinder(d={ hole_dia } , h=thick+2, center=true, $fn=24);
421+ { module_name } (show_holes=true);
460422''' )
461-
462- f .write (''' }
463- }
423+ elif part_code .startswith ('T' ):
424+ # Tubing parts
425+ module_name = scad_file_rel .split ('/' )[- 1 ].replace ('.scad' , '' )
426+ f .write (f'''use <{ scad_file_rel } >
464427
465- angle_iron_with_holes( );
428+ { module_name } (show_holes=false );
466429''' )
467430
431+ # Get part dimensions for camera positioning
432+ if part :
433+ if hasattr (part , 'length_mm' ):
434+ length = part .length_mm
435+ elif hasattr (part , 'width_mm' ):
436+ # For square/rectangular tubing
437+ length = max (part .width_mm , part .height_mm ) if hasattr (part , 'height_mm' ) else part .width_mm
438+ else :
439+ length = 425.0
440+
441+ # Determine typical dimensions
442+ if part_code .startswith ('T' ):
443+ # Tubular parts - use tube dimensions
444+ max_dim = 1200.0 # Approximate length of frame tubes
445+ else :
446+ # Angle iron parts
447+ leg = 50.8
448+ max_dim = max (length , leg * 2 )
449+ else :
450+ length = 425.0
451+ max_dim = 425.0
452+
468453 # Calculate camera distances based on part dimensions
469- # Use bounding box to determine good camera distance
470- max_dim = max (length , leg * 2 ) # diagonal of L-shape
471- # Camera distance to fit object at ~90% of view
472- # For ortho projection, distance affects the viewing volume
473454 cam_dist = max_dim * 1.2
474455
475456 # Camera configurations for different views with better positioning
@@ -726,6 +707,29 @@ def get_structural_parts():
726707 notes = "Bottom plate stiffeners. Split pattern to clear wheel axles."
727708 ))
728709
710+ # Square Tubing Parts - Frame Tubes
711+ # Front frame tube - 2" x 6" rectangular tubing
712+ parts .append (StructuralPart (
713+ part_code = "T1" ,
714+ name = "Front Frame Tube" ,
715+ material = '2" × 6" × 1/4" Rectangular Tubing' ,
716+ length_mm = 1200.0 , # Approximate - spans track width
717+ quantity = 1 ,
718+ holes = [],
719+ notes = "Front cross frame tube passing through side panels. Actual length = track width between panels."
720+ ))
721+
722+ # Rear frame tube - 2" x 6" rectangular tubing
723+ parts .append (StructuralPart (
724+ part_code = "T2" ,
725+ name = "Rear Frame Tube" ,
726+ material = '2" × 6" × 1/4" Rectangular Tubing' ,
727+ length_mm = 1200.0 , # Approximate - spans track width
728+ quantity = 1 ,
729+ holes = [],
730+ notes = "Rear cross frame tube passing through side panels. Actual length = track width between panels."
731+ ))
732+
729733 return parts
730734
731735
0 commit comments