fixed commetn from songxiao

This commit is contained in:
ykcheungab
2026-09-25 17:46:37 +08:00
parent 6effe74172
commit 12781854ca
56 changed files with 4935 additions and 419 deletions
+224 -2
View File
@@ -9,6 +9,7 @@ stage owes, and a synthetic one can only prove the code agrees with itself.
from __future__ import annotations
import json
import shutil
import struct
import zipfile
from pathlib import Path
@@ -42,8 +43,11 @@ from orisys_app_shared.scene3d.glb import (
from orisys_app_shared.scene3d.legacy import (
LegacyFingerImporter,
build_binding,
crease_aware_mesh,
estimate_meters_per_source_unit,
load_legacy_domain,
normals_disagree_with_faces,
split_at_crease_edges,
split_at_uv_seams,
uv_correspondence_residual,
validate_rigid_transform,
@@ -72,9 +76,11 @@ def _identity() -> np.ndarray:
def _import_run(**kwargs) -> SceneAssets:
export_dir = kwargs.pop("export_dir", RUN_DIR)
map_path = kwargs.pop("map_path", RUN_MAP)
return LegacyFingerImporter().convert(
RUN_DIR,
RUN_MAP,
export_dir,
map_path,
transform_sensor_from_source=kwargs.pop("transform", _identity()),
meters_per_source_unit=kwargs.pop("units", 1e-3),
**kwargs,
@@ -97,6 +103,79 @@ def test_the_real_export_imports_and_validates():
assert assets.source_vertex_of_render.shape == (1032,)
def _write_housing(path: Path) -> Path:
"""A tiny tetrahedron standing in for a mounting frame."""
vertices = np.array(
[[0.0, 0.0, 0.0], [10.0, 0.0, 0.0], [0.0, 10.0, 0.0], [0.0, 0.0, 10.0]],
dtype=np.float32,
)
faces = np.array([[0, 1, 2], [0, 1, 3], [0, 2, 3], [1, 2, 3]], dtype=np.int32)
np.savez(path, vertices=vertices, faces=faces)
return path
@requires_run
def test_a_housing_becomes_its_own_part_without_touching_the_geometry_ids(tmp_path: Path):
"""The frame is display-only: it must not enter the identities the device verifies."""
plain = _import_run()
housing_path = _write_housing(tmp_path / "housing.npz")
with_housing = _import_run(housing_path=housing_path)
assert [part.part_id for part in plain.parts] == ["sensing_surface"]
assert [(part.part_id, part.role) for part in with_housing.parts] == [
("sensing_surface", "sensing"),
("housing", "housing"),
]
assert with_housing.geometry_id == plain.geometry_id, (
"adding a housing changed the sensing geometry id, which the device verifies"
)
assert with_housing.source_geometry_id == plain.source_geometry_id
assert with_housing.asset_hash != plain.asset_hash, (
"the package content changed, so the asset hash has to say so"
)
assert validate_assets(with_housing) == ()
# Units and the rigid transform are applied to the housing exactly as to the surface.
frame = with_housing.part("housing")
assert frame is not None
assert np.allclose(np.ptp(np.asarray(frame.positions_sensor_m), axis=0), 0.01, atol=1e-6)
@requires_run
def test_a_housing_in_the_export_directory_is_used_automatically(tmp_path: Path, monkeypatch):
"""``<legacy-dir>/housing.npz`` is picked up, so a re-export needs no new flag."""
export = tmp_path / "export"
export.mkdir()
shutil.copy(RUN_DIR / "mesh.npz", export / "mesh.npz")
assert len(_import_run(export_dir=export).parts) == 1
_write_housing(export / "housing.npz")
assert [part.role for part in _import_run(export_dir=export).parts] == [
"sensing",
"housing",
]
@requires_run
def test_a_requested_housing_that_is_missing_is_refused(tmp_path: Path):
"""A missing frame must not look like a package that simply has none."""
with pytest.raises(ThreeDError) as caught:
_import_run(housing_path=tmp_path / "not-there.npz")
assert caught.value.diagnostic.code == "geometry_mismatch"
@requires_run
def test_a_housing_with_an_out_of_range_triangle_is_refused(tmp_path: Path):
path = tmp_path / "housing.npz"
np.savez(
path,
vertices=np.zeros((3, 3), dtype=np.float32),
faces=np.array([[0, 1, 9]], dtype=np.int32),
)
with pytest.raises(ThreeDError) as caught:
_import_run(housing_path=path)
assert caught.value.diagnostic.code == "geometry_mismatch"
@requires_run
def test_the_uv_convention_is_measured_against_the_asset():
"""The one fact the importer must not guess: which pixel a UV addresses."""
@@ -235,6 +314,149 @@ def test_vertex_normals_are_unit_and_area_weighted():
assert np.isfinite(lonely[4]).all()
def _box(half: float = 1.0) -> tuple[np.ndarray, np.ndarray]:
"""A closed cube: every corner is a 90° crease, every edge a smooth pair."""
positions = np.array(
[
[-half, -half, -half], [half, -half, -half], [half, half, -half],
[-half, half, -half], [-half, -half, half], [half, -half, half],
[half, half, half], [-half, half, half],
],
dtype=np.float64,
)
triangles = np.array(
[
[0, 2, 1], [0, 3, 2], # -z
[4, 5, 6], [4, 6, 7], # +z
[0, 1, 5], [0, 5, 4], # -y
[2, 3, 7], [2, 7, 6], # +y
[1, 2, 6], [1, 6, 5], # +x
[3, 0, 4], [3, 4, 7], # -x
],
dtype=np.int64,
)
return positions, triangles
def test_crease_aware_normals_agree_with_every_face_of_a_box():
"""The defect this fixes: an averaged corner normal agrees with *no* face."""
positions, triangles = _box()
averaged = vertex_normals(positions, triangles)
crease = crease_aware_mesh(positions, triangles)
split_positions, split_triangles, split_normals = crease
assert len(split_triangles) == len(triangles), "splitting must not change the faces"
assert len(split_positions) == 24, "each of the 8 corners needs 3 normals"
def worst(normals, faces, verts):
a, b, c = verts[faces[:, 0]], verts[faces[:, 1]], verts[faces[:, 2]]
face = np.cross(b - a, c - a)
unit = face / np.linalg.norm(face, axis=1, keepdims=True)
incident = [[] for _ in range(len(verts))]
for index, triangle in enumerate(faces):
for k in range(3):
incident[int(triangle[k])].append(index)
return max(
float(np.degrees(np.arccos(np.clip(unit[incident[v]] @ normals[v], -1, 1))).min())
for v in range(len(verts))
if incident[v]
)
assert worst(averaged, triangles, positions) > 30.0, (
"the fixture must actually exhibit the defect"
)
assert worst(split_normals, split_triangles, split_positions) < 1e-6, (
"a split corner normal must be exactly a face normal on a cube"
)
def test_crease_splitting_keeps_the_smooth_parts_welded():
"""A cylinder's curved side must survive whole; only its rim split."""
ring = 24
angles = np.linspace(0.0, 2.0 * np.pi, ring, endpoint=False)
positions = np.vstack(
[
np.column_stack([np.cos(angles), np.sin(angles), np.zeros(ring)]),
np.column_stack([np.cos(angles), np.sin(angles), np.ones(ring)]),
]
)
triangles = []
for i in range(ring):
j = (i + 1) % ring
triangles.append([i, j, ring + i])
triangles.append([j, ring + j, ring + i])
triangles = np.asarray(triangles, dtype=np.int64)
split_positions, split_triangles, _ = split_at_crease_edges(positions, triangles)
# The side is a smooth ring (3.7° per step), so nothing on it may be duplicated;
# the two rims are boundaries, so the split only separates the *caps'* edges.
assert len(split_triangles) == len(triangles)
assert len(split_positions) == len(positions), (
"a smoothly curved side must stay welded"
)
def test_normals_disagree_with_faces_detects_the_defect():
positions, triangles = _box()
assert normals_disagree_with_faces(
positions, triangles, vertex_normals(positions, triangles)
)
_, _, crease = crease_aware_mesh(positions, triangles)
split_positions, split_triangles, _ = split_at_crease_edges(positions, triangles)
assert not normals_disagree_with_faces(split_positions, split_triangles, crease)
# A flat sheet has no crease at all.
flat = np.array([[0.0, 0.0, 0.0], [1.0, 0.0, 0.0], [0.0, 1.0, 0.0]])
assert not normals_disagree_with_faces(
flat, np.array([[0, 1, 2]]), np.array([[0.0, 0.0, 1.0]] * 3)
)
@requires_run
def test_the_shipped_housing_has_no_stale_shading():
"""The real housing: 134 of 2172 edges are creases, so plain averaging bands."""
import io
import zipfile
package = (
Path(__file__).resolve().parents[2]
/ "apps" / "studio" / "config" / "sensors" / "finger" / "scene"
/ "finger-display-1.0.0.oryscene"
)
if not package.is_file():
pytest.skip("the compiled finger package is not present")
with zipfile.ZipFile(package) as archive:
positions = np.load(io.BytesIO(archive.read("housing/positions.npy"))).astype(np.float64)
triangles = np.load(io.BytesIO(archive.read("housing/triangles.npy"))).astype(np.int64)
normals = np.load(io.BytesIO(archive.read("housing/normals.npy"))).astype(np.float64)
# Every stored normal agrees with an incident face, which is only possible
# because the source mesh's 726 vertices became 861 (one per side of a crease).
assert not normals_disagree_with_faces(positions, triangles, normals), (
"the shipped housing still carries normals averaged across its 90° corners"
)
# ...and the split is not a blanket unweld: the smooth vertices stay shared.
unique_positions = len(np.unique(positions, axis=0))
assert unique_positions == 726, (
f"{unique_positions} unique positions: the smooth surface was unwelded too"
)
assert len(positions) == 861, (
f"{len(positions)} vertices: the creases were not split into their own normals"
)
# The source mesh this was compiled from is the shape that used to be shipped,
# and plain averaging on it is exactly the defect.
source = Path(
r"D:\orisys_ws\orisys-sensor-design\build\export\finger\r01\compute\housing.npz"
)
if source.is_file():
with np.load(source, allow_pickle=False) as handle:
source_positions = np.asarray(handle["vertices"], dtype=np.float64)
source_triangles = np.asarray(handle["faces"], dtype=np.int64)
assert len(source_positions) == 726, len(source_positions)
assert normals_disagree_with_faces(
source_positions,
source_triangles,
vertex_normals(source_positions, source_triangles),
), "the detector does not fire on the geometry that actually banded"
# ------------------------------------------------------------------- binding
def _domain(shape_hw=(4, 5), flip_v=False, world=None):
valid = np.ones(shape_hw, dtype=bool)