"""Unit tests for stl_sampler.""" from __future__ import annotations import io import struct import numpy as np import pytest from presa_mano.perception.stl_sampler import parse_stl_bytes, sample_surface def _make_cube_stl_bytes(side_mm: float = 10.0) -> bytes: """Synthesize a binary STL of an axis-aligned cube centered at origin, from -side/2 to +side/2 on each axis. 12 triangles, no normals needed.""" s = side_mm / 2.0 v = [ (-s, -s, -s), ( s, -s, -s), ( s, s, -s), (-s, s, -s), (-s, -s, s), ( s, -s, s), ( s, s, s), (-s, s, s), ] # 6 faces x 2 tris (vertex order: any orientation works for our use) tris = [ (0, 1, 2), (0, 2, 3), # z=-s (4, 6, 5), (4, 7, 6), # z=+s (0, 4, 5), (0, 5, 1), # y=-s (3, 2, 6), (3, 6, 7), # y=+s (0, 3, 7), (0, 7, 4), # x=-s (1, 5, 6), (1, 6, 2), # x=+s ] buf = io.BytesIO() buf.write(b"\x00" * 80) # header buf.write(struct.pack("= 8% dei punti (perfetto = 100/6 ~= 16.7% per faccia, distribuita su 4 octanti adiacenti).""" stl_bytes = _make_cube_stl_bytes(side_mm=10.0) verts, tris = parse_stl_bytes(stl_bytes) pts = sample_surface(verts, tris, n=2000, seed=1) counts = np.zeros(8, dtype=np.int64) for p in pts: # bin (x>0, y>0, z>0) -> 0..7 idx = (int(p[0] > 0) << 2) | (int(p[1] > 0) << 1) | int(p[2] > 0) counts[idx] += 1 frac = counts / pts.shape[0] assert (frac > 0.08).all(), f"octant fractions too uneven: {frac}" def test_sample_surface_seed_deterministic(): stl_bytes = _make_cube_stl_bytes(side_mm=10.0) verts, tris = parse_stl_bytes(stl_bytes) a = sample_surface(verts, tris, n=100, seed=42) b = sample_surface(verts, tris, n=100, seed=42) np.testing.assert_array_equal(a, b) def test_parse_stl_bad_payload_raises(): with pytest.raises(Exception): # numpy-stl raises various; we just want it to not silently pass parse_stl_bytes(b"not a real STL")