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 0000000..3eb6ac4 Binary files /dev/null and b/cad/drawers/tools/__pycache__/save_fcstd.cpython-311.pyc differ diff --git a/cad/drawers/tools/box_folding_tool.FCStd b/cad/drawers/tools/box_folding_tool.FCStd new file mode 100644 index 0000000..58fce83 Binary files /dev/null and b/cad/drawers/tools/box_folding_tool.FCStd differ 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