From 64f676a716c7487222bbcdeb6d33ae59b71307eb Mon Sep 17 00:00:00 2001 From: babayaga Date: Fri, 4 Jul 2025 12:53:10 +0200 Subject: [PATCH] Smooth Saw Operator :) --- .../__pycache__/save_fcstd.cpython-311.pyc | Bin 0 -> 1481 bytes cad/drawers/tools/box_folding_tool.FCStd | Bin 0 -> 40521 bytes cad/drawers/tools/box_folding_tool.scad | 61 ++++++++++++++- .../tools/box_folding_tool_unfolded.dxf | 70 ++++++++++++++++++ cad/drawers/tools/cutlist.txt | 14 ++++ cad/drawers/tools/export_dxf.sh | 41 ++++++++++ cad/drawers/tools/export_freecad.sh | 44 +++++++++++ cad/drawers/tools/generate_cutlist.sh | 51 +++++++++++++ cad/drawers/tools/save_fcstd.py | 41 ++++++++++ 9 files changed, 321 insertions(+), 1 deletion(-) create mode 100644 cad/drawers/tools/__pycache__/save_fcstd.cpython-311.pyc create mode 100644 cad/drawers/tools/box_folding_tool.FCStd create mode 100644 cad/drawers/tools/box_folding_tool_unfolded.dxf create mode 100644 cad/drawers/tools/cutlist.txt create mode 100644 cad/drawers/tools/export_dxf.sh create mode 100644 cad/drawers/tools/export_freecad.sh create mode 100644 cad/drawers/tools/generate_cutlist.sh create mode 100644 cad/drawers/tools/save_fcstd.py diff --git a/cad/drawers/tools/__pycache__/save_fcstd.cpython-311.pyc b/cad/drawers/tools/__pycache__/save_fcstd.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3eb6ac4dfc8e5ec7b71099f7d5eb6d8656f08aec GIT binary patch literal 1481 zcmZux-D}%c6hE@A{2|-5wq|8x>mpcL;;;m^EHFY6$gGydq0L6a! z?D$D3hV?NIfd$5(4%YR$HGc8g`aKy}SnlUGdJx)wdi zZCl1#-~W30|6X2R_SwE{rZ#*d**992o9V5<;EMH98LA{pDcb)`A`fMCoBxkk(q z)R^HzEWXc z%6N@@z=HX&Lo4hY@EpetMBtK+=+7?Pa)Q}~q!Y|R6j01rbZDz_wAxxd{`4(~cTnC%`7TO1xz<*yXI|X?>D@M(>!3Lo&9Qui_;(MVJv`cKZ8=*Zn}3#fGt+G(caZENxfdq? zc^fTt(2|Rm#*%kf0T;cPG=K;8+KFw b5BJC7`dn@rUQP>2ntyrkLnY4t8TaWo>XU)Z literal 0 HcmV?d00001 diff --git a/cad/drawers/tools/box_folding_tool.FCStd b/cad/drawers/tools/box_folding_tool.FCStd new file mode 100644 index 0000000000000000000000000000000000000000..58fce831fb7aa0ac462f5463b4664232d295e488 GIT binary patch literal 40521 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 F@i$*v3XcE) literal 0 HcmV?d00001 diff --git a/cad/drawers/tools/box_folding_tool.scad b/cad/drawers/tools/box_folding_tool.scad index 1f87ca0..a82e343 100644 --- a/cad/drawers/tools/box_folding_tool.scad +++ b/cad/drawers/tools/box_folding_tool.scad @@ -18,7 +18,7 @@ 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"] +view_mode = "preview"; // ["preview", "export", "dxf", "cutlist"] // 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. @@ -254,11 +254,70 @@ module internal_divider_horizontal_export(length, compartment_u_size) { } } +// --------------------------------------------------------------------- +// Module to generate a cut list for the operator +// --------------------------------------------------------------------- +module generate_cutlist() { + // --- Calculations --- + InnerWidth = TotalWidth - 2 * Height; + InnerLength = TotalLength - 2 * Height; + + // --- Header --- + echo("--- Cut List for Saw Operator ---"); + echo(str("Board Dimensions: ", TotalWidth, " x ", TotalLength, " mm")); + echo("All distances are for the centerline of the slots."); + echo("---"); + + // --- Vertical Cuts (Parallel to Y-axis) --- + echo("VERTICAL CUTS (Distances from left edge):"); + // Outer walls + v_outer_1 = Height; + v_outer_2 = TotalWidth - Height; + echo(str(" Outer Wall 1: ", v_outer_1, " mm")); + echo(str(" Outer Wall 2: ", v_outer_2, " mm")); + + // Internal dividers + if (Nb_Boxes_U > 1) { + CompartmentWidth = (InnerWidth - (Nb_Boxes_U - 1) * Slot_Width_Walls) / Nb_Boxes_U; + for (i = [1 : Nb_Boxes_U - 1]) { + x_pos_abs = Height + i * CompartmentWidth + i * Slot_Width_Walls; + echo(str(" Internal Divider ", i, ": ", x_pos_abs, " mm")); + } + } + echo("---"); + + // --- Horizontal Cuts (Parallel to X-axis) --- + echo("HORIZONTAL CUTS (Distances from bottom edge):"); + // Outer walls + h_outer_1 = Height; + h_outer_2 = TotalLength - Height; + echo(str(" Outer Wall 1: ", h_outer_1, " mm")); + echo(str(" Outer Wall 2: ", h_outer_2, " mm")); + + // Internal dividers + if (Nb_Boxes_V > 1) { + CompartmentLength = (InnerLength - (Nb_Boxes_V - 1) * Slot_Width_Walls) / Nb_Boxes_V; + for (i = [1 : Nb_Boxes_V - 1]) { + y_pos_abs = Height + i * CompartmentLength + i * Slot_Width_Walls; + echo(str(" Internal Divider ", i, ": ", y_pos_abs, " mm")); + } + } + echo("--- End of List ---"); + + // 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 == "cutlist") { + generate_cutlist(); } else { if (Folded_View) { folded_box(); diff --git a/cad/drawers/tools/box_folding_tool_unfolded.dxf b/cad/drawers/tools/box_folding_tool_unfolded.dxf new file mode 100644 index 0000000..d858911 --- /dev/null +++ b/cad/drawers/tools/box_folding_tool_unfolded.dxf @@ -0,0 +1,70 @@ + 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 +ENDSEC + 0 +SECTION + 2 +OBJECTS + 0 +DICTIONARY + 0 +ENDSEC + 0 +EOF diff --git a/cad/drawers/tools/cutlist.txt b/cad/drawers/tools/cutlist.txt new file mode 100644 index 0000000..d6671c1 --- /dev/null +++ b/cad/drawers/tools/cutlist.txt @@ -0,0 +1,14 @@ +--- Cut List for Saw Operator --- +Board Dimensions: 500 x 500 mm +All distances are for the centerline of the slots. +--- +VERTICAL CUTS (Distances from left edge): + Outer Wall 1: 80 mm + Outer Wall 2: 420 mm + Internal Divider 1: 254 mm +--- +HORIZONTAL CUTS (Distances from bottom edge): + Outer Wall 1: 80 mm + Outer Wall 2: 420 mm + Internal Divider 1: 254 mm +--- End of List --- diff --git a/cad/drawers/tools/export_dxf.sh b/cad/drawers/tools/export_dxf.sh new file mode 100644 index 0000000..219df3d --- /dev/null +++ b/cad/drawers/tools/export_dxf.sh @@ -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 [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 [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 \ No newline at end of file diff --git a/cad/drawers/tools/export_freecad.sh b/cad/drawers/tools/export_freecad.sh new file mode 100644 index 0000000..628614a --- /dev/null +++ b/cad/drawers/tools/export_freecad.sh @@ -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 [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 [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." \ No newline at end of file diff --git a/cad/drawers/tools/generate_cutlist.sh b/cad/drawers/tools/generate_cutlist.sh new file mode 100644 index 0000000..e60f67d --- /dev/null +++ b/cad/drawers/tools/generate_cutlist.sh @@ -0,0 +1,51 @@ +#!/bin/bash + +# --- generate_cutlist.sh --- +# Generates a cut list of slot distances from an OpenSCAD file. +# +# Usage: ./generate_cutlist.sh [output.txt] +# If output file is not provided, prints to console. + +# --- Input Validation --- +if [ -z "$1" ]; then + echo "Usage: $0 [output.txt]" + echo "Error: Source file not specified." + exit 1 +fi + +SOURCE_FILE="$1" +OUTPUT_FILE="$2" +DUMMY_OUTPUT="cutlist_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. +CUTLIST_CONTENT=$(openscad \ + -o "$DUMMY_OUTPUT" \ + -D "view_mode=\"cutlist\"" \ + "$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 List ---" + echo "$CUTLIST_CONTENT" + echo "--------------------------" +else + echo "$CUTLIST_CONTENT" > "$OUTPUT_FILE" + echo "Cut list successfully saved to '$OUTPUT_FILE'." +fi \ No newline at end of file diff --git a/cad/drawers/tools/save_fcstd.py b/cad/drawers/tools/save_fcstd.py new file mode 100644 index 0000000..174093f --- /dev/null +++ b/cad/drawers/tools/save_fcstd.py @@ -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: ") + 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) \ No newline at end of file