Skip to content

Commit 0160935

Browse files
Copilotdorkmo
andcommitted
Create individual SCAD files for structural parts and add square tubing to cut list
Co-authored-by: dorkmo <1923070+dorkmo@users.noreply.github.com>
1 parent ebbe7bb commit 0160935

File tree

8 files changed

+385
-72
lines changed

8 files changed

+385
-72
lines changed

LifeTrac-v25/mechanical_design/generate_cut_list.py

Lines changed: 76 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -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>
405412
use <../openscad/parts/platform_angle_arm.scad>
406413
407-
// Render with holes visible
408414
platform_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

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
// angle_iron_a2_frame_mount.scad
2+
// Frame Tube Mounting Angle - Part A2
3+
// 2" × 2" × 1/4" Angle Iron
4+
// Used to mount frame tubes to side panels
5+
// Quantity needed: 16 (2 per tube × 2 tubes × 4 panels)
6+
7+
include <../../lifetrac_v25_params.scad>
8+
use <../../modules/structural_steel.scad>
9+
10+
/**
11+
* Frame tube mounting angle iron with holes
12+
* Length: 146.05mm (5.75") - 6" stock minus 2×1/8" trim
13+
* Material: 2" × 2" × 1/4" angle iron
14+
*/
15+
module angle_iron_a2_frame_mount(show_holes=true) {
16+
leg = 50.8; // 2" angle iron leg
17+
thick = 6.35; // 1/4" thickness
18+
length = 146.05; // 5.75" (6" stock - 2×trim)
19+
20+
// Hole specifications
21+
hole_dia = 12.7; // 1/2" (12.7mm)
22+
hole1_pos = 22.86; // First hole position from end
23+
hole2_pos = 123.19; // Second hole position from end
24+
25+
difference() {
26+
// Main angle iron shape
27+
color("Gray")
28+
rotate([90, 0, 0])
29+
linear_extrude(height=length)
30+
polygon([
31+
[0, 0],
32+
[leg, 0],
33+
[leg, thick],
34+
[thick, thick],
35+
[thick, leg],
36+
[0, leg]
37+
]);
38+
39+
if (show_holes) {
40+
// Holes through horizontal leg (for plate mounting)
41+
translate([leg/2, -hole1_pos, thick/2])
42+
cylinder(d=hole_dia, h=thick+2, center=true, $fn=24);
43+
44+
translate([leg/2, -hole2_pos, thick/2])
45+
cylinder(d=hole_dia, h=thick+2, center=true, $fn=24);
46+
47+
// Holes through vertical leg (for tube mounting)
48+
translate([thick/2, -hole1_pos, leg/2])
49+
rotate([0, 90, 0])
50+
cylinder(d=hole_dia, h=thick+2, center=true, $fn=24);
51+
52+
translate([thick/2, -hole2_pos, leg/2])
53+
rotate([0, 90, 0])
54+
cylinder(d=hole_dia, h=thick+2, center=true, $fn=24);
55+
}
56+
}
57+
}
58+
59+
// Render the part
60+
angle_iron_a2_frame_mount(show_holes=true);
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
// angle_iron_a3_loader_mount.scad
2+
// Loader Arm Mounting Angle - Part A3
3+
// 2" × 2" × 1/4" Angle Iron
4+
// Connects loader arm to side panels
5+
// Quantity needed: 4 (2 per arm × 2 arms)
6+
7+
include <../../lifetrac_v25_params.scad>
8+
use <../../modules/structural_steel.scad>
9+
10+
/**
11+
* Loader arm mounting angle iron with holes
12+
* Length: 146.05mm (5.75") - same as frame mount
13+
* Material: 2" × 2" × 1/4" angle iron
14+
*/
15+
module angle_iron_a3_loader_mount(show_holes=true) {
16+
leg = 50.8; // 2" angle iron leg
17+
thick = 6.35; // 1/4" thickness
18+
length = 146.05; // 5.75"
19+
20+
// Hole specifications
21+
hole_dia = 12.7; // 1/2" (12.7mm)
22+
// Holes through horizontal leg (for plate mounting)
23+
plate_hole1_pos = 22.86;
24+
plate_hole2_pos = 123.19;
25+
// Holes through vertical leg (for beam mounting - different positions)
26+
beam_hole1_pos = 48.26;
27+
beam_hole2_pos = 97.79;
28+
29+
difference() {
30+
// Main angle iron shape
31+
color("Gray")
32+
rotate([90, 0, 0])
33+
linear_extrude(height=length)
34+
polygon([
35+
[0, 0],
36+
[leg, 0],
37+
[leg, thick],
38+
[thick, thick],
39+
[thick, leg],
40+
[0, leg]
41+
]);
42+
43+
if (show_holes) {
44+
// Holes through horizontal leg (for plate mounting)
45+
translate([leg/2, -plate_hole1_pos, thick/2])
46+
cylinder(d=hole_dia, h=thick+2, center=true, $fn=24);
47+
48+
translate([leg/2, -plate_hole2_pos, thick/2])
49+
cylinder(d=hole_dia, h=thick+2, center=true, $fn=24);
50+
51+
// Holes through vertical leg (for beam mounting)
52+
translate([thick/2, -beam_hole1_pos, leg/2])
53+
rotate([0, 90, 0])
54+
cylinder(d=hole_dia, h=thick+2, center=true, $fn=24);
55+
56+
translate([thick/2, -beam_hole2_pos, leg/2])
57+
rotate([0, 90, 0])
58+
cylinder(d=hole_dia, h=thick+2, center=true, $fn=24);
59+
}
60+
}
61+
}
62+
63+
// Render the part
64+
angle_iron_a3_loader_mount(show_holes=true);
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
// angle_iron_a4_side_panel_vertical.scad
2+
// Side Panel Vertical Angle - Part A4
3+
// 2" × 2" × 1/4" Angle Iron
4+
// Vertical stiffeners for side panels
5+
// Quantity needed: 8
6+
7+
include <../../lifetrac_v25_params.scad>
8+
use <../../modules/structural_steel.scad>
9+
10+
/**
11+
* Side panel vertical stiffener angle iron with holes
12+
* Length: 550mm (21.65")
13+
* Material: 2" × 2" × 1/4" angle iron
14+
*/
15+
module angle_iron_a4_side_panel_vertical(show_holes=true) {
16+
leg = 50.8; // 2" angle iron leg
17+
thick = 6.35; // 1/4" thickness
18+
length = 550.0; // 550mm
19+
20+
// Hole specifications
21+
hole_dia = 9.525; // 3/8" (9.525mm)
22+
hole1_pos = 60.0; // First hole
23+
hole2_pos = 490.0; // Second hole
24+
25+
difference() {
26+
// Main angle iron shape
27+
color("Gray")
28+
rotate([90, 0, 0])
29+
linear_extrude(height=length)
30+
polygon([
31+
[0, 0],
32+
[leg, 0],
33+
[leg, thick],
34+
[thick, thick],
35+
[thick, leg],
36+
[0, leg]
37+
]);
38+
39+
if (show_holes) {
40+
// Holes through horizontal leg (for panel mounting)
41+
translate([leg/2, -hole1_pos, thick/2])
42+
cylinder(d=hole_dia, h=thick+2, center=true, $fn=24);
43+
44+
translate([leg/2, -hole2_pos, thick/2])
45+
cylinder(d=hole_dia, h=thick+2, center=true, $fn=24);
46+
}
47+
}
48+
}
49+
50+
// Render the part
51+
angle_iron_a4_side_panel_vertical(show_holes=true);

0 commit comments

Comments
 (0)