nicolamustone commited on
Commit
cacc8d5
·
1 Parent(s): 44a941b

Added stl-scanner helper script

Browse files
Files changed (1) hide show
  1. stl-scanner.py +109 -0
stl-scanner.py ADDED
@@ -0,0 +1,109 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python
2
+ import argparse
3
+ import os
4
+ from pathlib import Path
5
+
6
+ import pandas as pd
7
+ import trimesh
8
+
9
+
10
+ def parse_args():
11
+ parser = argparse.ArgumentParser(
12
+ description="Extract basic geometric features from STL file(s) using trimesh."
13
+ )
14
+ parser.add_argument(
15
+ "--stl_path",
16
+ help="Path to a single STL file or a folder containing STL files (non-recursive). Defaults to current directory.",
17
+ default=".",
18
+ )
19
+ parser.add_argument(
20
+ "--output_path",
21
+ help="Folder where the resulting CSV will be saved. Defaults to current directory.",
22
+ default=".",
23
+ )
24
+ return parser.parse_args()
25
+
26
+
27
+ def collect_stl_files(stl_path: Path):
28
+ if stl_path.is_file():
29
+ if stl_path.suffix.lower() != ".stl":
30
+ raise ValueError(f"Provided file is not an STL: {stl_path}")
31
+ return [stl_path]
32
+
33
+ if stl_path.is_dir():
34
+ files = []
35
+ for name in os.listdir(stl_path):
36
+ p = stl_path / name
37
+ if p.is_file() and p.suffix.lower() == ".stl":
38
+ files.append(p)
39
+ if not files:
40
+ raise ValueError(f"No .stl files found in folder: {stl_path}")
41
+ return files
42
+
43
+ raise FileNotFoundError(f"Path does not exist: {stl_path}")
44
+
45
+
46
+ def extract_features(stl_file: Path):
47
+ mesh = trimesh.load(stl_file, force="mesh")
48
+ if mesh.is_empty:
49
+ raise ValueError(f"Empty mesh in file: {stl_file}")
50
+
51
+ file_weight_kb = os.path.getsize(stl_file) / 1024.0
52
+ bbox_x, bbox_y, bbox_z = mesh.bounding_box.extents
53
+
54
+ volume = mesh.volume
55
+ surface_area = mesh.area
56
+
57
+ stl = {
58
+ "file_name": stl_file.name,
59
+ "file_path": str(stl_file),
60
+ "kb": file_weight_kb,
61
+ "volume": volume,
62
+ "surface_area": surface_area,
63
+ "scale": mesh.scale,
64
+ "bbox_area": bbox_x * bbox_y * bbox_z,
65
+ "euler_number": mesh.euler_number,
66
+ "surface_volume_ratio": surface_area / volume if volume != 0 else None,
67
+ }
68
+ return stl
69
+
70
+
71
+ def main():
72
+ args = parse_args()
73
+
74
+ stl_path = Path(args.stl_path).expanduser().resolve()
75
+ output_dir = Path(args.output_path).expanduser().resolve()
76
+
77
+ output_dir.mkdir(parents=True, exist_ok=True)
78
+
79
+ stl_files = collect_stl_files(stl_path)
80
+ total = len(stl_files)
81
+
82
+ rows = []
83
+ for i, f in enumerate(stl_files, start=1):
84
+ try:
85
+ features = extract_features(f)
86
+ rows.append(features)
87
+ except Exception as e:
88
+ print(f"\n[WARN] Skipping {f}: {e}")
89
+ # simple progress bar
90
+ pct = i / total * 100
91
+ bar_len = 30
92
+ filled = int(bar_len * i / total)
93
+ bar = "#" * filled + "-" * (bar_len - filled)
94
+ print(f"\r[{bar}] {i}/{total} ({pct:5.1f}%)", end="", flush=True)
95
+
96
+ print() # newline after progress bar
97
+
98
+ if not rows:
99
+ raise RuntimeError("No valid STL files processed; nothing to save.")
100
+
101
+ df = pd.DataFrame(rows)
102
+
103
+ out_csv = output_dir / "stl_features.csv"
104
+ df.to_csv(out_csv, index=False)
105
+ print(f"Saved {len(df)} rows to {out_csv}")
106
+
107
+
108
+ if __name__ == "__main__":
109
+ main()