#!/usr/bin/env bash # openscad-stl-analyze.sh — Extract geometry data from binary STL files # Outputs bounding box, vertex distributions, and internal structure hints set -euo pipefail usage() { cat <<'EOF' Usage: openscad-stl-analyze.sh [--cross-section ] [--gaps ] Commands: Full bounding box and triangle count --cross-section Show vertex distribution at a cross-section axis: x, y, or z; value: coordinate --gaps Find gaps in vertex distribution along axis (useful for finding internal features) Examples: openscad-stl-analyze.sh model.stl openscad-stl-analyze.sh model.stl --cross-section z 0 openscad-stl-analyze.sh model.stl --gaps y EOF exit 1 } [[ $# -lt 1 ]] && usage STL_FILE="$1" shift if [[ ! -f "$STL_FILE" ]]; then echo "ERROR: File not found: $STL_FILE" >&2 exit 1 fi # Default: full analysis if [[ $# -eq 0 ]]; then python3 -c " import struct, math, sys from collections import defaultdict path = '$STL_FILE' with open(path, 'rb') as f: header = f.read(80) n = struct.unpack(' (max(vals)-min(vals)) * 0.05: # gaps > 5% of range gaps.append((sorted_unique[i], sorted_unique[i+1], gap)) if gaps: print(f'{axis_name}-axis gaps (>5% of range):') for v1, v2, g in gaps: print(f' {v1:.3f} to {v2:.3f} (gap={g:.3f} mm) — possible internal feature boundary') print() " exit 0 fi # Cross-section analysis if [[ "$1" == "--cross-section" ]]; then [[ $# -lt 3 ]] && usage AXIS="$2" VALUE="$3" python3 -c " import struct path = '$STL_FILE' axis = '$AXIS' value = float($VALUE) with open(path, 'rb') as f: f.read(80) n = struct.unpack(' 0.5: print(f' GAP: |{name}|={abs_vals[i]:.4f} to |{name}|={abs_vals[i+1]:.4f} (width={gap:.4f})') print(f' -> Possible feature boundary at |{name}|={abs_vals[i]:.4f}') " exit 0 fi # Gap analysis if [[ "$1" == "--gaps" ]]; then [[ $# -lt 2 ]] && usage AXIS="$2" python3 -c " import struct from collections import defaultdict path = '$STL_FILE' axis = '$AXIS' axis_idx = {'x':0, 'y':1, 'z':2}[axis] axis_names = 'XYZ' with open(path, 'rb') as f: f.read(80) n = struct.unpack(' 0.5: gaps.append((abs_vals[i], abs_vals[i+1], g)) if gaps: print(f'{axis_names[axis_idx]}={level:6.3f}: |{axis_names[oa]}| gaps:') for v1, v2, g in gaps: print(f' {v1:.4f} to {v2:.4f} (gap={g:.4f}) — feature boundary') " exit 0 fi usage