Spaces:
Sleeping
Sleeping
File size: 6,746 Bytes
7c72eb2 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 | import tempfile
from pathlib import Path
import numpy as np
import pytest
from server.preprocessor import (
normalize_shape,
sample_surface_points,
voxelize,
preprocess_from_code,
_occ_to_trimesh,
)
class TestNormalizeShape:
def test_centered_at_origin(self, flat_plate_shape):
normalized, info = normalize_shape(flat_plate_shape)
bb = normalized.BoundingBox()
cx = (bb.xmin + bb.xmax) / 2
cy = (bb.ymin + bb.ymax) / 2
cz = (bb.zmin + bb.zmax) / 2
assert abs(cx) < 0.02
assert abs(cy) < 0.02
assert abs(cz) < 0.02
def test_longest_axis_is_x(self, flat_plate_shape):
normalized, info = normalize_shape(flat_plate_shape)
bb = normalized.BoundingBox()
assert bb.xlen >= bb.ylen
assert bb.xlen >= bb.zlen
def test_preserves_volume(self, flat_plate_shape):
original_vol = flat_plate_shape.Volume()
normalized, _ = normalize_shape(flat_plate_shape)
new_vol = normalized.Volume()
assert abs(original_vol - new_vol) / original_vol < 0.01
def test_transform_info(self, flat_plate_shape):
_, info = normalize_shape(flat_plate_shape)
assert "units" in info
assert info["units"] == "mm"
assert "translation_to_origin" in info
assert "longest_axis" in info
assert info["longest_axis"] == "X"
def test_box_with_hole_normalized(self, box_with_hole_shape):
normalized, info = normalize_shape(box_with_hole_shape)
bb = normalized.BoundingBox()
assert bb.xlen >= bb.ylen >= bb.zlen
class TestOccToTrimesh:
def test_returns_trimesh(self, flat_plate_shape):
normalized, _ = normalize_shape(flat_plate_shape)
mesh = _occ_to_trimesh(normalized)
import trimesh
assert isinstance(mesh, trimesh.Trimesh)
assert len(mesh.vertices) > 0
assert len(mesh.faces) > 0
def test_mesh_is_valid(self, flat_plate_shape):
normalized, _ = normalize_shape(flat_plate_shape)
mesh = _occ_to_trimesh(normalized)
assert not mesh.is_empty
class TestSampleSurfacePoints:
def test_returns_correct_shape(self, flat_plate_shape):
normalized, _ = normalize_shape(flat_plate_shape)
points = sample_surface_points(normalized, n_points=1024)
assert points.shape == (1024, 3)
assert points.dtype == np.float32
def test_points_near_surface(self, flat_plate_shape):
normalized, _ = normalize_shape(flat_plate_shape)
bb = normalized.BoundingBox()
points = sample_surface_points(normalized, n_points=2048)
assert np.all(points[:, 0] >= bb.xmin - 0.1)
assert np.all(points[:, 0] <= bb.xmax + 0.1)
assert np.all(points[:, 1] >= bb.ymin - 0.1)
assert np.all(points[:, 1] <= bb.ymax + 0.1)
assert np.all(points[:, 2] >= bb.zmin - 0.1)
assert np.all(points[:, 2] <= bb.zmax + 0.1)
def test_different_n_points(self, flat_plate_shape):
normalized, _ = normalize_shape(flat_plate_shape)
for n in [256, 512, 2048]:
pts = sample_surface_points(normalized, n_points=n)
assert pts.shape[0] == n
class TestVoxelize:
def test_returns_correct_shape(self, flat_plate_shape):
normalized, _ = normalize_shape(flat_plate_shape)
grid = voxelize(normalized, resolution=32)
assert grid.shape == (32, 32, 32)
assert grid.dtype == bool
def test_has_filled_voxels(self, flat_plate_shape):
normalized, _ = normalize_shape(flat_plate_shape)
grid = voxelize(normalized, resolution=32)
assert grid.sum() > 0
def test_not_all_filled(self, flat_plate_shape):
normalized, _ = normalize_shape(flat_plate_shape)
grid = voxelize(normalized, resolution=32)
assert grid.sum() < 32 * 32 * 32
def test_hollow_shape_has_fewer_voxels(self, flat_plate_shape, box_with_hole_shape):
norm_plate, _ = normalize_shape(flat_plate_shape)
norm_hole, _ = normalize_shape(box_with_hole_shape)
grid_plate = voxelize(norm_plate, resolution=32)
grid_hole = voxelize(norm_hole, resolution=32)
plate_fill = grid_plate.sum() / (32**3)
hole_fill = grid_hole.sum() / (32**3)
assert plate_fill > 0
assert hole_fill > 0
def test_resolution_64(self, flat_plate_shape):
normalized, _ = normalize_shape(flat_plate_shape)
grid = voxelize(normalized, resolution=64)
assert grid.shape == (64, 64, 64)
assert grid.sum() > 0
class TestPreprocessFromCode:
def test_generates_all_files(self, flat_plate_code):
with tempfile.TemporaryDirectory() as tmpdir:
gt = preprocess_from_code(flat_plate_code, tmpdir, task_id="test_flat_plate")
output_path = Path(tmpdir)
assert (output_path / "ground_truth.json").exists()
assert (output_path / "ground_truth.step").exists()
assert (output_path / "ground_truth_normalized.step").exists()
assert (output_path / "surface_points.npy").exists()
assert (output_path / "voxels_64.npy").exists()
def test_ground_truth_json_contents(self, flat_plate_code):
with tempfile.TemporaryDirectory() as tmpdir:
gt = preprocess_from_code(flat_plate_code, tmpdir, task_id="test_flat_plate")
assert "volume_mm3" in gt
assert "bbox_mm" in gt
assert "face_count" in gt
assert "dominant_face_type" in gt
assert "surface_points_file" in gt
assert "voxels_file" in gt
assert gt["volume_mm3"] > 0
assert gt["face_count"] == 6
def test_surface_points_file(self, flat_plate_code):
with tempfile.TemporaryDirectory() as tmpdir:
preprocess_from_code(flat_plate_code, tmpdir)
pts = np.load(str(Path(tmpdir) / "surface_points.npy"))
assert pts.shape == (2048, 3)
def test_voxels_file(self, flat_plate_code):
with tempfile.TemporaryDirectory() as tmpdir:
preprocess_from_code(flat_plate_code, tmpdir)
vox = np.load(str(Path(tmpdir) / "voxels_64.npy"))
assert vox.shape == (64, 64, 64)
assert vox.sum() > 0
def test_invalid_code_raises(self, invalid_code):
with tempfile.TemporaryDirectory() as tmpdir:
with pytest.raises(Exception):
preprocess_from_code(invalid_code, tmpdir)
def test_no_result_raises(self, no_result_code):
with tempfile.TemporaryDirectory() as tmpdir:
with pytest.raises(ValueError, match="result"):
preprocess_from_code(no_result_code, tmpdir)
|