AnasSarkiz/magnetic-shutter-remote-r8
A USB‑C rechargeable battery-powered ESP32‑C3 wireless controller with Li‑ion charging, protected 3.3‑V buck‑boost regulation, thermal/safety monitoring, status LEDs, buttons, programming UART, crystal clock, and 2.4‑GHz antenna matching network.
- Version
- 0.4.0-prototype
- License
- unset
- Stars
- 0
scripts/review-product-stls.py
"""Independent binary STL readback: exact edges, winding, areas and components."""
import argparse
import collections
import hashlib
import json
import math
from pathlib import Path
import struct
ROOT = Path(__file__).resolve().parents[1]
def review(output):
reports = []
for path in sorted((ROOT/'product/prints').glob('*.stl')):
blob = path.read_bytes()
count = struct.unpack_from('<I', blob, 80)[0]
if len(blob) != 84+50*count:
raise ValueError(f'Invalid binary STL length: {path.name}')
edges, directed = collections.Counter(), collections.Counter()
vertices, areas = [], []
neighbours = collections.defaultdict(set)
for index in range(count):
coordinates = struct.unpack_from('<12fH', blob, 84+50*index)[3:12]
if not all(math.isfinite(c) for c in coordinates):
raise ValueError(f'Nonfinite STL coordinate: {path.name}')
triangle = [tuple(coordinates[start:start+3]) for start in (0, 3, 6)]
a, b, c = triangle
u, v = [b[i]-a[i] for i in range(3)], [c[i]-a[i] for i in range(3)]
cross = (u[1]*v[2]-u[2]*v[1], u[2]*v[0]-u[0]*v[2], u[0]*v[1]-u[1]*v[0])
areas.append(math.sqrt(sum(component**2 for component in cross))/2)
vertices.extend(triangle)
for start, end in zip(triangle, triangle[1:]+triangle[:1]):
edges[tuple(sorted((start, end)))] += 1
directed[(start, end)] += 1
neighbours[start].add(end)
neighbours[end].add(start)
remaining, components = set(vertices), 0
while remaining:
components += 1
queue = [remaining.pop()]
while queue:
for vertex in neighbours[queue.pop()]:
if vertex in remaining:
remaining.remove(vertex)
queue.append(vertex)
report = {
'file': str(path.relative_to(ROOT)),
'sha256': hashlib.sha256(blob).hexdigest(),
'triangles': count,
'zero_area_triangles': sum(area == 0 for area in areas),
'nonmanifold_edges': sum(count != 2 for count in edges.values()),
'winding_errors': sum(count != directed[(end, start)] for (start, end), count in directed.items()),
'connected_components': components,
'minimum_triangle_area_mm2': min(areas),
'bounds_mm': [[min(v[a] for v in vertices) for a in range(3)],
[max(v[a] for v in vertices) for a in range(3)]],
}
reports.append(report)
output.parent.mkdir(parents=True, exist_ok=True)
output.write_text(json.dumps(reports, indent=2)+'\n')
if len(reports) != 8 or any(r['zero_area_triangles'] or r['nonmanifold_edges'] or
r['winding_errors'] or r['connected_components'] != 1 for r in reports):
raise ValueError('Independent actual STL readback failed; inspect the retained report')
print('Eight exact binary STL edge/winding/area/component checks pass')
if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument('--output', type=Path, required=True)
review(parser.parse_args().output)