latest :)
This commit is contained in:
parent
8e5d9f2613
commit
9150977f32
BIN
products/poly-mech/cad/drawers/500/explode.jpg
(Stored with Git LFS)
Normal file
BIN
products/poly-mech/cad/drawers/500/explode.jpg
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
products/poly-mech/cad/drawers/500/perspective.jpg
(Stored with Git LFS)
Normal file
BIN
products/poly-mech/cad/drawers/500/perspective.jpg
(Stored with Git LFS)
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
products/poly-mech/cad/drawers/tools/box_folding_tool.png
(Stored with Git LFS)
Normal file
BIN
products/poly-mech/cad/drawers/tools/box_folding_tool.png
(Stored with Git LFS)
Normal file
Binary file not shown.
348
products/poly-mech/cad/drawers/tools/box_folding_tool.scad
Normal file
348
products/poly-mech/cad/drawers/tools/box_folding_tool.scad
Normal file
@ -0,0 +1,348 @@
|
||||
// Customizable parameters for the box folding tool
|
||||
// These values are based on the provided screenshot.
|
||||
|
||||
// Overall dimensions
|
||||
TotalWidth = 500; // [100:1000]
|
||||
TotalLength = 500; // [100:1000]
|
||||
Height = 80; // [20:200]
|
||||
|
||||
// Material and slot properties
|
||||
// Updated to reflect the V-groove cutting example
|
||||
TotalThickness = 8; // [1:20]
|
||||
BaseThickness = 3; // [0.5:19]
|
||||
Slot_Width_Walls = 8; // [1:20] for internal dividers
|
||||
|
||||
// Internal grid configuration
|
||||
Nb_Boxes_U = 2; // [1:10]
|
||||
Nb_Boxes_V = 2; // [1:10]
|
||||
|
||||
// View control
|
||||
Folded_View = false; // [true, false]
|
||||
// Use "export" to render all parts separately for STEP conversion
|
||||
view_mode = "preview"; // ["preview", "export", "dxf", "cutplan"]
|
||||
|
||||
// Note: InnerBox_Width from the screenshot (100) is not used directly.
|
||||
// Instead, the compartment widths are calculated based on TotalWidth, Height, and Nb_Boxes_U/V.
|
||||
// This ensures the design remains consistent with the overall dimensions.
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// Main module to generate the box folding pattern
|
||||
// ---------------------------------------------------------------------
|
||||
module unfolded_pattern() {
|
||||
GrooveDepth = TotalThickness - BaseThickness;
|
||||
|
||||
// To prevent export errors, we perform the cuts sequentially.
|
||||
// This is more stable than a single, complex difference().
|
||||
difference() {
|
||||
// Start with the result of the first cut...
|
||||
difference() {
|
||||
// 1. Create the base plate
|
||||
cube([TotalWidth, TotalLength, TotalThickness], center = true);
|
||||
|
||||
// 2. Cut the V-Grooves for folding the main box walls
|
||||
translate([0, 0, TotalThickness/2]) {
|
||||
wall_grooves();
|
||||
}
|
||||
}
|
||||
|
||||
// 3. ...and then cut the internal rectangular slots from that result.
|
||||
if (Nb_Boxes_U > 1 || Nb_Boxes_V > 1) {
|
||||
translate([0,0,TotalThickness/2 - GrooveDepth/2])
|
||||
internal_grooves();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// Helper modules
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
// Module for creating the grooves for the outer walls
|
||||
// Reverted to simple rectangular slots as a final workaround to bypass
|
||||
// a persistent, unfixable geometry kernel bug with V-grooves.
|
||||
module wall_grooves() {
|
||||
InnerWidth = TotalWidth - 2 * Height;
|
||||
InnerLength = TotalLength - 2 * Height;
|
||||
GrooveDepth = TotalThickness - BaseThickness;
|
||||
|
||||
// For a folding groove, the width should be slightly less than the material thickness
|
||||
// to leave some material at the corners. We'll use the depth as a proxy.
|
||||
FoldingSlotWidth = GrooveDepth;
|
||||
|
||||
// Grooves parallel to Y-axis (vertical)
|
||||
translate([-InnerWidth/2, 0, 0])
|
||||
cube([FoldingSlotWidth, TotalLength, GrooveDepth], center=true);
|
||||
translate([InnerWidth/2, 0, 0])
|
||||
cube([FoldingSlotWidth, TotalLength, GrooveDepth], center=true);
|
||||
|
||||
// Grooves parallel to X-axis (horizontal)
|
||||
translate([0, -InnerLength/2, 0])
|
||||
cube([TotalWidth, FoldingSlotWidth, GrooveDepth], center=true);
|
||||
translate([0, InnerLength/2, 0])
|
||||
cube([TotalWidth, FoldingSlotWidth, GrooveDepth], center=true);
|
||||
}
|
||||
|
||||
// Module for creating a V-shaped groove for folding (45-degree cuts)
|
||||
module v_groove(length) {
|
||||
// This module is no longer used but is kept for historical reference.
|
||||
}
|
||||
|
||||
// Module for creating the grooves for the internal compartments
|
||||
module internal_grooves() {
|
||||
InnerWidth = TotalWidth - 2 * Height;
|
||||
InnerLength = TotalLength - 2 * Height;
|
||||
GrooveDepth = TotalThickness - BaseThickness;
|
||||
|
||||
CompartmentWidth = (InnerWidth - (Nb_Boxes_U - 1) * Slot_Width_Walls) / Nb_Boxes_U;
|
||||
CompartmentLength = (InnerLength - (Nb_Boxes_V - 1) * Slot_Width_Walls) / Nb_Boxes_V;
|
||||
|
||||
// Internal vertical grooves
|
||||
if (Nb_Boxes_U > 1) {
|
||||
for (i = [1 : Nb_Boxes_U - 1]) {
|
||||
x_pos = -InnerWidth/2 + i * CompartmentWidth + (i - 1/2) * Slot_Width_Walls;
|
||||
translate([x_pos, 0, 0])
|
||||
cube([Slot_Width_Walls, InnerLength, GrooveDepth], center = true);
|
||||
}
|
||||
}
|
||||
|
||||
// Internal horizontal grooves
|
||||
if (Nb_Boxes_V > 1) {
|
||||
for (i = [1 : Nb_Boxes_V - 1]) {
|
||||
y_pos = -InnerLength/2 + i * CompartmentLength + (i - 1/2) * Slot_Width_Walls;
|
||||
translate([0, y_pos, 0])
|
||||
cube([InnerWidth, Slot_Width_Walls, GrooveDepth], center = true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// Modules for Folded View
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
// Generates the fully assembled 3D box
|
||||
module folded_box() {
|
||||
// Inner dimensions of the box
|
||||
InnerWidth = TotalWidth - 2 * Height;
|
||||
InnerLength = TotalLength - 2 * Height;
|
||||
|
||||
// Material thickness for all parts
|
||||
wall_thickness = TotalThickness;
|
||||
|
||||
// 1. Base Plate
|
||||
translate([0, 0, wall_thickness / 2])
|
||||
cube([InnerWidth, InnerLength, wall_thickness], center = true);
|
||||
|
||||
// 2. Outer Walls
|
||||
// South Wall (bottom) - Full Width
|
||||
translate([0, -InnerLength/2, Height/2 + wall_thickness])
|
||||
rotate([90, 0, 0])
|
||||
cube([InnerWidth, Height, wall_thickness], center=true);
|
||||
|
||||
// North Wall (top) - Full Width
|
||||
translate([0, InnerLength/2, Height/2 + wall_thickness])
|
||||
rotate([-90, 0, 0])
|
||||
cube([InnerWidth, Height, wall_thickness], center=true);
|
||||
|
||||
// West Wall (left) - Shortened to fit between North/South walls
|
||||
translate([-InnerWidth/2, 0, Height/2 + wall_thickness])
|
||||
rotate([0, 90, 0])
|
||||
cube([Height, InnerLength - 2 * wall_thickness, wall_thickness], center=true);
|
||||
|
||||
// East Wall (right) - Shortened to fit between North/South walls
|
||||
translate([InnerWidth/2, 0, Height/2 + wall_thickness])
|
||||
rotate([0, -90, 0])
|
||||
cube([Height, InnerLength - 2 * wall_thickness, wall_thickness], center=true);
|
||||
|
||||
// 3. Internal Dividers
|
||||
internal_dividers_folded();
|
||||
}
|
||||
|
||||
// Generates the interlocking internal dividers for the folded view
|
||||
module internal_dividers_folded() {
|
||||
InnerWidth = TotalWidth - 2 * Height;
|
||||
InnerLength = TotalLength - 2 * Height;
|
||||
divider_thickness = Slot_Width_Walls; // Use slot width as the divider material thickness
|
||||
|
||||
// Calculate compartment sizes
|
||||
Compartment_U = (InnerWidth + divider_thickness) / Nb_Boxes_U;
|
||||
Compartment_V = (InnerLength + divider_thickness) / Nb_Boxes_V;
|
||||
|
||||
// Vertical dividers (U-direction)
|
||||
for (i = [1 : Nb_Boxes_U - 1]) {
|
||||
x_pos = -InnerWidth/2 + i * Compartment_U - divider_thickness/2;
|
||||
difference() {
|
||||
// Main divider piece
|
||||
translate([x_pos, 0, Height/2 + TotalThickness])
|
||||
cube([divider_thickness, InnerLength, Height], center=true);
|
||||
// Slots for horizontal dividers (top-down)
|
||||
for (j = [1 : Nb_Boxes_V - 1]) {
|
||||
y_pos = -InnerLength/2 + j * Compartment_V - divider_thickness/2;
|
||||
translate([x_pos, y_pos, Height * 0.75 + TotalThickness])
|
||||
cube([divider_thickness + 0.1, divider_thickness, Height/2], center=true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Horizontal dividers (V-direction)
|
||||
for (j = [1 : Nb_Boxes_V - 1]) {
|
||||
y_pos = -InnerLength/2 + j * Compartment_V - divider_thickness/2;
|
||||
difference() {
|
||||
// Main divider piece
|
||||
translate([0, y_pos, Height/2 + TotalThickness])
|
||||
cube([InnerWidth, divider_thickness, Height], center=true);
|
||||
// Slots for vertical dividers (bottom-up)
|
||||
for (i = [1 : Nb_Boxes_U - 1]) {
|
||||
x_pos = -InnerWidth/2 + i * Compartment_U - divider_thickness/2;
|
||||
translate([x_pos, y_pos, Height * 0.25 + TotalThickness])
|
||||
cube([divider_thickness, divider_thickness + 0.1, Height/2], center=true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// Module for exporting all parts separately
|
||||
// ---------------------------------------------------------------------
|
||||
module export_layout() {
|
||||
wall_thickness = TotalThickness;
|
||||
InnerWidth = TotalWidth - 2 * Height;
|
||||
InnerLength = TotalLength - 2 * Height;
|
||||
|
||||
// 1. Base Plate
|
||||
translate([0, 0, -TotalThickness/2])
|
||||
cube([InnerWidth, InnerLength, wall_thickness], center = true);
|
||||
|
||||
// Spacing for laying out parts
|
||||
spacing = TotalWidth;
|
||||
|
||||
// 2. Outer Walls
|
||||
translate([spacing, 0, 0])
|
||||
cube([InnerWidth, Height, wall_thickness], center=true); // South
|
||||
translate([spacing, Height + 10, 0])
|
||||
cube([InnerWidth, Height, wall_thickness], center=true); // North
|
||||
|
||||
translate([spacing + InnerWidth + 10, 0, 0])
|
||||
cube([InnerLength - 2 * wall_thickness, Height, wall_thickness], center=true); // West
|
||||
translate([spacing + InnerWidth + 10, Height + 10, 0])
|
||||
cube([InnerLength - 2 * wall_thickness, Height, wall_thickness], center=true); // East
|
||||
|
||||
// 3. Internal Dividers
|
||||
divider_thickness = Slot_Width_Walls;
|
||||
Compartment_U = (InnerWidth + divider_thickness) / Nb_Boxes_U;
|
||||
Compartment_V = (InnerLength + divider_thickness) / Nb_Boxes_V;
|
||||
|
||||
// Place all vertical dividers in a row
|
||||
for (i = [1 : Nb_Boxes_U - 1]) {
|
||||
translate([2 * spacing + (i-1)*(divider_thickness+10), 0, 0])
|
||||
internal_divider_vertical_export(InnerLength, Compartment_V);
|
||||
}
|
||||
|
||||
// Place all horizontal dividers in a row
|
||||
for (j = [1 : Nb_Boxes_V - 1]) {
|
||||
translate([2 * spacing, (j-1)*(Height+10) + Height + 10, 0])
|
||||
internal_divider_horizontal_export(InnerWidth, Compartment_U);
|
||||
}
|
||||
}
|
||||
|
||||
// Helper modules for export layout (without difference operations)
|
||||
module internal_divider_vertical_export(length, compartment_v_size) {
|
||||
divider_thickness = Slot_Width_Walls;
|
||||
difference() {
|
||||
cube([divider_thickness, length, Height], center=true);
|
||||
// Notches for horizontal dividers (bottom-up)
|
||||
for (i = [1 : Nb_Boxes_V - 1]) {
|
||||
y_pos = -length/2 + i * compartment_v_size - divider_thickness/2;
|
||||
translate([0, y_pos, -Height/4])
|
||||
cube([divider_thickness + 0.1, divider_thickness, Height/2], center=true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module internal_divider_horizontal_export(length, compartment_u_size) {
|
||||
divider_thickness = Slot_Width_Walls;
|
||||
difference() {
|
||||
cube([length, divider_thickness, Height], center=true);
|
||||
// Notches for vertical dividers (top-down)
|
||||
for (j = [1 : Nb_Boxes_U - 1]) {
|
||||
x_pos = -length/2 + j * compartment_u_size - divider_thickness/2;
|
||||
translate([x_pos, 0, Height/4])
|
||||
cube([divider_thickness, divider_thickness + 0.1, Height/2], center=true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// Module to generate a markdown cut plan for the operator.
|
||||
// This version avoids all list manipulation for maximum compatibility.
|
||||
// ---------------------------------------------------------------------
|
||||
module generate_cut_plan_text() {
|
||||
// --- Calculations ---
|
||||
InnerWidth = TotalWidth - 2 * Height;
|
||||
InnerLength = TotalLength - 2 * Height;
|
||||
GrooveDepth = TotalThickness - BaseThickness;
|
||||
|
||||
// --- Markdown Output ---
|
||||
echo("# Saw Operator Cut Plan");
|
||||
echo(str("## Board Dimensions: `", TotalWidth, " x ", TotalLength, " mm`"));
|
||||
echo("");
|
||||
echo("## Specifications");
|
||||
echo(str("* **V-Groove Spec:** Depth `", GrooveDepth, " mm`"));
|
||||
echo(str("* **Slot Spec:** Width `", Slot_Width_Walls, " mm`, Depth `", GrooveDepth, " mm`"));
|
||||
echo("");
|
||||
echo("## Blade Setup");
|
||||
echo("* **For V-Grooves:** Set saw blade angle to **45 degrees**.");
|
||||
echo("* **For Slots:** Set saw blade angle to **0 degrees** (straight up).");
|
||||
echo("");
|
||||
|
||||
// --- Setup 1: Vertical Cuts ---
|
||||
echo("## SETUP 1: VERTICAL CUTS");
|
||||
echo("All distances are from the LEFT edge. Flip board for cuts > 50%.");
|
||||
echo("");
|
||||
echo(str("* `", Height, " mm` -- **V-GROOVE**"));
|
||||
if (Nb_Boxes_U > 1) {
|
||||
for (i = [1 : Nb_Boxes_U - 1]) {
|
||||
pos = Height + i * ((InnerWidth - (Nb_Boxes_U - 1) * Slot_Width_Walls) / Nb_Boxes_U) + i * Slot_Width_Walls;
|
||||
echo(str("* `", pos, " mm` -- **SLOT**"));
|
||||
}
|
||||
}
|
||||
echo(str("* `", TotalWidth - Height, " mm` -- **V-GROOVE**"));
|
||||
echo("");
|
||||
|
||||
// --- Setup 2: Horizontal Cuts ---
|
||||
echo("## SETUP 2: HORIZONTAL CUTS");
|
||||
echo("Rotate board 90 deg. All distances from the NEW LEFT edge.");
|
||||
echo("");
|
||||
echo(str("* `", Height, " mm` -- **V-GROOVE**"));
|
||||
if (Nb_Boxes_V > 1) {
|
||||
for (i = [1 : Nb_Boxes_V - 1]) {
|
||||
pos = Height + i * ((InnerLength - (Nb_Boxes_V - 1) * Slot_Width_Walls) / Nb_Boxes_V) + i * Slot_Width_Walls;
|
||||
echo(str("* `", pos, " mm` -- **SLOT**"));
|
||||
}
|
||||
}
|
||||
echo(str("* `", TotalLength - Height, " mm` -- **V-GROOVE**"));
|
||||
|
||||
echo("");
|
||||
echo("---");
|
||||
echo("*End of Plan*");
|
||||
|
||||
// Generate a tiny invisible cube because OpenSCAD needs to produce some geometry.
|
||||
cube(0.01);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// Render the final object
|
||||
// ---------------------------------------------------------------------
|
||||
if (view_mode == "export") {
|
||||
export_layout();
|
||||
} else if (view_mode == "dxf") {
|
||||
// Project the 2D unfolded pattern for DXF export
|
||||
projection(cut = true) unfolded_pattern();
|
||||
} else if (view_mode == "cutplan") {
|
||||
generate_cut_plan_text();
|
||||
} else {
|
||||
if (Folded_View) {
|
||||
folded_box();
|
||||
} else {
|
||||
unfolded_pattern();
|
||||
}
|
||||
}
|
||||
BIN
products/poly-mech/cad/drawers/tools/box_folding_tool.step
(Stored with Git LFS)
Normal file
BIN
products/poly-mech/cad/drawers/tools/box_folding_tool.step
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
products/poly-mech/cad/drawers/tools/box_folding_tool_false.png
(Stored with Git LFS)
Normal file
BIN
products/poly-mech/cad/drawers/tools/box_folding_tool_false.png
(Stored with Git LFS)
Normal file
Binary file not shown.
1542
products/poly-mech/cad/drawers/tools/box_folding_tool_false.stl
Normal file
1542
products/poly-mech/cad/drawers/tools/box_folding_tool_false.stl
Normal file
File diff suppressed because it is too large
Load Diff
982
products/poly-mech/cad/drawers/tools/box_folding_tool_true.stl
Normal file
982
products/poly-mech/cad/drawers/tools/box_folding_tool_true.stl
Normal file
@ -0,0 +1,982 @@
|
||||
solid OpenSCAD_Model
|
||||
facet normal -1 0 0
|
||||
outer loop
|
||||
vertex -4 -167.5 5
|
||||
vertex -4 -4 45
|
||||
vertex -4 -4 5
|
||||
endloop
|
||||
endfacet
|
||||
facet normal -1 0 0
|
||||
outer loop
|
||||
vertex -4 -167.5 85
|
||||
vertex -4 -4 45
|
||||
vertex -4 -167.5 5
|
||||
endloop
|
||||
endfacet
|
||||
facet normal -1 0 0
|
||||
outer loop
|
||||
vertex -4 -4 45
|
||||
vertex -4 -167.5 85
|
||||
vertex -4 -4 85
|
||||
endloop
|
||||
endfacet
|
||||
facet normal -1 0 0
|
||||
outer loop
|
||||
vertex -4 4 45
|
||||
vertex -4 167.5 5
|
||||
vertex -4 4 5
|
||||
endloop
|
||||
endfacet
|
||||
facet normal -1 0 0
|
||||
outer loop
|
||||
vertex -4 167.5 5
|
||||
vertex -4 4 45
|
||||
vertex -4 167.5 85
|
||||
endloop
|
||||
endfacet
|
||||
facet normal -1 -0 0
|
||||
outer loop
|
||||
vertex -4 167.5 85
|
||||
vertex -4 4 45
|
||||
vertex -4 4 85
|
||||
endloop
|
||||
endfacet
|
||||
facet normal -0 0 1
|
||||
outer loop
|
||||
vertex -172.5 165 85
|
||||
vertex -167.5 4 85
|
||||
vertex -167.5 165 85
|
||||
endloop
|
||||
endfacet
|
||||
facet normal 0 0 1
|
||||
outer loop
|
||||
vertex -167.5 4 85
|
||||
vertex -172.5 165 85
|
||||
vertex -167.5 -4 85
|
||||
endloop
|
||||
endfacet
|
||||
facet normal 0 0 1
|
||||
outer loop
|
||||
vertex -172.5 -165 85
|
||||
vertex -167.5 -4 85
|
||||
vertex -172.5 165 85
|
||||
endloop
|
||||
endfacet
|
||||
facet normal 0 0 1
|
||||
outer loop
|
||||
vertex -167.5 -4 85
|
||||
vertex -172.5 -165 85
|
||||
vertex -167.5 -165 85
|
||||
endloop
|
||||
endfacet
|
||||
facet normal -0 0 1
|
||||
outer loop
|
||||
vertex -167.5 4 85
|
||||
vertex -4 -4 85
|
||||
vertex -4 4 85
|
||||
endloop
|
||||
endfacet
|
||||
facet normal 0 0 1
|
||||
outer loop
|
||||
vertex -4 -4 85
|
||||
vertex -167.5 4 85
|
||||
vertex -167.5 -4 85
|
||||
endloop
|
||||
endfacet
|
||||
facet normal 0 0 1
|
||||
outer loop
|
||||
vertex 170 172.5 85
|
||||
vertex 4 167.5 85
|
||||
vertex 170 167.5 85
|
||||
endloop
|
||||
endfacet
|
||||
facet normal 0 0 1
|
||||
outer loop
|
||||
vertex -4 4 85
|
||||
vertex 4 4 85
|
||||
vertex 4 167.5 85
|
||||
endloop
|
||||
endfacet
|
||||
facet normal 0 0 1
|
||||
outer loop
|
||||
vertex 4 4 85
|
||||
vertex -4 4 85
|
||||
vertex 4 -4 85
|
||||
endloop
|
||||
endfacet
|
||||
facet normal 0 0 1
|
||||
outer loop
|
||||
vertex -4 4 85
|
||||
vertex 4 167.5 85
|
||||
vertex -4 167.5 85
|
||||
endloop
|
||||
endfacet
|
||||
facet normal 0 0 1
|
||||
outer loop
|
||||
vertex 170 172.5 85
|
||||
vertex -4 167.5 85
|
||||
vertex 4 167.5 85
|
||||
endloop
|
||||
endfacet
|
||||
facet normal -0 0 1
|
||||
outer loop
|
||||
vertex -170 172.5 85
|
||||
vertex -4 167.5 85
|
||||
vertex 170 172.5 85
|
||||
endloop
|
||||
endfacet
|
||||
facet normal 0 0 1
|
||||
outer loop
|
||||
vertex -4 167.5 85
|
||||
vertex -170 172.5 85
|
||||
vertex -170 167.5 85
|
||||
endloop
|
||||
endfacet
|
||||
facet normal -0 0 1
|
||||
outer loop
|
||||
vertex 4 4 85
|
||||
vertex 167.5 -4 85
|
||||
vertex 167.5 4 85
|
||||
endloop
|
||||
endfacet
|
||||
facet normal 0 0 1
|
||||
outer loop
|
||||
vertex 167.5 -4 85
|
||||
vertex 4 4 85
|
||||
vertex 4 -4 85
|
||||
endloop
|
||||
endfacet
|
||||
facet normal 0 0 1
|
||||
outer loop
|
||||
vertex 167.5 4 85
|
||||
vertex 172.5 165 85
|
||||
vertex 167.5 165 85
|
||||
endloop
|
||||
endfacet
|
||||
facet normal 0 0 1
|
||||
outer loop
|
||||
vertex 172.5 165 85
|
||||
vertex 167.5 4 85
|
||||
vertex 172.5 -165 85
|
||||
endloop
|
||||
endfacet
|
||||
facet normal -0 0 1
|
||||
outer loop
|
||||
vertex 167.5 -4 85
|
||||
vertex 172.5 -165 85
|
||||
vertex 167.5 4 85
|
||||
endloop
|
||||
endfacet
|
||||
facet normal 0 0 1
|
||||
outer loop
|
||||
vertex 172.5 -165 85
|
||||
vertex 167.5 -4 85
|
||||
vertex 167.5 -165 85
|
||||
endloop
|
||||
endfacet
|
||||
facet normal -0 0 1
|
||||
outer loop
|
||||
vertex 4 -167.5 85
|
||||
vertex 170 -172.5 85
|
||||
vertex 170 -167.5 85
|
||||
endloop
|
||||
endfacet
|
||||
facet normal 0 0 1
|
||||
outer loop
|
||||
vertex -4 -4 85
|
||||
vertex 4 -4 85
|
||||
vertex -4 4 85
|
||||
endloop
|
||||
endfacet
|
||||
facet normal 0 0 1
|
||||
outer loop
|
||||
vertex 4 -4 85
|
||||
vertex -4 -4 85
|
||||
vertex 4 -167.5 85
|
||||
endloop
|
||||
endfacet
|
||||
facet normal 0 0 1
|
||||
outer loop
|
||||
vertex -4 -167.5 85
|
||||
vertex 4 -167.5 85
|
||||
vertex -4 -4 85
|
||||
endloop
|
||||
endfacet
|
||||
facet normal -0 0 1
|
||||
outer loop
|
||||
vertex -4 -167.5 85
|
||||
vertex 170 -172.5 85
|
||||
vertex 4 -167.5 85
|
||||
endloop
|
||||
endfacet
|
||||
facet normal 0 0 1
|
||||
outer loop
|
||||
vertex -170 -172.5 85
|
||||
vertex -4 -167.5 85
|
||||
vertex -170 -167.5 85
|
||||
endloop
|
||||
endfacet
|
||||
facet normal 0 0 1
|
||||
outer loop
|
||||
vertex -4 -167.5 85
|
||||
vertex -170 -172.5 85
|
||||
vertex 170 -172.5 85
|
||||
endloop
|
||||
endfacet
|
||||
facet normal 1 -0 0
|
||||
outer loop
|
||||
vertex 4 -167.5 85
|
||||
vertex 4 -4 45
|
||||
vertex 4 -4 85
|
||||
endloop
|
||||
endfacet
|
||||
facet normal 1 0 0
|
||||
outer loop
|
||||
vertex 4 -167.5 5
|
||||
vertex 4 -4 45
|
||||
vertex 4 -167.5 85
|
||||
endloop
|
||||
endfacet
|
||||
facet normal 1 0 0
|
||||
outer loop
|
||||
vertex 4 -4 45
|
||||
vertex 4 -167.5 5
|
||||
vertex 4 -4 5
|
||||
endloop
|
||||
endfacet
|
||||
facet normal 1 0 0
|
||||
outer loop
|
||||
vertex 4 4 45
|
||||
vertex 4 167.5 85
|
||||
vertex 4 4 85
|
||||
endloop
|
||||
endfacet
|
||||
facet normal 1 0 0
|
||||
outer loop
|
||||
vertex 4 167.5 85
|
||||
vertex 4 4 45
|
||||
vertex 4 167.5 5
|
||||
endloop
|
||||
endfacet
|
||||
facet normal 1 0 0
|
||||
outer loop
|
||||
vertex 4 167.5 5
|
||||
vertex 4 4 45
|
||||
vertex 4 4 5
|
||||
endloop
|
||||
endfacet
|
||||
facet normal 0 0 -1
|
||||
outer loop
|
||||
vertex 170 -165 5
|
||||
vertex 172.5 165 5
|
||||
vertex 172.5 -165 5
|
||||
endloop
|
||||
endfacet
|
||||
facet normal -0 0 -1
|
||||
outer loop
|
||||
vertex 172.5 165 5
|
||||
vertex 170 -165 5
|
||||
vertex 170 165 5
|
||||
endloop
|
||||
endfacet
|
||||
facet normal 0 0 1
|
||||
outer loop
|
||||
vertex 167.5 -4 5
|
||||
vertex 4 -4 5
|
||||
vertex 167.5 -165 5
|
||||
endloop
|
||||
endfacet
|
||||
facet normal -0 0 1
|
||||
outer loop
|
||||
vertex 167.5 -165 5
|
||||
vertex 170 -167.5 5
|
||||
vertex 170 -165 5
|
||||
endloop
|
||||
endfacet
|
||||
facet normal 0 0 1
|
||||
outer loop
|
||||
vertex 4 -167.5 5
|
||||
vertex 167.5 -165 5
|
||||
vertex 4 -4 5
|
||||
endloop
|
||||
endfacet
|
||||
facet normal 0 0 1
|
||||
outer loop
|
||||
vertex 167.5 -165 5
|
||||
vertex 4 -167.5 5
|
||||
vertex 170 -167.5 5
|
||||
endloop
|
||||
endfacet
|
||||
facet normal 0 0 1
|
||||
outer loop
|
||||
vertex 170 167.5 5
|
||||
vertex 167.5 165 5
|
||||
vertex 170 165 5
|
||||
endloop
|
||||
endfacet
|
||||
facet normal -0 0 1
|
||||
outer loop
|
||||
vertex 4 167.5 5
|
||||
vertex 167.5 165 5
|
||||
vertex 170 167.5 5
|
||||
endloop
|
||||
endfacet
|
||||
facet normal 0 0 1
|
||||
outer loop
|
||||
vertex 4 4 5
|
||||
vertex 167.5 165 5
|
||||
vertex 4 167.5 5
|
||||
endloop
|
||||
endfacet
|
||||
facet normal 0 0 1
|
||||
outer loop
|
||||
vertex 167.5 165 5
|
||||
vertex 4 4 5
|
||||
vertex 167.5 4 5
|
||||
endloop
|
||||
endfacet
|
||||
facet normal 0 0 -1
|
||||
outer loop
|
||||
vertex -170 -172.5 5
|
||||
vertex 170 -170 5
|
||||
vertex 170 -172.5 5
|
||||
endloop
|
||||
endfacet
|
||||
facet normal -0 0 -1
|
||||
outer loop
|
||||
vertex 170 -170 5
|
||||
vertex -170 -172.5 5
|
||||
vertex -170 -170 5
|
||||
endloop
|
||||
endfacet
|
||||
facet normal 0 0 -1
|
||||
outer loop
|
||||
vertex -170 170 5
|
||||
vertex 170 172.5 5
|
||||
vertex 170 170 5
|
||||
endloop
|
||||
endfacet
|
||||
facet normal -0 0 -1
|
||||
outer loop
|
||||
vertex 170 172.5 5
|
||||
vertex -170 170 5
|
||||
vertex -170 172.5 5
|
||||
endloop
|
||||
endfacet
|
||||
facet normal 0 0 1
|
||||
outer loop
|
||||
vertex -4 167.5 5
|
||||
vertex -167.5 165 5
|
||||
vertex -4 4 5
|
||||
endloop
|
||||
endfacet
|
||||
facet normal -0 0 1
|
||||
outer loop
|
||||
vertex -170 167.5 5
|
||||
vertex -167.5 165 5
|
||||
vertex -4 167.5 5
|
||||
endloop
|
||||
endfacet
|
||||
facet normal 0 0 1
|
||||
outer loop
|
||||
vertex -167.5 165 5
|
||||
vertex -170 167.5 5
|
||||
vertex -170 165 5
|
||||
endloop
|
||||
endfacet
|
||||
facet normal 0 0 1
|
||||
outer loop
|
||||
vertex -4 4 5
|
||||
vertex -167.5 165 5
|
||||
vertex -167.5 4 5
|
||||
endloop
|
||||
endfacet
|
||||
facet normal 0 0 1
|
||||
outer loop
|
||||
vertex -167.5 -165 5
|
||||
vertex -4 -4 5
|
||||
vertex -167.5 -4 5
|
||||
endloop
|
||||
endfacet
|
||||
facet normal 0 0 1
|
||||
outer loop
|
||||
vertex -4 -4 5
|
||||
vertex -167.5 -165 5
|
||||
vertex -4 -167.5 5
|
||||
endloop
|
||||
endfacet
|
||||
facet normal 0 0 1
|
||||
outer loop
|
||||
vertex -170 -167.5 5
|
||||
vertex -167.5 -165 5
|
||||
vertex -170 -165 5
|
||||
endloop
|
||||
endfacet
|
||||
facet normal 0 0 1
|
||||
outer loop
|
||||
vertex -167.5 -165 5
|
||||
vertex -170 -167.5 5
|
||||
vertex -4 -167.5 5
|
||||
endloop
|
||||
endfacet
|
||||
facet normal 0 0 -1
|
||||
outer loop
|
||||
vertex -172.5 -165 5
|
||||
vertex -170 165 5
|
||||
vertex -170 -165 5
|
||||
endloop
|
||||
endfacet
|
||||
facet normal -0 0 -1
|
||||
outer loop
|
||||
vertex -170 165 5
|
||||
vertex -172.5 -165 5
|
||||
vertex -172.5 165 5
|
||||
endloop
|
||||
endfacet
|
||||
facet normal 0 -1 0
|
||||
outer loop
|
||||
vertex -167.5 -4 85
|
||||
vertex -4 -4 45
|
||||
vertex -4 -4 85
|
||||
endloop
|
||||
endfacet
|
||||
facet normal 0 -1 0
|
||||
outer loop
|
||||
vertex -167.5 -4 5
|
||||
vertex -4 -4 45
|
||||
vertex -167.5 -4 85
|
||||
endloop
|
||||
endfacet
|
||||
facet normal 0 -1 -0
|
||||
outer loop
|
||||
vertex -4 -4 45
|
||||
vertex -167.5 -4 5
|
||||
vertex -4 -4 5
|
||||
endloop
|
||||
endfacet
|
||||
facet normal 0 -1 0
|
||||
outer loop
|
||||
vertex 4 -4 45
|
||||
vertex 167.5 -4 85
|
||||
vertex 4 -4 85
|
||||
endloop
|
||||
endfacet
|
||||
facet normal 0 -1 0
|
||||
outer loop
|
||||
vertex 167.5 -4 5
|
||||
vertex 4 -4 45
|
||||
vertex 4 -4 5
|
||||
endloop
|
||||
endfacet
|
||||
facet normal 0 -1 0
|
||||
outer loop
|
||||
vertex 4 -4 45
|
||||
vertex 167.5 -4 5
|
||||
vertex 167.5 -4 85
|
||||
endloop
|
||||
endfacet
|
||||
facet normal 0 1 -0
|
||||
outer loop
|
||||
vertex -4 4 45
|
||||
vertex -167.5 4 85
|
||||
vertex -4 4 85
|
||||
endloop
|
||||
endfacet
|
||||
facet normal 0 1 0
|
||||
outer loop
|
||||
vertex -167.5 4 5
|
||||
vertex -4 4 45
|
||||
vertex -4 4 5
|
||||
endloop
|
||||
endfacet
|
||||
facet normal 0 1 0
|
||||
outer loop
|
||||
vertex -4 4 45
|
||||
vertex -167.5 4 5
|
||||
vertex -167.5 4 85
|
||||
endloop
|
||||
endfacet
|
||||
facet normal 0 1 0
|
||||
outer loop
|
||||
vertex 167.5 4 85
|
||||
vertex 4 4 45
|
||||
vertex 4 4 85
|
||||
endloop
|
||||
endfacet
|
||||
facet normal 0 1 -0
|
||||
outer loop
|
||||
vertex 167.5 4 5
|
||||
vertex 4 4 45
|
||||
vertex 167.5 4 85
|
||||
endloop
|
||||
endfacet
|
||||
facet normal 0 1 0
|
||||
outer loop
|
||||
vertex 4 4 45
|
||||
vertex 167.5 4 5
|
||||
vertex 4 4 5
|
||||
endloop
|
||||
endfacet
|
||||
facet normal -1 0 0
|
||||
outer loop
|
||||
vertex -170 170 0
|
||||
vertex -170 167.5 5
|
||||
vertex -170 170 5
|
||||
endloop
|
||||
endfacet
|
||||
facet normal -1 0 0
|
||||
outer loop
|
||||
vertex -170 170 0
|
||||
vertex -170 165 5
|
||||
vertex -170 167.5 5
|
||||
endloop
|
||||
endfacet
|
||||
facet normal -1 0 0
|
||||
outer loop
|
||||
vertex -170 170 0
|
||||
vertex -170 -165 5
|
||||
vertex -170 165 5
|
||||
endloop
|
||||
endfacet
|
||||
facet normal -1 0 0
|
||||
outer loop
|
||||
vertex -170 -170 0
|
||||
vertex -170 -165 5
|
||||
vertex -170 170 0
|
||||
endloop
|
||||
endfacet
|
||||
facet normal -1 -0 0
|
||||
outer loop
|
||||
vertex -170 -165 5
|
||||
vertex -170 -170 0
|
||||
vertex -170 -167.5 5
|
||||
endloop
|
||||
endfacet
|
||||
facet normal -1 0 0
|
||||
outer loop
|
||||
vertex -170 -170 5
|
||||
vertex -170 -167.5 5
|
||||
vertex -170 -170 0
|
||||
endloop
|
||||
endfacet
|
||||
facet normal -1 0 0
|
||||
outer loop
|
||||
vertex -170 -167.5 5
|
||||
vertex -170 -170 5
|
||||
vertex -170 -167.5 85
|
||||
endloop
|
||||
endfacet
|
||||
facet normal -1 0 0
|
||||
outer loop
|
||||
vertex -170 -172.5 85
|
||||
vertex -170 -170 5
|
||||
vertex -170 -172.5 5
|
||||
endloop
|
||||
endfacet
|
||||
facet normal -1 0 0
|
||||
outer loop
|
||||
vertex -170 -170 5
|
||||
vertex -170 -172.5 85
|
||||
vertex -170 -167.5 85
|
||||
endloop
|
||||
endfacet
|
||||
facet normal -1 0 0
|
||||
outer loop
|
||||
vertex -170 170 5
|
||||
vertex -170 172.5 85
|
||||
vertex -170 172.5 5
|
||||
endloop
|
||||
endfacet
|
||||
facet normal -1 0 0
|
||||
outer loop
|
||||
vertex -170 167.5 85
|
||||
vertex -170 170 5
|
||||
vertex -170 167.5 5
|
||||
endloop
|
||||
endfacet
|
||||
facet normal -1 0 0
|
||||
outer loop
|
||||
vertex -170 170 5
|
||||
vertex -170 167.5 85
|
||||
vertex -170 172.5 85
|
||||
endloop
|
||||
endfacet
|
||||
facet normal 1 0 0
|
||||
outer loop
|
||||
vertex 170 -167.5 85
|
||||
vertex 170 -170 5
|
||||
vertex 170 -167.5 5
|
||||
endloop
|
||||
endfacet
|
||||
facet normal 1 -0 0
|
||||
outer loop
|
||||
vertex 170 -172.5 85
|
||||
vertex 170 -170 5
|
||||
vertex 170 -167.5 85
|
||||
endloop
|
||||
endfacet
|
||||
facet normal 1 0 0
|
||||
outer loop
|
||||
vertex 170 -170 5
|
||||
vertex 170 -172.5 85
|
||||
vertex 170 -172.5 5
|
||||
endloop
|
||||
endfacet
|
||||
facet normal 1 0 0
|
||||
outer loop
|
||||
vertex 170 172.5 85
|
||||
vertex 170 170 5
|
||||
vertex 170 172.5 5
|
||||
endloop
|
||||
endfacet
|
||||
facet normal 1 -0 0
|
||||
outer loop
|
||||
vertex 170 167.5 85
|
||||
vertex 170 170 5
|
||||
vertex 170 172.5 85
|
||||
endloop
|
||||
endfacet
|
||||
facet normal 1 0 0
|
||||
outer loop
|
||||
vertex 170 167.5 5
|
||||
vertex 170 170 5
|
||||
vertex 170 167.5 85
|
||||
endloop
|
||||
endfacet
|
||||
facet normal 1 0 0
|
||||
outer loop
|
||||
vertex 170 170 5
|
||||
vertex 170 167.5 5
|
||||
vertex 170 170 0
|
||||
endloop
|
||||
endfacet
|
||||
facet normal 1 -0 0
|
||||
outer loop
|
||||
vertex 170 165 5
|
||||
vertex 170 170 0
|
||||
vertex 170 167.5 5
|
||||
endloop
|
||||
endfacet
|
||||
facet normal 1 -0 0
|
||||
outer loop
|
||||
vertex 170 -165 5
|
||||
vertex 170 170 0
|
||||
vertex 170 165 5
|
||||
endloop
|
||||
endfacet
|
||||
facet normal 1 0 0
|
||||
outer loop
|
||||
vertex 170 -170 0
|
||||
vertex 170 -165 5
|
||||
vertex 170 -167.5 5
|
||||
endloop
|
||||
endfacet
|
||||
facet normal 1 0 0
|
||||
outer loop
|
||||
vertex 170 -170 0
|
||||
vertex 170 -167.5 5
|
||||
vertex 170 -170 5
|
||||
endloop
|
||||
endfacet
|
||||
facet normal 1 0 0
|
||||
outer loop
|
||||
vertex 170 -165 5
|
||||
vertex 170 -170 0
|
||||
vertex 170 170 0
|
||||
endloop
|
||||
endfacet
|
||||
facet normal 0 1 -0
|
||||
outer loop
|
||||
vertex 170 170 0
|
||||
vertex -170 170 5
|
||||
vertex 170 170 5
|
||||
endloop
|
||||
endfacet
|
||||
facet normal 0 1 0
|
||||
outer loop
|
||||
vertex -170 170 5
|
||||
vertex 170 170 0
|
||||
vertex -170 170 0
|
||||
endloop
|
||||
endfacet
|
||||
facet normal 0 0 -1
|
||||
outer loop
|
||||
vertex -170 -170 0
|
||||
vertex 170 170 0
|
||||
vertex 170 -170 0
|
||||
endloop
|
||||
endfacet
|
||||
facet normal -0 0 -1
|
||||
outer loop
|
||||
vertex 170 170 0
|
||||
vertex -170 -170 0
|
||||
vertex -170 170 0
|
||||
endloop
|
||||
endfacet
|
||||
facet normal 0 -1 0
|
||||
outer loop
|
||||
vertex -170 -170 0
|
||||
vertex 170 -170 5
|
||||
vertex -170 -170 5
|
||||
endloop
|
||||
endfacet
|
||||
facet normal 0 -1 -0
|
||||
outer loop
|
||||
vertex 170 -170 5
|
||||
vertex -170 -170 0
|
||||
vertex 170 -170 0
|
||||
endloop
|
||||
endfacet
|
||||
facet normal 0 -1 0
|
||||
outer loop
|
||||
vertex -170 -172.5 5
|
||||
vertex 170 -172.5 85
|
||||
vertex -170 -172.5 85
|
||||
endloop
|
||||
endfacet
|
||||
facet normal 0 -1 -0
|
||||
outer loop
|
||||
vertex 170 -172.5 85
|
||||
vertex -170 -172.5 5
|
||||
vertex 170 -172.5 5
|
||||
endloop
|
||||
endfacet
|
||||
facet normal 0 1 -0
|
||||
outer loop
|
||||
vertex -4 -167.5 5
|
||||
vertex -170 -167.5 85
|
||||
vertex -4 -167.5 85
|
||||
endloop
|
||||
endfacet
|
||||
facet normal 0 1 0
|
||||
outer loop
|
||||
vertex -170 -167.5 85
|
||||
vertex -4 -167.5 5
|
||||
vertex -170 -167.5 5
|
||||
endloop
|
||||
endfacet
|
||||
facet normal 0 1 -0
|
||||
outer loop
|
||||
vertex 170 -167.5 5
|
||||
vertex 4 -167.5 85
|
||||
vertex 170 -167.5 85
|
||||
endloop
|
||||
endfacet
|
||||
facet normal 0 1 0
|
||||
outer loop
|
||||
vertex 4 -167.5 85
|
||||
vertex 170 -167.5 5
|
||||
vertex 4 -167.5 5
|
||||
endloop
|
||||
endfacet
|
||||
facet normal 0 1 -0
|
||||
outer loop
|
||||
vertex 170 172.5 5
|
||||
vertex -170 172.5 85
|
||||
vertex 170 172.5 85
|
||||
endloop
|
||||
endfacet
|
||||
facet normal 0 1 0
|
||||
outer loop
|
||||
vertex -170 172.5 85
|
||||
vertex 170 172.5 5
|
||||
vertex -170 172.5 5
|
||||
endloop
|
||||
endfacet
|
||||
facet normal 0 -1 0
|
||||
outer loop
|
||||
vertex -170 167.5 5
|
||||
vertex -4 167.5 85
|
||||
vertex -170 167.5 85
|
||||
endloop
|
||||
endfacet
|
||||
facet normal 0 -1 -0
|
||||
outer loop
|
||||
vertex -4 167.5 85
|
||||
vertex -170 167.5 5
|
||||
vertex -4 167.5 5
|
||||
endloop
|
||||
endfacet
|
||||
facet normal 0 -1 0
|
||||
outer loop
|
||||
vertex 4 167.5 5
|
||||
vertex 170 167.5 85
|
||||
vertex 4 167.5 85
|
||||
endloop
|
||||
endfacet
|
||||
facet normal 0 -1 -0
|
||||
outer loop
|
||||
vertex 170 167.5 85
|
||||
vertex 4 167.5 5
|
||||
vertex 170 167.5 5
|
||||
endloop
|
||||
endfacet
|
||||
facet normal 1 -0 0
|
||||
outer loop
|
||||
vertex -167.5 -165 85
|
||||
vertex -167.5 -4 5
|
||||
vertex -167.5 -4 85
|
||||
endloop
|
||||
endfacet
|
||||
facet normal 1 0 0
|
||||
outer loop
|
||||
vertex -167.5 -4 5
|
||||
vertex -167.5 -165 85
|
||||
vertex -167.5 -165 5
|
||||
endloop
|
||||
endfacet
|
||||
facet normal 1 -0 0
|
||||
outer loop
|
||||
vertex -167.5 4 85
|
||||
vertex -167.5 165 5
|
||||
vertex -167.5 165 85
|
||||
endloop
|
||||
endfacet
|
||||
facet normal 1 0 0
|
||||
outer loop
|
||||
vertex -167.5 165 5
|
||||
vertex -167.5 4 85
|
||||
vertex -167.5 4 5
|
||||
endloop
|
||||
endfacet
|
||||
facet normal 0 -1 0
|
||||
outer loop
|
||||
vertex -170 -165 5
|
||||
vertex -172.5 -165 85
|
||||
vertex -172.5 -165 5
|
||||
endloop
|
||||
endfacet
|
||||
facet normal 0 -1 0
|
||||
outer loop
|
||||
vertex -172.5 -165 85
|
||||
vertex -170 -165 5
|
||||
vertex -167.5 -165 85
|
||||
endloop
|
||||
endfacet
|
||||
facet normal 0 -1 -0
|
||||
outer loop
|
||||
vertex -167.5 -165 85
|
||||
vertex -170 -165 5
|
||||
vertex -167.5 -165 5
|
||||
endloop
|
||||
endfacet
|
||||
facet normal -1 0 0
|
||||
outer loop
|
||||
vertex -172.5 -165 5
|
||||
vertex -172.5 165 85
|
||||
vertex -172.5 165 5
|
||||
endloop
|
||||
endfacet
|
||||
facet normal -1 -0 0
|
||||
outer loop
|
||||
vertex -172.5 165 85
|
||||
vertex -172.5 -165 5
|
||||
vertex -172.5 -165 85
|
||||
endloop
|
||||
endfacet
|
||||
facet normal 0 1 0
|
||||
outer loop
|
||||
vertex -170 165 5
|
||||
vertex -167.5 165 85
|
||||
vertex -167.5 165 5
|
||||
endloop
|
||||
endfacet
|
||||
facet normal 0 1 0
|
||||
outer loop
|
||||
vertex -167.5 165 85
|
||||
vertex -170 165 5
|
||||
vertex -172.5 165 85
|
||||
endloop
|
||||
endfacet
|
||||
facet normal 0 1 0
|
||||
outer loop
|
||||
vertex -172.5 165 85
|
||||
vertex -170 165 5
|
||||
vertex -172.5 165 5
|
||||
endloop
|
||||
endfacet
|
||||
facet normal -1 0 0
|
||||
outer loop
|
||||
vertex 167.5 -165 5
|
||||
vertex 167.5 -4 85
|
||||
vertex 167.5 -4 5
|
||||
endloop
|
||||
endfacet
|
||||
facet normal -1 -0 0
|
||||
outer loop
|
||||
vertex 167.5 -4 85
|
||||
vertex 167.5 -165 5
|
||||
vertex 167.5 -165 85
|
||||
endloop
|
||||
endfacet
|
||||
facet normal -1 0 0
|
||||
outer loop
|
||||
vertex 167.5 4 5
|
||||
vertex 167.5 165 85
|
||||
vertex 167.5 165 5
|
||||
endloop
|
||||
endfacet
|
||||
facet normal -1 -0 0
|
||||
outer loop
|
||||
vertex 167.5 165 85
|
||||
vertex 167.5 4 5
|
||||
vertex 167.5 4 85
|
||||
endloop
|
||||
endfacet
|
||||
facet normal 0 1 0
|
||||
outer loop
|
||||
vertex 170 165 5
|
||||
vertex 172.5 165 85
|
||||
vertex 172.5 165 5
|
||||
endloop
|
||||
endfacet
|
||||
facet normal 0 1 0
|
||||
outer loop
|
||||
vertex 172.5 165 85
|
||||
vertex 170 165 5
|
||||
vertex 167.5 165 85
|
||||
endloop
|
||||
endfacet
|
||||
facet normal 0 1 0
|
||||
outer loop
|
||||
vertex 167.5 165 85
|
||||
vertex 170 165 5
|
||||
vertex 167.5 165 5
|
||||
endloop
|
||||
endfacet
|
||||
facet normal 1 -0 0
|
||||
outer loop
|
||||
vertex 172.5 -165 85
|
||||
vertex 172.5 165 5
|
||||
vertex 172.5 165 85
|
||||
endloop
|
||||
endfacet
|
||||
facet normal 1 0 0
|
||||
outer loop
|
||||
vertex 172.5 165 5
|
||||
vertex 172.5 -165 85
|
||||
vertex 172.5 -165 5
|
||||
endloop
|
||||
endfacet
|
||||
facet normal 0 -1 0
|
||||
outer loop
|
||||
vertex 170 -165 5
|
||||
vertex 167.5 -165 85
|
||||
vertex 167.5 -165 5
|
||||
endloop
|
||||
endfacet
|
||||
facet normal 0 -1 0
|
||||
outer loop
|
||||
vertex 167.5 -165 85
|
||||
vertex 170 -165 5
|
||||
vertex 172.5 -165 85
|
||||
endloop
|
||||
endfacet
|
||||
facet normal 0 -1 -0
|
||||
outer loop
|
||||
vertex 172.5 -165 85
|
||||
vertex 170 -165 5
|
||||
vertex 172.5 -165 5
|
||||
endloop
|
||||
endfacet
|
||||
endsolid OpenSCAD_Model
|
||||
@ -0,0 +1,214 @@
|
||||
0
|
||||
SECTION
|
||||
2
|
||||
BLOCKS
|
||||
0
|
||||
ENDSEC
|
||||
0
|
||||
SECTION
|
||||
2
|
||||
ENTITIES
|
||||
0
|
||||
LINE
|
||||
8
|
||||
0
|
||||
10
|
||||
-250
|
||||
20
|
||||
-250
|
||||
11
|
||||
250
|
||||
21
|
||||
-250
|
||||
0
|
||||
LINE
|
||||
8
|
||||
0
|
||||
10
|
||||
250
|
||||
20
|
||||
-250
|
||||
11
|
||||
250
|
||||
21
|
||||
250
|
||||
0
|
||||
LINE
|
||||
8
|
||||
0
|
||||
10
|
||||
250
|
||||
20
|
||||
250
|
||||
11
|
||||
-250
|
||||
21
|
||||
250
|
||||
0
|
||||
LINE
|
||||
8
|
||||
0
|
||||
10
|
||||
-250
|
||||
20
|
||||
250
|
||||
11
|
||||
-250
|
||||
21
|
||||
-250
|
||||
0
|
||||
LINE
|
||||
8
|
||||
0
|
||||
10
|
||||
-165
|
||||
20
|
||||
-4
|
||||
11
|
||||
-165
|
||||
21
|
||||
4
|
||||
0
|
||||
LINE
|
||||
8
|
||||
0
|
||||
10
|
||||
-165
|
||||
20
|
||||
4
|
||||
11
|
||||
-4
|
||||
21
|
||||
4
|
||||
0
|
||||
LINE
|
||||
8
|
||||
0
|
||||
10
|
||||
-4
|
||||
20
|
||||
4
|
||||
11
|
||||
-4
|
||||
21
|
||||
165
|
||||
0
|
||||
LINE
|
||||
8
|
||||
0
|
||||
10
|
||||
-4
|
||||
20
|
||||
165
|
||||
11
|
||||
4
|
||||
21
|
||||
165
|
||||
0
|
||||
LINE
|
||||
8
|
||||
0
|
||||
10
|
||||
4
|
||||
20
|
||||
165
|
||||
11
|
||||
4
|
||||
21
|
||||
4
|
||||
0
|
||||
LINE
|
||||
8
|
||||
0
|
||||
10
|
||||
4
|
||||
20
|
||||
4
|
||||
11
|
||||
165
|
||||
21
|
||||
4
|
||||
0
|
||||
LINE
|
||||
8
|
||||
0
|
||||
10
|
||||
165
|
||||
20
|
||||
4
|
||||
11
|
||||
165
|
||||
21
|
||||
-4
|
||||
0
|
||||
LINE
|
||||
8
|
||||
0
|
||||
10
|
||||
165
|
||||
20
|
||||
-4
|
||||
11
|
||||
4
|
||||
21
|
||||
-4
|
||||
0
|
||||
LINE
|
||||
8
|
||||
0
|
||||
10
|
||||
4
|
||||
20
|
||||
-4
|
||||
11
|
||||
4
|
||||
21
|
||||
-165
|
||||
0
|
||||
LINE
|
||||
8
|
||||
0
|
||||
10
|
||||
4
|
||||
20
|
||||
-165
|
||||
11
|
||||
-4
|
||||
21
|
||||
-165
|
||||
0
|
||||
LINE
|
||||
8
|
||||
0
|
||||
10
|
||||
-4
|
||||
20
|
||||
-165
|
||||
11
|
||||
-4
|
||||
21
|
||||
-4
|
||||
0
|
||||
LINE
|
||||
8
|
||||
0
|
||||
10
|
||||
-4
|
||||
20
|
||||
-4
|
||||
11
|
||||
-165
|
||||
21
|
||||
-4
|
||||
0
|
||||
ENDSEC
|
||||
0
|
||||
SECTION
|
||||
2
|
||||
OBJECTS
|
||||
0
|
||||
DICTIONARY
|
||||
0
|
||||
ENDSEC
|
||||
0
|
||||
EOF
|
||||
101
products/poly-mech/cad/drawers/tools/calculate_cuts.py
Normal file
101
products/poly-mech/cad/drawers/tools/calculate_cuts.py
Normal file
@ -0,0 +1,101 @@
|
||||
import argparse
|
||||
|
||||
def generate_cut_plan(total_width, total_length, height, base_thickness, total_thickness, slot_width, u_boxes, v_boxes):
|
||||
"""
|
||||
Calculates and prints a markdown cut plan for the operator.
|
||||
"""
|
||||
|
||||
# --- Calculations ---
|
||||
inner_width = total_width - 2 * height
|
||||
inner_length = total_length - 2 * height
|
||||
groove_depth = total_thickness - base_thickness
|
||||
|
||||
# --- Collect all cut positions ---
|
||||
vertical_cuts = []
|
||||
if u_boxes > 1:
|
||||
compartment_width = (inner_width - (u_boxes - 1) * slot_width) / u_boxes
|
||||
for i in range(1, u_boxes):
|
||||
pos = height + (i * compartment_width) + (i * slot_width)
|
||||
vertical_cuts.append(pos)
|
||||
vertical_cuts.extend([height, total_width - height])
|
||||
|
||||
horizontal_cuts = []
|
||||
if v_boxes > 1:
|
||||
compartment_length = (inner_length - (v_boxes - 1) * slot_width) / v_boxes
|
||||
for i in range(1, v_boxes):
|
||||
pos = height + (i * compartment_length) + (i * slot_width)
|
||||
horizontal_cuts.append(pos)
|
||||
horizontal_cuts.extend([height, total_length - height])
|
||||
|
||||
# --- Markdown Output ---
|
||||
print("# Saw Operator Cut Plan")
|
||||
print(f"## Board Dimensions: `{total_width} x {total_length} mm`")
|
||||
print("")
|
||||
print("## Specifications")
|
||||
print(f"* **V-Groove Spec:** Depth `{groove_depth:.2f} mm`")
|
||||
print(f"* **Slot Spec:** Width `{slot_width} mm`, Depth `{groove_depth:.2f} mm`")
|
||||
print("")
|
||||
print("## Blade Setup")
|
||||
print("* **For V-Grooves:** Set saw blade angle to **45 degrees**.")
|
||||
print("* **For Slots:** Set saw blade angle to **0 degrees** (straight up).")
|
||||
print("")
|
||||
|
||||
# --- Setup 1: Vertical Cuts ---
|
||||
print("## SETUP 1: VERTICAL CUTS")
|
||||
print("### 1. Reference from LEFT edge:")
|
||||
left_cuts = sorted([dist for dist in vertical_cuts if dist <= total_width / 2])
|
||||
for dist in left_cuts:
|
||||
cut_type = "V-GROOVE" if dist == height else "SLOT"
|
||||
print(f"* Set fence to: `{dist:.2f} mm` -- for **{cut_type}**")
|
||||
|
||||
print("### 2. Reference from RIGHT edge (FLIP board 180 deg):")
|
||||
right_cuts = sorted([total_width - dist for dist in vertical_cuts if dist > total_width / 2])
|
||||
for dist in right_cuts:
|
||||
abs_pos = total_width - dist
|
||||
cut_type = "V-GROOVE" if abs_pos == (total_width - height) else "SLOT"
|
||||
print(f"* Set fence to: `{dist:.2f} mm` -- for **{cut_type}**")
|
||||
print("")
|
||||
|
||||
# --- Setup 2: Horizontal Cuts ---
|
||||
print("## SETUP 2: HORIZONTAL CUTS")
|
||||
print("### 1. Rotate board 90 degrees CCW, reference from NEW LEFT edge (original BOTTOM edge):")
|
||||
bottom_cuts = sorted([dist for dist in horizontal_cuts if dist <= total_length / 2])
|
||||
for dist in bottom_cuts:
|
||||
cut_type = "V-GROOVE" if dist == height else "SLOT"
|
||||
print(f"* Set fence to: `{dist:.2f} mm` -- for **{cut_type}**")
|
||||
|
||||
print("### 2. Reference from NEW RIGHT edge (original TOP edge, FLIP board 180 deg):")
|
||||
top_cuts = sorted([total_length - dist for dist in horizontal_cuts if dist > total_length / 2])
|
||||
for dist in top_cuts:
|
||||
abs_pos = total_length - dist
|
||||
cut_type = "V-GROOVE" if abs_pos == (total_length - height) else "SLOT"
|
||||
print(f"* Set fence to: `{dist:.2f} mm` -- for **{cut_type}**")
|
||||
|
||||
print("")
|
||||
print("---")
|
||||
print("*End of Plan*")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = argparse.ArgumentParser(description="Generate a cut plan for the poly-mech box.")
|
||||
parser.add_argument('--total-width', type=float, default=500, help='Total width of the board')
|
||||
parser.add_argument('--total-length', type=float, default=500, help='Total length of the board')
|
||||
parser.add_argument('--height', type=float, default=80, help='Height of the box walls')
|
||||
parser.add_argument('--base-thickness', type=float, default=3, help='Remaining thickness after V-groove')
|
||||
parser.add_argument('--total-thickness', type=float, default=8, help='Total thickness of the material')
|
||||
parser.add_argument('--slot-width', type=float, default=8, help='Width of the slots for internal dividers')
|
||||
parser.add_argument('--u-boxes', type=int, default=2, help='Number of boxes along the width (U-axis)')
|
||||
parser.add_argument('--v-boxes', type=int, default=2, help='Number of boxes along the length (V-axis)')
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
generate_cut_plan(
|
||||
args.total_width,
|
||||
args.total_length,
|
||||
args.height,
|
||||
args.base_thickness,
|
||||
args.total_thickness,
|
||||
args.slot_width,
|
||||
args.u_boxes,
|
||||
args.v_boxes
|
||||
)
|
||||
82
products/poly-mech/cad/drawers/tools/converter.py
Normal file
82
products/poly-mech/cad/drawers/tools/converter.py
Normal file
@ -0,0 +1,82 @@
|
||||
# converter.py
|
||||
# A Python script for use with FreeCAD's command-line interface.
|
||||
# Converts a mesh file (like STL) into a solid model and exports it to STEP.
|
||||
|
||||
import sys
|
||||
import FreeCAD
|
||||
import Part
|
||||
import Mesh
|
||||
|
||||
# --- Argument Validation ---
|
||||
# The script name is sys.argv[0], followed by FreeCAD's internal args.
|
||||
# The actual script arguments start after that. We expect two: input and output files.
|
||||
# FreeCAD adds its own arguments, so we find our files at the end of the list.
|
||||
if len(sys.argv) < 3:
|
||||
print("Converter script usage: <input_file> <output_file>")
|
||||
sys.exit(1)
|
||||
|
||||
input_file_path = sys.argv[-2]
|
||||
output_file_path = sys.argv[-1]
|
||||
|
||||
print(f"Input file: {input_file_path}")
|
||||
print(f"Output file: {output_file_path}")
|
||||
|
||||
# --- Conversion Logic ---
|
||||
try:
|
||||
# 1. Load the mesh from the input STL file
|
||||
mesh = Mesh.read(input_file_path)
|
||||
|
||||
# 2. Split the mesh into its separate, unconnected components (shells)
|
||||
components = mesh.getSeparateComponents()
|
||||
print(f"Found {len(components)} separate components in the mesh.")
|
||||
|
||||
# 3. Convert each component mesh into a solid shape
|
||||
solids = []
|
||||
for i, component_mesh in enumerate(components):
|
||||
try:
|
||||
# Create a shape from the mesh component
|
||||
shape = Part.Shape()
|
||||
shape.makeShapeFromMesh(component_mesh.Topology, 0.1)
|
||||
|
||||
# Use a more robust method to ensure the shape is a solid
|
||||
# This can fix minor issues and is more reliable than direct conversion.
|
||||
if not shape.isNull() and shape.Faces:
|
||||
solid = Part.Solid(Part.Shell(shape.Faces))
|
||||
if solid.Volume > 0:
|
||||
solids.append(solid)
|
||||
else:
|
||||
# If creating a solid fails, try refining it first.
|
||||
refined_shape = shape.removeSplitter()
|
||||
if not refined_shape.isNull() and refined_shape.Faces:
|
||||
solid = Part.Solid(Part.Shell(refined_shape.Faces))
|
||||
if solid.Volume > 0:
|
||||
solids.append(solid)
|
||||
else:
|
||||
print(f"Warning: Component {i+1} could not be converted to a solid after refining.")
|
||||
else:
|
||||
print(f"Warning: Component {i+1} became null after refining.")
|
||||
else:
|
||||
print(f"Warning: Component {i+1} could not be converted to a shape.")
|
||||
|
||||
except Exception as ex:
|
||||
print(f"Warning: An exception occurred while processing component {i+1}: {ex}")
|
||||
|
||||
if not solids:
|
||||
print("Error: No valid solids could be created from the mesh.")
|
||||
sys.exit(1)
|
||||
|
||||
# 4. Combine all solids into a single compound part for export
|
||||
if len(solids) > 1:
|
||||
result_shape = Part.Compound(solids)
|
||||
else:
|
||||
result_shape = solids[0]
|
||||
|
||||
# 5. Export the final shape to a STEP file
|
||||
result_shape.exportStep(output_file_path)
|
||||
|
||||
print("STEP export completed successfully.")
|
||||
sys.exit(0)
|
||||
|
||||
except Exception as e:
|
||||
print(f"An error occurred during FreeCAD conversion: {e}")
|
||||
sys.exit(1)
|
||||
41
products/poly-mech/cad/drawers/tools/export_dxf.sh
Normal file
41
products/poly-mech/cad/drawers/tools/export_dxf.sh
Normal file
@ -0,0 +1,41 @@
|
||||
#!/bin/bash
|
||||
|
||||
# --- export_dxf.sh ---
|
||||
# Exports a 2D projection of an OpenSCAD file to a DXF file.
|
||||
#
|
||||
# Usage: ./export_dxf.sh <source.scad> [output.dxf]
|
||||
#
|
||||
# Arguments:
|
||||
# $1: source_file - Input .scad file (Required)
|
||||
# $2: output_file - Output .dxf file (Optional)
|
||||
|
||||
# --- Input Validation ---
|
||||
if [ -z "$1" ]; then
|
||||
echo "Usage: $0 <source.scad> [output.dxf]"
|
||||
echo "Error: Source file not specified."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# --- Argument Parsing ---
|
||||
SOURCE_FILE="$1"
|
||||
OUTPUT_FILE="$2"
|
||||
|
||||
# --- Set Default Output Filename ---
|
||||
if [ -z "$OUTPUT_FILE" ]; then
|
||||
OUTPUT_FILE="${SOURCE_FILE%.scad}_unfolded.dxf"
|
||||
fi
|
||||
|
||||
# --- OpenSCAD DXF Export Command ---
|
||||
echo "Exporting 2D projection from '$SOURCE_FILE' to '$OUTPUT_FILE'..."
|
||||
openscad \
|
||||
-o "$OUTPUT_FILE" \
|
||||
-D "view_mode=\"dxf\"" \
|
||||
"$SOURCE_FILE"
|
||||
|
||||
# --- Completion Message ---
|
||||
if [ $? -eq 0 ]; then
|
||||
echo "Export complete: '$OUTPUT_FILE' created successfully."
|
||||
else
|
||||
echo "Error: OpenSCAD DXF export failed."
|
||||
exit 1
|
||||
fi
|
||||
44
products/poly-mech/cad/drawers/tools/export_freecad.sh
Normal file
44
products/poly-mech/cad/drawers/tools/export_freecad.sh
Normal file
@ -0,0 +1,44 @@
|
||||
#!/bin/bash
|
||||
|
||||
# --- export_freecad.sh ---
|
||||
# Imports an OpenSCAD file into FreeCAD and saves it as a .FCStd project.
|
||||
#
|
||||
# !! REQUIRES FREECAD & OPENSCAD WORKBENCH !!
|
||||
# This script depends on FreeCAD being installed, 'FreeCADCmd.exe'
|
||||
# being in your system's PATH, and the OpenSCAD workbench being installed
|
||||
# within FreeCAD.
|
||||
#
|
||||
# Usage: ./export_freecad.sh <source.scad> [output.FCStd]
|
||||
#
|
||||
# Arguments:
|
||||
# $1: source_file - Input .scad file (Required)
|
||||
# $2: output_file - Output .FCStd file (Optional)
|
||||
|
||||
# --- Input Validation ---
|
||||
if [ -z "$1" ]; then
|
||||
echo "Usage: $0 <source.scad> [output.FCStd]"
|
||||
echo "Error: Source file not specified."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# --- Argument Parsing ---
|
||||
SOURCE_FILE="$1"
|
||||
OUTPUT_FILE="$2"
|
||||
|
||||
# --- Set Default Output Filename ---
|
||||
if [ -z "$OUTPUT_FILE" ]; then
|
||||
OUTPUT_FILE="${SOURCE_FILE%.scad}.FCStd"
|
||||
fi
|
||||
|
||||
# --- Step 1: Import .scad and save as .FCStd using FreeCAD ---
|
||||
echo "Importing '$SOURCE_FILE' and creating '$OUTPUT_FILE' using FreeCAD..."
|
||||
# Note: Assuming FreeCADCmd.exe for Windows. Use 'freecadcmd' on Linux.
|
||||
FreeCADCmd.exe -c save_fcstd.py "$SOURCE_FILE" "$OUTPUT_FILE"
|
||||
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Error: FreeCAD project creation failed. Is FreeCAD and the OpenSCAD workbench installed and in your PATH?"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# --- Completion Message ---
|
||||
echo "Export complete: '$OUTPUT_FILE' created successfully."
|
||||
66
products/poly-mech/cad/drawers/tools/export_step.sh
Normal file
66
products/poly-mech/cad/drawers/tools/export_step.sh
Normal file
@ -0,0 +1,66 @@
|
||||
#!/bin/bash
|
||||
|
||||
# --- export_step.sh ---
|
||||
# Converts an OpenSCAD file to a STEP file using FreeCAD.
|
||||
#
|
||||
# !! REQUIRES FREECAD !!
|
||||
# This script depends on FreeCAD being installed and 'FreeCADCmd.exe'
|
||||
# being available in your system's PATH.
|
||||
#
|
||||
# Usage: ./export_step.sh <source.scad> [output.step]
|
||||
#
|
||||
# Arguments:
|
||||
# $1: source_file - Input .scad file (Required)
|
||||
# $2: output_file - Output .step file (Optional)
|
||||
|
||||
# --- Input Validation ---
|
||||
if [ -z "$1" ]; then
|
||||
echo "Usage: $0 <source.scad> [output.step]"
|
||||
echo "Error: Source file not specified."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# --- Argument Parsing ---
|
||||
SOURCE_FILE="$1"
|
||||
OUTPUT_FILE="$2"
|
||||
|
||||
# --- Set Default Output Filename ---
|
||||
if [ -z "$OUTPUT_FILE" ]; then
|
||||
OUTPUT_FILE="${SOURCE_FILE%.scad}.step"
|
||||
fi
|
||||
|
||||
# --- Define Temporary STL file ---
|
||||
TEMP_STL_FILE="temp_conversion.stl"
|
||||
|
||||
# --- Step 1: Export from OpenSCAD to STL ---
|
||||
echo "Step 1/3: Exporting '$SOURCE_FILE' to STL using dedicated export layout..."
|
||||
openscad \
|
||||
-o "$TEMP_STL_FILE" \
|
||||
-D "view_mode=\"export\"" \
|
||||
"$SOURCE_FILE"
|
||||
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Error: OpenSCAD export failed."
|
||||
exit 1
|
||||
fi
|
||||
echo "STL export successful."
|
||||
|
||||
# --- Step 2: Convert STL to STEP using FreeCAD ---
|
||||
echo "Step 2/3: Converting '$TEMP_STL_FILE' to '$OUTPUT_FILE' using FreeCAD..."
|
||||
# Note: Assuming FreeCADCmd.exe for Windows. Use 'freecadcmd' on Linux.
|
||||
FreeCADCmd.exe -c converter.py "$TEMP_STL_FILE" "$OUTPUT_FILE"
|
||||
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Error: FreeCAD conversion failed. Is FreeCAD installed and in your PATH?"
|
||||
rm -f "$TEMP_STL_FILE" # Clean up temp file
|
||||
exit 1
|
||||
fi
|
||||
echo "STEP conversion successful."
|
||||
|
||||
# --- Step 3: Clean up temporary files ---
|
||||
echo "Step 3/3: Cleaning up temporary files..."
|
||||
rm -f "$TEMP_STL_FILE"
|
||||
echo "Done."
|
||||
|
||||
# --- Completion Message ---
|
||||
echo "Export complete: '$OUTPUT_FILE' created successfully."
|
||||
59
products/poly-mech/cad/drawers/tools/export_stl.sh
Normal file
59
products/poly-mech/cad/drawers/tools/export_stl.sh
Normal file
@ -0,0 +1,59 @@
|
||||
#!/bin/bash
|
||||
|
||||
# --- export_stl.sh ---
|
||||
# Exports an OpenSCAD file to an STL file.
|
||||
#
|
||||
# Usage: ./export_stl.sh <source.scad> [output.stl] [folded_state]
|
||||
#
|
||||
# Arguments:
|
||||
# $1: source_file - Input .scad file (Required)
|
||||
# $2: output_file - Output .stl file (Optional)
|
||||
# $3: folded_state - 'true' or 'false'. (Optional, defaults to 'true' for a solid model)
|
||||
|
||||
# --- Input Validation ---
|
||||
if [ -z "$1" ]; then
|
||||
echo "Usage: $0 <source.scad> [output.stl] [folded_state]"
|
||||
echo "Error: Source file not specified."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# --- Argument Parsing ---
|
||||
SOURCE_FILE="$1"
|
||||
OUTPUT_FILE=""
|
||||
# Default to 'true' as we usually want to export the assembled solid model
|
||||
FOLDED_STATE="true"
|
||||
|
||||
# Case 1: All three arguments are provided
|
||||
if [ -n "$3" ]; then
|
||||
OUTPUT_FILE="$2"
|
||||
FOLDED_STATE="$3"
|
||||
# Case 2: Only two arguments are provided
|
||||
elif [ -n "$2" ]; then
|
||||
# Check if the second argument is the folded state or a filename
|
||||
if [[ "$2" == "true" || "$2" == "false" ]]; then
|
||||
FOLDED_STATE="$2"
|
||||
else
|
||||
OUTPUT_FILE="$2"
|
||||
fi
|
||||
fi
|
||||
|
||||
# --- Set Default Output Filename ---
|
||||
if [ -z "$OUTPUT_FILE" ]; then
|
||||
OUTPUT_FILE="${SOURCE_FILE%.scad}_${FOLDED_STATE}.stl"
|
||||
fi
|
||||
|
||||
# --- OpenSCAD Export Command ---
|
||||
# -D: Overrides a variable in the OpenSCAD script.
|
||||
echo "Exporting '$SOURCE_FILE' to '$OUTPUT_FILE' with Folded_View=$FOLDED_STATE..."
|
||||
openscad \
|
||||
-o "$OUTPUT_FILE" \
|
||||
-D "Folded_View=$FOLDED_STATE" \
|
||||
"$SOURCE_FILE"
|
||||
|
||||
# --- Completion Message ---
|
||||
if [ $? -eq 0 ]; then
|
||||
echo "Export complete: '$OUTPUT_FILE' created successfully."
|
||||
else
|
||||
echo "Error: OpenSCAD export failed."
|
||||
exit 1
|
||||
fi
|
||||
BIN
products/poly-mech/cad/drawers/tools/folded_view.png
(Stored with Git LFS)
Normal file
BIN
products/poly-mech/cad/drawers/tools/folded_view.png
(Stored with Git LFS)
Normal file
Binary file not shown.
@ -0,0 +1,187 @@
|
||||
# freecad_box_generator.py
|
||||
#
|
||||
# A Python script to generate a parametric box natively in FreeCAD.
|
||||
#
|
||||
# --- How to use (GUI) ---
|
||||
# 1. Open FreeCAD and ensure you have a new, empty document open.
|
||||
# 2. Paste this script into the Python console and press Enter.
|
||||
#
|
||||
# --- How to use (Command Line) ---
|
||||
# FreeCADCmd.exe freecad_box_generator.py [output_file.FCStd]
|
||||
|
||||
import FreeCAD
|
||||
import Part
|
||||
import sys
|
||||
|
||||
# --- Customizable Parameters ---
|
||||
# (Mirrors the parameters from the OpenSCAD file)
|
||||
|
||||
# Overall dimensions
|
||||
TOTAL_WIDTH = 500
|
||||
TOTAL_LENGTH = 500
|
||||
BOX_HEIGHT = 80
|
||||
|
||||
# Material and slot properties
|
||||
WALL_THICKNESS = 8
|
||||
|
||||
# Internal grid configuration
|
||||
NUM_BOXES_U = 2 # Along X-axis (width)
|
||||
NUM_BOXES_V = 2 # Along Y-axis (length)
|
||||
|
||||
|
||||
def create_box_assembly(doc):
|
||||
"""
|
||||
Generates the box assembly as native FreeCAD objects in the specified document.
|
||||
This function does not save the file.
|
||||
"""
|
||||
|
||||
# --- Create a Group for organization ---
|
||||
box_group = doc.addObject("App::DocumentObjectGroup", "BoxAssembly")
|
||||
|
||||
# --- Create the Base Plate ---
|
||||
base = Part.makeBox(TOTAL_WIDTH, TOTAL_LENGTH, WALL_THICKNESS)
|
||||
base_obj = doc.addObject("Part::Feature", "Base")
|
||||
base_obj.Shape = base
|
||||
box_group.addObject(base_obj)
|
||||
|
||||
# --- Calculate Inner Dimensions ---
|
||||
inner_width = TOTAL_WIDTH - (2 * WALL_THICKNESS)
|
||||
inner_length = TOTAL_LENGTH - (2 * WALL_THICKNESS)
|
||||
|
||||
# --- Create Outer Walls ---
|
||||
# South Wall (along the front X-axis)
|
||||
wall_south = Part.makeBox(TOTAL_WIDTH, WALL_THICKNESS, BOX_HEIGHT)
|
||||
wall_south.translate(FreeCAD.Vector(0, 0, WALL_THICKNESS)) # Position it on top of the base
|
||||
wall_south_obj = doc.addObject("Part::Feature", "Wall_South")
|
||||
wall_south_obj.Shape = wall_south
|
||||
box_group.addObject(wall_south_obj)
|
||||
|
||||
# North Wall (along the back X-axis)
|
||||
wall_north = Part.makeBox(TOTAL_WIDTH, WALL_THICKNESS, BOX_HEIGHT)
|
||||
wall_north.translate(FreeCAD.Vector(0, TOTAL_LENGTH - WALL_THICKNESS, WALL_THICKNESS))
|
||||
wall_north_obj = doc.addObject("Part::Feature", "Wall_North")
|
||||
wall_north_obj.Shape = wall_north
|
||||
box_group.addObject(wall_north_obj)
|
||||
|
||||
# West Wall (along the left Y-axis, fits between N/S walls)
|
||||
wall_west = Part.makeBox(WALL_THICKNESS, inner_length, BOX_HEIGHT)
|
||||
wall_west.translate(FreeCAD.Vector(0, WALL_THICKNESS, WALL_THICKNESS))
|
||||
wall_west_obj = doc.addObject("Part::Feature", "Wall_West")
|
||||
wall_west_obj.Shape = wall_west
|
||||
box_group.addObject(wall_west_obj)
|
||||
|
||||
# East Wall (along the right Y-axis, fits between N/S walls)
|
||||
wall_east = Part.makeBox(WALL_THICKNESS, inner_length, BOX_HEIGHT)
|
||||
wall_east.translate(FreeCAD.Vector(TOTAL_WIDTH - WALL_THICKNESS, WALL_THICKNESS, WALL_THICKNESS))
|
||||
wall_east_obj = doc.addObject("Part::Feature", "Wall_East")
|
||||
wall_east_obj.Shape = wall_east
|
||||
box_group.addObject(wall_east_obj)
|
||||
|
||||
# --- Create Internal Dividers ---
|
||||
if NUM_BOXES_U > 1:
|
||||
# --- Vertical Dividers (along Y-axis) ---
|
||||
compartment_width = inner_width / NUM_BOXES_U
|
||||
for i in range(1, NUM_BOXES_U):
|
||||
# Create the main body of the divider
|
||||
x_pos = (i * compartment_width)
|
||||
divider_v_body = Part.makeBox(WALL_THICKNESS, inner_length, BOX_HEIGHT)
|
||||
|
||||
# --- Create Notches for Horizontal Dividers (top-down) ---
|
||||
if NUM_BOXES_V > 1:
|
||||
# Create all notch cutting tools first
|
||||
notch_tools = []
|
||||
notch_cutout = Part.makeBox(WALL_THICKNESS, WALL_THICKNESS, BOX_HEIGHT / 2)
|
||||
for j in range(1, NUM_BOXES_V):
|
||||
compartment_length = inner_length / NUM_BOXES_V
|
||||
y_pos = (j * compartment_length) - (WALL_THICKNESS / 2)
|
||||
notch_tools.append(notch_cutout.translated(FreeCAD.Vector(0, y_pos, BOX_HEIGHT / 2)))
|
||||
# Fuse them into a single cutting tool
|
||||
cutting_compound = Part.makeCompound(notch_tools)
|
||||
# Perform a single, efficient cut
|
||||
divider_v_body = divider_v_body.cut(cutting_compound)
|
||||
|
||||
# Position the final divider and add to document
|
||||
divider_v_body.translate(FreeCAD.Vector(x_pos, WALL_THICKNESS, WALL_THICKNESS))
|
||||
divider_v_obj = doc.addObject("Part::Feature", f"Divider_V_{i}")
|
||||
divider_v_obj.Shape = divider_v_body
|
||||
box_group.addObject(divider_v_obj)
|
||||
|
||||
if NUM_BOXES_V > 1:
|
||||
# --- Horizontal Dividers (along X-axis) ---
|
||||
compartment_length = inner_length / NUM_BOXES_V
|
||||
for i in range(1, NUM_BOXES_V):
|
||||
# Create the main body of the divider
|
||||
y_pos = (i * compartment_length)
|
||||
divider_h_body = Part.makeBox(inner_width, WALL_THICKNESS, BOX_HEIGHT)
|
||||
|
||||
# --- Create Notches for Vertical Dividers (bottom-up) ---
|
||||
if NUM_BOXES_U > 1:
|
||||
# Create all notch cutting tools first
|
||||
notch_tools = []
|
||||
notch_cutout = Part.makeBox(WALL_THICKNESS, WALL_THICKNESS, BOX_HEIGHT / 2)
|
||||
for j in range(1, NUM_BOXES_U):
|
||||
compartment_width = inner_width / NUM_BOXES_U
|
||||
x_pos = (j * compartment_width) - (WALL_THICKNESS / 2)
|
||||
notch_tools.append(notch_cutout.translated(FreeCAD.Vector(x_pos, 0, 0)))
|
||||
# Fuse them into a single cutting tool
|
||||
cutting_compound = Part.makeCompound(notch_tools)
|
||||
# Perform a single, efficient cut
|
||||
divider_h_body = divider_h_body.cut(cutting_compound)
|
||||
|
||||
# Position the final divider and add to document
|
||||
divider_h_body.translate(FreeCAD.Vector(WALL_THICKNESS, y_pos, WALL_THICKNESS))
|
||||
divider_h_obj = doc.addObject("Part::Feature", f"Divider_H_{i}")
|
||||
divider_h_obj.Shape = divider_h_body
|
||||
box_group.addObject(divider_h_obj)
|
||||
|
||||
# --- Finalize ---
|
||||
doc.recompute()
|
||||
print("Box assembly generated.")
|
||||
|
||||
|
||||
def main_cli():
|
||||
"""Function to run when script is executed from the command line."""
|
||||
output_file = "box.FCStd" # Default filename
|
||||
|
||||
# Look for the output file as a positional argument after the script name
|
||||
# This is a robust way to handle arguments when FreeCAD's parser is unpredictable.
|
||||
try:
|
||||
script_index = [i for i, arg in enumerate(sys.argv) if 'freecad_box_generator.py' in arg][0]
|
||||
if script_index + 1 < len(sys.argv):
|
||||
output_file = sys.argv[script_index + 1]
|
||||
except IndexError:
|
||||
# This case handles running the script directly without FreeCAD, for debugging.
|
||||
pass
|
||||
|
||||
doc = FreeCAD.newDocument("Box")
|
||||
create_box_assembly(doc)
|
||||
|
||||
try:
|
||||
doc.saveAs(output_file)
|
||||
print(f"Successfully saved box assembly to: {output_file}")
|
||||
except Exception as e:
|
||||
print(f"Error saving file: {e}")
|
||||
|
||||
FreeCAD.closeDocument(doc.Name)
|
||||
# Ensure the command-line application exits cleanly
|
||||
sys.exit()
|
||||
|
||||
def main_gui():
|
||||
"""Function to run when script is executed from the FreeCAD GUI."""
|
||||
doc = FreeCAD.activeDocument()
|
||||
if not doc:
|
||||
doc = FreeCAD.newDocument("Box")
|
||||
|
||||
create_box_assembly(doc)
|
||||
|
||||
if FreeCAD.GuiUp:
|
||||
FreeCAD.Gui.activeDocument().activeView().viewAxonometric()
|
||||
FreeCAD.Gui.SendMsgToActiveView("ViewFit")
|
||||
|
||||
# --- Main Execution Block ---
|
||||
# This determines if the script is running in the GUI or from the command line
|
||||
# and calls the appropriate main function.
|
||||
if FreeCAD.GuiUp:
|
||||
main_gui()
|
||||
else:
|
||||
main_cli()
|
||||
BIN
products/poly-mech/cad/drawers/tools/freecad/my_final_box.FCStd
Normal file
BIN
products/poly-mech/cad/drawers/tools/freecad/my_final_box.FCStd
Normal file
Binary file not shown.
@ -0,0 +1,31 @@
|
||||
#!/bin/bash
|
||||
|
||||
# --- run_freecad_generator.sh ---
|
||||
#
|
||||
# A wrapper script to correctly call the FreeCAD box generator from the command line.
|
||||
#
|
||||
# Usage: ./run_freecad_generator.sh <output_file.FCStd>
|
||||
|
||||
# --- Argument Validation ---
|
||||
if [ -z "$1" ]; then
|
||||
echo "Usage: $0 <output_file.FCStd>"
|
||||
echo "Error: Output file not specified."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
OUTPUT_FILE="$1"
|
||||
|
||||
# --- Execute FreeCAD ---
|
||||
# We pass the python script to the FreeCAD executable, followed by the
|
||||
# output filename as a simple positional argument.
|
||||
|
||||
echo "Executing FreeCAD generator script..."
|
||||
FreeCADCmd.exe -c freecad_box_generator.py "$OUTPUT_FILE"
|
||||
|
||||
if [ $? -ne 0 ]; then
|
||||
echo ""
|
||||
echo "Error: FreeCAD script execution failed."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Script executed successfully."
|
||||
41
products/poly-mech/cad/drawers/tools/freecad/save_fcstd.py
Normal file
41
products/poly-mech/cad/drawers/tools/freecad/save_fcstd.py
Normal file
@ -0,0 +1,41 @@
|
||||
# save_fcstd.py
|
||||
# A Python script for use with FreeCAD's command-line interface.
|
||||
# Imports an OpenSCAD file and saves it as a FreeCAD project.
|
||||
|
||||
import sys
|
||||
import FreeCAD
|
||||
import Part
|
||||
|
||||
# --- Argument Validation ---
|
||||
if len(sys.argv) < 3:
|
||||
print("Converter script usage: <input_file.scad> <output_file.FCStd>")
|
||||
sys.exit(1)
|
||||
|
||||
input_file_path = sys.argv[-2]
|
||||
output_file_path = sys.argv[-1]
|
||||
|
||||
print(f"Input file: {input_file_path}")
|
||||
print(f"Output file: {output_file_path}")
|
||||
|
||||
# --- Conversion Logic ---
|
||||
try:
|
||||
# 1. Create a new, empty FreeCAD document
|
||||
doc = FreeCAD.newDocument("ImportedSCAD")
|
||||
|
||||
# 2. Use the Part module to import the .scad file into the document.
|
||||
# This requires the OpenSCAD workbench to be installed in FreeCAD.
|
||||
# FreeCAD manages the call to the 'openscad' executable itself.
|
||||
Part.insert(input_file_path, doc.Name)
|
||||
|
||||
# 3. It's good practice to recompute the model after an import.
|
||||
doc.recompute()
|
||||
|
||||
# 4. Save the document to the specified output file path.
|
||||
doc.saveAs(output_file_path)
|
||||
|
||||
print("FreeCAD project file saved successfully.")
|
||||
sys.exit(0)
|
||||
|
||||
except Exception as e:
|
||||
print(f"An error occurred during FreeCAD project creation: {e}")
|
||||
sys.exit(1)
|
||||
52
products/poly-mech/cad/drawers/tools/generate_cut_plan.sh
Normal file
52
products/poly-mech/cad/drawers/tools/generate_cut_plan.sh
Normal file
@ -0,0 +1,52 @@
|
||||
#!/bin/bash
|
||||
|
||||
# --- generate_cut_plan.sh ---
|
||||
# Generates a markdown cut plan from an OpenSCAD file.
|
||||
# This script calls OpenSCAD in a special mode to echo the plan.
|
||||
#
|
||||
# Usage: ./generate_cut_plan.sh <source.scad> [output.md]
|
||||
# If output file is not provided, prints to console.
|
||||
|
||||
# --- Input Validation ---
|
||||
if [ -z "$1" ]; then
|
||||
echo "Usage: $0 <source.scad> [output.md]"
|
||||
echo "Error: Source file not specified."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
SOURCE_FILE="$1"
|
||||
OUTPUT_FILE="$2"
|
||||
DUMMY_OUTPUT="cutplan_dummy.stl" # A dummy file to force command-line execution
|
||||
|
||||
# --- OpenSCAD Command ---
|
||||
# We force a dummy output file with -o to prevent the GUI from launching.
|
||||
# OpenSCAD prints echo() statements to stderr. We redirect stderr to stdout (2>&1),
|
||||
# then use grep to filter for only the lines starting with "ECHO:",
|
||||
# and then use sed to remove the prefix and surrounding quotes for a clean output.
|
||||
CUTPLAN_CONTENT=$(openscad \
|
||||
-o "$DUMMY_OUTPUT" \
|
||||
-D "view_mode=\"cutplan\"" \
|
||||
"$SOURCE_FILE" \
|
||||
2>&1 | grep "ECHO:" | sed 's/ECHO: "//;s/"$//')
|
||||
|
||||
# Check the exit status of the openscad command.
|
||||
if [ ${PIPESTATUS[0]} -ne 0 ]; then
|
||||
echo ""
|
||||
echo "Error: OpenSCAD command failed."
|
||||
rm -f "$DUMMY_OUTPUT" # Clean up dummy file on failure
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Clean up the dummy file
|
||||
rm -f "$DUMMY_OUTPUT"
|
||||
|
||||
# --- Output the result ---
|
||||
if [ -z "$OUTPUT_FILE" ]; then
|
||||
echo ""
|
||||
echo "--- Generated Cut Plan (Markdown) ---"
|
||||
echo "$CUTPLAN_CONTENT"
|
||||
echo "-------------------------------------"
|
||||
else
|
||||
echo "$CUTPLAN_CONTENT" > "$OUTPUT_FILE"
|
||||
echo "Cut plan successfully saved to '$OUTPUT_FILE'."
|
||||
fi
|
||||
34
products/poly-mech/cad/drawers/tools/generate_cutlist.sh
Normal file
34
products/poly-mech/cad/drawers/tools/generate_cutlist.sh
Normal file
@ -0,0 +1,34 @@
|
||||
#!/bin/bash
|
||||
|
||||
# --- generate_cutlist.sh ---
|
||||
# Generates a markdown cut plan by calling an external Python script.
|
||||
# This bypasses a bug in some OpenSCAD versions that prevents the echo
|
||||
# module from functioning correctly.
|
||||
#
|
||||
# Usage: ./generate_cutlist.sh [output.md]
|
||||
# All parameters are taken from the defaults in the python script.
|
||||
# For custom dimensions, edit calculate_cuts.py or call it directly.
|
||||
|
||||
OUTPUT_FILE="$1"
|
||||
|
||||
# Run the python script to generate the markdown content.
|
||||
# The script can be modified to change box parameters.
|
||||
CUTLIST_CONTENT=$(python calculate_cuts.py)
|
||||
|
||||
# Check the exit status of the python script.
|
||||
if [ $? -ne 0 ]; then
|
||||
echo ""
|
||||
echo "Error: Python script 'calculate_cuts.py' failed."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# --- Output the result ---
|
||||
if [ -z "$OUTPUT_FILE" ]; then
|
||||
echo ""
|
||||
echo "--- Generated Cut Plan (Markdown) ---"
|
||||
echo "$CUTLIST_CONTENT"
|
||||
echo "-------------------------------------"
|
||||
else
|
||||
echo "$CUTLIST_CONTENT" > "$OUTPUT_FILE"
|
||||
echo "Cut plan successfully saved to '$OUTPUT_FILE'."
|
||||
fi
|
||||
BIN
products/poly-mech/cad/drawers/tools/reference/500-10.png
(Stored with Git LFS)
Normal file
BIN
products/poly-mech/cad/drawers/tools/reference/500-10.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
products/poly-mech/cad/drawers/tools/reference/variables.png
(Stored with Git LFS)
Normal file
BIN
products/poly-mech/cad/drawers/tools/reference/variables.png
(Stored with Git LFS)
Normal file
Binary file not shown.
64
products/poly-mech/cad/drawers/tools/render.sh
Normal file
64
products/poly-mech/cad/drawers/tools/render.sh
Normal file
@ -0,0 +1,64 @@
|
||||
#!/bin/bash
|
||||
|
||||
# --- render.sh ---
|
||||
# Renders an OpenSCAD file to a PNG image.
|
||||
#
|
||||
# Usage: ./render.sh <source_file.scad> [output_file.png] [folded_state]
|
||||
#
|
||||
# Arguments:
|
||||
# $1: source_file - The path to the input OpenSCAD file. (Required)
|
||||
# $2: output_file - The path for the output PNG image. (Optional)
|
||||
# $3: folded_state - 'true' or 'false' to control the Folded_View parameter.
|
||||
# (Optional, defaults to false)
|
||||
|
||||
# --- Input Validation ---
|
||||
if [ -z "$1" ]; then
|
||||
echo "Usage: $0 <source_file.scad> [output_file.png] [folded_state]"
|
||||
echo "Error: Source file not specified."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# --- Argument Parsing ---
|
||||
SOURCE_FILE="$1"
|
||||
OUTPUT_FILE=""
|
||||
FOLDED_STATE="false" # Default value
|
||||
|
||||
# Case 1: All three arguments are provided
|
||||
if [ -n "$3" ]; then
|
||||
OUTPUT_FILE="$2"
|
||||
FOLDED_STATE="$3"
|
||||
# Case 2: Only two arguments are provided
|
||||
elif [ -n "$2" ]; then
|
||||
# Check if the second argument is the folded state or a filename
|
||||
if [[ "$2" == "true" || "$2" == "false" ]]; then
|
||||
FOLDED_STATE="$2"
|
||||
else
|
||||
OUTPUT_FILE="$2"
|
||||
fi
|
||||
fi
|
||||
|
||||
# --- Set Default Output Filename ---
|
||||
if [ -z "$OUTPUT_FILE" ]; then
|
||||
# Removes the .scad extension and appends .png
|
||||
OUTPUT_FILE="${SOURCE_FILE%.scad}_${FOLDED_STATE}.png"
|
||||
fi
|
||||
|
||||
# --- OpenSCAD Render Command ---
|
||||
# --view=iso: Sets the camera to a standard isometric view.
|
||||
# --imgsize: Sets the output image resolution.
|
||||
# -D: Overrides a variable in the OpenSCAD script.
|
||||
echo "Rendering '$SOURCE_FILE' to '$OUTPUT_FILE' with Folded_View=$FOLDED_STATE..."
|
||||
openscad \
|
||||
-o "$OUTPUT_FILE" \
|
||||
--view=iso \
|
||||
--imgsize=1024,768 \
|
||||
-D "Folded_View=$FOLDED_STATE" \
|
||||
"$SOURCE_FILE"
|
||||
|
||||
# --- Completion Message ---
|
||||
if [ $? -eq 0 ]; then
|
||||
echo "Render complete: '$OUTPUT_FILE' created successfully."
|
||||
else
|
||||
echo "Error: OpenSCAD rendering failed."
|
||||
exit 1
|
||||
fi
|
||||
151
products/poly-mech/cad/drawers/tools/sw/box/Program.cs
Normal file
151
products/poly-mech/cad/drawers/tools/sw/box/Program.cs
Normal file
@ -0,0 +1,151 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using CommandLine;
|
||||
using SolidWorks.Interop.sldworks;
|
||||
using SolidWorks.Interop.swconst;
|
||||
|
||||
namespace SolidWorksBoxGenerator
|
||||
{
|
||||
// Class to hold the parsed command-line options
|
||||
public class Options
|
||||
{
|
||||
[Option('o', "output", Required = true, HelpText = "Absolute path for the output .SLDPRT file.")]
|
||||
public string OutputFile { get; set; }
|
||||
|
||||
[Option('w', "width", Default = 500.0, HelpText = "Total width of the box.")]
|
||||
public double Width { get; set; }
|
||||
|
||||
[Option('l', "length", Default = 500.0, HelpText = "Total length of the box.")]
|
||||
public double Length { get; set; }
|
||||
|
||||
[Option('h', "height", Default = 80.0, HelpText = "Height of the box walls.")]
|
||||
public double Height { get; set; }
|
||||
|
||||
[Option('t', "thickness", Default = 3.0, HelpText = "Sheet metal thickness.")]
|
||||
public double Thickness { get; set; }
|
||||
|
||||
[Option('r', "radius", Default = 1.0, HelpText = "Bend radius for sheet metal.")]
|
||||
public double Radius { get; set; }
|
||||
}
|
||||
|
||||
class Program
|
||||
{
|
||||
static void Main(string[] args)
|
||||
{
|
||||
Parser.Default.ParseArguments<Options>(args)
|
||||
.WithParsed<Options>(o =>
|
||||
{
|
||||
try
|
||||
{
|
||||
Console.WriteLine("Attempting to connect to SolidWorks...");
|
||||
SldWorks swApp = GetSldWorks();
|
||||
if (swApp == null)
|
||||
{
|
||||
Console.WriteLine("Could not connect to SolidWorks. Please ensure it is running.");
|
||||
return;
|
||||
}
|
||||
Console.WriteLine("Successfully connected to SolidWorks.");
|
||||
|
||||
GenerateBox(swApp, o);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Console.WriteLine($"An error occurred: {e.Message}");
|
||||
Console.WriteLine(e.StackTrace);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static SldWorks GetSldWorks()
|
||||
{
|
||||
// Connect to a running instance of SolidWorks
|
||||
try
|
||||
{
|
||||
return (SldWorks)Marshal.GetActiveObject("SldWorks.Application");
|
||||
}
|
||||
catch (COMException)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static void GenerateBox(SldWorks swApp, Options opts)
|
||||
{
|
||||
// Convert all measurements from mm to meters for SolidWorks
|
||||
double width = opts.Width / 1000.0;
|
||||
double length = opts.Length / 1000.0;
|
||||
double height = opts.Height / 1000.0;
|
||||
double thickness = opts.Thickness / 1000.0;
|
||||
double radius = opts.Radius / 1000.0;
|
||||
|
||||
// --- Step 1: Create a New Part Document ---
|
||||
Console.WriteLine("Creating new part document...");
|
||||
ModelDoc2 swModel = (ModelDoc2)swApp.NewPart();
|
||||
if (swModel == null)
|
||||
{
|
||||
Console.WriteLine("Failed to create new part.");
|
||||
return;
|
||||
}
|
||||
|
||||
FeatureManager featMan = swModel.FeatureManager;
|
||||
SketchManager skMan = swModel.SketchManager;
|
||||
swModel.ClearSelection2(true);
|
||||
|
||||
// --- Step 2: Create the Base Flange ---
|
||||
Console.WriteLine("Creating base flange...");
|
||||
// Select the Top Plane (defined as "Plane3" internally by the API)
|
||||
swModel.Extension.SelectByID2("Plane3", "PLANE", 0, 0, 0, false, 0, null, 0);
|
||||
skMan.InsertSketch(true);
|
||||
skMan.CreateCenterRectangle(0, 0, 0, width / 2, length / 2, 0);
|
||||
skMan.InsertSketch(true);
|
||||
|
||||
Feature sheetMetalFeature = featMan.InsertSheetMetalBaseFlange2(thickness, false, radius, 0, 0, 0, 0.5, 0, 0, 0, false, false, false, false);
|
||||
if(sheetMetalFeature == null)
|
||||
{
|
||||
Console.WriteLine("Failed to create base flange.");
|
||||
swApp.CloseDoc(swModel.GetTitle());
|
||||
return;
|
||||
}
|
||||
swModel.ClearSelection2(true);
|
||||
|
||||
// --- Step 3: Create Edge Flanges (Walls) ---
|
||||
Console.WriteLine("Creating edge flanges for walls...");
|
||||
object[] edges = new object[4];
|
||||
edges[0] = GetEdgeByVertex(swModel, width / 2, length / 2, 0); // Front-Right edge
|
||||
edges[1] = GetEdgeByVertex(swModel, -width / 2, length / 2, 0); // Front-Left edge
|
||||
edges[2] = GetEdgeByVertex(swModel, -width / 2, -length / 2, 0); // Back-Left edge
|
||||
edges[3] = GetEdgeByVertex(swModel, width / 2, -length / 2, 0); // Back-Right edge
|
||||
|
||||
// Selecting all 4 edges at once to create mitered corners automatically
|
||||
swModel.Extension.SelectByID2(((IEntity)edges[0]).GetSelectionId(), "EDGE", 0,0,0, true, 1, null, 0);
|
||||
swModel.Extension.SelectByID2(((IEntity)edges[1]).GetSelectionId(), "EDGE", 0,0,0, true, 1, null, 0);
|
||||
swModel.Extension.SelectByID2(((IEntity)edges[2]).GetSelectionId(), "EDGE", 0,0,0, true, 1, null, 0);
|
||||
swModel.Extension.SelectByID2(((IEntity)edges[3]).GetSelectionId(), "EDGE", 0,0,0, true, 1, null, 0);
|
||||
|
||||
featMan.InsertSheetMetalEdgeFlange(height, radius, (90.0 * Math.PI / 180.0), (int)swSheetMetalFlangeLengthMethod_e.swSheetMetalFlangeLengthMethod_OuterVirtualSharp, 0, (int)swSheetMetalFlangePosition_e.swSheetMetalFlangePosition_MaterialInside, false, 0, 0, 0, 0, false, false);
|
||||
swModel.ClearSelection2(true);
|
||||
|
||||
// --- Step 4: Save and Close ---
|
||||
Console.WriteLine($"Saving file to {opts.OutputFile}...");
|
||||
bool saveSuccess = swModel.Extension.SaveAs(opts.OutputFile, (int)swSaveAsVersion_e.swSaveAsCurrentVersion, (int)swSaveAsOptions_e.swSaveAsOptions_Silent, null, 0, 0);
|
||||
|
||||
if (saveSuccess)
|
||||
{
|
||||
Console.WriteLine("File saved successfully.");
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine("Failed to save the file.");
|
||||
}
|
||||
swApp.CloseDoc(swModel.GetTitle());
|
||||
}
|
||||
|
||||
// Helper function to find an edge based on one of its vertices' coordinates
|
||||
private static IEdge GetEdgeByVertex(ModelDoc2 model, double x, double y, double z)
|
||||
{
|
||||
var body = ((PartDoc)model).GetBodies2((int)swBodyType_e.swSolidBody, true)[0] as IBody2;
|
||||
var vertex = body.GetFinniestVertex(x,y,z) as IVertex;
|
||||
return vertex.GetEdges()[0] as IEdge;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,38 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net48</TargetFramework>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<AppendTargetFrameworkToOutputPath>true</AppendTargetFrameworkToOutputPath>
|
||||
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<!--
|
||||
This is a reference to the main SolidWorks Interop Assembly.
|
||||
You MUST update the HintPath to match the location of this file on your system.
|
||||
It is typically in the SolidWorks installation directory.
|
||||
-->
|
||||
<Reference Include="SolidWorks.Interop.sldworks">
|
||||
<HintPath>C:\Program Files\SOLIDWORKS Corp\SOLIDWORKS\api\redist\SolidWorks.Interop.sldworks.dll</HintPath>
|
||||
<EmbedInteropTypes>true</EmbedInteropTypes>
|
||||
</Reference>
|
||||
<!--
|
||||
This is a reference to the SolidWorks constants Interop Assembly.
|
||||
Update the HintPath to match the location of this file on your system.
|
||||
-->
|
||||
<Reference Include="SolidWorks.Interop.swconst">
|
||||
<HintPath>C:\Program Files\SOLIDWORKS Corp\SOLIDWORKS\api\redist\SolidWorks.Interop.swconst.dll</HintPath>
|
||||
<EmbedInteropTypes>true</EmbedInteropTypes>
|
||||
</Reference>
|
||||
<!-- A reference for standard COM marshalling -->
|
||||
<Reference Include="System"/>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<!-- This adds a popular library for parsing command-line arguments -->
|
||||
<PackageReference Include="CommandLineParser" Version="2.9.1" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
100
products/poly-mech/cad/drawers/tools/sw/cli/cli.js
Normal file
100
products/poly-mech/cad/drawers/tools/sw/cli/cli.js
Normal file
@ -0,0 +1,100 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
const yargs = require('yargs/yargs');
|
||||
const { hideBin } = require('yargs/helpers');
|
||||
const { spawn } = require('child_process');
|
||||
const path = require('path');
|
||||
|
||||
// --- Command-Line Interface Definition ---
|
||||
const argv = yargs(hideBin(process.argv))
|
||||
.command(
|
||||
'$0 [output]',
|
||||
'Generate a parametric sheet metal box in SolidWorks',
|
||||
(yargs) => {
|
||||
return yargs
|
||||
.positional('output', {
|
||||
describe: 'Absolute path to the output .SLDPRT file. Defaults to a file in your Documents folder.',
|
||||
default: path.join(require('os').homedir(), 'Documents', 'sw-generated-box.SLDPRT')
|
||||
});
|
||||
}
|
||||
)
|
||||
.option('width', {
|
||||
alias: 'w',
|
||||
type: 'number',
|
||||
description: 'Total width of the box',
|
||||
default: 500
|
||||
})
|
||||
.option('length', {
|
||||
alias: 'l',
|
||||
type: 'number',
|
||||
description: 'Total length of the box',
|
||||
default: 500
|
||||
})
|
||||
.option('height', {
|
||||
alias: 'h',
|
||||
type: 'number',
|
||||
description: 'Height of the box walls',
|
||||
default: 80
|
||||
})
|
||||
.option('thickness', {
|
||||
alias: 't',
|
||||
type: 'number',
|
||||
description: 'Sheet metal thickness',
|
||||
default: 3
|
||||
})
|
||||
.option('radius', {
|
||||
alias: 'r',
|
||||
type: 'number',
|
||||
description: 'Bend radius for sheet metal',
|
||||
default: 1
|
||||
})
|
||||
.help()
|
||||
.argv;
|
||||
|
||||
// --- Constructing the Arguments for the C# Application ---
|
||||
|
||||
// Path to the C# executable. We assume it's in './sw/box/bin/Debug/net48/SolidWorksBoxGenerator.exe'
|
||||
// You may need to adjust the '.net48' folder depending on your target framework version.
|
||||
const generatorExePath = path.resolve(__dirname, '..', 'box', 'bin', 'Debug', 'net48', 'SolidWorksBoxGenerator.exe');
|
||||
|
||||
// The C# app expects arguments in the format "--key value"
|
||||
const generatorArgs = [
|
||||
'--output', argv.output,
|
||||
'--width', argv.width,
|
||||
'--length', argv.length,
|
||||
'--height', argv.height,
|
||||
'--thickness', argv.thickness,
|
||||
'--radius', argv.radius
|
||||
];
|
||||
|
||||
// --- Executing the C# Application ---
|
||||
|
||||
console.log('Executing SolidWorks Box Generator...');
|
||||
console.log(`Command: "${generatorExePath}" ${generatorArgs.join(' ')}`);
|
||||
|
||||
try {
|
||||
const generatorProcess = spawn(generatorExePath, generatorArgs);
|
||||
|
||||
generatorProcess.stdout.on('data', (data) => {
|
||||
// Trim whitespace from generator output for cleaner logging
|
||||
process.stdout.write(`[Generator]: ${data.toString().trim()}\n`);
|
||||
});
|
||||
|
||||
generatorProcess.stderr.on('data', (data) => {
|
||||
console.error(`[Generator ERROR]: ${data}`);
|
||||
});
|
||||
|
||||
generatorProcess.on('close', (code) => {
|
||||
console.log(`\nGenerator process exited with code ${code}`);
|
||||
if (code !== 0) {
|
||||
console.error("Box generation failed. Ensure SolidWorks is running.");
|
||||
} else {
|
||||
console.log(`Box generation complete. File saved to: ${argv.output}`);
|
||||
}
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
console.error(`Failed to start the generator process. Make sure the C# project has been built.`);
|
||||
console.error(`Expected executable at: ${generatorExePath}`);
|
||||
console.error(error);
|
||||
}
|
||||
196
products/poly-mech/cad/drawers/tools/sw/cli/package-lock.json
generated
Normal file
196
products/poly-mech/cad/drawers/tools/sw/cli/package-lock.json
generated
Normal file
@ -0,0 +1,196 @@
|
||||
{
|
||||
"name": "solidworks-box-generator-cli",
|
||||
"version": "1.0.0",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "solidworks-box-generator-cli",
|
||||
"version": "1.0.0",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"yargs": "^17.0.0"
|
||||
},
|
||||
"bin": {
|
||||
"generate-box": "cli.js"
|
||||
}
|
||||
},
|
||||
"node_modules/ansi-regex": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
|
||||
"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/ansi-styles": {
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
|
||||
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"color-convert": "^2.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/cliui": {
|
||||
"version": "8.0.1",
|
||||
"resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz",
|
||||
"integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"string-width": "^4.2.0",
|
||||
"strip-ansi": "^6.0.1",
|
||||
"wrap-ansi": "^7.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/color-convert": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
|
||||
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"color-name": "~1.1.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=7.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/color-name": {
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
|
||||
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/emoji-regex": {
|
||||
"version": "8.0.0",
|
||||
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
|
||||
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/escalade": {
|
||||
"version": "3.2.0",
|
||||
"resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz",
|
||||
"integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/get-caller-file": {
|
||||
"version": "2.0.5",
|
||||
"resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
|
||||
"integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
|
||||
"license": "ISC",
|
||||
"engines": {
|
||||
"node": "6.* || 8.* || >= 10.*"
|
||||
}
|
||||
},
|
||||
"node_modules/is-fullwidth-code-point": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
|
||||
"integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/require-directory": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
|
||||
"integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/string-width": {
|
||||
"version": "4.2.3",
|
||||
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
|
||||
"integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"emoji-regex": "^8.0.0",
|
||||
"is-fullwidth-code-point": "^3.0.0",
|
||||
"strip-ansi": "^6.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/strip-ansi": {
|
||||
"version": "6.0.1",
|
||||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
|
||||
"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"ansi-regex": "^5.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/wrap-ansi": {
|
||||
"version": "7.0.0",
|
||||
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
|
||||
"integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"ansi-styles": "^4.0.0",
|
||||
"string-width": "^4.1.0",
|
||||
"strip-ansi": "^6.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/chalk/wrap-ansi?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/y18n": {
|
||||
"version": "5.0.8",
|
||||
"resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
|
||||
"integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==",
|
||||
"license": "ISC",
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/yargs": {
|
||||
"version": "17.7.2",
|
||||
"resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz",
|
||||
"integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"cliui": "^8.0.1",
|
||||
"escalade": "^3.1.1",
|
||||
"get-caller-file": "^2.0.5",
|
||||
"require-directory": "^2.1.1",
|
||||
"string-width": "^4.2.3",
|
||||
"y18n": "^5.0.5",
|
||||
"yargs-parser": "^21.1.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/yargs-parser": {
|
||||
"version": "21.1.1",
|
||||
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz",
|
||||
"integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==",
|
||||
"license": "ISC",
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
18
products/poly-mech/cad/drawers/tools/sw/cli/package.json
Normal file
18
products/poly-mech/cad/drawers/tools/sw/cli/package.json
Normal file
@ -0,0 +1,18 @@
|
||||
{
|
||||
"name": "solidworks-box-generator-cli",
|
||||
"version": "1.0.0",
|
||||
"description": "A CLI for generating boxes in SolidWorks.",
|
||||
"main": "cli.js",
|
||||
"bin": {
|
||||
"generate-box": "./cli.js"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "node cli.js",
|
||||
"build": "echo 'Build step not required for this simple CLI. Linting or packaging could go here.'"
|
||||
},
|
||||
"dependencies": {
|
||||
"yargs": "^17.0.0"
|
||||
},
|
||||
"author": "",
|
||||
"license": "ISC"
|
||||
}
|
||||
348
products/poly-mech/cad/drawers/tools/test/box_folding_tool.scad
Normal file
348
products/poly-mech/cad/drawers/tools/test/box_folding_tool.scad
Normal file
@ -0,0 +1,348 @@
|
||||
// Customizable parameters for the box folding tool
|
||||
// These values are based on the provided screenshot.
|
||||
|
||||
// Overall dimensions
|
||||
TotalWidth = 500; // [100:1000]
|
||||
TotalLength = 500; // [100:1000]
|
||||
Height = 80; // [20:200]
|
||||
|
||||
// Material and slot properties
|
||||
// Updated to reflect the V-groove cutting example
|
||||
TotalThickness = 8; // [1:20]
|
||||
BaseThickness = 3; // [0.5:19]
|
||||
Slot_Width_Walls = 8; // [1:20] for internal dividers
|
||||
|
||||
// Internal grid configuration
|
||||
Nb_Boxes_U = 2; // [1:10]
|
||||
Nb_Boxes_V = 2; // [1:10]
|
||||
|
||||
// View control
|
||||
Folded_View = false; // [true, false]
|
||||
// Use "export" to render all parts separately for STEP conversion
|
||||
view_mode = "preview"; // ["preview", "export", "dxf", "cutplan"]
|
||||
|
||||
// Note: InnerBox_Width from the screenshot (100) is not used directly.
|
||||
// Instead, the compartment widths are calculated based on TotalWidth, Height, and Nb_Boxes_U/V.
|
||||
// This ensures the design remains consistent with the overall dimensions.
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// Main module to generate the box folding pattern
|
||||
// ---------------------------------------------------------------------
|
||||
module unfolded_pattern() {
|
||||
GrooveDepth = TotalThickness - BaseThickness;
|
||||
|
||||
// To prevent export errors, we perform the cuts sequentially.
|
||||
// This is more stable than a single, complex difference().
|
||||
difference() {
|
||||
// Start with the result of the first cut...
|
||||
difference() {
|
||||
// 1. Create the base plate
|
||||
cube([TotalWidth, TotalLength, TotalThickness], center = true);
|
||||
|
||||
// 2. Cut the V-Grooves for folding the main box walls
|
||||
translate([0, 0, TotalThickness/2]) {
|
||||
wall_grooves();
|
||||
}
|
||||
}
|
||||
|
||||
// 3. ...and then cut the internal rectangular slots from that result.
|
||||
if (Nb_Boxes_U > 1 || Nb_Boxes_V > 1) {
|
||||
translate([0,0,TotalThickness/2 - GrooveDepth/2])
|
||||
internal_grooves();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// Helper modules
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
// Module for creating the grooves for the outer walls
|
||||
// Reverted to simple rectangular slots as a final workaround to bypass
|
||||
// a persistent, unfixable geometry kernel bug with V-grooves.
|
||||
module wall_grooves() {
|
||||
InnerWidth = TotalWidth - 2 * Height;
|
||||
InnerLength = TotalLength - 2 * Height;
|
||||
GrooveDepth = TotalThickness - BaseThickness;
|
||||
|
||||
// For a folding groove, the width should be slightly less than the material thickness
|
||||
// to leave some material at the corners. We'll use the depth as a proxy.
|
||||
FoldingSlotWidth = GrooveDepth;
|
||||
|
||||
// Grooves parallel to Y-axis (vertical)
|
||||
translate([-InnerWidth/2, 0, 0])
|
||||
cube([FoldingSlotWidth, TotalLength, GrooveDepth], center=true);
|
||||
translate([InnerWidth/2, 0, 0])
|
||||
cube([FoldingSlotWidth, TotalLength, GrooveDepth], center=true);
|
||||
|
||||
// Grooves parallel to X-axis (horizontal)
|
||||
translate([0, -InnerLength/2, 0])
|
||||
cube([TotalWidth, FoldingSlotWidth, GrooveDepth], center=true);
|
||||
translate([0, InnerLength/2, 0])
|
||||
cube([TotalWidth, FoldingSlotWidth, GrooveDepth], center=true);
|
||||
}
|
||||
|
||||
// Module for creating a V-shaped groove for folding (45-degree cuts)
|
||||
module v_groove(length) {
|
||||
// This module is no longer used but is kept for historical reference.
|
||||
}
|
||||
|
||||
// Module for creating the grooves for the internal compartments
|
||||
module internal_grooves() {
|
||||
InnerWidth = TotalWidth - 2 * Height;
|
||||
InnerLength = TotalLength - 2 * Height;
|
||||
GrooveDepth = TotalThickness - BaseThickness;
|
||||
|
||||
CompartmentWidth = (InnerWidth - (Nb_Boxes_U - 1) * Slot_Width_Walls) / Nb_Boxes_U;
|
||||
CompartmentLength = (InnerLength - (Nb_Boxes_V - 1) * Slot_Width_Walls) / Nb_Boxes_V;
|
||||
|
||||
// Internal vertical grooves
|
||||
if (Nb_Boxes_U > 1) {
|
||||
for (i = [1 : Nb_Boxes_U - 1]) {
|
||||
x_pos = -InnerWidth/2 + i * CompartmentWidth + (i - 1/2) * Slot_Width_Walls;
|
||||
translate([x_pos, 0, 0])
|
||||
cube([Slot_Width_Walls, InnerLength, GrooveDepth], center = true);
|
||||
}
|
||||
}
|
||||
|
||||
// Internal horizontal grooves
|
||||
if (Nb_Boxes_V > 1) {
|
||||
for (i = [1 : Nb_Boxes_V - 1]) {
|
||||
y_pos = -InnerLength/2 + i * CompartmentLength + (i - 1/2) * Slot_Width_Walls;
|
||||
translate([0, y_pos, 0])
|
||||
cube([InnerWidth, Slot_Width_Walls, GrooveDepth], center = true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// Modules for Folded View
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
// Generates the fully assembled 3D box
|
||||
module folded_box() {
|
||||
// Inner dimensions of the box
|
||||
InnerWidth = TotalWidth - 2 * Height;
|
||||
InnerLength = TotalLength - 2 * Height;
|
||||
|
||||
// Material thickness for all parts
|
||||
wall_thickness = TotalThickness;
|
||||
|
||||
// 1. Base Plate
|
||||
translate([0, 0, wall_thickness / 2])
|
||||
cube([InnerWidth, InnerLength, wall_thickness], center = true);
|
||||
|
||||
// 2. Outer Walls
|
||||
// South Wall (bottom) - Full Width
|
||||
translate([0, -InnerLength/2, Height/2 + wall_thickness])
|
||||
rotate([90, 0, 0])
|
||||
cube([InnerWidth, Height, wall_thickness], center=true);
|
||||
|
||||
// North Wall (top) - Full Width
|
||||
translate([0, InnerLength/2, Height/2 + wall_thickness])
|
||||
rotate([-90, 0, 0])
|
||||
cube([InnerWidth, Height, wall_thickness], center=true);
|
||||
|
||||
// West Wall (left) - Shortened to fit between North/South walls
|
||||
translate([-InnerWidth/2, 0, Height/2 + wall_thickness])
|
||||
rotate([0, 90, 0])
|
||||
cube([Height, InnerLength - 2 * wall_thickness, wall_thickness], center=true);
|
||||
|
||||
// East Wall (right) - Shortened to fit between North/South walls
|
||||
translate([InnerWidth/2, 0, Height/2 + wall_thickness])
|
||||
rotate([0, -90, 0])
|
||||
cube([Height, InnerLength - 2 * wall_thickness, wall_thickness], center=true);
|
||||
|
||||
// 3. Internal Dividers
|
||||
internal_dividers_folded();
|
||||
}
|
||||
|
||||
// Generates the interlocking internal dividers for the folded view
|
||||
module internal_dividers_folded() {
|
||||
InnerWidth = TotalWidth - 2 * Height;
|
||||
InnerLength = TotalLength - 2 * Height;
|
||||
divider_thickness = Slot_Width_Walls; // Use slot width as the divider material thickness
|
||||
|
||||
// Calculate compartment sizes
|
||||
Compartment_U = (InnerWidth + divider_thickness) / Nb_Boxes_U;
|
||||
Compartment_V = (InnerLength + divider_thickness) / Nb_Boxes_V;
|
||||
|
||||
// Vertical dividers (U-direction)
|
||||
for (i = [1 : Nb_Boxes_U - 1]) {
|
||||
x_pos = -InnerWidth/2 + i * Compartment_U - divider_thickness/2;
|
||||
difference() {
|
||||
// Main divider piece
|
||||
translate([x_pos, 0, Height/2 + TotalThickness])
|
||||
cube([divider_thickness, InnerLength, Height], center=true);
|
||||
// Slots for horizontal dividers (top-down)
|
||||
for (j = [1 : Nb_Boxes_V - 1]) {
|
||||
y_pos = -InnerLength/2 + j * Compartment_V - divider_thickness/2;
|
||||
translate([x_pos, y_pos, Height * 0.75 + TotalThickness])
|
||||
cube([divider_thickness + 0.1, divider_thickness, Height/2], center=true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Horizontal dividers (V-direction)
|
||||
for (j = [1 : Nb_Boxes_V - 1]) {
|
||||
y_pos = -InnerLength/2 + j * Compartment_V - divider_thickness/2;
|
||||
difference() {
|
||||
// Main divider piece
|
||||
translate([0, y_pos, Height/2 + TotalThickness])
|
||||
cube([InnerWidth, divider_thickness, Height], center=true);
|
||||
// Slots for vertical dividers (bottom-up)
|
||||
for (i = [1 : Nb_Boxes_U - 1]) {
|
||||
x_pos = -InnerWidth/2 + i * Compartment_U - divider_thickness/2;
|
||||
translate([x_pos, y_pos, Height * 0.25 + TotalThickness])
|
||||
cube([divider_thickness, divider_thickness + 0.1, Height/2], center=true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// Module for exporting all parts separately
|
||||
// ---------------------------------------------------------------------
|
||||
module export_layout() {
|
||||
wall_thickness = TotalThickness;
|
||||
InnerWidth = TotalWidth - 2 * Height;
|
||||
InnerLength = TotalLength - 2 * Height;
|
||||
|
||||
// 1. Base Plate
|
||||
translate([0, 0, -TotalThickness/2])
|
||||
cube([InnerWidth, InnerLength, wall_thickness], center = true);
|
||||
|
||||
// Spacing for laying out parts
|
||||
spacing = TotalWidth;
|
||||
|
||||
// 2. Outer Walls
|
||||
translate([spacing, 0, 0])
|
||||
cube([InnerWidth, Height, wall_thickness], center=true); // South
|
||||
translate([spacing, Height + 10, 0])
|
||||
cube([InnerWidth, Height, wall_thickness], center=true); // North
|
||||
|
||||
translate([spacing + InnerWidth + 10, 0, 0])
|
||||
cube([InnerLength - 2 * wall_thickness, Height, wall_thickness], center=true); // West
|
||||
translate([spacing + InnerWidth + 10, Height + 10, 0])
|
||||
cube([InnerLength - 2 * wall_thickness, Height, wall_thickness], center=true); // East
|
||||
|
||||
// 3. Internal Dividers
|
||||
divider_thickness = Slot_Width_Walls;
|
||||
Compartment_U = (InnerWidth + divider_thickness) / Nb_Boxes_U;
|
||||
Compartment_V = (InnerLength + divider_thickness) / Nb_Boxes_V;
|
||||
|
||||
// Place all vertical dividers in a row
|
||||
for (i = [1 : Nb_Boxes_U - 1]) {
|
||||
translate([2 * spacing + (i-1)*(divider_thickness+10), 0, 0])
|
||||
internal_divider_vertical_export(InnerLength, Compartment_V);
|
||||
}
|
||||
|
||||
// Place all horizontal dividers in a row
|
||||
for (j = [1 : Nb_Boxes_V - 1]) {
|
||||
translate([2 * spacing, (j-1)*(Height+10) + Height + 10, 0])
|
||||
internal_divider_horizontal_export(InnerWidth, Compartment_U);
|
||||
}
|
||||
}
|
||||
|
||||
// Helper modules for export layout (without difference operations)
|
||||
module internal_divider_vertical_export(length, compartment_v_size) {
|
||||
divider_thickness = Slot_Width_Walls;
|
||||
difference() {
|
||||
cube([divider_thickness, length, Height], center=true);
|
||||
// Notches for horizontal dividers (bottom-up)
|
||||
for (i = [1 : Nb_Boxes_V - 1]) {
|
||||
y_pos = -length/2 + i * compartment_v_size - divider_thickness/2;
|
||||
translate([0, y_pos, -Height/4])
|
||||
cube([divider_thickness + 0.1, divider_thickness, Height/2], center=true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module internal_divider_horizontal_export(length, compartment_u_size) {
|
||||
divider_thickness = Slot_Width_Walls;
|
||||
difference() {
|
||||
cube([length, divider_thickness, Height], center=true);
|
||||
// Notches for vertical dividers (top-down)
|
||||
for (j = [1 : Nb_Boxes_U - 1]) {
|
||||
x_pos = -length/2 + j * compartment_u_size - divider_thickness/2;
|
||||
translate([x_pos, 0, Height/4])
|
||||
cube([divider_thickness, divider_thickness + 0.1, Height/2], center=true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// Module to generate a markdown cut plan for the operator.
|
||||
// This version avoids all list manipulation for maximum compatibility.
|
||||
// ---------------------------------------------------------------------
|
||||
module generate_cut_plan_text() {
|
||||
// --- Calculations ---
|
||||
InnerWidth = TotalWidth - 2 * Height;
|
||||
InnerLength = TotalLength - 2 * Height;
|
||||
GrooveDepth = TotalThickness - BaseThickness;
|
||||
|
||||
// --- Markdown Output ---
|
||||
echo("# Saw Operator Cut Plan");
|
||||
echo(str("## Board Dimensions: `", TotalWidth, " x ", TotalLength, " mm`"));
|
||||
echo("");
|
||||
echo("## Specifications");
|
||||
echo(str("* **V-Groove Spec:** Depth `", GrooveDepth, " mm`"));
|
||||
echo(str("* **Slot Spec:** Width `", Slot_Width_Walls, " mm`, Depth `", GrooveDepth, " mm`"));
|
||||
echo("");
|
||||
echo("## Blade Setup");
|
||||
echo("* **For V-Grooves:** Set saw blade angle to **45 degrees**.");
|
||||
echo("* **For Slots:** Set saw blade angle to **0 degrees** (straight up).");
|
||||
echo("");
|
||||
|
||||
// --- Setup 1: Vertical Cuts ---
|
||||
echo("## SETUP 1: VERTICAL CUTS");
|
||||
echo("All distances are from the LEFT edge. Flip board for cuts > 50%.");
|
||||
echo("");
|
||||
echo(str("* `", Height, " mm` -- **V-GROOVE**"));
|
||||
if (Nb_Boxes_U > 1) {
|
||||
for (i = [1 : Nb_Boxes_U - 1]) {
|
||||
pos = Height + i * ((InnerWidth - (Nb_Boxes_U - 1) * Slot_Width_Walls) / Nb_Boxes_U) + i * Slot_Width_Walls;
|
||||
echo(str("* `", pos, " mm` -- **SLOT**"));
|
||||
}
|
||||
}
|
||||
echo(str("* `", TotalWidth - Height, " mm` -- **V-GROOVE**"));
|
||||
echo("");
|
||||
|
||||
// --- Setup 2: Horizontal Cuts ---
|
||||
echo("## SETUP 2: HORIZONTAL CUTS");
|
||||
echo("Rotate board 90 deg. All distances from the NEW LEFT edge.");
|
||||
echo("");
|
||||
echo(str("* `", Height, " mm` -- **V-GROOVE**"));
|
||||
if (Nb_Boxes_V > 1) {
|
||||
for (i = [1 : Nb_Boxes_V - 1]) {
|
||||
pos = Height + i * ((InnerLength - (Nb_Boxes_V - 1) * Slot_Width_Walls) / Nb_Boxes_V) + i * Slot_Width_Walls;
|
||||
echo(str("* `", pos, " mm` -- **SLOT**"));
|
||||
}
|
||||
}
|
||||
echo(str("* `", TotalLength - Height, " mm` -- **V-GROOVE**"));
|
||||
|
||||
echo("");
|
||||
echo("---");
|
||||
echo("*End of Plan*");
|
||||
|
||||
// Generate a tiny invisible cube because OpenSCAD needs to produce some geometry.
|
||||
cube(0.01);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// Render the final object
|
||||
// ---------------------------------------------------------------------
|
||||
if (view_mode == "export") {
|
||||
export_layout();
|
||||
} else if (view_mode == "dxf") {
|
||||
// Project the 2D unfolded pattern for DXF export
|
||||
projection(cut = true) unfolded_pattern();
|
||||
} else if (view_mode == "cutplan") {
|
||||
generate_cut_plan_text();
|
||||
} else {
|
||||
if (Folded_View) {
|
||||
folded_box();
|
||||
} else {
|
||||
unfolded_pattern();
|
||||
}
|
||||
}
|
||||
BIN
sheetpress/components/900_Moulds/1300x650-10/cad/Mould-Frame-650-10-1300.STEP
(Stored with Git LFS)
Normal file
BIN
sheetpress/components/900_Moulds/1300x650-10/cad/Mould-Frame-650-10-1300.STEP
(Stored with Git LFS)
Normal file
Binary file not shown.
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
BIN
sheetpress/components/900_Moulds/1300x650-10/renderings/breakout.jpg
(Stored with Git LFS)
Normal file
BIN
sheetpress/components/900_Moulds/1300x650-10/renderings/breakout.jpg
(Stored with Git LFS)
Normal file
Binary file not shown.
@ -0,0 +1 @@
|
||||
${social}
|
||||
@ -0,0 +1,72 @@
|
||||
<span id="specs" style="padding: 16px">
|
||||
<table class="center specs">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Type
|
||||
</td>
|
||||
<td>Sheetpress
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Version
|
||||
</td>
|
||||
<td>0.1
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Weight
|
||||
</td>
|
||||
<td>80 - 120 Kg
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> Voltage
|
||||
</td>
|
||||
<td>380V
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> Status
|
||||
</td>
|
||||
<td>Development
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> Sheet Size
|
||||
</td>
|
||||
<td>60 x 60 cm
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> Plate Size
|
||||
</td>
|
||||
<td>70 x 70 cm
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> Pressure
|
||||
</td>
|
||||
<td> 2-5 tons, depending on the sheet thickness
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> Input Flake Size
|
||||
</td>
|
||||
<td>Medium, Small
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> Gearbox ratio
|
||||
</td>
|
||||
<td> 1:15
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Heaters
|
||||
</td>
|
||||
<td> 300 Watt x 32 (10kW)
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</span>
|
||||
@ -0,0 +1,6 @@
|
||||
**Product Resources**
|
||||
|
||||
- [3D Preview](${abs_url}/${product_rel}resources/edrawings.html)
|
||||
- [Product Page](${product_page})
|
||||
|
||||
${product_howtos}
|
||||
@ -0,0 +1 @@
|
||||
### Build the machine
|
||||
@ -0,0 +1 @@
|
||||
${social}
|
||||
@ -0,0 +1 @@
|
||||
### Media
|
||||
@ -0,0 +1,30 @@
|
||||
<span id="specs" style="padding: 16px">
|
||||
<table class="center specs">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Type:
|
||||
</td>
|
||||
<td>Sheetpress
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Version:
|
||||
</td>
|
||||
<td>0.1
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> Status:
|
||||
</td>
|
||||
<td> Development
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> Authors </td>
|
||||
<td>
|
||||
<li>[PlasticHub S.L.](${author_link})</li>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</span>
|
||||
@ -0,0 +1,2 @@
|
||||
- [3D Preview](${product_3d})
|
||||
- [Electrical wiring](${product_wiring})
|
||||
@ -0,0 +1 @@
|
||||
### Resources
|
||||
@ -0,0 +1,10 @@
|
||||
Flexible, modular dual sheetpress, including a heat and cooling press.
|
||||
|
||||
## Details / Features
|
||||
|
||||
- Sheet thickness up to 30mm
|
||||
- 15T of pressure
|
||||
- Stackable and interlockable (600x1300cm sheets)
|
||||
- cartridge heaters are embedded in the heat plates, enabling 30% better heat efficiency
|
||||
- Press plate options: heating, passive or active cooling
|
||||
- the hydraulic jack has a pneumatic port, to use a compressor instead
|
||||
@ -0,0 +1,4 @@
|
||||
[%- i18n %]
|
||||
- Sheet thickness up to 30mm
|
||||
- 15T of pressure
|
||||
[%- i18n-end %]
|
||||
@ -0,0 +1 @@
|
||||
### Build the machine
|
||||
@ -0,0 +1,37 @@
|
||||
|
||||
## Force Calculations
|
||||
|
||||
to demonstrate that the motor and gearbox are capable of at least 2 tons clamping force, lifting a platten that weighs 20kg
|
||||
|
||||
Lead screw calculation:
|
||||
|
||||
```math
|
||||
Torque(raise) = F x Dm/2x(L+u x PI x DM)/(PI x Dm-u x L)
|
||||
```
|
||||
|
||||
[See leadscrew force torque calculator](https://daycounter.com/Calculators/Lead-Screw-Force-Torque-Calculator.phtml)
|
||||
|
||||
Toggle clamp calculations:
|
||||
|
||||
```math
|
||||
P = F a / 2 h
|
||||
```
|
||||
|
||||
where P = input force, F = output force, a = arm length, h = height (displacement of toggle pivot from line between end pivots)
|
||||
|
||||
[See toggle joint calculation](https://www.engineeringtoolbox.com/toggle-joint-d_2077.html)
|
||||
|
||||
Torque of 25Nm from the gearbox (as claimed) on a 20mm screw with a 4mm pitch and a brass nut with a frictional coefficient of 0.06 gives about 1575N pushing force on the nut.
|
||||
|
||||
Connected to an equal toggle mechanism of 125mm arm lengths, this would generate a perpendicular force of 820 newtons (80Kg) at the bottom of the stroke (toggle displacement 120mm), 98438 newtons (10 tons) at the top of the stroke (toggle displacement 1mm).
|
||||
|
||||
With a toggle diplacement of 5mm (press almost fully closed) the force generated is 19688 newtons or around 2 tons.
|
||||
|
||||
18nm from the gearbox (1.2NM x 15:1) gives 1135N push on the screw, generating 70938N (7.2T) at 1mm toggle displacement and 14118N (1.4T)at 5mm
|
||||
|
||||
Using a higher frictional coefficient of 0.1, torque of 18Nm from the gearbox gives 690N push on the screw, generating 359N (40Kg) at 120mm displacement 8628N (900Kg) at 5mm and 43125 (4.4T) at 1mm displacement. This seems like a more realistic estimate, given that friction on the collar and toggle pivot joints is not accounted for in this equation. Even half this would give a comfortable 2 ton max clamping force and still be able to lift 20kg from fully open. Also these calculations are based on the smallest stepper in the Nema 23 package size, up to 3nm are available
|
||||
|
||||
More detailed calculations will be performed using the [calculator](https://cdn.automationdirect.com/static/manuals/surestepmanual/appxc.pdf)
|
||||
|
||||
At max motor speed of 400 RRM with the 15:1 gearbox and 4mm pitch screw, the motor would move the nut on the screw at 1.7mm/s, meaning the plattens would take about 70s to perform a full 120mm stroke. If a 10:1 gearbox were used, it would take 45s.
|
||||
|
||||
@ -0,0 +1 @@
|
||||
${social}
|
||||
@ -0,0 +1,35 @@
|
||||
---
|
||||
title: "Cassandra v1.0 - revision-A DataSheet"
|
||||
permalink: "/specs/products/cassandra"
|
||||
layout: "print"
|
||||
---
|
||||
|
||||
## {{page.title}}
|
||||
|
||||
### Specification
|
||||
|
||||
| Specification | |
|
||||
|----------|-------------|
|
||||
| Title | Cassandra |
|
||||
| Version | v1.0 |
|
||||
| Type | Sheetpress |
|
||||
| Weight | 100 kg |
|
||||
| Package Dimension | 1052 x 1100 x 900 mm |
|
||||
| Power (W) | 3 kW |
|
||||
| Voltage | 380V or 220V |
|
||||
| Amperage | 16A |
|
||||
| Input Flake Size | Small |
|
||||
| Screw diameter | 30mm |
|
||||
| Rated Motor Power | 3 kW |
|
||||
| Motor Type | |
|
||||
|
||||
<div class="col">
|
||||
<h3 class="text-center" id="dimensions">Dimensions</h3>
|
||||
<div class="vertical-margin vertical-gap">
|
||||
{% include product_image.html size="medium" src="/products/cassandra/drawings/dimensions.jpg" target="/products/cassandra/drawings/dimensions.PDF" %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
### Components & Parts
|
||||
|
||||
{% include product_image.html size="small" src="/products/cassandra/drawings/parts.jpg" %}
|
||||
@ -0,0 +1,2 @@
|
||||
- [3D Preview](${product_3d})
|
||||
- [Electrical wiring](${product_wiring})
|
||||
@ -0,0 +1 @@
|
||||
### Resources
|
||||
BIN
sheetpress/components/900_Moulds/1300x650-15/cad/Mould-Seg-1030-650-15.STEP
(Stored with Git LFS)
Normal file
BIN
sheetpress/components/900_Moulds/1300x650-15/cad/Mould-Seg-1030-650-15.STEP
(Stored with Git LFS)
Normal file
Binary file not shown.
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
BIN
sheetpress/components/900_Moulds/1300x650-15/renderings/breakout.jpg
(Stored with Git LFS)
Normal file
BIN
sheetpress/components/900_Moulds/1300x650-15/renderings/breakout.jpg
(Stored with Git LFS)
Normal file
Binary file not shown.
@ -0,0 +1 @@
|
||||
${social}
|
||||
@ -0,0 +1,72 @@
|
||||
<span id="specs" style="padding: 16px">
|
||||
<table class="center specs">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Type
|
||||
</td>
|
||||
<td>Sheetpress
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Version
|
||||
</td>
|
||||
<td>0.1
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Weight
|
||||
</td>
|
||||
<td>80 - 120 Kg
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> Voltage
|
||||
</td>
|
||||
<td>380V
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> Status
|
||||
</td>
|
||||
<td>Development
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> Sheet Size
|
||||
</td>
|
||||
<td>60 x 60 cm
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> Plate Size
|
||||
</td>
|
||||
<td>70 x 70 cm
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> Pressure
|
||||
</td>
|
||||
<td> 2-5 tons, depending on the sheet thickness
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> Input Flake Size
|
||||
</td>
|
||||
<td>Medium, Small
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> Gearbox ratio
|
||||
</td>
|
||||
<td> 1:15
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Heaters
|
||||
</td>
|
||||
<td> 300 Watt x 32 (10kW)
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</span>
|
||||
@ -0,0 +1,6 @@
|
||||
**Product Resources**
|
||||
|
||||
- [3D Preview](${abs_url}/${product_rel}resources/edrawings.html)
|
||||
- [Product Page](${product_page})
|
||||
|
||||
${product_howtos}
|
||||
@ -0,0 +1 @@
|
||||
### Build the machine
|
||||
@ -0,0 +1 @@
|
||||
${social}
|
||||
@ -0,0 +1 @@
|
||||
### Media
|
||||
@ -0,0 +1,30 @@
|
||||
<span id="specs" style="padding: 16px">
|
||||
<table class="center specs">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Type:
|
||||
</td>
|
||||
<td>Sheetpress
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Version:
|
||||
</td>
|
||||
<td>0.1
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> Status:
|
||||
</td>
|
||||
<td> Development
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> Authors </td>
|
||||
<td>
|
||||
<li>[PlasticHub S.L.](${author_link})</li>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</span>
|
||||
@ -0,0 +1,2 @@
|
||||
- [3D Preview](${product_3d})
|
||||
- [Electrical wiring](${product_wiring})
|
||||
@ -0,0 +1 @@
|
||||
### Resources
|
||||
@ -0,0 +1,10 @@
|
||||
Flexible, modular dual sheetpress, including a heat and cooling press.
|
||||
|
||||
## Details / Features
|
||||
|
||||
- Sheet thickness up to 30mm
|
||||
- 15T of pressure
|
||||
- Stackable and interlockable (600x1300cm sheets)
|
||||
- cartridge heaters are embedded in the heat plates, enabling 30% better heat efficiency
|
||||
- Press plate options: heating, passive or active cooling
|
||||
- the hydraulic jack has a pneumatic port, to use a compressor instead
|
||||
@ -0,0 +1,4 @@
|
||||
[%- i18n %]
|
||||
- Sheet thickness up to 30mm
|
||||
- 15T of pressure
|
||||
[%- i18n-end %]
|
||||
@ -0,0 +1 @@
|
||||
### Build the machine
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user