feat(core): slab + sparse motifs, slice 1 -- flat field, monolith, platform at 0.52 s (L56); research R25
Motif vocabulary v3: version-1 records keyed by (seed, strate, stable ID) with route keepouts, band clearance and pairwise spacing. A rounded capped-cylinder monolith (r 1.4 m, 24 m tall) and a rounded-box plinth, smooth-unioned into a flatField floor with a 0.55 m geometric rounding (measured fillets 0.73-1.17 m). Exact radial/box interval bounds, a BVH, isTileShapeFree aware (0 brute-force misses, false-proof controls rejected). Final-field route passes; whole-surface audit covers foot, cap and platform edges. Cold whole view 0.524 s. Owner world unchanged. fast/medium/full PASS (Clang and GCC). Research R25 (self-checked): FloatingIslands LOD0 column cache conflicts. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016dhxM43dnWvUu2B5Ph1iG1
This commit is contained in:
1 parent
aee1487410
commit
4e64b75044
15 files changed
+1560
-12
No files matched your search
@@ -0,0 +1,213 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Audit LOD0 triangles in the resolved monolith and platform surface ROIs."""
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import array
|
||||
import json
|
||||
import math
|
||||
from pathlib import Path
|
||||
import struct
|
||||
import sys
|
||||
|
||||
|
||||
def solve3(matrix, vector):
|
||||
rows = [list(matrix[i]) + [vector[i]] for i in range(3)]
|
||||
for column in range(3):
|
||||
pivot = max(range(column, 3), key=lambda row: abs(rows[row][column]))
|
||||
if abs(rows[pivot][column]) < 1.0e-10:
|
||||
return None
|
||||
rows[column], rows[pivot] = rows[pivot], rows[column]
|
||||
scale = rows[column][column]
|
||||
rows[column] = [value / scale for value in rows[column]]
|
||||
for row in range(3):
|
||||
if row == column:
|
||||
continue
|
||||
scale = rows[row][column]
|
||||
rows[row] = [rows[row][i] - scale * rows[column][i] for i in range(4)]
|
||||
return [rows[row][3] for row in range(3)]
|
||||
|
||||
|
||||
def fit_radius(points, center_x, center_z, center_y, window=1.05, y_window=1.3):
|
||||
selected = sorted({(round(x, 4), round(z, 4)) for x, y, z in points
|
||||
if abs(y - center_y) <= y_window
|
||||
and abs(x - center_x) <= window and abs(z - center_z) <= window})
|
||||
if len(selected) < 8:
|
||||
return None, len(selected)
|
||||
sums = [0.0] * 9
|
||||
rhs = [0.0] * 3
|
||||
for x, z in selected:
|
||||
row = (x, z, 1.0)
|
||||
target = -(x * x + z * z)
|
||||
for i in range(3):
|
||||
rhs[i] += row[i] * target
|
||||
for j in range(3):
|
||||
sums[i * 3 + j] += row[i] * row[j]
|
||||
solution = solve3([sums[0:3], sums[3:6], [sums[6], sums[7], sums[8]]], rhs)
|
||||
if solution is None:
|
||||
return None, len(selected)
|
||||
a, b, c = solution
|
||||
radius_squared = (a * a + b * b) * 0.25 - c
|
||||
if radius_squared <= 0.0:
|
||||
return None, len(selected)
|
||||
return math.sqrt(radius_squared), len(selected)
|
||||
|
||||
|
||||
def read_mesh(path: Path):
|
||||
triangles = []
|
||||
vertices_all = []
|
||||
selected_tiles = 0
|
||||
with path.open("rb") as stream:
|
||||
prefix = stream.read(60)
|
||||
if len(prefix) != 60 or prefix[:8] != b"VFMSH001":
|
||||
raise ValueError(f"{path}: invalid VFMSH001 header")
|
||||
version, voxel_um, tile_count = struct.unpack_from("<3I", prefix, 8)
|
||||
if version != 1 or voxel_um <= 0 or tile_count > 1_000_000:
|
||||
raise ValueError(f"{path}: invalid mesh version or size")
|
||||
for _ in range(tile_count):
|
||||
header = stream.read(36)
|
||||
if len(header) != 36:
|
||||
raise ValueError(f"{path}: truncated tile header")
|
||||
key = struct.unpack_from("<4i", header, 0)
|
||||
surface_count, _aux_count, vertex_count, index_count, mask_count = \
|
||||
struct.unpack_from("<5I", header, 16)
|
||||
position_bytes = stream.read(vertex_count * 12)
|
||||
normal_bytes = stream.read(vertex_count * 12)
|
||||
index_bytes = stream.read(index_count * 4)
|
||||
masks = stream.read(mask_count)
|
||||
if (len(position_bytes) != vertex_count * 12
|
||||
or len(normal_bytes) != vertex_count * 12
|
||||
or len(index_bytes) != index_count * 4
|
||||
or len(masks) != mask_count):
|
||||
raise ValueError(f"{path}: truncated tile payload")
|
||||
if key[3] != 0:
|
||||
continue
|
||||
selected_tiles += 1
|
||||
positions = array.array("f")
|
||||
positions.frombytes(position_bytes)
|
||||
indices = array.array("I")
|
||||
indices.frombytes(index_bytes)
|
||||
if sys.byteorder != "little":
|
||||
positions.byteswap()
|
||||
indices.byteswap()
|
||||
points = [tuple(float(positions[index * 3 + axis])
|
||||
for axis in range(3)) for index in range(vertex_count)]
|
||||
vertices_all.extend(points)
|
||||
for offset in range(0, index_count - 2, 3):
|
||||
if masks and masks[offset // 3]:
|
||||
continue
|
||||
ids = indices[offset:offset + 3]
|
||||
if max(ids) >= surface_count:
|
||||
continue
|
||||
verts = tuple(points[index] for index in ids)
|
||||
edge_a = tuple(verts[1][axis] - verts[0][axis] for axis in range(3))
|
||||
edge_b = tuple(verts[2][axis] - verts[0][axis] for axis in range(3))
|
||||
cross = (edge_a[1] * edge_b[2] - edge_a[2] * edge_b[1],
|
||||
edge_a[2] * edge_b[0] - edge_a[0] * edge_b[2],
|
||||
edge_a[0] * edge_b[1] - edge_a[1] * edge_b[0])
|
||||
area_twice = math.sqrt(sum(value * value for value in cross))
|
||||
if area_twice <= 1.0e-10:
|
||||
continue
|
||||
center = tuple(sum(vertex[axis] for vertex in verts) / 3.0
|
||||
for axis in range(3))
|
||||
triangles.append((center, area_twice * 0.5, verts))
|
||||
if stream.read(1):
|
||||
raise ValueError(f"{path}: trailing mesh data")
|
||||
return triangles, vertices_all, selected_tiles
|
||||
|
||||
|
||||
def main() -> int:
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument("meshes", type=Path, nargs="+")
|
||||
parser.add_argument("layout", type=Path)
|
||||
parser.add_argument("--view", required=True, choices=("combined",))
|
||||
args = parser.parse_args()
|
||||
layout = json.loads(args.layout.read_text(encoding="utf-8"))
|
||||
motifs = layout.get("stamps", [])
|
||||
monolith = next(row for row in motifs if row["kind"] == 5)
|
||||
platform = next(row for row in motifs if row["kind"] == 6)
|
||||
mesh_rows = [read_mesh(path) for path in args.meshes]
|
||||
triangles = [triangle for row in mesh_rows for triangle in row[0]]
|
||||
vertices = [vertex for row in mesh_rows for vertex in row[1]]
|
||||
tiles = sum(row[2] for row in mesh_rows)
|
||||
if not triangles:
|
||||
raise ValueError("meshes have no LOD0 surface triangles")
|
||||
|
||||
def metres(point):
|
||||
return tuple(value / 1_000_000.0 for value in point)
|
||||
|
||||
mono = metres(monolith["position_um"])
|
||||
floor = monolith["floor_um"] / 1_000_000.0
|
||||
radius = monolith["half_extents_um"][0] / 1_000_000.0
|
||||
half_height = monolith["half_extents_um"][2] / 1_000_000.0
|
||||
mono_round = monolith["rounding_radius_um"] / 1_000_000.0
|
||||
plat = metres(platform["position_um"])
|
||||
half = tuple(value / 1_000_000.0 for value in platform["half_extents_um"])
|
||||
plat_round = platform["rounding_radius_um"] / 1_000_000.0
|
||||
top = floor + 2.0 * half_height
|
||||
|
||||
rois = {
|
||||
"monolith_foot": lambda p: math.hypot(p[0] - mono[0], p[1] - mono[1]) <= radius + 1.4
|
||||
and floor - 1.0 <= p[2] <= floor + 2.1,
|
||||
"monolith_cap": lambda p: math.hypot(p[0] - mono[0], p[1] - mono[1]) <= radius + 1.6
|
||||
and top - 2.0 <= p[2] <= top + 1.1,
|
||||
"platform_edges": lambda p: abs(p[0] - plat[0]) <= half[0] + 1.2
|
||||
and abs(p[1] - plat[1]) <= half[1] + 1.2
|
||||
and floor - 0.8 <= p[2] <= floor + 2.4 * half[2] + 0.8,
|
||||
}
|
||||
roi_counts = {name: sum(1 for center, _area, _verts in triangles if predicate(center))
|
||||
for name, predicate in rois.items()}
|
||||
bad_area = sum(1 for _center, area, _verts in triangles if not math.isfinite(area) or area <= 0.0)
|
||||
foot_radius, foot_points = fit_radius(vertices, mono[0] + radius - mono_round,
|
||||
floor + mono_round, mono[1], window=1.1)
|
||||
cap_radius, cap_points = fit_radius(vertices, mono[0] + radius - mono_round,
|
||||
top - mono_round, mono[1], window=1.1)
|
||||
platform_radius, platform_points = fit_radius(vertices,
|
||||
plat[0] + half[0] - plat_round, floor + 2.0 * half[2] - plat_round,
|
||||
plat[1], window=1.1)
|
||||
radii = (foot_radius, cap_radius, platform_radius)
|
||||
fit_counts = (foot_points, cap_points, platform_points)
|
||||
def surface_pass(tile_count, degenerate_count, rois, measured_radii):
|
||||
covered = all(count >= 8 for count in rois.values())
|
||||
rounded = all(value is not None and value >= 0.5 for value in measured_radii)
|
||||
return tile_count > 0 and degenerate_count == 0 and covered and rounded
|
||||
|
||||
radius_ok = all(value is not None and value >= 0.5 for value in radii)
|
||||
coverage_ok = all(count >= 8 for count in roi_counts.values())
|
||||
missing_roi = dict(roi_counts)
|
||||
missing_roi["monolith_foot"] = 0
|
||||
sharp_edge = list(radii)
|
||||
sharp_edge[0] = 0.25
|
||||
controls_rejected = (
|
||||
not surface_pass(tiles, bad_area, missing_roi, radii)
|
||||
and not surface_pass(tiles, bad_area, roi_counts, sharp_edge)
|
||||
and not surface_pass(0, 0, roi_counts, radii)
|
||||
)
|
||||
passed = surface_pass(tiles, bad_area, roi_counts, radii) and controls_rejected
|
||||
for name, count in roi_counts.items():
|
||||
print(f"[MotifSurfaceROI] view={args.view} name={name} triangles={count} "
|
||||
f"whole_surface=LOD0 status={'PASS' if count >= 8 else 'FAIL'}")
|
||||
if all(value is not None for value in radii):
|
||||
print(f"[MotifFilletMeasure] view={args.view} foot_radius_m={foot_radius:.3f} "
|
||||
f"cap_radius_m={cap_radius:.3f} platform_radius_m={platform_radius:.3f} "
|
||||
f"fit_points={fit_counts} target_min_m=0.500")
|
||||
else:
|
||||
print(f"[MotifFilletMeasure] view={args.view} foot_radius_m={foot_radius} "
|
||||
f"cap_radius_m={cap_radius} platform_radius_m={platform_radius} "
|
||||
f"fit_points={fit_counts} target_min_m=0.500")
|
||||
print(f"[MotifSurfaceAudit] view={args.view} meshes={len(mesh_rows)} lod0_tiles={tiles} triangles={len(triangles)} "
|
||||
f"degenerate={bad_area} feature_rois={len(roi_counts)} covered={coverage_ok} "
|
||||
f"fillets_ge_0.5m={radius_ok} missing_roi_control={'REJECTED' if not surface_pass(tiles, bad_area, missing_roi, radii) else 'FAILED'} "
|
||||
f"sharp_fillet_control={'REJECTED' if not surface_pass(tiles, bad_area, roi_counts, sharp_edge) else 'FAILED'} "
|
||||
f"empty_mesh_control={'REJECTED' if not surface_pass(0, 0, roi_counts, radii) else 'FAILED'} "
|
||||
f"negative_controls={'REJECTED' if controls_rejected else 'FAILED'} "
|
||||
f"status={'PASS' if passed else 'FAIL'}")
|
||||
return 0 if passed else 1
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
try:
|
||||
raise SystemExit(main())
|
||||
except Exception as error:
|
||||
print(f"[MotifSurfaceAudit] status=FAIL error={error}", file=sys.stderr)
|
||||
raise SystemExit(1)
|
||||
Reference in new issue
Block a user