#!/bin/bash # --- DEFAULTS --- THICKNESS_MM="0.1" EXPORT_DPI="1494" PADDING_MM="0.0" # Default padding # --- ARGUMENT PARSING --- INVERT_SUFFIXES=() PROJECT_PREFIX="" # Helper function to show usage show_usage() { echo "Usage: ./svg2stl.sh [options] " echo "" echo "Options:" echo " -t, --thickness Final 3D model thickness (Default: $THICKNESS_MM)" echo " -p, --padding Extra margin around inverted models (Default: $PADDING_MM)" echo " -d, --printer-lcd-dpi DPI for Inkscape export (Default: $EXPORT_DPI)" echo " -i, --invert Generate inverted (negative) model for this suffix" echo "" echo "Example:" echo " ./svg2stl.sh --thickness 0.2 --padding 5.0 -i B_Mask examples/MyBoard" exit 1 } while [[ $# -gt 0 ]]; do case $1 in -t|--thickness) if [[ -n "$2" && "$2" != -* ]]; then THICKNESS_MM="$2" shift; shift else echo "Error: --thickness requires a value (mm)." exit 1 fi ;; -p|--padding) if [[ -n "$2" && "$2" != -* ]]; then PADDING_MM="$2" shift; shift else echo "Error: --padding requires a value (mm)." exit 1 fi ;; -d|--printer-lcd-dpi) if [[ -n "$2" && "$2" != -* ]]; then EXPORT_DPI="$2" shift; shift else echo "Error: --printer-lcd-dpi requires a value." exit 1 fi ;; -i|--invert) if [[ -n "$2" && "$2" != -* ]]; then INVERT_SUFFIXES+=("$2") shift; shift else echo "Error: --invert requires a suffix argument." exit 1 fi ;; -h|--help) show_usage ;; *) if [[ -z "$PROJECT_PREFIX" ]]; then PROJECT_PREFIX="$1" shift else echo "Error: Unknown argument '$1' or Project Prefix already set." show_usage fi ;; esac done if [[ -z "$PROJECT_PREFIX" ]]; then echo "Error: No Project Prefix provided." show_usage fi # Find files matching the prefix shopt -s nullglob FILES=(${PROJECT_PREFIX}*.svg) shopt -u nullglob if [ ${#FILES[@]} -eq 0 ]; then echo "Error: No files found starting with '${PROJECT_PREFIX}' ending in .svg" exit 1 fi PREFIX_BASENAME="$(basename "$PROJECT_PREFIX")" echo "========================================" echo "Project Name: $PREFIX_BASENAME" echo "Thickness: $THICKNESS_MM mm" echo "Padding: $PADDING_MM mm (Inverted only)" echo "Printer DPI: $EXPORT_DPI" echo "Invert Suffixes: ${INVERT_SUFFIXES[*]}" echo "========================================" for INPUT_FILE in "${FILES[@]}"; do # Resolve paths INPUT_FILE="$(readlink -f "$INPUT_FILE")" DIR="$(dirname "$INPUT_FILE")" FILENAME="$(basename "$INPUT_FILE")" BASENAME="${FILENAME%.*}" # --- Suffix Extraction --- SUFFIX_TEMP="${BASENAME#$PREFIX_BASENAME}" SUFFIX="${SUFFIX_TEMP#-}" # Check invert mode INVERT_MODE="0" for i in "${INVERT_SUFFIXES[@]}"; do if [[ "$i" == "$SUFFIX" ]]; then INVERT_MODE="1" break fi done echo "Processing: $FILENAME" if [ "$INVERT_MODE" == "1" ]; then echo " -> Mode: INVERTED (Negative) + ${PADDING_MM}mm Padding" OUTPUT_STL="$DIR/${BASENAME}_inverted.stl" else echo " -> Mode: STANDARD (Positive)" OUTPUT_STL="$DIR/${BASENAME}.stl" fi TEMP_SVG="$DIR/${BASENAME}_temp_proc.svg" # --- Step 1: Inkscape --- ACTIONS="select-by-element:text;delete;select-all;object-stroke-to-path;path-union;export-plain-svg;export-filename:$TEMP_SVG;export-do" INK_ARGS="--export-dpi=$EXPORT_DPI --actions=$ACTIONS" inkscape "$INPUT_FILE" $INK_ARGS > /dev/null 2>&1 if [ ! -f "$TEMP_SVG" ]; then echo " ERROR: Inkscape failed to process $FILENAME" continue fi # --- Step 2: Blender --- # Passing PADDING_MM as the 5th argument blender --background --python pcb_to_stl.py -- "$TEMP_SVG" "$OUTPUT_STL" "$THICKNESS_MM" "$INVERT_MODE" "$PADDING_MM" | grep -v "Blender" | grep -v "Read prefs" rm "$TEMP_SVG" echo " -> Done." echo "----------------------------------------" done