wip(l59): open helix shaft (ledge open to the core) -- PARKED: jagged inner ramp edge, audit ROI missed it

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016dhxM43dnWvUu2B5Ph1iG1
This commit is contained in:
Fr0zkaandClaude Opus 5.5 committed 2026-10-25 20:27:04 +01:00
1 parent 6c6cc37e1d
commit 54ba1b49ab
17 files changed
+1167 -172

No files matched your search

+25 -21
View File
@@ -2265,32 +2265,36 @@ mouth and off the walk route. It stays disabled by default. Active records carry
L43's report records the off/on hashes, walk and interface audits, outside-stamp timing, tier L43's report records the off/on hashes, walk and interface audits, outside-stamp timing, tier
results, captures and any failed runs. results, captures and any failed runs.
### 8.54 Opt-in native lattice field — World Assembler M3 R26 slice 1 (Linux L58) ### 8.54 Opt-in native lattice field — World Assembler M3 R26 slices 1–2 (Linux L58–L59)
`Core.Lattice.PrimitiveField` is a version-1 recipe selected only for one Maze or VerticalShafts `Core.Lattice.PrimitiveField` is an opt-in recipe selected only for one Maze or VerticalShafts
strate by `--recipe=lattice --lattice-strate=N`. The legacy generator assets and their default strate by `--recipe=lattice --lattice-strate=N`. The legacy generator assets and their default
dispatch stay unchanged. Planning first binds the actual incoming lower mouth and outgoing upper dispatch stay unchanged. Version 2 binds the actual incoming lower mouth and outgoing upper mouth,
mouth from the resolved passage records, then creates arrival/exit overlap corridors, a mandatory then creates arrival/exit overlap corridors, an open vertical shaft and the maze spine; two
four-turn helix and the maze spine; two deterministic dead ends are added after that route. The deterministic dead ends are added after that route. Resolved room and edge seeds use
resolved room and edge seeds use `(world seed, strate, recipe version, stable ID)`. An audit control `(world seed, strate, recipe version, stable ID)`. The orphan control translates the shaft 20 m
translates the helix 20 m away from both route junctions to make the shaft network orphaned. away from both route junctions and must fail reachability.
The prototype helix uses a 6 m centreline radius, 3 m clear width, 5 m pitch, four turns and 2.6 m The version-2 shaft core is a vertical cylinder of 4.5 m radius. Its air continues 8 m above the
finished floor-to-soffit height. Its centreline descends 20 m over roughly 151 m; the inner-edge top tread and 2 m below the bottom tread. The ramp winds around the core at a 6 m centreline radius,
grade is about 10.0 degrees. The 2.4 m floor-wall smooth-max gives an isolated ideal fillet radius with 3 m clear width, 5 m pitch and four turns. The open annular shaft air joins the core air, while
of 0.8485 m. A separate 0.4 m feature-union blend prevents adjoining ramps from erasing the tread. one-metre support slabs follow the helix under each tread. This leaves a 4 m vertical gap between
The swept-clear diameter is 15 m; the conservative padded feature envelope is about 20.6 m (the one tread and the underside of the next. The ledge's inner edge is open to the well; the route
approved approximately 21 m site envelope). centreline stays 1.5 m from the drop and leaves 1.16 m beyond the 0.34 m capsule radius. Its inner
edge grade is about 10.0 degrees. The maze retains 2.6 m room headroom. The shaft's padded outer
design envelope is 21 m. The 1.9 m floor-wall smooth-max gives an isolated ideal fillet radius of
0.6718 m; the separate 0.05 m feature-union blend keeps route junctions connected.
The layout reuses the resolved cavern graph vocabulary. A per-strate opt-in selects the native The layout reuses the resolved cavern graph vocabulary. A per-strate opt-in selects the native
negative-solid/positive-air field; canonical feature order is stable-ID order. Room/corridor bounds negative-solid/positive-air field; canonical feature order is stable-ID order. The ring-shaped shaft
are indexed by the graph BVH and polyline segments have a nested deterministic BVH for density and air and its support layers use an analytic helix lookup instead of testing every polyline segment
interval queries. Box classification stays conservative, and `isTileShapeFree` refuses any tile per density sample. The core cylinder and annular wall have conservative interval bounds; false
that intersects the graph. The L58 pipeline audits the composed field from actual mouth to mouth all-air and all-solid controls remain rejected, and `isTileShapeFree` refuses occupied tiles. The
with a 0.34 m by 1.76 m capsule, per-station support, 2.2 m clearance and a 15 degree grade limit; L59 pipeline checks the composed field from actual mouth to mouth with a 0.34 m by 1.76 m capsule,
it also checks the orphan control, brute-force interval samples and the composed wall-foot fillet. support at every station, 2.2 m clearance and a 15 degree grade limit. It also checks the orphan
The Linux58 report contains the measured reachability, surface, peer-determinism, timing and capture control, whole-surface ramp lip/wall-foot/underside, brute-force interval samples and the composed
results; the code path is not promoted to legacy Maze/VerticalShafts generation. wall-foot fillet. See the Linux58 and Linux59 reports for evidence. This code path is not promoted
to legacy Maze/VerticalShafts generation.
## 9. Multiplayer model (listen-server first, dedicated-friendly) ## 9. Multiplayer model (listen-server first, dedicated-friendly)
+11 -10
View File
@@ -170,8 +170,8 @@ remains `0`, and lateral regions remain gated off.
| `../../VoxelForgeCore/Private/ModuleEntry/` | Unreal module entry and an isolated `CoreMinimal.h` shim for the actual engine header. | | `../../VoxelForgeCore/Private/ModuleEntry/` | Unreal module entry and an isolated `CoreMinimal.h` shim for the actual engine header. |
| `../../Standalone/Core/include/VoxelForgeCore/VoxelForgeCore.h` | Standard-library-only public Core API. `VOXELFORGECORE_API` exports the API from the Unreal module and is empty for standalone builds. | | `../../Standalone/Core/include/VoxelForgeCore/VoxelForgeCore.h` | Standard-library-only public Core API. `VOXELFORGECORE_API` exports the API from the Unreal module and is empty for standalone builds. |
| `../../Standalone/Core/include/VoxelForgeCore/VoxelForgeCore.h` / `../../Standalone/Core/src/ResolvedLayoutInternal.h` | `ResolvedLayoutSnapshotV3`: physical layout-chunk width, versioned micrometre intervals, owned ceiling/content/bedrock bands, honored transition settings, deterministic per-column transition bands, recipe anchors, director-planned passages, canonical JSON/FNV identity, compatibility/strict validators, and negative-control audit. Built once from the director-resolved plan and consumed by bounds planning, Core dispatch, composition, and validation. §8.40–8.42, §8.46. | | `../../Standalone/Core/include/VoxelForgeCore/VoxelForgeCore.h` / `../../Standalone/Core/src/ResolvedLayoutInternal.h` | `ResolvedLayoutSnapshotV3`: physical layout-chunk width, versioned micrometre intervals, owned ceiling/content/bedrock bands, honored transition settings, deterministic per-column transition bands, recipe anchors, director-planned passages, canonical JSON/FNV identity, compatibility/strict validators, and negative-control audit. Built once from the director-resolved plan and consumed by bounds planning, Core dispatch, composition, and validation. §8.40–8.42, §8.46. |
| `ResolvedLayoutStratePassageCapabilitiesV1::{hasNativeCaveField,hasNativeLatticeField}`, `IsNativeLatticeFieldStratum`, `HasNativeGraphField` | `Standalone/Core/include/VoxelForgeCore/VoxelForgeCore.h` / `Standalone/Core/src/ResolvedLayoutInternal.h` | Explicit per-strate native graph capability; `Core.Lattice.PrimitiveField` is restricted to Maze/VerticalShafts recipe version 1. Lattice seeds include world seed, strate, recipe version and stable feature ID; explicit polyline records keep their endpoints and receive conservative bounds. §8.54. | | `NativeLatticeFieldRecipeVersion`, `IsNativeLatticeFieldStratum`, `LayoutLatticeFeatureSeed` | `Standalone/Core/include/VoxelForgeCore/VoxelForgeCore.h` / `Standalone/Core/src/ResolvedLayoutInternal.h` | Explicit Maze/VerticalShafts opt-in at lattice recipe version 2; stable feature seeds include world seed, strate, recipe version and feature ID. §8.54. |
| `FCavernRuntimeFeature::FSegmentNode`, `ApplyResolvedNativeCavesField`, `ClassifyNativeCaveFieldBox` | `Standalone/Core/src/ShapeWorldInternal.h` | A deterministic nested segment BVH accelerates native graph distance and conservative interval evaluation; the outer graph BVH still supplies tile candidates and protects `isTileShapeFree`. The 0.4 m feature-union width is separate from the floor fillet width. §8.54. | | `FCavernRuntimeFeature::openShaftRamp`, `ApplyResolvedNativeCavesField`, `ClassifyNativeCaveFieldBox` | `Standalone/Core/src/ShapeWorldInternal.h` | Analytic open shaft ring, helical support lookup, exact cylinder core bounds and conservative interval proofs; the outer graph BVH supplies tile candidates and protects `isTileShapeFree`. §8.54. |
| `../../Standalone/Core/src/FloatingIslandsInternal.h` | Canonical standalone/Core floating-island planner, geometry-versioned field, manifest serializer, influence bounds, capsule-route checks, and thickness audit. | | `../../Standalone/Core/src/FloatingIslandsInternal.h` | Canonical standalone/Core floating-island planner, geometry-versioned field, manifest serializer, influence bounds, capsule-route checks, and thickness audit. |
| `Tools/VoxelForgeTest.ps1` | The single guarded test entry point. `-Scenario canonical|owner|probe|perf|tests|surface-fall|crossing|gate-stress|visual-edit|visual-lod|visual-gap-walk|visual-gap-inject|dig-motion|parity|horizon|horizon-render|determinism|region-eval|step2d|step2e|step2f|step2f-capture|step3-scale|step3-game`, optional `-Build`, `-Assets owner|default`, `-Cvars`, absolute `-Out`, `-Label`, `-HorizonLevel`, `-HorizonRenderDistanceChunks`, `-Step2fProfile=0..7`, `-Step2fCaptureView=inside|wall-closeup`, `-ParityExportSize=32|64|128`, `-ParityExportTile=x,y,z`, `-SharedDDC`, `-SampleDensityStacks`, `-StackSampleIntervalUs`, and `-RegionHashProbe -RegionWorkers N -RegionReferenceHash HASH`; stages the host/assets, isolates user/DDC/config state, serializes one Unreal launch at a time, enforces the 8 GiB/30-minute guards, waits for 6 GiB free RAM before launches, and emits compact `result.json`/`summary.txt` plus full logs. Parity can render its game leg with `-EnableRender` and compares the selected export region against the exact streamed tile hashes. `visual-gap-walk` records camera-frustum surface-point coverage at 6000 cm/s; `visual-gap-inject` proves an early component hide is detected; `dig-motion` logs per-frame vertical velocity, gate, support readiness, and movement mode. `-Cvars @{ 'voxel.TestGapAuditLegacyHandoff'=1 }` replays the old visibility handoff for A/B audit baselines. Horizon traces report desired/loaded tiles, resident stream geometry, worker seconds, steady wall time, and peak private memory; `horizon-render` captures the owner view; `step2f-capture` selects one of eight parameter sets, finds a positive-density camera point and aims at a sampled rock wall for an inside or wall-closeup view, then saves it under `Saved/Research/step2f/captures` (pass the persistent render DDC with `-SharedDDC`); `determinism` compares per-tile hashes across the default CRT path and `-voxel.CrtFma3=0`; `region-eval` compares the live path with the default-off editor chunk program on the 259³ lattice and five-seed probe set; `step2d` retains the earlier independent field; `step2e` retains its earlier benchmark; `step2f` compares frozen step 2e and the coherent field for all eight profiles on the same 259³ ring, applies geometry gates, and checks sound bounds, seams, and 1-vs-6-worker hashes. `-RegionHashProbe -RegionWorkers N -RegionReferenceHash HASH` checks a full-ring hash at another partition count. `-SampleDensityStacks` captures profiles, and `-StackSampleIntervalUs` sets the sampling interval. | `Tools/VoxelForgeTest.ps1` | The single guarded test entry point. `-Scenario canonical|owner|probe|perf|tests|surface-fall|crossing|gate-stress|visual-edit|visual-lod|visual-gap-walk|visual-gap-inject|dig-motion|parity|horizon|horizon-render|determinism|region-eval|step2d|step2e|step2f|step2f-capture|step3-scale|step3-game`, optional `-Build`, `-Assets owner|default`, `-Cvars`, absolute `-Out`, `-Label`, `-HorizonLevel`, `-HorizonRenderDistanceChunks`, `-Step2fProfile=0..7`, `-Step2fCaptureView=inside|wall-closeup`, `-ParityExportSize=32|64|128`, `-ParityExportTile=x,y,z`, `-SharedDDC`, `-SampleDensityStacks`, `-StackSampleIntervalUs`, and `-RegionHashProbe -RegionWorkers N -RegionReferenceHash HASH`; stages the host/assets, isolates user/DDC/config state, serializes one Unreal launch at a time, enforces the 8 GiB/30-minute guards, waits for 6 GiB free RAM before launches, and emits compact `result.json`/`summary.txt` plus full logs. Parity can render its game leg with `-EnableRender` and compares the selected export region against the exact streamed tile hashes. `visual-gap-walk` records camera-frustum surface-point coverage at 6000 cm/s; `visual-gap-inject` proves an early component hide is detected; `dig-motion` logs per-frame vertical velocity, gate, support readiness, and movement mode. `-Cvars @{ 'voxel.TestGapAuditLegacyHandoff'=1 }` replays the old visibility handoff for A/B audit baselines. Horizon traces report desired/loaded tiles, resident stream geometry, worker seconds, steady wall time, and peak private memory; `horizon-render` captures the owner view; `step2f-capture` selects one of eight parameter sets, finds a positive-density camera point and aims at a sampled rock wall for an inside or wall-closeup view, then saves it under `Saved/Research/step2f/captures` (pass the persistent render DDC with `-SharedDDC`); `determinism` compares per-tile hashes across the default CRT path and `-voxel.CrtFma3=0`; `region-eval` compares the live path with the default-off editor chunk program on the 259³ lattice and five-seed probe set; `step2d` retains the earlier independent field; `step2e` retains its earlier benchmark; `step2f` compares frozen step 2e and the coherent field for all eight profiles on the same 259³ ring, applies geometry gates, and checks sound bounds, seams, and 1-vs-6-worker hashes. `-RegionHashProbe -RegionWorkers N -RegionReferenceHash HASH` checks a full-ring hash at another partition count. `-SampleDensityStacks` captures profiles, and `-StackSampleIntervalUs` sets the sampling interval.
| Step-3 scale and game validation | `step3-scale` measures the same 519³ and 259³ six-worker lattices at 12.5 cm. The cached medians are 7.347496 s and 1.169567 s respectively; determinism and brick sound-proof audits pass. `step3-game` routes in-game generation through the brick evaluator and records tile timings, spawn fill, moving frames, and profile-switch rebuilds. The visible D3D12 run measured tile generation p50/p95/max 3.326/31.045/169.867 ms, full-detail L0 fill 12.369 s for 2,765 tiles, and moving-frame p50/p95/p99/max 4.856/8.922/13.090/80.575 ms. Switching profiles rebuilt 5,815 loaded tiles. Both high-resolution screenshot requests were logged, but the harness found only one fresh PNG and it is a blank pale viewport; no lit comparison capture is accepted. Raw output: `Saved/TestHarness/step3_game_visible_final`; scale output: `Saved/Research/step3/scale/step3_scale_cacheperf_v1`. | | Step-3 scale and game validation | `step3-scale` measures the same 519³ and 259³ six-worker lattices at 12.5 cm. The cached medians are 7.347496 s and 1.169567 s respectively; determinism and brick sound-proof audits pass. `step3-game` routes in-game generation through the brick evaluator and records tile timings, spawn fill, moving frames, and profile-switch rebuilds. The visible D3D12 run measured tile generation p50/p95/max 3.326/31.045/169.867 ms, full-detail L0 fill 12.369 s for 2,765 tiles, and moving-frame p50/p95/p99/max 4.856/8.922/13.090/80.575 ms. Switching profiles rebuilt 5,815 loaded tiles. Both high-resolution screenshot requests were logged, but the harness found only one fresh PNG and it is a blank pale viewport; no lit comparison capture is accepted. Raw output: `Saved/TestHarness/step3_game_visible_final`; scale output: `Saved/Research/step3/scale/step3_scale_cacheperf_v1`. |
@@ -1310,18 +1310,19 @@ See ARCHITECTURE §8.53 and
[`Standalone/Research/WorldAssemblerM3/Linux43/REPORT.md`](Standalone/Research/WorldAssemblerM3/Linux43/REPORT.md) [`Standalone/Research/WorldAssemblerM3/Linux43/REPORT.md`](Standalone/Research/WorldAssemblerM3/Linux43/REPORT.md)
for layout identities, owner hashes, outside-box timing, audits and captures. for layout identities, owner hashes, outside-box timing, audits and captures.
### 3.36 Native lattice field — World Assembler M3 R26 slice 1 (Linux L58) ### 3.36 Native lattice field — World Assembler M3 R26 slices 1–2 (Linux L58–L59)
| Symbol | Canonical file | Role | | Symbol | Canonical file | Role |
|---|---|---| |---|---|---|
| `IsNativeLatticeFieldStratum`, `LayoutLatticeFeatureSeed`, `ResolvedCavernRoomV1::unionWidthMicrometres`, `ResolvedCavernEdgeV1::unionWidthMicrometres` | `Standalone/Core/include/VoxelForgeCore/VoxelForgeCore.h`, `Standalone/Core/src/ResolvedLayoutInternal.h` | Versioned Maze/VerticalShafts opt-in and deterministic seed from `(seed, strate, recipe version, stable ID)`; optional union width preserves prior cave JSON when unset. | | `NativeLatticeFieldRecipeVersion`, `IsNativeLatticeFieldStratum`, `LayoutLatticeFeatureSeed` | `Standalone/Core/include/VoxelForgeCore/VoxelForgeCore.h`, `Standalone/Core/src/ResolvedLayoutInternal.h` | Version-2 Maze/VerticalShafts opt-in and deterministic seed from `(seed, strate, recipe version, stable ID)`. |
| `MakeNativeLatticeSpine`, `--recipe=lattice`, `--lattice-strate=N` | `Standalone/Source/StreamBenchmarkHeadless.cpp` | Resolves actual adjacent mouths, builds a mandatory four-turn helix and maze spine, then adds two seeded dead ends; `--lattice-orphan-control` moves the helix away from both junctions. | | `MakeNativeLatticeSpine`, `--recipe=lattice`, `--lattice-strate=N` | `Standalone/Source/StreamBenchmarkHeadless.cpp` | Resolves actual adjacent mouths, builds the radius-4.5 m open shaft core, supported four-turn wall ledge and maze spine, then adds two seeded dead ends; the orphan control translates the shaft away from both junctions. |
| `AuditNativeLatticeField` | `Standalone/Source/StreamBenchmarkPipeline.h` | Samples the final field along the mouth-to-mouth capsule route, checking support, headroom, grade, orphan rejection, composed fillet, interval signs and feature-tile exclusion. | | `AuditNativeLatticeField` | `Standalone/Source/StreamBenchmarkPipeline.h` | Samples the final field along the mouth-to-mouth capsule route, checking every-station support, headroom, grade, orphan rejection, composed fillet, shaft air/wall intervals and tile exclusion. |
| `BuildLatticeFixtureL58.py`, `CaptureNativeLatticeL58.py`, `AuditLatticeSurfaceL58.py` | `Standalone/Research/WorldAssemblerM3/Linux58/` | Isolated Maze strate fixture, four reviewed captures and the L54 whole-surface triangle audit adapted to explicit native polylines. | | `BuildLatticeFixtureL59.py`, `CaptureNativeLatticeL59.py`, `AuditLatticeSurfaceL59.py` | `Standalone/Research/WorldAssemblerM3/Linux59/` | Isolated Maze fixture, four JPEG views of the open shaft and maze, and L54 whole-surface audit extended to include the ramp underside. |
See ARCHITECTURE §8.54 and See ARCHITECTURE §8.54 and the
[`Standalone/Research/WorldAssemblerM3/Linux58/REPORT.md`](Standalone/Research/WorldAssemblerM3/Linux58/REPORT.md) [`Linux59 report`](Standalone/Research/WorldAssemblerM3/Linux59/REPORT.md) for the open shaft's
for resolved records, final-field reachability, controls, timing, hashes and captures. measured geometry, final-field reachability, controls, timing, hashes and captures. The L58 report
retains the first-slice evidence.
## 4. The density pipeline (most-edited hot path) ## 4. The density pipeline (most-edited hot path)
@@ -1004,11 +1004,13 @@ namespace VoxelForgeCore
&&stratum.recipeVersion==1; &&stratum.recipeVersion==1;
} }
inline constexpr std::uint32_t NativeLatticeFieldRecipeVersion=2;
inline bool IsNativeLatticeFieldStratum(const ResolvedLayoutStratumV2& stratum) noexcept inline bool IsNativeLatticeFieldStratum(const ResolvedLayoutStratumV2& stratum) noexcept
{ {
return (stratum.generatorKind=="Maze"||stratum.generatorKind=="VerticalShafts") return (stratum.generatorKind=="Maze"||stratum.generatorKind=="VerticalShafts")
&&stratum.recipeId=="Core.Lattice.PrimitiveField" &&stratum.recipeId=="Core.Lattice.PrimitiveField"
&&stratum.recipeVersion==1; &&stratum.recipeVersion==NativeLatticeFieldRecipeVersion;
} }
inline bool HasNativeGraphField(const ResolvedLayoutStratumV2& stratum) noexcept inline bool HasNativeGraphField(const ResolvedLayoutStratumV2& stratum) noexcept
+4 -2
View File
@@ -1901,7 +1901,8 @@ bool ResolveResolvedCavernGraphV1(ResolvedLayoutSnapshotV3& layout,std::int32_t
// The shared JSON value type stores numbers as IEEE-754 doubles. Keep the // The shared JSON value type stores numbers as IEEE-754 doubles. Keep the
// serialized seed in the exact integer range, as the stamp vocabulary does. // serialized seed in the exact integer range, as the stamp vocabulary does.
room.irregularitySeed=(isNativeLatticeStrate(room.strateIndex) room.irregularitySeed=(isNativeLatticeStrate(room.strateIndex)
?LayoutLatticeFeatureSeed(seed,room.strateIndex,1,room.stableId) ?LayoutLatticeFeatureSeed(seed,room.strateIndex,
NativeLatticeFieldRecipeVersion,room.stableId)
:LayoutStampSeed(seed,room.strateIndex,room.stableId)) :LayoutStampSeed(seed,room.strateIndex,room.stableId))
&0x001fffffffffffffull; &0x001fffffffffffffull;
const std::int64_t pad=room.smoothWidthMicrometres const std::int64_t pad=room.smoothWidthMicrometres
@@ -1918,7 +1919,8 @@ bool ResolveResolvedCavernGraphV1(ResolvedLayoutSnapshotV3& layout,std::int32_t
{ {
const bool nativeLattice=isNativeLatticeStrate(edge.strateIndex); const bool nativeLattice=isNativeLatticeStrate(edge.strateIndex);
edge.irregularitySeed=(nativeLattice edge.irregularitySeed=(nativeLattice
?LayoutLatticeFeatureSeed(seed,edge.strateIndex,1,edge.stableId) ?LayoutLatticeFeatureSeed(seed,edge.strateIndex,
NativeLatticeFieldRecipeVersion,edge.stableId)
:LayoutStampSeed(seed,edge.strateIndex,edge.stableId)) :LayoutStampSeed(seed,edge.strateIndex,edge.stableId))
&0x001fffffffffffffull; &0x001fffffffffffffull;
using FCurvePoint=std::array<double,3>; using FCurvePoint=std::array<double,3>;
+412 -90
View File
@@ -3332,6 +3332,14 @@ private:
const VoxelForgeCore::ResolvedCavernRoomV1* room=nullptr; const VoxelForgeCore::ResolvedCavernRoomV1* room=nullptr;
const VoxelForgeCore::ResolvedCavernEdgeV1* edge=nullptr; const VoxelForgeCore::ResolvedCavernEdgeV1* edge=nullptr;
bool nativeGraph=false; bool nativeGraph=false;
bool openShaftRamp=false;
std::array<double,2> openShaftCenterMetres{};
std::array<double,2> openShaftStartDirection{1.0,0.0};
double openShaftCenterlineRadiusMetres=0.0;
double openShaftStartFloorMetres=0.0;
double openShaftPitchPerTurnMetres=0.0;
double openShaftTurnCount=0.0;
double openShaftRotationSign=1.0;
std::array<std::int64_t,3> boundsMinimumMicrometres{},boundsMaximumMicrometres{}; std::array<std::int64_t,3> boundsMinimumMicrometres{},boundsMaximumMicrometres{};
std::array<double,3> centerMetres{},halfExtentsMetres{}; std::array<double,3> centerMetres{},halfExtentsMetres{};
struct FSegment struct FSegment
@@ -3792,6 +3800,15 @@ private:
:found->passageCapabilities.hasNativeLatticeField); :found->passageCapabilities.hasNativeLatticeField);
}; };
const float micronsPerVoxel=static_cast<float>(Owner->CoreVoxelSizeMicrons); const float micronsPerVoxel=static_cast<float>(Owner->CoreVoxelSizeMicrons);
const auto shaftCoreRoom=std::find_if(ResolvedLayout->cavernRooms.begin(),
ResolvedLayout->cavernRooms.end(),[](const auto& room)
{return room.stableId=="lattice/spine/shaft-core-v2";});
std::array<double,2> shaftCoreCenter{};
if(shaftCoreRoom!=ResolvedLayout->cavernRooms.end())
{
shaftCoreCenter={shaftCoreRoom->centerMicrometres[0]/1.0e6,
shaftCoreRoom->centerMicrometres[1]/1.0e6};
}
for(const auto& room:ResolvedLayout->cavernRooms) for(const auto& room:ResolvedLayout->cavernRooms)
{ {
FCavernRuntimeFeature runtime;runtime.room=&room; FCavernRuntimeFeature runtime;runtime.room=&room;
@@ -3822,6 +3839,11 @@ private:
{ {
FCavernRuntimeFeature runtime;runtime.edge=&edge; FCavernRuntimeFeature runtime;runtime.edge=&edge;
runtime.nativeGraph=isNativeGraphStrate(edge.strateIndex); runtime.nativeGraph=isNativeGraphStrate(edge.strateIndex);
runtime.openShaftRamp=runtime.nativeGraph
&&edge.stableId=="lattice/spine/01-helix-ramp-v1"
&&shaftCoreRoom!=ResolvedLayout->cavernRooms.end();
if(runtime.openShaftRamp)
runtime.openShaftCenterMetres=shaftCoreCenter;
runtime.boundsMinimumMicrometres=edge.boundsMinimumMicrometres; runtime.boundsMinimumMicrometres=edge.boundsMinimumMicrometres;
runtime.boundsMaximumMicrometres=edge.boundsMaximumMicrometres; runtime.boundsMaximumMicrometres=edge.boundsMaximumMicrometres;
for(std::size_t point=0;point<4;++point) for(std::size_t point=0;point<4;++point)
@@ -3865,6 +3887,37 @@ private:
std::abs((segment.end[2]-segment.start[2])/horizontal)); std::abs((segment.end[2]-segment.start[2])/horizontal));
runtime.segments.push_back(segment); runtime.segments.push_back(segment);
} }
if(runtime.openShaftRamp&&!runtime.segments.empty())
{
const auto& first=runtime.segments.front().start;
const auto& last=runtime.segments.back().end;
const double startX=first[0]-shaftCoreCenter[0];
const double startY=first[1]-shaftCoreCenter[1];
runtime.openShaftCenterlineRadiusMetres=std::hypot(startX,startY);
if(runtime.openShaftCenterlineRadiusMetres>1.0e-9)
runtime.openShaftStartDirection={
startX/runtime.openShaftCenterlineRadiusMetres,
startY/runtime.openShaftCenterlineRadiusMetres};
runtime.openShaftStartFloorMetres=first[2];
double totalAngle=0.0;
for(std::size_t segment=0;segment<runtime.segments.size();++segment)
{
const auto& previous=runtime.segments[segment].start;
const auto& current=runtime.segments[segment].end;
const double previousX=previous[0]-shaftCoreCenter[0];
const double previousY=previous[1]-shaftCoreCenter[1];
const double currentX=current[0]-shaftCoreCenter[0];
const double currentY=current[1]-shaftCoreCenter[1];
totalAngle+=std::atan2(previousX*currentY-previousY*currentX,
previousX*currentX+previousY*currentY);
}
constexpr double TwoPi=6.283185307179586476925286766559;
runtime.openShaftTurnCount=std::max(1.0,
std::round(std::abs(totalAngle)/TwoPi));
runtime.openShaftRotationSign=totalAngle<0.0?-1.0:1.0;
runtime.openShaftPitchPerTurnMetres=(first[2]-last[2])
/runtime.openShaftTurnCount;
}
runtime.segmentOrder.resize(runtime.segments.size()); runtime.segmentOrder.resize(runtime.segments.size());
for(std::size_t index=0;index<runtime.segmentOrder.size();++index) for(std::size_t index=0;index<runtime.segmentOrder.size();++index)
runtime.segmentOrder[index]=static_cast<std::uint32_t>(index); runtime.segmentOrder[index]=static_cast<std::uint32_t>(index);
@@ -5245,9 +5298,50 @@ public:
const std::int32_t featureStrate=feature.room?feature.room->strateIndex const std::int32_t featureStrate=feature.room?feature.room->strateIndex
:feature.edge?feature.edge->strateIndex:-1; :feature.edge?feature.edge->strateIndex:-1;
if(featureStrate!=strateIndex)continue; if(featureStrate!=strateIndex)continue;
bool featureOverlapsBox=true,boxWithinFeatureBounds=true;
for(std::size_t axis=0;axis<3;++axis)
{
const double featureMinimum=feature.boundsMinimumMicrometres[axis]/1.0e6;
const double featureMaximum=feature.boundsMaximumMicrometres[axis]/1.0e6;
if(hi[axis]<featureMinimum||lo[axis]>featureMaximum)
{featureOverlapsBox=false;break;}
boxWithinFeatureBounds=boxWithinFeatureBounds
&&lo[axis]>=featureMinimum&&hi[axis]<=featureMaximum;
}
if(!featureOverlapsBox)continue;
// The point field omits a record outside its resolved bounds. A partial
// overlap cannot reuse the record's unbounded SDF for an all-air proof.
if(!boxWithinFeatureBounds)return {0.0,0.0,false};
FMetricInterval featureVoid; FMetricInterval featureVoid;
bool openHelixSupportCouldApply=true;
double openHelixSupportLowerBound=std::numeric_limits<double>::infinity();
if(feature.room) if(feature.room)
{ {
if(nativeLattice
&&feature.room->stableId=="lattice/spine/shaft-core-v2")
{
const double radius=feature.halfExtentsMetres[0];
if(!(radius>0.0))return {0.0,0.0,false};
double radialMinimumSquared=0.0,radialMaximumSquared=0.0;
for(std::size_t axis=0;axis<2;++axis)
{
const double center=feature.centerMetres[axis];
const double deltaMinimum=center<lo[axis]?lo[axis]-center
:center>hi[axis]?center-hi[axis]:0.0;
const double deltaMaximum=std::max(std::abs(lo[axis]-center),
std::abs(hi[axis]-center));
radialMinimumSquared+=deltaMinimum*deltaMinimum;
radialMaximumSquared+=deltaMaximum*deltaMaximum;
}
const double radialMinimum=std::sqrt(radialMinimumSquared)-radius;
const double radialMaximum=std::sqrt(radialMaximumSquared)-radius;
const double floorZ=feature.room->floorMicrometres/1000000.0;
const FMetricInterval bottom={floorZ-hi[2],floorZ-lo[2],true};
featureVoid={std::max(radialMinimum,bottom.minimum),
std::max(radialMaximum,bottom.maximum),true};
}
else
{
double normalizedMinimumSquared=0.0,normalizedMaximumSquared=0.0; double normalizedMinimumSquared=0.0,normalizedMaximumSquared=0.0;
double meanRadius=0.0; double meanRadius=0.0;
for(std::size_t axis=0;axis<3;++axis) for(std::size_t axis=0;axis<3;++axis)
@@ -5271,14 +5365,135 @@ public:
const double width=feature.room->smoothWidthMicrometres/1000000.0; const double width=feature.room->smoothWidthMicrometres/1000000.0;
featureVoid={SmoothMaxMetres(ellipsoid.minimum,floor.minimum,width), featureVoid={SmoothMaxMetres(ellipsoid.minimum,floor.minimum,width),
SmoothMaxMetres(ellipsoid.maximum,floor.maximum,width),true}; SmoothMaxMetres(ellipsoid.maximum,floor.maximum,width),true};
}
} }
else if(feature.edge&&!feature.segments.empty()) else if(feature.edge&&!feature.segments.empty())
{ {
const bool openHelixRamp=nativeLattice&&feature.openShaftRamp;
const double radius=feature.edge->boreRadiusMicrometres/1000000.0; const double radius=feature.edge->boreRadiusMicrometres/1000000.0;
const double height=feature.edge->boreHeightMicrometres/1000000.0; const double height=feature.edge->boreHeightMicrometres/1000000.0;
if(!(radius>0.0&&height>0.0))return {0.0,0.0,false}; if(!(radius>0.0&&height>0.0))return {0.0,0.0,false};
double tubeMinimum=std::numeric_limits<double>::infinity(); double tubeMinimum=std::numeric_limits<double>::infinity();
double tubeMaximum=std::numeric_limits<double>::infinity(); double tubeMaximum=std::numeric_limits<double>::infinity();
if(openHelixRamp)
{
double radialMinimumSquared=0.0,radialMaximumSquared=0.0;
for(std::size_t axis=0;axis<2;++axis)
{
const double center=feature.openShaftCenterMetres[axis];
const double deltaMinimum=center<lo[axis]?lo[axis]-center
:center>hi[axis]?center-hi[axis]:0.0;
const double deltaMaximum=std::max(std::abs(lo[axis]-center),
std::abs(hi[axis]-center));
radialMinimumSquared+=deltaMinimum*deltaMinimum;
radialMaximumSquared+=deltaMaximum*deltaMaximum;
}
const double radialMinimum=std::sqrt(radialMinimumSquared);
const double radialMaximum=std::sqrt(radialMaximumSquared);
const double centerline=feature.openShaftCenterlineRadiusMetres;
const double nearestRingDistance=centerline<radialMinimum
?radialMinimum-centerline:centerline>radialMaximum
?centerline-radialMaximum:0.0;
tubeMinimum=nearestRingDistance-radius;
tubeMaximum=std::max(std::abs(radialMinimum-centerline),
std::abs(radialMaximum-centerline))-radius;
openHelixSupportCouldApply=tubeMinimum<0.0;
const double startFloor=feature.openShaftStartFloorMetres;
const double pitch=feature.openShaftPitchPerTurnMetres;
const double turnCount=feature.openShaftTurnCount;
if(!std::isfinite(tubeMinimum)||!std::isfinite(tubeMaximum)
||!std::isfinite(startFloor)||!(pitch>0.0)
||!(turnCount>=1.0))return {0.0,0.0,false};
const FMetricInterval tube={tubeMinimum,tubeMaximum,true};
const double grade=pitch/(6.283185307179586476925286766559
*feature.openShaftCenterlineRadiusMetres);
const double verticalScale=1.0/std::sqrt(1.0+grade*grade);
double phaseMinimum=0.0,phaseMaximum=1.0;
const double boxCenterX=(lo[0]+hi[0])*0.5;
const double boxCenterY=(lo[1]+hi[1])*0.5;
const double centerDx=boxCenterX-feature.openShaftCenterMetres[0];
const double centerDy=boxCenterY-feature.openShaftCenterMetres[1];
const double centerDistance=std::hypot(centerDx,centerDy);
const double halfDiagonal=0.5*std::hypot(hi[0]-lo[0],hi[1]-lo[1]);
if(centerDistance>halfDiagonal)
{
const double angle=std::atan2(feature.openShaftRotationSign
*(feature.openShaftStartDirection[0]*centerDy
-feature.openShaftStartDirection[1]*centerDx),
feature.openShaftStartDirection[0]*centerDx
+feature.openShaftStartDirection[1]*centerDy);
constexpr double TwoPi=6.283185307179586476925286766559;
double centerPhase=angle/TwoPi;
const double angleRadius=std::asin(std::clamp(
halfDiagonal/centerDistance,0.0,1.0));
const double phaseRadius=angleRadius/TwoPi;
// Point evaluation normalizes phase into [0,1). If this box
// crosses the start ray, retain the full phase range; otherwise
// unwrap its center into the same range as the point field.
if(std::abs(angle)>angleRadius)
{
if(centerPhase<0.0)centerPhase+=1.0;
phaseMinimum=centerPhase-phaseRadius;
phaseMaximum=centerPhase+phaseRadius;
}
}
double verticalMinimum=std::numeric_limits<double>::infinity();
double verticalMaximum=-std::numeric_limits<double>::infinity();
const double coordinateMinimum=(startFloor-hi[2])/pitch-phaseMaximum;
const double coordinateMaximum=(startFloor-lo[2])/pitch-phaseMinimum;
if(!std::isfinite(coordinateMinimum)||!std::isfinite(coordinateMaximum))
return {0.0,0.0,false};
const int lastTurn=std::max(0,static_cast<int>(turnCount)-1);
const int firstPossibleTurn=std::clamp(
static_cast<int>(std::floor(coordinateMinimum)),-1,lastTurn+1);
const int lastPossibleTurn=std::clamp(
static_cast<int>(std::floor(coordinateMaximum)),-1,lastTurn+1);
const auto corridorInterval=[&](int turn)
{
const double floorMinimum=startFloor-pitch*(turn+phaseMaximum);
const double floorMaximum=startFloor-pitch*(turn+phaseMinimum);
const double floorToQueryMinimum=(floorMinimum-hi[2])*verticalScale;
const double floorToQueryMaximum=(floorMaximum-lo[2])*verticalScale;
const double queryToCeilingMinimum=(lo[2]-floorMaximum-height)
*verticalScale;
const double queryToCeilingMaximum=(hi[2]-floorMinimum-height)
*verticalScale;
const double turnMinimum=std::max(floorToQueryMinimum,
queryToCeilingMinimum);
const double turnMaximum=std::max(floorToQueryMaximum,
queryToCeilingMaximum);
return FMetricInterval{turnMinimum,turnMaximum,true};
};
for(int turn=firstPossibleTurn;turn<=lastPossibleTurn;++turn)
{
const int turnA=std::clamp(turn,0,lastTurn);
const int turnB=std::clamp(turn+1,0,lastTurn);
const FMetricInterval corridorA=corridorInterval(turnA);
const FMetricInterval corridorB=corridorInterval(turnB);
verticalMinimum=std::min(verticalMinimum,
std::min(corridorA.minimum,corridorB.minimum));
verticalMaximum=std::max(verticalMaximum,
std::min(corridorA.maximum,corridorB.maximum));
const double supportDepth=feature.edge->floorSupportDepthMicrometres
/1000000.0;
const double progressMinimum=turn+phaseMinimum;
const double progressMaximum=turn+phaseMaximum;
const double floorMinimum=startFloor-pitch*progressMaximum;
const double floorMaximum=startFloor-pitch*progressMinimum;
const double supportFloorMinimum=(floorMinimum-hi[2])*verticalScale;
const double supportUndersideMinimum=(lo[2]-floorMaximum+supportDepth)
*verticalScale;
openHelixSupportLowerBound=std::min(openHelixSupportLowerBound,
std::max({tubeMinimum,supportFloorMinimum,
supportUndersideMinimum}));
}
const FMetricInterval vertical={verticalMinimum,verticalMaximum,true};
const double width=feature.edge->smoothWidthMicrometres/1000000.0;
featureVoid={SmoothMaxMetres(tube.minimum,vertical.minimum,width),
SmoothMaxMetres(tube.maximum,vertical.maximum,width),true};
}
else
{
const std::array<double,3> inverseScale={1.0/radius,1.0/radius, const std::array<double,3> inverseScale={1.0/radius,1.0/radius,
1.0/height}; 1.0/height};
const std::array<double,3> boxMinimum={lo[0]*inverseScale[0], const std::array<double,3> boxMinimum={lo[0]*inverseScale[0],
@@ -5387,6 +5602,7 @@ public:
const double width=feature.edge->smoothWidthMicrometres/1000000.0; const double width=feature.edge->smoothWidthMicrometres/1000000.0;
featureVoid={SmoothMaxMetres(tube.minimum,floor.minimum,width), featureVoid={SmoothMaxMetres(tube.minimum,floor.minimum,width),
SmoothMaxMetres(tube.maximum,floor.maximum,width),true}; SmoothMaxMetres(tube.maximum,floor.maximum,width),true};
}
} }
else return {0.0,0.0,false}; else return {0.0,0.0,false};
if(nativeLattice) if(nativeLattice)
@@ -5401,10 +5617,17 @@ public:
&&lo[0]<=feature.boundsMaximumMicrometres[0]/1.0e6 &&lo[0]<=feature.boundsMaximumMicrometres[0]/1.0e6
&&hi[1]>=feature.boundsMinimumMicrometres[1]/1.0e6 &&hi[1]>=feature.boundsMinimumMicrometres[1]/1.0e6
&&lo[1]<=feature.boundsMaximumMicrometres[1]/1.0e6; &&lo[1]<=feature.boundsMaximumMicrometres[1]/1.0e6;
if(supportDepth>0.0&&overlapsXY const bool supportCouldApply=overlapsXY
&&(!feature.openShaftRamp||openHelixSupportCouldApply);
if(supportDepth>0.0&&supportCouldApply
&&hi[2]>=floorMinimum-supportDepth&&lo[2]<=floorMaximum) &&hi[2]>=floorMinimum-supportDepth&&lo[2]<=floorMaximum)
{
double supportLower=std::max(-supportDepth,lo[2]-floorMaximum);
if(feature.openShaftRamp)
supportLower=openHelixSupportLowerBound;
latticeFloorSupportLowerBound=std::min(latticeFloorSupportLowerBound, latticeFloorSupportLowerBound=std::min(latticeFloorSupportLowerBound,
std::max(-supportDepth,lo[2]-floorMaximum)); supportLower);
}
} }
if(!std::isfinite(featureVoid.minimum)||!std::isfinite(featureVoid.maximum)) if(!std::isfinite(featureVoid.minimum)||!std::isfinite(featureVoid.maximum))
return {0.0,0.0,false}; return {0.0,0.0,false};
@@ -6962,6 +7185,10 @@ private:
return; return;
} }
if(!feature.edge)return; if(!feature.edge)return;
// The open helix is already carved with its exact cylindrical/turn
// field above. Its four serialized control points are a compact record
// envelope, not a walkable Bezier centerline for this legacy cap.
if(feature.openShaftRamp)return;
const auto bezier=[&](float t,std::size_t axis) const auto bezier=[&](float t,std::size_t axis)
{ {
const float one=1.0f-t; const float one=1.0f-t;
@@ -7098,114 +7325,209 @@ private:
const std::int32_t strateIndex=feature.room?feature.room->strateIndex const std::int32_t strateIndex=feature.room?feature.room->strateIndex
:feature.edge?feature.edge->strateIndex:-1; :feature.edge?feature.edge->strateIndex:-1;
if(strateIndex!=bound.StrateIndex)continue; if(strateIndex!=bound.StrateIndex)continue;
bool insideFeatureBounds=true;
for(std::size_t axis=0;axis<3;++axis)
insideFeatureBounds=insideFeatureBounds
&&point[axis]*1000000.0>=feature.boundsMinimumMicrometres[axis]
&&point[axis]*1000000.0<=feature.boundsMaximumMicrometres[axis];
if(!insideFeatureBounds)continue;
double featureVoid=std::numeric_limits<double>::infinity(); double featureVoid=std::numeric_limits<double>::infinity();
if(feature.room) if(feature.room)
{ {
double normalizedSquared=0.0,meanRadius=0.0; if(nativeLattice
for(std::size_t axis=0;axis<3;++axis) &&feature.room->stableId=="lattice/spine/shaft-core-v2")
{ {
const double radius=feature.halfExtentsMetres[axis]; const double radius=feature.halfExtentsMetres[0];
if(!(radius>0.0)){normalizedSquared=std::numeric_limits<double>::infinity();break;} if(!(radius>0.0))continue;
const double delta=(point[axis]-feature.centerMetres[axis])/radius; const double radial=std::hypot(
normalizedSquared+=delta*delta;meanRadius+=radius/3.0; point[0]-feature.centerMetres[0],
point[1]-feature.centerMetres[1])-radius;
const double bottom=feature.room->floorMicrometres/1000000.0-point[2];
featureVoid=std::max(radial,bottom);
}
else
{
double normalizedSquared=0.0,meanRadius=0.0;
for(std::size_t axis=0;axis<3;++axis)
{
const double radius=feature.halfExtentsMetres[axis];
if(!(radius>0.0))
{normalizedSquared=std::numeric_limits<double>::infinity();break;}
const double delta=(point[axis]-feature.centerMetres[axis])/radius;
normalizedSquared+=delta*delta;meanRadius+=radius/3.0;
}
const double ellipsoid=(std::sqrt(normalizedSquared)-1.0)*meanRadius;
const double floor=feature.room->floorMicrometres/1000000.0-point[2];
const double width=feature.room->smoothWidthMicrometres/1000000.0;
featureVoid=SmoothMaxMetres(ellipsoid,floor,width);
} }
const double ellipsoid=(std::sqrt(normalizedSquared)-1.0)*meanRadius;
const double floor=feature.room->floorMicrometres/1000000.0-point[2];
const double width=feature.room->smoothWidthMicrometres/1000000.0;
featureVoid=SmoothMaxMetres(ellipsoid,floor,width);
} }
else if(feature.edge&&!feature.segments.empty()) else if(feature.edge&&!feature.segments.empty())
{ {
const bool openHelixRamp=nativeLattice&&feature.openShaftRamp;
double tube=std::numeric_limits<double>::infinity(); double tube=std::numeric_limits<double>::infinity();
double nearestFloor=0.0,nearestGrade=0.0,nearestRadial=0.0; double nearestFloor=0.0,nearestGrade=0.0,nearestRadial=0.0;
double openHelixVerticalSdf=std::numeric_limits<double>::infinity();
double openHelixPhase=0.0;
int openHelixTurnA=0,openHelixTurnB=0;
double openHelixVerticalScale=1.0;
const double radius=feature.edge->boreRadiusMicrometres/1000000.0; const double radius=feature.edge->boreRadiusMicrometres/1000000.0;
const double height=feature.edge->boreHeightMicrometres/1000000.0; const double height=feature.edge->boreHeightMicrometres/1000000.0;
if(!(radius>0.0&&height>0.0))continue; if(!(radius>0.0&&height>0.0))continue;
const double minScale=std::min(radius,height); const double minScale=std::min(radius,height);
std::uint32_t nearestSegment=std::numeric_limits<std::uint32_t>::max(); if(openHelixRamp)
const auto evaluateSegment=[&](std::uint32_t segmentIndex)
{ {
if(segmentIndex>=feature.segments.size())return; const double dx=point[0]-feature.openShaftCenterMetres[0];
const auto& segment=feature.segments[segmentIndex]; const double dy=point[1]-feature.openShaftCenterMetres[1];
double lengthSquared=0.0,dot=0.0; const double shaftRadial=std::hypot(dx,dy);
for(std::size_t axis=0;axis<3;++axis) nearestRadial=std::abs(shaftRadial
-feature.openShaftCenterlineRadiusMetres);
tube=nearestRadial-radius;
const double phase=std::atan2(feature.openShaftRotationSign
*(feature.openShaftStartDirection[0]*dy
-feature.openShaftStartDirection[1]*dx),
feature.openShaftStartDirection[0]*dx
+feature.openShaftStartDirection[1]*dy);
constexpr double TwoPi=6.283185307179586476925286766559;
openHelixPhase=(phase<0.0?phase+TwoPi:phase)/TwoPi;
const double pitch=feature.openShaftPitchPerTurnMetres;
if(!(pitch>0.0)||!(feature.openShaftTurnCount>=1.0))continue;
const double grade=pitch/(TwoPi
*feature.openShaftCenterlineRadiusMetres);
openHelixVerticalScale=1.0/std::sqrt(1.0+grade*grade);
const double turnCoordinate=(feature.openShaftStartFloorMetres-point[2])
/pitch-openHelixPhase;
const int turnFloor=static_cast<int>(std::floor(turnCoordinate));
const int lastTurn=std::max(0,
static_cast<int>(feature.openShaftTurnCount)-1);
openHelixTurnA=std::clamp(turnFloor,0,lastTurn);
openHelixTurnB=std::clamp(turnFloor+1,0,lastTurn);
const auto floorForTurn=[&](int turn)
{ {
const double delta=segment.end[axis]-segment.start[axis]; return feature.openShaftStartFloorMetres
lengthSquared+=delta*delta; -pitch*(turn+openHelixPhase);
dot+=(point[axis]-segment.start[axis])*delta;
}
const double t=lengthSquared>0.0
?std::clamp(dot/lengthSquared,0.0,1.0):0.0;
double radialSquared=0.0,vertical=0.0;
for(std::size_t axis=0;axis<3;++axis)
{
const double delta=point[axis]-(segment.start[axis]
+t*(segment.end[axis]-segment.start[axis]));
if(axis<2)radialSquared+=delta*delta;
else vertical=delta;
}
const double normalized=std::sqrt(radialSquared/(radius*radius)
+vertical*vertical/(height*height));
const double distance=(normalized-1.0)*std::min(radius,height);
if(distance<tube||(distance==tube&&segmentIndex<nearestSegment))
{
tube=distance;nearestSegment=segmentIndex;
nearestFloor=segment.start[2]+t*(segment.end[2]-segment.start[2]);
nearestRadial=std::sqrt(radialSquared);
const double horizontal=std::hypot(
segment.end[0]-segment.start[0],segment.end[1]-segment.start[1]);
nearestGrade=horizontal>1.0e-9
?(segment.end[2]-segment.start[2])/horizontal:0.0;
}
};
const auto nodeLowerBound=[&](const FCavernRuntimeFeature::FSegmentNode& node)
{
double gapSquared=0.0;
for(std::size_t axis=0;axis<3;++axis)
{
const double scale=axis==2?height:radius;
const double q=point[axis]/scale;
const double low=node.minimum[axis]/scale;
const double high=node.maximum[axis]/scale;
const double gap=q<low?low-q:q>high?q-high:0.0;
gapSquared+=gap*gap;
}
return (std::sqrt(gapSquared)-1.0)*minScale;
};
if(!feature.segmentNodes.empty())
{
const auto visitNode=[&](const auto& self,int nodeIndex)->void
{
if(nodeIndex<0||static_cast<std::size_t>(nodeIndex)>=feature.segmentNodes.size())return;
const auto& node=feature.segmentNodes[static_cast<std::size_t>(nodeIndex)];
if(nodeLowerBound(node)>tube)return;
if(node.left<0)
{
for(std::size_t offset=node.first;offset<node.end;++offset)
evaluateSegment(feature.segmentOrder[offset]);
return;
}
const double leftBound=nodeLowerBound(feature.segmentNodes[
static_cast<std::size_t>(node.left)]);
const double rightBound=nodeLowerBound(feature.segmentNodes[
static_cast<std::size_t>(node.right)]);
if(leftBound<=rightBound)
{self(self,node.left);self(self,node.right);}
else {self(self,node.right);self(self,node.left);}
}; };
visitNode(visitNode,0); const auto corridorSdf=[&](int turn)
{
const double floorZ=floorForTurn(turn);
return std::max((floorZ-point[2])*openHelixVerticalScale,
(point[2]-(floorZ+height))*openHelixVerticalScale);
};
openHelixVerticalSdf=std::min(corridorSdf(openHelixTurnA),
corridorSdf(openHelixTurnB));
}
else
{
std::uint32_t nearestSegment=std::numeric_limits<std::uint32_t>::max();
const auto evaluateSegment=[&](std::uint32_t segmentIndex)
{
if(segmentIndex>=feature.segments.size())return;
const auto& segment=feature.segments[segmentIndex];
double lengthSquared=0.0,dot=0.0;
for(std::size_t axis=0;axis<3;++axis)
{
const double delta=segment.end[axis]-segment.start[axis];
lengthSquared+=delta*delta;
dot+=(point[axis]-segment.start[axis])*delta;
}
const double t=lengthSquared>0.0
?std::clamp(dot/lengthSquared,0.0,1.0):0.0;
double radialSquared=0.0,vertical=0.0;
for(std::size_t axis=0;axis<3;++axis)
{
const double delta=point[axis]-(segment.start[axis]
+t*(segment.end[axis]-segment.start[axis]));
if(axis<2)radialSquared+=delta*delta;
else vertical=delta;
}
const double normalized=std::sqrt(radialSquared/(radius*radius)
+vertical*vertical/(height*height));
const double distance=(normalized-1.0)*minScale;
if(distance<tube||(distance==tube&&segmentIndex<nearestSegment))
{
tube=distance;nearestSegment=segmentIndex;
nearestFloor=segment.start[2]+t*(segment.end[2]-segment.start[2]);
nearestRadial=std::sqrt(radialSquared);
const double horizontal=std::hypot(
segment.end[0]-segment.start[0],segment.end[1]-segment.start[1]);
nearestGrade=horizontal>1.0e-9
?(segment.end[2]-segment.start[2])/horizontal:0.0;
}
};
const auto nodeLowerBound=[&](const FCavernRuntimeFeature::FSegmentNode& node)
{
double gapSquared=0.0;
for(std::size_t axis=0;axis<3;++axis)
{
const double scale=axis==2?height:radius;
const double q=point[axis]/scale;
const double low=node.minimum[axis]/scale;
const double high=node.maximum[axis]/scale;
const double gap=q<low?low-q:q>high?q-high:0.0;
gapSquared+=gap*gap;
}
return (std::sqrt(gapSquared)-1.0)*minScale;
};
if(!feature.segmentNodes.empty())
{
const auto visitNode=[&](const auto& self,int nodeIndex)->void
{
if(nodeIndex<0||static_cast<std::size_t>(nodeIndex)>=feature.segmentNodes.size())return;
const auto& node=feature.segmentNodes[static_cast<std::size_t>(nodeIndex)];
if(nodeLowerBound(node)>tube)return;
if(node.left<0)
{
for(std::size_t offset=node.first;offset<node.end;++offset)
evaluateSegment(feature.segmentOrder[offset]);
return;
}
const double leftBound=nodeLowerBound(feature.segmentNodes[
static_cast<std::size_t>(node.left)]);
const double rightBound=nodeLowerBound(feature.segmentNodes[
static_cast<std::size_t>(node.right)]);
if(leftBound<=rightBound)
{self(self,node.left);self(self,node.right);}
else {self(self,node.right);self(self,node.left);}
};
visitNode(visitNode,0);
}
else for(std::uint32_t segment=0;segment<feature.segments.size();++segment)
evaluateSegment(segment);
} }
else for(std::uint32_t segment=0;segment<feature.segments.size();++segment)
evaluateSegment(segment);
const double supportDepth=feature.edge->floorSupportDepthMicrometres/1000000.0; const double supportDepth=feature.edge->floorSupportDepthMicrometres/1000000.0;
if(nativeLattice&&supportDepth>0.0&&nearestRadial<radius-0.12 if(nativeLattice&&supportDepth>0.0)
&&point[2]<nearestFloor&&nearestFloor-point[2]<=supportDepth) {
latticeFloorSupportMinimum=std::min(latticeFloorSupportMinimum, if(openHelixRamp)
(point[2]-nearestFloor)/std::sqrt(1.0+nearestGrade*nearestGrade)); {
const double floor=(nearestFloor-point[2]) const auto supportSdf=[&](int turn)
/std::sqrt(1.0+nearestGrade*nearestGrade); {
const double floorZ=feature.openShaftStartFloorMetres
-feature.openShaftPitchPerTurnMetres
*(turn+openHelixPhase);
const double vertical=std::max(
(floorZ-point[2])*openHelixVerticalScale,
(point[2]-(floorZ-supportDepth))
*openHelixVerticalScale);
return std::max(nearestRadial-radius,vertical);
};
latticeFloorSupportMinimum=std::min(latticeFloorSupportMinimum,
std::min(supportSdf(openHelixTurnA),
supportSdf(openHelixTurnB)));
}
else if(nearestRadial<radius-0.12&&point[2]<nearestFloor
&&nearestFloor-point[2]<=supportDepth)
latticeFloorSupportMinimum=std::min(latticeFloorSupportMinimum,
(point[2]-nearestFloor)/std::sqrt(1.0+nearestGrade*nearestGrade));
}
const double width=feature.edge->smoothWidthMicrometres/1000000.0; const double width=feature.edge->smoothWidthMicrometres/1000000.0;
featureVoid=SmoothMaxMetres(tube,floor,width); if(openHelixRamp)
featureVoid=SmoothMaxMetres(tube,openHelixVerticalSdf,width);
else
{
const double floor=(nearestFloor-point[2])
/std::sqrt(1.0+nearestGrade*nearestGrade);
featureVoid=SmoothMaxMetres(tube,floor,width);
}
} }
if(!std::isfinite(featureVoid))continue; if(!std::isfinite(featureVoid))continue;
if(!std::isfinite(caveVoid))caveVoid=featureVoid; if(!std::isfinite(caveVoid))caveVoid=featureVoid;
@@ -0,0 +1,259 @@
#!/usr/bin/env python3
"""Run L54's triangle audit over L59's open-shaft lattice and controls."""
from __future__ import annotations
import argparse
import importlib.util
import json
import math
from pathlib import Path
ROOT = Path(__file__).resolve().parents[4]
AUDIT54 = ROOT / "Standalone/Research/WorldAssemblerM3/Linux54/AuditWholeSurfaceL54.py"
spec = importlib.util.spec_from_file_location("whole_surface_l54", AUDIT54)
audit54 = importlib.util.module_from_spec(spec)
assert spec and spec.loader
spec.loader.exec_module(audit54)
original_make_route = audit54.make_route
def build_segment_bvh(segments: list[tuple]) -> dict:
def build(indices: list[int]) -> dict:
minimum = tuple(min(min(segments[index][0][axis], segments[index][1][axis])
for index in indices) for axis in range(3))
maximum = tuple(max(max(segments[index][0][axis], segments[index][1][axis])
for index in indices) for axis in range(3))
if len(indices) <= 8:
return {"minimum": minimum, "maximum": maximum,
"segments": tuple(sorted(indices)), "left": None, "right": None}
axis = max(range(3), key=lambda value: maximum[value] - minimum[value])
indices.sort(key=lambda index: (segments[index][0][axis]
+ segments[index][1][axis]) * 0.5)
middle = len(indices) // 2
return {"minimum": minimum, "maximum": maximum, "segments": None,
"left": build(indices[:middle]), "right": build(indices[middle:])}
if not segments:
raise ValueError("lattice audit route has no measurable segments")
return build(list(range(len(segments))))
def make_lattice_route(layout: dict, phase_m: float = 0.0) -> dict:
edges = sorted((edge for edge in layout.get("cavern_edges", [])
if edge["stable_id"] in ("lattice/spine/00-arrival-portal-v1",
"lattice/spine/01-helix-ramp-v1", "lattice/spine/99-departure-portal-v1")
or edge["stable_id"].startswith("lattice/spine/maze-edge-")),
key=lambda edge: (0 if edge["stable_id"].startswith("lattice/spine/00-") else
1 if edge["stable_id"].startswith("lattice/spine/01-") else
2 if edge["stable_id"].startswith("lattice/spine/maze-edge-") else 3,
edge["stable_id"]))
if not edges:
raise ValueError("lattice audit needs its resolved mandatory spine edges")
segments = []
routes = []
for edge_index, edge in enumerate(edges):
points = [[value / 1_000_000.0 for value in row]
for row in edge.get("polyline_um", [])]
if len(points) < 2:
raise ValueError(f"{edge['stable_id']}: explicit path is missing")
radius = edge["bore_radius_um"] / 1_000_000.0
height = edge["bore_height_um"] / 1_000_000.0
support_depth = edge.get("floor_support_depth_um", 0) / 1_000_000.0
horizontal_s = [0.0]
for a, b in zip(points, points[1:]):
horizontal_s.append(horizontal_s[-1] + ((b[0] - a[0]) ** 2
+ (b[1] - a[1]) ** 2) ** 0.5)
first = points[1]
first_dx, first_dy = first[0] - points[0][0], first[1] - points[0][1]
first_length = max(1.0e-9, (first_dx * first_dx + first_dy * first_dy) ** 0.5)
extension = (points[0][0] - first_dx / first_length * audit54.OPEN_GROUND_EXTENSION_M,
points[0][1] - first_dy / first_length * audit54.OPEN_GROUND_EXTENSION_M,
points[0][2] - (first[2] - points[0][2]) / first_length
* audit54.OPEN_GROUND_EXTENSION_M)
route_points = [extension, *points]
route_s = [-audit54.OPEN_GROUND_EXTENSION_M, *horizontal_s]
for index, (a, b) in enumerate(zip(route_points, route_points[1:])):
segments.append((a, b, route_s[index], route_s[index + 1],
radius, height, edge_index))
routes.append({"edge": edge, "points": points, "radius": radius,
"height": height, "support_depth": support_depth,
"length": horizontal_s[-1], "index": edge_index})
# The shaft core is an open cylindrical volume, not a walkable room. Its
# axis-aligned bounds include unrelated rock outside the cylinder and
# above the ramp headroom; the helix corridor already includes the inner
# wall, lip, foot, and underside where those surfaces meet the route.
rooms = [{"room": room,
"center": tuple(value / 1_000_000.0 for value in room["center_um"]),
"half": tuple(value / 1_000_000.0 for value in room["half_extents_um"]),
"floor": room["floor_um"] / 1_000_000.0}
for room in sorted(layout.get("cavern_rooms", []), key=lambda row: row["stable_id"])
if room.get("stable_id") != "lattice/spine/shaft-core-v2"]
return {"segments": segments, "edges": routes, "rooms": rooms, "phase_m": phase_m,
"segment_bvh": build_segment_bvh(segments)}
def make_route(layout: dict, phase_m: float = 0.0) -> dict:
if any(edge.get("stable_id", "").startswith("lattice/")
for edge in layout.get("cavern_edges", [])):
return make_lattice_route(layout, phase_m)
return original_make_route(layout, phase_m)
def lattice_route_nearest(point: tuple[float, float, float], route: dict):
"""Resolve stacked helix turns in 3D, then measure corridor radius in XY."""
best = None
def consider(segment_index: int) -> None:
nonlocal best
a, b, s0, s1, radius, height, edge_index = route["segments"][segment_index]
dx, dy, dz = (b[axis] - a[axis] for axis in range(3))
length_squared = dx * dx + dy * dy + dz * dz
t = 0.0 if length_squared <= 1.0e-12 else max(0.0, min(1.0,
((point[0] - a[0]) * dx + (point[1] - a[1]) * dy
+ (point[2] - a[2]) * dz) / length_squared))
x, y, z = (a[axis] + (b[axis] - a[axis]) * t for axis in range(3))
distance3d_squared = ((point[0] - x) ** 2 + (point[1] - y) ** 2
+ (point[2] - z) ** 2)
if (best is None or distance3d_squared < best[0]
or (distance3d_squared == best[0] and segment_index < best[1])):
horizontal_length = math.hypot(dx, dy)
lateral = ((dx * (point[1] - y) - dy * (point[0] - x))
/ horizontal_length if horizontal_length > 1.0e-9 else 0.0)
best = (distance3d_squared, segment_index,
math.hypot(point[0] - x, point[1] - y),
s0 + (s1 - s0) * t, z, lateral, radius, height, edge_index,
route["edges"][edge_index]["length"])
def lower_bound_squared(node: dict) -> float:
distance_squared = 0.0
for axis in range(3):
gap = (node["minimum"][axis] - point[axis]
if point[axis] < node["minimum"][axis]
else point[axis] - node["maximum"][axis]
if point[axis] > node["maximum"][axis] else 0.0)
distance_squared += gap * gap
return distance_squared
def visit(node: dict) -> None:
if best is not None and lower_bound_squared(node) > best[0]:
return
if node["segments"] is not None:
for segment_index in node["segments"]:
consider(segment_index)
return
left, right = node["left"], node["right"]
left_bound, right_bound = lower_bound_squared(left), lower_bound_squared(right)
if left_bound <= right_bound:
visit(left)
visit(right)
else:
visit(right)
visit(left)
visit(route["segment_bvh"])
if best is None:
raise ValueError("lattice audit route has no measurable segments")
return best[2:]
def mark_lattice_region(triangles: list, route: dict) -> None:
margin = audit54.CORRIDOR_MARGIN_M
extension = audit54.OPEN_GROUND_EXTENSION_M
bounds = []
for edge in route["edges"]:
points = edge["points"]
radius, height = edge["radius"], edge["height"]
support_depth = edge["support_depth"]
bounds.append((
min(point[0] for point in points) - radius - margin,
max(point[0] for point in points) + radius + margin,
min(point[1] for point in points) - radius - margin,
max(point[1] for point in points) + radius + margin,
min(point[2] for point in points) - support_depth - margin,
max(point[2] for point in points) + height + margin))
for room in route["rooms"]:
center, half, floor = room["center"], room["half"], room["floor"]
bounds.append((center[0] - half[0] - margin, center[0] + half[0] + margin,
center[1] - half[1] - margin, center[1] + half[1] + margin,
floor - margin, floor + 2.0 * half[2] + margin))
for triangle in triangles:
x, y, z = triangle.center
if not any(low_x <= x <= high_x and low_y <= y <= high_y
and low_z <= z <= high_z
for low_x, high_x, low_y, high_y, low_z, high_z in bounds):
triangle.in_region = False
triangle.reference = False
continue
nearest = lattice_route_nearest(triangle.center, route)
distance, distance_s, floor_z, lateral, radius, height, edge_index, edge_length = nearest
support_depth = route["edges"][edge_index]["support_depth"]
corridor = (-extension <= distance_s <= edge_length
and distance <= radius + margin
and floor_z - support_depth - margin <= z <= floor_z + height + margin)
room_box = any(abs(x - room["center"][0]) <= room["half"][0] + margin
and abs(y - room["center"][1]) <= room["half"][1] + margin
and room["floor"] - margin <= z
<= room["floor"] + 2.0 * room["half"][2] + margin
for room in route["rooms"])
triangle.in_region = corridor or room_box
inside_room = any(abs(x - room["center"][0]) <= room["half"][0] + 0.45
and abs(y - room["center"][1]) <= room["half"][1] + 0.45
for room in route["rooms"])
outside_bore = distance > radius + 0.45 and not inside_room
triangle.reference = (triangle.in_region and outside_bore
and triangle.smooth[2] >= 0.45)
def main() -> int:
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--case", nargs=5, action="append", required=True,
metavar=("LABEL", "MESH", "LAYOUT_OR_DASH", "EXPECT", "FOCUS"))
parser.add_argument("--json", type=Path, required=True)
parser.add_argument("--svg-dir", type=Path)
parser.add_argument("--phase", type=float, choices=(-0.5, 0.0, 0.5), default=0.0)
args = parser.parse_args()
audit54.make_route = make_route
results = []
for label, mesh, layout, expect, focus in args.case:
if expect not in ("pass", "fail", "measure") or focus not in ("whole", "floor"):
parser.error("EXPECT must be pass/fail/measure and FOCUS must be whole/floor")
native_lattice = layout != "-" and any(
edge.get("stable_id", "").startswith("lattice/")
for edge in json.loads(Path(layout).read_text(encoding="utf-8")).get(
"cavern_edges", []))
original_margin = audit54.CORRIDOR_MARGIN_M
original_extension = audit54.OPEN_GROUND_EXTENSION_M
original_nearest = audit54.route_nearest
original_mark_region = audit54.mark_region
if native_lattice:
# Keep the whole-surface test on native records: one core voxel of
# tolerance captures their meshed walls while excluding the separate
# legacy transition above the resolved mouth.
audit54.CORRIDOR_MARGIN_M = 0.25
audit54.OPEN_GROUND_EXTENSION_M = 0.0
audit54.route_nearest = lattice_route_nearest
audit54.mark_region = mark_lattice_region
try:
results.append(audit54.audit_case(label, Path(mesh), Path(layout), expect,
focus, args.svg_dir, args.phase))
finally:
audit54.CORRIDOR_MARGIN_M = original_margin
audit54.OPEN_GROUND_EXTENSION_M = original_extension
audit54.route_nearest = original_nearest
audit54.mark_region = original_mark_region
if native_lattice:
print("[L59LatticeAuditScope] margin_m=0.250 ramp_underside_depth_m=1.000 "
"outside_mouth_extension_m=0.000 nearest_centerline=3D "
"radius_measure=horizontal status=PASS")
args.json.parent.mkdir(parents=True, exist_ok=True)
args.json.write_text(json.dumps({"audit": "whole-surface-open-shaft-l59-v1",
"cases": results}, indent=2) + "\n", encoding="utf-8")
failures = [result for result in results if result["status"] != "PASS"]
print(f"[L59WholeSurfaceAuditSummary] cases={len(results)} failed={len(failures)} "
f"json={args.json} status={'FAIL' if failures else 'PASS'}")
return 1 if failures else 0
if __name__ == "__main__":
raise SystemExit(main())
@@ -0,0 +1,83 @@
#!/usr/bin/env python3
"""Split the owner surface strate around the L59 native lattice fixture."""
from __future__ import annotations
import argparse
import hashlib
import json
from pathlib import Path
def sha256(path: Path) -> str:
digest = hashlib.sha256()
with path.open("rb") as stream:
for block in iter(lambda: stream.read(1024 * 1024), b""):
digest.update(block)
return digest.hexdigest()
def main() -> int:
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--owner", type=Path, required=True)
parser.add_argument("--out", type=Path, required=True)
args = parser.parse_args()
root = json.loads(args.owner.read_text(encoding="utf-8"))
strates = root.get("strates")
if not isinstance(strates, list):
raise ValueError("owner input has no strates array")
by_index = {int(row.get("index", -1)): row for row in strates if isinstance(row, dict)}
if set(by_index) != {0, 1} or len(strates) != 2:
raise ValueError("fixture requires the reviewed two-strate owner input")
upper, surface = by_index[0], by_index[1]
if (int(upper.get("asset", {}).get("GeneratorType", -1)) != 0
or int(surface.get("asset", {}).get("GeneratorType", -1)) != 4):
raise ValueError("fixture requires TunnelNetwork over SurfaceWorld")
if int(upper.get("passage_config", {}).get("Connections", -1)) != 1:
raise ValueError("owner arrival passage count differs from the reviewed input")
# Keep both resolved mouths in the small synthetic Maze layer. The authored
# owner reach ranges are intentionally broad and can place a synthetic mouth
# hundreds of metres beyond a four-chunk prototype layer.
upper["passage_config"].update({"ReachMin": 32, "ReachMax": 32})
upper["asset"]["PassageConfig"].update({"ReachMin": 32, "ReachMax": 32})
maze = json.loads(json.dumps(surface))
maze.update({"index": 1, "top_chunk_z": -16, "bottom_chunk_z": -19,
"height_chunks": 4})
maze["asset"].update({"StrateName": "L59 Native Lattice Maze",
"GeneratorType": 3, "StrateHeightInChunks": 4})
maze["asset"].setdefault("MazeParams", {})["BoundarySealThickness"] = 8
maze["passage_config"]["Connections"] = 1
maze["passage_config"].update({"ReachMin": 32, "ReachMax": 32})
maze["asset"]["PassageConfig"].update({"Connections": 1, "ReachMin": 32, "ReachMax": 32})
lower = json.loads(json.dumps(surface))
lower.update({"index": 2, "top_chunk_z": -20, "bottom_chunk_z": -23,
"height_chunks": 4})
lower["asset"].update({"StrateName": "L59 Lower Surface", "GeneratorType": 4,
"StrateHeightInChunks": 4})
lower["passage_config"]["Connections"] = 1
lower["asset"]["PassageConfig"]["Connections"] = 1
root["total_strates"] = 3
root["strates"] = [upper, maze, lower]
# Keep the legacy passage portals proportional to this compact native
# prototype; the owner world remains at its authored scale.
root.update({"owner_voxel_size_cm": 6.25,
"owner_voxel_size_microns": 62500,
"core_voxel_size_cm": 25,
"core_voxel_size_microns": 250000,
"owner_to_core_length_scale": 0.25})
args.out.parent.mkdir(parents=True, exist_ok=True)
args.out.write_text(json.dumps(root, indent=2, sort_keys=True) + "\n",
encoding="utf-8")
print(f"[LatticeFixtureBuild] source={args.owner} source_sha256={sha256(args.owner)} "
f"fixture={args.out} fixture_sha256={sha256(args.out)} "
"strates=0:TunnelNetwork,1:Maze[4 chunks],2:SurfaceWorld[60 chunks] "
"owner_input_untouched=true status=PASS")
return 0
if __name__ == "__main__":
raise SystemExit(main())
@@ -0,0 +1,179 @@
#!/usr/bin/env python3
"""Export the L59 open-shaft lattice and render four reviewed viewpoints."""
from __future__ import annotations
import argparse
import hashlib
import importlib.util
import json
import math
import os
from pathlib import Path
import subprocess
import sys
ROOT = Path(__file__).resolve().parents[4]
CAPTURE54 = ROOT / "Standalone/Research/WorldAssemblerM3/Linux54/CaptureNativeCavesL54.py"
spec = importlib.util.spec_from_file_location("capture_native_caves_l54", CAPTURE54)
capture54 = importlib.util.module_from_spec(spec)
assert spec and spec.loader
spec.loader.exec_module(capture54)
run_step = capture54.run_step
camera_angles = capture54.camera_angles
filter_mesh_y_leq = capture54.filter_mesh_y_leq
fmt = capture54.fmt
def sha256(path: Path) -> str:
digest = hashlib.sha256()
with path.open("rb") as stream:
for block in iter(lambda: stream.read(1024 * 1024), b""):
digest.update(block)
return digest.hexdigest()
def midpoint(points: list[list[float]]) -> tuple[float, float, float]:
return tuple(sum(point[axis] for point in points) / len(points) for axis in range(3))
def main() -> int:
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--out", type=Path, required=True)
parser.add_argument("--fixture", type=Path, required=True)
parser.add_argument("--layout", type=Path, required=True)
parser.add_argument("--headless", type=Path, required=True)
parser.add_argument("--renderer", type=Path, required=True)
parser.add_argument("--artifact-dir", type=Path, required=True)
args = parser.parse_args()
out = args.out.resolve()
artifact_dir = args.artifact_dir.resolve()
capture_dir = out / "lattice-capture-png"
mesh_dir = out / "lattice-meshes"
for directory in (capture_dir, mesh_dir, artifact_dir):
directory.mkdir(parents=True, exist_ok=True)
layout = json.loads(args.layout.read_text(encoding="utf-8"))
edges = sorted(layout.get("cavern_edges", []), key=lambda row: row["stable_id"])
helix = next((edge for edge in edges
if edge["stable_id"] == "lattice/spine/01-helix-ramp-v1"), None)
shaft_core = next((room for room in layout.get("cavern_rooms", [])
if room["stable_id"] == "lattice/spine/shaft-core-v2"), None)
maze_edges = [edge for edge in edges
if edge["stable_id"].startswith("lattice/spine/maze-edge-")]
if helix is None or shaft_core is None or len(maze_edges) < 4:
raise ValueError("layout is missing the resolved open shaft, helix, or maze spine")
helix_points = [[value / 1_000_000.0 for value in point]
for point in helix["polyline_um"]]
core_center = [value / 1_000_000.0 for value in shaft_core["center_um"]]
shaft_center = (core_center[0], core_center[1], core_center[2])
top = helix_points[0]
bottom = helix_points[-1]
whole_mesh = mesh_dir / "lattice-whole-view.vfmesh"
export_layout = out / "layouts" / "lattice-capture-layout.json"
env = os.environ.copy()
env["LP_NUM_THREADS"] = "12"
env["XDG_CACHE_HOME"] = str(out / "xdg-cache")
export_camera = (top[0], top[1], top[2] + 1.5, 0.0, -8.0)
run_step("lattice-whole-view-export", [args.headless, args.fixture,
"--workers=12", "--world-assembler-prototype", "--stream-benchmark",
"--stream-pipeline", "--force-generate", "--clip-radius=4",
"--max-clip-level=0", "--max-level=0", "--render-distance-chunks=0",
"--recipe=lattice", "--lattice-strate=1",
f"--camera={fmt(export_camera)}", f"--resolved-layout-output={export_layout}",
f"--mesh-export={whole_mesh}"], out / "capture-lattice-export.log",
env=env, stamped=True)
if not whole_mesh.is_file() or whole_mesh.stat().st_size == 0:
raise RuntimeError("whole-lattice export produced no mesh")
cutaway_mesh = mesh_dir / "lattice-cutaway-y-center.vfmesh"
cutaway_triangles = filter_mesh_y_leq(whole_mesh, cutaway_mesh, shaft_center[1])
print(f"[L59LatticeCutaway] plane_y_m={shaft_center[1]:.3f} "
f"retained_triangles={cutaway_triangles} mesh={cutaway_mesh}", flush=True)
# Start inside the open shaft, offset toward the first tread so the view
# follows the well down while keeping the helical ledges in frame.
start_dx = top[0] - shaft_center[0]
start_dy = top[1] - shaft_center[1]
start_radius = max(1.0e-9, math.hypot(start_dx, start_dy))
top_camera = (shaft_center[0] + start_dx / start_radius * 3.5,
shaft_center[1] + start_dy / start_radius * 3.5,
top[2] + 1.6)
top_target = (shaft_center[0], shaft_center[1], bottom[2] + 1.3)
eye_index = len(helix_points) // 2
eye_floor = helix_points[eye_index]
eye_dx = eye_floor[0] - shaft_center[0]
eye_dy = eye_floor[1] - shaft_center[1]
eye_radius = max(1.0e-9, math.hypot(eye_dx, eye_dy))
# Put the eye on the walk line, looking across the open core at the far
# wall and the ledges above and below.
eye_camera = (eye_floor[0], eye_floor[1], eye_floor[2] + 1.35)
eye_target = (shaft_center[0], shaft_center[1], eye_camera[2] + 0.35)
maze_edge = next(edge for edge in maze_edges
if edge["stable_id"] == "lattice/spine/maze-edge-02-v1")
maze_points = [[value / 1_000_000.0 for value in point]
for point in maze_edge["polyline_um"]]
maze_a, maze_b = maze_points[0], maze_points[-1]
maze_t = 0.5
maze_floor = tuple(maze_a[axis] + (maze_b[axis] - maze_a[axis]) * maze_t
for axis in range(3))
maze_horizontal = max(1.0e-9, math.hypot(maze_b[0] - maze_a[0],
maze_b[1] - maze_a[1]))
maze_camera = (maze_floor[0] - (maze_b[1] - maze_a[1]) / maze_horizontal * 0.2,
maze_floor[1] + (maze_b[0] - maze_a[0]) / maze_horizontal * 0.2,
maze_floor[2] + 1.4)
maze_target = (maze_camera[0] + (maze_b[0] - maze_a[0]) / maze_horizontal * 8.0,
maze_camera[1] + (maze_b[1] - maze_a[1]) / maze_horizontal * 8.0,
maze_camera[2] + (maze_b[2] - maze_a[2]) / maze_horizontal * 8.0)
overview_camera = (shaft_center[0], shaft_center[1] + 12.0, top[2] + 4.0)
overview_target = (shaft_center[0], shaft_center[1],
(top[2] + bottom[2]) * 0.5 - 2.0)
views = (
("shaft-top-down", whole_mesh, top_camera, top_target, 22.0, 78.0, None),
("ramp-eye-across", whole_mesh, eye_camera, eye_target, 15.0, 100.0, None),
("maze-corridor", whole_mesh, maze_camera, maze_target, 8.0, 45.0, None),
("shaft-overview", cutaway_mesh, overview_camera, overview_target, 40.0, 80.0, None),
)
quality = ROOT / "Standalone/Tools/verify/capture_quality.py"
for name, render_mesh, camera, target, focus_radius, fov, clip_plane in views:
yaw, pitch = camera_angles(camera, target)
if name == "ramp-eye-across":
yaw, pitch = camera_angles(camera, target)
png = capture_dir / f"lattice-{name}.png"
image = artifact_dir / f"lattice-{name}.jpg"
height_tint = "off" if name == "maze-corridor" else "on"
render_args = [args.renderer, render_mesh, png,
"--size=1280x720", f"--fov-deg={fov:.1f}",
f"--camera-m={fmt(camera)}", f"--yaw-deg={yaw:.6f}",
f"--pitch-deg={pitch:.6f}", "--tile-skirts=off", "--shade=readable",
"--headlamp=on", f"--height-tint={height_tint}",
f"--height-center-m={(top[2] + bottom[2]) * 0.5:.6f}",
"--height-range-m=24", "--tile-edges=off",
f"--focus-region={fmt((*target, focus_radius))}"]
if clip_plane is not None:
render_args.append(f"--clip-plane={fmt(clip_plane)}")
run_step(f"{name}-render", render_args,
out / f"capture-{name}-render.log", env=env, stamped=True)
run_step(f"{name}-jpeg", ["ffmpeg", "-nostdin", "-hide_banner", "-loglevel",
"error", "-y", "-i", png, "-frames:v", "1", "-q:v", "5", image],
out / f"capture-{name}-jpeg.log", env=env)
quality_output = run_step(f"{name}-quality", [sys.executable, quality, image],
out / f"capture-{name}-quality.log", env=env)
quality_lines = [line for line in quality_output.splitlines()
if line.startswith("[CaptureQuality]")]
if not quality_lines or not quality_lines[-1].endswith("status=PASS"):
raise RuntimeError(f"capture quality gate failed for {name}")
size = image.stat().st_size
if size > 300_000:
raise RuntimeError(f"capture exceeds 300 KB: {image} ({size} bytes)")
print(f"[L59LatticeCapture] view={name} file={image} bytes={size} "
f"sha256={sha256(image)} status=PASS", flush=True)
return 0
if __name__ == "__main__":
try:
raise SystemExit(main())
except Exception as error:
print(f"[L59LatticeCapture] status=FAIL error={error}", file=sys.stderr, flush=True)
raise SystemExit(1)
@@ -0,0 +1,49 @@
# Linux59 report
## Geometry and route
Resolved shaft: 21.0 m outer envelope; 4.5 m core radius; four-turn ramp at 6.0 m centerline radius, 3.0 m clear width, and 5.0 m pitch. The ramp spans radii 4.5–7.5 m and has 1.0 m floor support. Its inner edge is open to the core. The route keeps a 1.5 m margin from that edge (1.16 m capsule drop clearance). No raised lip was added.
Maximum route grade is 10.028° at the inner edge; minimum measured headroom is 2.20 m. Arrival-to-departure reachability passes all 883 stations, 44,150 capsule samples, and 4,415 support/headroom samples. The orphan-shaft control is disconnected as expected.
## Audits and determinism
The final-field interval oracle checked 2,058 samples in six boxes with zero misses. It proves shaft-core air, returns a mixed result at the core wall, rejects false all-air and all-solid proofs, and blocks the occupied maze tile.
The whole-surface audit passes with zero flagged triangles and zero clusters. Its scope includes a 0.25 m ramp-edge margin and the 1.0 m underside. The L45 ramp, L46 entrance, and L47 wall-foot controls fail as expected; the plain-native control passes. GCC and Clang camera peers at the shaft center `(11.790, 4.090, -130.630)` match across W1/W8/W12.
## Speed
| Measurement | L58 instrumented | L59 final |
|---|---:|---:|
| First tile | 0.222 s | 0.210 s |
| Near ring | 0.364 s | 0.328 s |
| Whole view | 1.625 s (1.69 s cited) | 1.605 s |
| Moving p50 / p95 | 90.567 / 165.304 ms | 479.544 / 963.764 ms |
The roughly 1 s whole-view target was not reached; the measured whole view improved only slightly, and moving latency regressed. L59 tile-drain instrumentation recorded 972 stage rows and 28,507 ms summed worker time: 23,332 ms in marching cubes and 717 ms in column work. Marching cubes dominates the measured worker time.
## Hashes, tiers, and captures
Source stamp: `389ac77f5d35328a68e4639cac4f7d03ad5ab13b72d4832e89459437cf960ca4`
Resolved layout: `resolved-layout-v3-fnv64:ab2f330ada023393`
Headless SHA-256: Clang `9fc1ac6c4c5a18b6bbdc0d907d26fcaaa63a49c163a68365f3cc79726db1c474`; GCC `47b37a28a7f132af2a3f91cdd61693fb8ac519e2f23f4064b48bec0b7f8ad964`.
Fast passed in 174.7 s; medium passed in 1,140.1 s; full passed in 1,206.4 s with its own 7,200 s timeout. Trial count: 15/15. Earlier failed trials exposed ramp-surface spikes and an orphan-control interval false proof; the final surface and interval controls pass.
All captures are JPEG and under 300 KB:
- [Shaft top-down](captures/lattice-shaft-top-down.jpg) — 31,500 B — SHA-256 `83e38fce238ddbde84fe3ee13867f5722eac30fe177c44e746eb06b7ae341783`
- [Ramp eye across shaft](captures/lattice-ramp-eye-across.jpg) — 24,409 B — SHA-256 `985a16fbd45c986c5bcdd0974e1cc32aac82a06a84b2df98a7b6a358f930cf14`
- [Maze corridor](captures/lattice-maze-corridor.jpg) — 15,746 B — SHA-256 `fe72cdd5a3907f8b9071784b08889719593d8839f69a863aa45dc9ac547e771d`
- [Shaft overview](captures/lattice-shaft-overview.jpg) — 39,081 B — SHA-256 `6394f0656200f91e77a23aed9c135e2e913dd0053c301921dff24336713c52d2`
## Orchestrator review (Claude)
**Parked on `wip/l59-open-shaft`, not merged.** The top-down capture finally reads as an open shaft with a ledge
spiralling down the wall, so the concept is right. But the ramp's **inner (open) edge is severely jagged:** shard-like
torn scallops along the whole edge (`lattice-ramp-eye-across.jpg`, and the top-down rim). The whole-surface audit
passed only because its ROI stops 0.25 m in from the ramp edge: the blind-spot pattern again. Speed moved only
1.69 → 1.61 s, at 15 of 15 trials. `assembler/world` keeps L58. Likely cause, to verify: a 1 m-thick ledge with a free
edge is a thin feature meshed at 25 cm. The edge needs a bullnose/fillet radius of at least 2 voxels and a thickness
the sampler resolves, and the audit ROI must include the edge itself.
Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

+32 -5
View File
@@ -1032,8 +1032,9 @@ namespace
constexpr double FloorToSoffit=2.6; constexpr double FloorToSoffit=2.6;
constexpr double Pitch=5.0; constexpr double Pitch=5.0;
constexpr int Turns=4; constexpr int Turns=4;
constexpr double RampSupportDepth=1.0;
constexpr double FloorBlend=1.9; constexpr double FloorBlend=1.9;
constexpr double FeatureUnionBlend=0.05; constexpr double FeatureUnionBlend=1.0;
constexpr double CorridorSpacing=14.0; constexpr double CorridorSpacing=14.0;
constexpr double MazeCellSpan=16.0; constexpr double MazeCellSpan=16.0;
constexpr double RouteGradeLimit=13.0; constexpr double RouteGradeLimit=13.0;
@@ -1053,7 +1054,7 @@ namespace
{for(int byte=0;byte<8;++byte){hash^=static_cast<std::uint8_t>(word>>(byte*8));hash*=1099511628211ull;}}; {for(int byte=0;byte<8;++byte){hash^=static_cast<std::uint8_t>(word>>(byte*8));hash*=1099511628211ull;}};
addWord(static_cast<std::uint32_t>(seed)); addWord(static_cast<std::uint32_t>(seed));
addWord(static_cast<std::uint32_t>(latticeStrateIndex)); addWord(static_cast<std::uint32_t>(latticeStrateIndex));
addWord(1); addWord(NativeLatticeFieldRecipeVersion);
for(unsigned char value:stableId){hash^=value;hash*=1099511628211ull;} for(unsigned char value:stableId){hash^=value;hash*=1099511628211ull;}
hash^=hash>>30;hash*=0xbf58476d1ce4e5b9ull; hash^=hash>>30;hash*=0xbf58476d1ce4e5b9ull;
hash^=hash>>27;hash*=0x94d049bb133111ebull; hash^=hash>>27;hash*=0x94d049bb133111ebull;
@@ -1083,7 +1084,8 @@ namespace
edge.boreRadiusMicrometres=1500000; edge.boreRadiusMicrometres=1500000;
edge.boreHeightMicrometres=static_cast<std::int64_t>( edge.boreHeightMicrometres=static_cast<std::int64_t>(
std::llround(FloorToSoffit*1.0e6)); std::llround(FloorToSoffit*1.0e6));
edge.floorSupportDepthMicrometres=1000000; edge.floorSupportDepthMicrometres=static_cast<std::int64_t>(
std::llround(RampSupportDepth*1.0e6));
edge.smoothWidthMicrometres=static_cast<std::int64_t>(std::llround(FloorBlend*1.0e6)); edge.smoothWidthMicrometres=static_cast<std::int64_t>(std::llround(FloorBlend*1.0e6));
edge.unionWidthMicrometres=static_cast<std::int64_t>( edge.unionWidthMicrometres=static_cast<std::int64_t>(
std::llround(FeatureUnionBlend*1.0e6)); std::llround(FeatureUnionBlend*1.0e6));
@@ -1121,6 +1123,26 @@ namespace
helixEnd[1]+orphanOffset[1],helixEnd[2]}); helixEnd[1]+orphanOffset[1],helixEnd[2]});
const std::string departureRoomId="lattice/spine/departure-room-v1"; const std::string departureRoomId="lattice/spine/departure-room-v1";
addRoom(departureRoomId,{departure[0],departure[1],departureFloor}); addRoom(departureRoomId,{departure[0],departure[1],departureFloor});
constexpr double ShaftCoreRadius=CenterlineRadius-ClearWidth*0.5;
constexpr double ShaftCoreBottomExtension=2.0;
constexpr double ShaftCoreTopExtension=8.0;
const double shaftCoreBottom=helixEndFloor-ShaftCoreBottomExtension;
const double shaftCoreTop=helixStart[2]+ShaftCoreTopExtension;
ResolvedCavernRoomV1 shaftCore;
shaftCore.stableId="lattice/spine/shaft-core-v2";
shaftCore.strateIndex=latticeStrateIndex;
shaftCore.centerMicrometres=micronPoint({
helixCenter[0]+orphanOffset[0],helixCenter[1]+orphanOffset[1],
(shaftCoreBottom+shaftCoreTop)*0.5});
shaftCore.halfExtentsMicrometres={
static_cast<std::int64_t>(std::llround(ShaftCoreRadius*1.0e6)),
static_cast<std::int64_t>(std::llround(ShaftCoreRadius*1.0e6)),
static_cast<std::int64_t>(std::llround((shaftCoreTop-shaftCoreBottom)*0.5e6))};
shaftCore.floorMicrometres=static_cast<std::int64_t>(
std::llround(shaftCoreBottom*1.0e6));
shaftCore.smoothWidthMicrometres=0;
shaftCore.unionWidthMicrometres=0;
rooms.push_back(std::move(shaftCore));
edges.push_back(addEdge("lattice/spine/00-arrival-portal-v1", edges.push_back(addEdge("lattice/spine/00-arrival-portal-v1",
arrivals.front()->stableId+"/lower-mouth",arrivalRoomId, arrivals.front()->stableId+"/lower-mouth",arrivalRoomId,
{{arrival[0],arrival[1],arrivalFloor},helixStart})); {{arrival[0],arrival[1],arrivalFloor},helixStart}));
@@ -1220,9 +1242,14 @@ namespace
std::printf("[LatticeResolvedMouths] arrival=%s side=lower xyz_m=(%.3f,%.3f,%.3f) departure=%s side=upper xyz_m=(%.3f,%.3f,%.3f) binding=actual-resolved status=PASS\n", std::printf("[LatticeResolvedMouths] arrival=%s side=lower xyz_m=(%.3f,%.3f,%.3f) departure=%s side=upper xyz_m=(%.3f,%.3f,%.3f) binding=actual-resolved status=PASS\n",
arrivals.front()->stableId.c_str(),arrival[0],arrival[1],arrival[2], arrivals.front()->stableId.c_str(),arrival[0],arrival[1],arrival[2],
departures.front()->stableId.c_str(),departure[0],departure[1],departure[2]); departures.front()->stableId.c_str(),departure[0],departure[1],departure[2]);
std::printf("[LatticeSpinePlan] recipe=Core.Lattice.PrimitiveField version=1 strate=%d stable_key=seed,strate,recipe_version,stable_id spine_first=true arrival=%s departure=%s helix_id=lattice/spine/01-helix-ramp-v1 centerline_radius_m=%.3f clear_width_m=%.3f pitch_m=%.3f turns=%d floor_to_soffit_m=%.3f centerline_grade_deg=%.3f inner_edge_grade_deg=%.3f floor_blend_m=%.3f union_envelope_m=%.3f maze_cells=%d dead_ends=2 orphan_control=%s status=PASS\n", std::printf("[LatticeSpinePlan] recipe=Core.Lattice.PrimitiveField version=%u strate=%d stable_key=seed,strate,recipe_version,stable_id spine_first=true arrival=%s departure=%s helix_id=lattice/spine/01-helix-ramp-v1 shaft_core_id=%s shaft_core_radius_m=%.3f centerline_radius_m=%.3f clear_width_m=%.3f pitch_m=%.3f turns=%d inner_edge_margin_m=%.3f capsule_drop_clearance_m=%.3f support_depth_m=%.3f ramp_vertical_clearance_m=%.3f shaft_outer_envelope_m=%.3f maze_headroom_m=%.3f centerline_grade_deg=%.3f inner_edge_grade_deg=%.3f floor_blend_m=%.3f union_envelope_m=%.3f maze_cells=%d dead_ends=2 orphan_control=%s status=PASS\n",
NativeLatticeFieldRecipeVersion,
latticeStrateIndex,arrivals.front()->stableId.c_str(),departures.front()->stableId.c_str(), latticeStrateIndex,arrivals.front()->stableId.c_str(),departures.front()->stableId.c_str(),
CenterlineRadius,ClearWidth,Pitch,Turns,FloorToSoffit,centerlineGrade,innerEdgeGrade, "lattice/spine/shaft-core-v2",ShaftCoreRadius,CenterlineRadius,ClearWidth,Pitch,Turns,
CenterlineRadius-ShaftCoreRadius,CenterlineRadius-ShaftCoreRadius-0.34,
RampSupportDepth,Pitch-RampSupportDepth,
2.0*(CenterlineRadius+ClearWidth*0.5+3.0),
FloorToSoffit,centerlineGrade,innerEdgeGrade,
FloorBlend,FeatureUnionBlend,routeEdges+1,orphanControl?"enabled":"disabled"); FloorBlend,FeatureUnionBlend,routeEdges+1,orphanControl?"enabled":"disabled");
return true; return true;
} }
+31 -5
View File
@@ -1452,7 +1452,10 @@ namespace StandaloneStreamBenchmark
} }
std::sort(mazeEdges.begin(),mazeEdges.end(),[](const auto* a,const auto* b) std::sort(mazeEdges.begin(),mazeEdges.end(),[](const auto* a,const auto* b)
{return a->stableId<b->stableId;}); {return a->stableId<b->stableId;});
const auto shaftCore=std::find_if(layout.cavernRooms.begin(),layout.cavernRooms.end(),
[](const auto& room){return room.stableId=="lattice/spine/shaft-core-v2";});
if(!arrivalPortal||!helix||!departurePortal||mazeEdges.size()<4 if(!arrivalPortal||!helix||!departurePortal||mazeEdges.size()<4
||shaftCore==layout.cavernRooms.end()
||layout.cavernRooms.size()<mazeEdges.size()+1)return false; ||layout.cavernRooms.size()<mazeEdges.size()+1)return false;
std::vector<const ResolvedCavernEdgeV1*> ordered={arrivalPortal,helix}; std::vector<const ResolvedCavernEdgeV1*> ordered={arrivalPortal,helix};
ordered.insert(ordered.end(),mazeEdges.begin(),mazeEdges.end()); ordered.insert(ordered.end(),mazeEdges.begin(),mazeEdges.end());
@@ -1641,6 +1644,17 @@ namespace StandaloneStreamBenchmark
struct FIntervalCheck {const char* name;std::array<double,3> p;}; struct FIntervalCheck {const char* name;std::array<double,3> p;};
const auto mazeA=metres(mazeEdges.front()->polylineMicrometres.front()); const auto mazeA=metres(mazeEdges.front()->polylineMicrometres.front());
const auto mazeB=metres(mazeEdges.front()->polylineMicrometres.back()); const auto mazeB=metres(mazeEdges.front()->polylineMicrometres.back());
const auto helixFirst=metres(helix->polylineMicrometres.front());
const double helixCenterlineRadius=std::hypot(
helixFirst[0]-shaftCore->centerMicrometres[0]/1.0e6,
helixFirst[1]-shaftCore->centerMicrometres[1]/1.0e6);
const double helixBoreRadius=helix->boreRadiusMicrometres/1.0e6;
const double outerWallRadius=helixCenterlineRadius+helixBoreRadius;
const double wallScale=outerWallRadius/std::max(1.0e-9,helixCenterlineRadius);
const double outerWallX=shaftCore->centerMicrometres[0]/1.0e6
+(helixFirst[0]-shaftCore->centerMicrometres[0]/1.0e6)*wallScale;
const double outerWallY=shaftCore->centerMicrometres[1]/1.0e6
+(helixFirst[1]-shaftCore->centerMicrometres[1]/1.0e6)*wallScale;
const std::array<double,3> mazeMid={(mazeA[0]+mazeB[0])*0.5, const std::array<double,3> mazeMid={(mazeA[0]+mazeB[0])*0.5,
(mazeA[1]+mazeB[1])*0.5,(mazeA[2]+mazeB[2])*0.5}; (mazeA[1]+mazeB[1])*0.5,(mazeA[2]+mazeB[2])*0.5};
const double mazeLength=std::hypot(mazeB[0]-mazeA[0],mazeB[1]-mazeA[1]); const double mazeLength=std::hypot(mazeB[0]-mazeA[0],mazeB[1]-mazeA[1]);
@@ -1653,17 +1667,23 @@ namespace StandaloneStreamBenchmark
for(const auto& edge:layout.cavernEdges)if(edge.strateIndex==lattice->strateIndex) for(const auto& edge:layout.cavernEdges)if(edge.strateIndex==lattice->strateIndex)
for(const auto& point:edge.polylineMicrometres) for(const auto& point:edge.polylineMicrometres)
{const auto p=metres(point);maxX=std::max(maxX,p[0]);minY=std::min(minY,p[1]);maxY=std::max(maxY,p[1]);} {const auto p=metres(point);maxX=std::max(maxX,p[0]);minY=std::min(minY,p[1]);maxY=std::max(maxY,p[1]);}
const std::array<FIntervalCheck,4> checks={{{"host-rock",{maxX+8.0, const std::array<FIntervalCheck,6> checks={{{"host-rock",{maxX+8.0,
(minY+maxY)*0.5,midZ+1.2}}, (minY+maxY)*0.5,midZ+1.2}},
{"maze-air",{mazeMid[0],mazeMid[1],mazeMid[2]+1.25}}, {"maze-air",{mazeMid[0],mazeMid[1],mazeMid[2]+1.25}},
{"maze-wall-foot",{mazeMid[0]+wallX*1.30,mazeMid[1]+wallY*1.30, {"maze-wall-foot",{mazeMid[0]+wallX*1.30,mazeMid[1]+wallY*1.30,
mazeMid[2]+0.25}}, mazeMid[2]+0.25}},
{"helix-air",{helix->polylineMicrometres[helix->polylineMicrometres.size()/2][0]/1.0e6, {"helix-air",{helix->polylineMicrometres[helix->polylineMicrometres.size()/2][0]/1.0e6,
helix->polylineMicrometres[helix->polylineMicrometres.size()/2][1]/1.0e6, helix->polylineMicrometres[helix->polylineMicrometres.size()/2][1]/1.0e6,
helix->polylineMicrometres[helix->polylineMicrometres.size()/2][2]/1.0e6+1.25}}}}; helix->polylineMicrometres[helix->polylineMicrometres.size()/2][2]/1.0e6+1.25}},
{"shaft-core-air",{shaftCore->centerMicrometres[0]/1.0e6,
shaftCore->centerMicrometres[1]/1.0e6,
shaftCore->centerMicrometres[2]/1.0e6}},
{"shaft-outer-wall",{outerWallX,outerWallY,
helixFirst[2]+1.25}}}};
std::uint64_t boxes=0,samples=0,misses=0,allAir=0,allSolid=0,mixed=0; std::uint64_t boxes=0,samples=0,misses=0,allAir=0,allSolid=0,mixed=0;
bool falseAllAirRejected=false,falseAllSolidRejected=false,wallMixed=false; bool falseAllAirRejected=false,falseAllSolidRejected=false,wallMixed=false;
bool isTileShapeFreeAware=false,latticeTileFree=false; bool isTileShapeFreeAware=false,latticeTileFree=false;
bool shaftCoreAirProved=false,shaftCoreWallMixed=false;
for(const auto& check:checks) for(const auto& check:checks)
{ {
const Vec3i origin{static_cast<int>(std::llround(check.p[0]/vm)), const Vec3i origin{static_cast<int>(std::llround(check.p[0]/vm)),
@@ -1684,6 +1704,10 @@ namespace StandaloneStreamBenchmark
falseAllAirRejected|=bruteSolid&&verdict!=TileClass::allAir; falseAllAirRejected|=bruteSolid&&verdict!=TileClass::allAir;
falseAllSolidRejected|=bruteAir&&verdict!=TileClass::allSolid; falseAllSolidRejected|=bruteAir&&verdict!=TileClass::allSolid;
if(std::string_view(check.name)=="maze-wall-foot")wallMixed=verdict==TileClass::mixed; if(std::string_view(check.name)=="maze-wall-foot")wallMixed=verdict==TileClass::mixed;
if(std::string_view(check.name)=="shaft-core-air")
shaftCoreAirProved=verdict==TileClass::allAir&&bruteAir;
if(std::string_view(check.name)=="shaft-outer-wall")
shaftCoreWallMixed=verdict==TileClass::mixed&&!bruteAir&&!bruteSolid;
if(std::string_view(check.name)=="maze-air") if(std::string_view(check.name)=="maze-air")
{ {
const int32 tileWidth=CoreTileVoxelCount; const int32 tileWidth=CoreTileVoxelCount;
@@ -1701,9 +1725,9 @@ namespace StandaloneStreamBenchmark
(verdict==TileClass::allAir?!bruteAir: (verdict==TileClass::allAir?!bruteAir:
verdict==TileClass::allSolid?!bruteSolid:false)?"yes":"no"); verdict==TileClass::allSolid?!bruteSolid:false)?"yes":"no");
} }
const bool intervalOk=boxes>=4&&allSolid>=1&&mixed>=1 const bool intervalOk=boxes>=6&&allAir>=1&&allSolid>=1&&mixed>=2
&&misses==0&&falseAllAirRejected&&falseAllSolidRejected&&wallMixed &&misses==0&&falseAllAirRejected&&falseAllSolidRejected&&wallMixed
&&isTileShapeFreeAware; &&shaftCoreAirProved&&shaftCoreWallMixed&&isTileShapeFreeAware;
const bool pathOk=continuous&&capsuleClear&&allSupported&&headroomClear const bool pathOk=continuous&&capsuleClear&&allSupported&&headroomClear
&&maximumGrade<=15.0&&minimumHeadroom>=2.2; &&maximumGrade<=15.0&&minimumHeadroom>=2.2;
std::printf("[LatticeCapsuleReachability] arrival=%s departure=%s edges=%zu path_points=%zu stations=%llu capsule_samples=%llu capsule_failures=%llu first_capsule_failure_m=(%.3f,%.3f,%.3f) support_samples=%llu support_failures=%llu first_support_failure_m=(%.3f,%.3f,%.3f) head_samples=%llu head_failures=%llu first_head_failure_m=(%.3f,%.3f,%.3f) max_grade_deg=%.3f min_headroom_m=%.3f required_headroom_m=2.200 support=every-station reachable=%s status=%s\n", std::printf("[LatticeCapsuleReachability] arrival=%s departure=%s edges=%zu path_points=%zu stations=%llu capsule_samples=%llu capsule_failures=%llu first_capsule_failure_m=(%.3f,%.3f,%.3f) support_samples=%llu support_failures=%llu first_support_failure_m=(%.3f,%.3f,%.3f) head_samples=%llu head_failures=%llu first_head_failure_m=(%.3f,%.3f,%.3f) max_grade_deg=%.3f min_headroom_m=%.3f required_headroom_m=2.200 support=every-station reachable=%s status=%s\n",
@@ -1721,10 +1745,12 @@ namespace StandaloneStreamBenchmark
minimumHeadroom, pathOk?"yes":"no",pathOk?"PASS":"FAIL"); minimumHeadroom, pathOk?"yes":"no",pathOk?"PASS":"FAIL");
std::printf("[LatticeFilletAudit] smooth_max=cubic width_m=%.6f measured_radius_m=%.6f ideal_radius_m=%.6f status=%s\n", std::printf("[LatticeFilletAudit] smooth_max=cubic width_m=%.6f measured_radius_m=%.6f ideal_radius_m=%.6f status=%s\n",
width,measuredFillet,idealFillet,measuredFillet>=0.5?"PASS":"FAIL"); width,measuredFillet,idealFillet,measuredFillet>=0.5?"PASS":"FAIL");
std::printf("[LatticeIntervalOracle] boxes=%llu all_air=%llu all_solid=%llu mixed=%llu samples=%llu misses=%llu false_all_air=%s false_all_solid=%s wall_foot=%s isTileShapeFree=%s tile_free=%s status=%s\n", std::printf("[LatticeIntervalOracle] boxes=%llu all_air=%llu all_solid=%llu mixed=%llu samples=%llu misses=%llu shaft_core_air=%s shaft_core_wall=%s false_all_air=%s false_all_solid=%s wall_foot=%s isTileShapeFree=%s tile_free=%s status=%s\n",
static_cast<unsigned long long>(boxes),static_cast<unsigned long long>(allAir), static_cast<unsigned long long>(boxes),static_cast<unsigned long long>(allAir),
static_cast<unsigned long long>(allSolid),static_cast<unsigned long long>(mixed), static_cast<unsigned long long>(allSolid),static_cast<unsigned long long>(mixed),
static_cast<unsigned long long>(samples),static_cast<unsigned long long>(misses), static_cast<unsigned long long>(samples),static_cast<unsigned long long>(misses),
shaftCoreAirProved?"PROVED":"FAILED",
shaftCoreWallMixed?"mixed":"not-mixed",
falseAllAirRejected?"REJECTED":"FAILED", falseAllAirRejected?"REJECTED":"FAILED",
falseAllSolidRejected?"REJECTED":"FAILED",wallMixed?"mixed":"not-mixed", falseAllSolidRejected?"REJECTED":"FAILED",wallMixed?"mixed":"not-mixed",
isTileShapeFreeAware?"BLOCKED":"FAILED",latticeTileFree?"yes":"no", isTileShapeFreeAware?"BLOCKED":"FAILED",latticeTileFree?"yes":"no",
+2 -1
View File
@@ -1153,7 +1153,8 @@ namespace StandaloneWorldAssemblyPrototype
:nativeCaves?"Core.Caves.PrimitiveField" :nativeCaves?"Core.Caves.PrimitiveField"
:type==ECaveGeneratorType::SurfaceWorld?"SurfaceWorld.Heightfield2D" :type==ECaveGeneratorType::SurfaceWorld?"SurfaceWorld.Heightfield2D"
:type==ECaveGeneratorType::FloatingIslands?"FloatingIslands.ClusterField":"legacy."+std::string(GeneratorKind(type)); :type==ECaveGeneratorType::FloatingIslands?"FloatingIslands.ClusterField":"legacy."+std::string(GeneratorKind(type));
s.recipeVersion=(nativeCaves||nativeLattice)?1 s.recipeVersion=nativeCaves?1
:nativeLattice?VoxelForgeCore::NativeLatticeFieldRecipeVersion
:type==ECaveGeneratorType::SurfaceWorld?assembly.recipe.schemaVersion :type==ECaveGeneratorType::SurfaceWorld?assembly.recipe.schemaVersion
:type==ECaveGeneratorType::FloatingIslands&&!assembly.floatingIslands.empty() :type==ECaveGeneratorType::FloatingIslands&&!assembly.floatingIslands.empty()
?assembly.floatingIslands.front().manifest.recipe.geometryVersion:0; ?assembly.floatingIslands.front().manifest.recipe.geometryVersion:0;
+77 -37
View File
@@ -27,7 +27,7 @@ LINUX47 = ROOT / "Standalone/Research/WorldAssemblerM3/Linux47"
LINUX53 = ROOT / "Standalone/Research/WorldAssemblerM3/Linux53" LINUX53 = ROOT / "Standalone/Research/WorldAssemblerM3/Linux53"
LINUX54 = ROOT / "Standalone/Research/WorldAssemblerM3/Linux54" LINUX54 = ROOT / "Standalone/Research/WorldAssemblerM3/Linux54"
LINUX56 = ROOT / "Standalone/Research/WorldAssemblerM3/Linux56" LINUX56 = ROOT / "Standalone/Research/WorldAssemblerM3/Linux56"
LINUX58 = ROOT / "Standalone/Research/WorldAssemblerM3/Linux58" LINUX59 = ROOT / "Standalone/Research/WorldAssemblerM3/Linux59"
OWNER = ROOT / "Standalone/data/owner_world.json" OWNER = ROOT / "Standalone/data/owner_world.json"
OUT_DEFAULT = ROOT / "Saved/Linux/l42" OUT_DEFAULT = ROOT / "Saved/Linux/l42"
@@ -672,9 +672,9 @@ def run_native_caves_field_audit(runner: VerificationRunner, binary: Path) -> tu
def build_lattice_fixture(runner: VerificationRunner, binary: Path) -> Path: def build_lattice_fixture(runner: VerificationRunner, binary: Path) -> Path:
fixture = OUT / "fixtures" / "lattice-l58.json" fixture = OUT / "fixtures" / "lattice-l59.json"
builder = LINUX58 / "BuildLatticeFixtureL58.py" builder = LINUX59 / "BuildLatticeFixtureL59.py"
runner.run_stage("build-native-lattice-fixture-l58", builder, runner.run_stage("build-native-lattice-fixture-l59", builder,
["--owner", str(OWNER), "--out", str(fixture)], binary=binary, ["--owner", str(OWNER), "--out", str(fixture)], binary=binary,
data=OWNER, recipe="lattice", style=None, env=env_for(), data=OWNER, recipe="lattice", style=None, env=env_for(),
script_inputs=[builder, OWNER]) script_inputs=[builder, OWNER])
@@ -686,19 +686,24 @@ def run_native_lattice_field_audit(runner: VerificationRunner, binary: Path) ->
compiler = compiler_name(binary) compiler = compiler_name(binary)
layout_path = OUT / "layouts" / f"native-lattice-field-{compiler}.json" layout_path = OUT / "layouts" / f"native-lattice-field-{compiler}.json"
styles = {"0": 2, "1": 1, "2": 1} styles = {"0": 2, "1": 1, "2": 1}
inputs = [LINUX58 / "BuildLatticeFixtureL58.py"] inputs = [LINUX59 / "BuildLatticeFixtureL59.py"]
row, output = runner.run_cpp(f"native-lattice-field-{compiler}", binary, fixture, row, output = runner.run_cpp(f"native-lattice-field-{compiler}", binary, fixture,
"lattice", ["--lattice-strate=1", "--audit-native-lattice", "lattice", ["--lattice-strate=1", "--audit-native-lattice",
"--max-clip-level=0", "--render-distance-chunks=0"], "--max-clip-level=0", "--render-distance-chunks=0"],
expected_style=None, expected_strate_styles=styles, workers=12, expected_style=None, expected_strate_styles=styles, workers=12,
max_level=0, layout_path=layout_path, script_inputs=inputs) max_level=0, layout_path=layout_path, script_inputs=inputs)
plan = re.search(r"^\[LatticeSpinePlan\] .*recipe=Core\.Lattice\.PrimitiveField version=1 " plan = re.search(r"^\[LatticeSpinePlan\] .*recipe=Core\.Lattice\.PrimitiveField version=2 "
r"strate=1 .*spine_first=true .*centerline_radius_m=6\.000 clear_width_m=3\.000 " r"strate=1 .*spine_first=true .*shaft_core_id=lattice/spine/shaft-core-v2 "
r"pitch_m=5\.000 turns=4 floor_to_soffit_m=2\.600 .*inner_edge_grade_deg=([0-9.]+) " r"shaft_core_radius_m=4\.500 centerline_radius_m=6\.000 clear_width_m=3\.000 "
r"floor_blend_m=1\.900 union_envelope_m=0\.050 maze_cells=([0-9]+) dead_ends=2 .*status=PASS$", r"pitch_m=5\.000 turns=4 inner_edge_margin_m=1\.500 "
r"capsule_drop_clearance_m=1\.160 support_depth_m=1\.000 "
r"ramp_vertical_clearance_m=4\.000 shaft_outer_envelope_m=21\.000 "
r"maze_headroom_m=2\.600 centerline_grade_deg=[0-9.]+ "
r"inner_edge_grade_deg=([0-9.]+) floor_blend_m=1\.900 "
r"union_envelope_m=1\.000 maze_cells=([0-9]+) dead_ends=2 .*status=PASS$",
output, re.M) output, re.M)
runner.require(f"native-lattice-field-{compiler}:recipe-and-spine", bool(plan), runner.require(f"native-lattice-field-{compiler}:recipe-and-spine", bool(plan),
"native opt-in version-1 lattice, actual mouths first, four-turn ramp and two branches") "native version-2 open well, measured inner margin, supported four-turn ramp and maze branches")
fillet = re.search(r"^\[LatticeFilletAudit\].*measured_radius_m=([0-9.]+) .*status=PASS$", fillet = re.search(r"^\[LatticeFilletAudit\].*measured_radius_m=([0-9.]+) .*status=PASS$",
output, re.M) output, re.M)
runner.require(f"native-lattice-field-{compiler}:measured-fillet", runner.require(f"native-lattice-field-{compiler}:measured-fillet",
@@ -713,8 +718,9 @@ def run_native_lattice_field_audit(runner: VerificationRunner, binary: Path) ->
f"headroom_m={reach.group(2) if reach else 'MISSING'}") f"headroom_m={reach.group(2) if reach else 'MISSING'}")
runner.require(f"native-lattice-field-{compiler}:interval-oracle-and-shape-free", runner.require(f"native-lattice-field-{compiler}:interval-oracle-and-shape-free",
all_match(output, r"^\[LatticeIntervalOracle\].*misses=0 " all_match(output, r"^\[LatticeIntervalOracle\].*misses=0 "
r"shaft_core_air=PROVED shaft_core_wall=mixed "
r"false_all_air=REJECTED false_all_solid=REJECTED .*isTileShapeFree=BLOCKED .*status=PASS$"), r"false_all_air=REJECTED false_all_solid=REJECTED .*isTileShapeFree=BLOCKED .*status=PASS$"),
"BVH intervals match brute-force samples, reject both false proofs and block occupied tiles") "interval bounds prove the shaft core air, find the outer wall, reject false proofs and block occupied tiles")
orphan_name = f"native-lattice-orphan-control-{compiler}" orphan_name = f"native-lattice-orphan-control-{compiler}"
orphan_layout = OUT / "layouts" / f"{orphan_name}.json" orphan_layout = OUT / "layouts" / f"{orphan_name}.json"
@@ -735,6 +741,7 @@ def run_native_lattice_field_audit(runner: VerificationRunner, binary: Path) ->
if row.get("strate_index") == 1] if row.get("strate_index") == 1]
graph_ok = (layout.get("cavern_graph_vocabulary_version") == 1 graph_ok = (layout.get("cavern_graph_vocabulary_version") == 1
and len(edges) >= 9 and len(rooms) >= 8 and len(edges) >= 9 and len(rooms) >= 8
and any(room.get("stable_id") == "lattice/spine/shaft-core-v2" for room in rooms)
and len(lattice_rows) == 1 and len(lattice_rows) == 1
and lattice_rows[0].get("generator_kind") == "Maze" and lattice_rows[0].get("generator_kind") == "Maze"
and lattice_rows[0].get("recipe_id") == "Core.Lattice.PrimitiveField" and lattice_rows[0].get("recipe_id") == "Core.Lattice.PrimitiveField"
@@ -759,8 +766,10 @@ def lattice_camera_positions(layout_path: Path, count: int = 4) -> list[tuple[fl
edges = sorted(layout.get("cavern_edges", []), key=lambda edge: edge["stable_id"]) edges = sorted(layout.get("cavern_edges", []), key=lambda edge: edge["stable_id"])
helix = next((edge for edge in edges helix = next((edge for edge in edges
if edge["stable_id"] == "lattice/spine/01-helix-ramp-v1"), None) if edge["stable_id"] == "lattice/spine/01-helix-ramp-v1"), None)
if layout.get("cavern_graph_vocabulary_version") != 1 or helix is None: core = next((room for room in layout.get("cavern_rooms", [])
raise VerificationFailure(f"missing resolved lattice helix in {layout_path}") if room["stable_id"] == "lattice/spine/shaft-core-v2"), None)
if layout.get("cavern_graph_vocabulary_version") != 1 or helix is None or core is None:
raise VerificationFailure(f"missing resolved open shaft or helix in {layout_path}")
helix_points = [[value / 1_000_000.0 for value in point] helix_points = [[value / 1_000_000.0 for value in point]
for point in helix.get("polyline_um", [])] for point in helix.get("polyline_um", [])]
if len(helix_points) < 4: if len(helix_points) < 4:
@@ -773,11 +782,8 @@ def lattice_camera_positions(layout_path: Path, count: int = 4) -> list[tuple[fl
point = helix_points[index] point = helix_points[index]
tangent = [helix_points[index + 1][axis] - helix_points[index - 1][axis] tangent = [helix_points[index + 1][axis] - helix_points[index - 1][axis]
for axis in range(3)] for axis in range(3)]
lateral = rng.between(-0.35, 0.35) center = [value / 1_000_000.0 for value in core["center_um"]]
horizontal = max(1.0e-9, math.hypot(tangent[0], tangent[1])) x, y, z = center
x = point[0] - tangent[1] / horizontal * lateral
y = point[1] + tangent[0] / horizontal * lateral
z = point[2] + rng.between(1.35, 1.55)
else: else:
route_edges = [edge for edge in edges if edge["stable_id"].startswith( route_edges = [edge for edge in edges if edge["stable_id"].startswith(
"lattice/spine/maze-edge-")] "lattice/spine/maze-edge-")]
@@ -830,7 +836,7 @@ def run_lattice_determinism(runner: VerificationRunner, binary: Path,
peer_layouts: dict[int, str] = {} peer_layouts: dict[int, str] = {}
key = f"p{camera_index:02d}" key = f"p{camera_index:02d}"
current[key] = {"camera_m": [round(value, 6) for value in camera[:3]], current[key] = {"camera_m": [round(value, 6) for value in camera[:3]],
"inside_helix": camera_index == 0} "inside_shaft_core": camera_index == 0}
for workers in (1, 8, 12): for workers in (1, 8, 12):
name = (f"lattice-camera-{compiler}-s{LATTICE_CAMERA_SWEEP_SEED:06x}-" name = (f"lattice-camera-{compiler}-s{LATTICE_CAMERA_SWEEP_SEED:06x}-"
f"p{camera_index:02d}-w{workers}") f"p{camera_index:02d}-w{workers}")
@@ -841,7 +847,7 @@ def run_lattice_determinism(runner: VerificationRunner, binary: Path,
"--render-distance-chunks=0"], expected_style=None, "--render-distance-chunks=0"], expected_style=None,
expected_strate_styles=styles, workers=workers, max_level=0, expected_strate_styles=styles, workers=workers, max_level=0,
layout_path=run_layout, layout_path=run_layout,
script_inputs=[LINUX58 / "BuildLatticeFixtureL58.py"]) script_inputs=[LINUX59 / "BuildLatticeFixtureL59.py"])
tiles = parse_tile_hashes(output) tiles = parse_tile_hashes(output)
whole = re.search(r"^\[PipelineWholeViewHash\] tiles=(\d+)", output, re.M) whole = re.search(r"^\[PipelineWholeViewHash\] tiles=(\d+)", output, re.M)
expected_rows = int(whole.group(1)) if whole else -1 expected_rows = int(whole.group(1)) if whole else -1
@@ -871,17 +877,34 @@ def run_lattice_determinism(runner: VerificationRunner, binary: Path,
def run_lattice_performance(runner: VerificationRunner, binary: Path, def run_lattice_performance(runner: VerificationRunner, binary: Path,
fixture: Path, layout_path: Path) -> None: fixture: Path, layout_path: Path) -> None:
compiler = compiler_name(binary) compiler = compiler_name(binary)
camera = lattice_camera_positions(layout_path, count=1)[0] layout = json.loads(layout_path.read_text(encoding="utf-8"))
helix = next(edge for edge in layout.get("cavern_edges", [])
if edge["stable_id"] == "lattice/spine/01-helix-ramp-v1")
helix_points = [[value / 1_000_000.0 for value in point]
for point in helix.get("polyline_um", [])]
index = len(helix_points) // 2
point = helix_points[index]
tangent = [helix_points[index + 1][axis] - helix_points[index - 1][axis]
for axis in range(3)]
horizontal = max(1.0e-9, math.hypot(tangent[0], tangent[1]))
rng = _SplitMix64(LATTICE_CAMERA_SWEEP_SEED)
lateral = rng.between(-0.35, 0.35)
x = point[0] - tangent[1] / horizontal * lateral
y = point[1] + tangent[0] / horizontal * lateral
z = point[2] + rng.between(1.35, 1.55)
yaw = math.degrees(math.atan2(tangent[0], tangent[1])) + rng.between(-14.0, 14.0)
pitch = rng.between(-6.0, 6.0)
camera = (x, y, z, yaw, pitch)
x, y, z, yaw, pitch = camera x, y, z, yaw, pitch = camera
camera_flag = f"--camera={x:.6f},{y:.6f},{z:.6f},{yaw:.3f},{pitch:.3f}" camera_flag = f"--camera={x:.6f},{y:.6f},{z:.6f},{yaw:.3f},{pitch:.3f}"
name = f"lattice-speed-{compiler}-w12" name = f"lattice-speed-{compiler}-w12"
row, output = runner.run_cpp(name, binary, fixture, "lattice", row, output = runner.run_cpp(name, binary, fixture, "lattice",
["--lattice-strate=1", camera_flag, "--clip-radius=4", "--max-clip-level=0", ["--lattice-strate=1", camera_flag, "--clip-radius=4", "--max-clip-level=0",
"--max-level=0", "--render-distance-chunks=0", "--camera-step=24,0,0", "--max-level=0", "--render-distance-chunks=0", "--camera-step=24,0,0",
"--region-crossing"], expected_style=None, "--region-crossing", "--instrument-tile-drain"], expected_style=None,
expected_strate_styles={"0": 2, "1": 1, "2": 1}, workers=12, expected_strate_styles={"0": 2, "1": 1, "2": 1}, workers=12,
max_level=0, layout_path=OUT / "layouts" / f"{name}.json", max_level=0, layout_path=OUT / "layouts" / f"{name}.json",
script_inputs=[LINUX58 / "BuildLatticeFixtureL58.py"]) script_inputs=[LINUX59 / "BuildLatticeFixtureL59.py"])
stream = re.search(r"^\[StreamPipeline\] .*first_tile_ready=([0-9.]+)s " stream = re.search(r"^\[StreamPipeline\] .*first_tile_ready=([0-9.]+)s "
r".*neighborhood_ready=([0-9.]+)s .*whole_view_ready=([0-9.]+)s .*cache_hits=0", r".*neighborhood_ready=([0-9.]+)s .*whole_view_ready=([0-9.]+)s .*cache_hits=0",
output, re.M) output, re.M)
@@ -895,6 +918,20 @@ def run_lattice_performance(runner: VerificationRunner, binary: Path,
f"whole_view_s={stream.group(3) if stream else 'MISSING'} " f"whole_view_s={stream.group(3) if stream else 'MISSING'} "
f"moving_p50_ms={moving.group(2) if moving else 'MISSING'} " f"moving_p50_ms={moving.group(2) if moving else 'MISSING'} "
f"moving_p95_ms={moving.group(3) if moving else 'MISSING'}") f"moving_p95_ms={moving.group(3) if moving else 'MISSING'}")
stage_rows = re.findall(r"^\[CpuTileStages\] (.*)$", output, re.M)
def sum_stage(field: str) -> float:
values = [float(value) for value in re.findall(
rf"(?:^| ){re.escape(field)}=([0-9.]+)(?: |$)", "\n".join(stage_rows))]
return sum(values)
stage_summary = {field: sum_stage(field) for field in (
"worker_ms", "classify_ms", "column_exclusive_ms", "mc_ms",
"mc_grid_ms", "mc_cell_ms", "mc_gradient_ms", "mc_interpolation_ms",
"mc_dedup_ms", "mc_skirt_ms", "mc_other_ms", "mesh_assembly_ms")}
runner.require(f"{name}:tile-drain-instrumentation",
bool(stage_rows) and stage_summary["worker_ms"] > 0.0,
f"tile_stage_rows={len(stage_rows)} worker_sum_ms={stage_summary['worker_ms']:.3f} "
f"mc_ms={stage_summary['mc_ms']:.3f} "
f"column_ms={stage_summary['column_exclusive_ms']:.3f}")
if stream and moving: if stream and moving:
row["speed_metrics"] = { row["speed_metrics"] = {
"cold_first_tile_seconds": float(stream.group(1)), "cold_first_tile_seconds": float(stream.group(1)),
@@ -905,6 +942,8 @@ def run_lattice_performance(runner: VerificationRunner, binary: Path,
"moving_p95_ms": float(moving.group(3)), "moving_p95_ms": float(moving.group(3)),
"workers": 12, "camera_m": [round(value, 6) for value in camera[:3]], "workers": 12, "camera_m": [round(value, 6) for value in camera[:3]],
} }
row["tile_drain_instrumentation"] = {
"stage_rows": len(stage_rows), "aggregate_ms": stage_summary}
def cave_camera_positions(layout_path: Path, count: int = 4) -> list[tuple[float, float, float, float, float]]: def cave_camera_positions(layout_path: Path, count: int = 4) -> list[tuple[float, float, float, float, float]]:
@@ -1103,25 +1142,25 @@ def run_caves_surface_evidence(runner: VerificationRunner, fixture: Path,
def run_lattice_surface_evidence(runner: VerificationRunner, fixture: Path, def run_lattice_surface_evidence(runner: VerificationRunner, fixture: Path,
layout_path: Path) -> None: layout_path: Path) -> None:
capture_script = LINUX58 / "CaptureNativeLatticeL58.py" capture_script = LINUX59 / "CaptureNativeLatticeL59.py"
artifact_dir = LINUX58 / "captures" artifact_dir = LINUX59 / "captures"
_, capture_output = runner.run_stage("capture-native-lattice-l58", capture_script, _, capture_output = runner.run_stage("capture-native-lattice-l59", capture_script,
["--out", str(OUT), "--fixture", str(fixture), "--layout", str(layout_path), ["--out", str(OUT), "--fixture", str(fixture), "--layout", str(layout_path),
"--headless", str(CLANG), "--renderer", str(RENDERER), "--headless", str(CLANG), "--renderer", str(RENDERER),
"--artifact-dir", str(artifact_dir)], binary=CLANG, data=fixture, "--artifact-dir", str(artifact_dir)], binary=CLANG, data=fixture,
recipe="lattice", style=2, env=env_for(capture=True), recipe="lattice", style=2, env=env_for(capture=True),
script_inputs=[capture_script, LINUX54 / "CaptureNativeCavesL54.py", script_inputs=[capture_script, LINUX54 / "CaptureNativeCavesL54.py",
VERIFY_DIR / "capture_quality.py"]) VERIFY_DIR / "capture_quality.py"])
capture_rows = re.findall(r"^\[L58LatticeCapture\] view=([^ ]+) file=(\S+) " capture_rows = re.findall(r"^\[L59LatticeCapture\] view=([^ ]+) file=(\S+) "
r"bytes=(\d+) sha256=([0-9a-f]{64}) status=PASS$", capture_output, re.M) r"bytes=(\d+) sha256=([0-9a-f]{64}) status=PASS$", capture_output, re.M)
expected_views = {"helix-top-down", "ramp-eye-next-turn", "maze-eye-level", expected_views = {"shaft-top-down", "ramp-eye-across", "maze-corridor",
"cutaway-overview"} "shaft-overview"}
runner.require("capture-native-lattice-l58:coverage-and-size", runner.require("capture-native-lattice-l59:coverage-and-size",
{row[0] for row in capture_rows} == expected_views and len(capture_rows) == 4 {row[0] for row in capture_rows} == expected_views and len(capture_rows) == 4
and all(int(row[2]) <= 300_000 for row in capture_rows), and all(int(row[2]) <= 300_000 for row in capture_rows),
f"views={[(row[0], int(row[2])) for row in capture_rows]}") f"views={[(row[0], int(row[2])) for row in capture_rows]}")
surface_script = LINUX58 / "AuditLatticeSurfaceL58.py" surface_script = LINUX59 / "AuditLatticeSurfaceL59.py"
audit_layout = ROOT / "Saved/Linux/l48/layouts/landmark-reachability-clang.json" audit_layout = ROOT / "Saved/Linux/l48/layouts/landmark-reachability-clang.json"
candidate_mesh = OUT / "lattice-meshes" / "lattice-whole-view.vfmesh" candidate_mesh = OUT / "lattice-meshes" / "lattice-whole-view.vfmesh"
controls = ( controls = (
@@ -1130,26 +1169,27 @@ def run_lattice_surface_evidence(runner: VerificationRunner, fixture: Path,
("L47-wall-foot-control", ROOT / "Saved/Linux/l47/landmark-l47.vfmesh", "fail"), ("L47-wall-foot-control", ROOT / "Saved/Linux/l47/landmark-l47.vfmesh", "fail"),
("plain-native-control", ROOT / "Saved/Linux/l48/control-plain-native.vfmesh", "pass"), ("plain-native-control", ROOT / "Saved/Linux/l48/control-plain-native.vfmesh", "pass"),
) )
args = ["--json", str(OUT / "whole-surface-lattice-l58.json"), svg_dir = OUT / "surface-audit-svg"
"--svg-dir", str(artifact_dir), "--case", "lattice-whole", args = ["--json", str(OUT / "whole-surface-lattice-l59.json"),
"--svg-dir", str(svg_dir), "--case", "lattice-whole",
str(candidate_mesh), str(layout_path), "measure", "whole"] str(candidate_mesh), str(layout_path), "measure", "whole"]
for label, mesh, expectation in controls: for label, mesh, expectation in controls:
args.extend(("--case", label, str(mesh), str(audit_layout), expectation, "whole")) args.extend(("--case", label, str(mesh), str(audit_layout), expectation, "whole"))
_, audit_output = runner.run_stage("whole-surface-lattice-l58", surface_script, _, audit_output = runner.run_stage("whole-surface-lattice-l59", surface_script,
args, binary=CLANG, data=fixture, recipe="lattice", style=2, args, binary=CLANG, data=fixture, recipe="lattice", style=2,
layout_path=layout_path, env=env_for(), layout_path=layout_path, env=env_for(),
script_inputs=[surface_script, LINUX54 / "AuditWholeSurfaceL54.py", script_inputs=[surface_script, LINUX54 / "AuditWholeSurfaceL54.py",
candidate_mesh, layout_path, audit_layout, *(item[1] for item in controls)]) candidate_mesh, layout_path, audit_layout, *(item[1] for item in controls)])
candidate = re.search(r"^\[WholeSurfaceAudit\] label=lattice-whole .*" candidate = re.search(r"^\[WholeSurfaceAudit\] label=lattice-whole .*"
r"observed=(PASS|FAIL) expected=MEASURE status=PASS$", audit_output, re.M) r"observed=(PASS|FAIL) expected=MEASURE status=PASS$", audit_output, re.M)
runner.require("whole-surface-lattice-l58:helix-and-maze", runner.require("whole-surface-lattice-l59:shaft-lip-wall-foot-and-underside",
bool(candidate and candidate.group(1) == "PASS"), bool(candidate and candidate.group(1) == "PASS"),
f"observed={candidate.group(1) if candidate else 'MISSING'} over helix ramp edges and maze wall feet") f"observed={candidate.group(1) if candidate else 'MISSING'} over helix ramp edges and maze wall feet")
for label, _mesh, expectation in controls: for label, _mesh, expectation in controls:
match = re.search(rf"^\[WholeSurfaceAudit\] label={re.escape(label)} .*" match = re.search(rf"^\[WholeSurfaceAudit\] label={re.escape(label)} .*"
rf"observed=(PASS|FAIL) expected={expectation.upper()} status=PASS$", rf"observed=(PASS|FAIL) expected={expectation.upper()} status=PASS$",
audit_output, re.M) audit_output, re.M)
runner.require(f"whole-surface-lattice-l58:{label}", bool(match), runner.require(f"whole-surface-lattice-l59:{label}", bool(match),
f"control_expectation={expectation} observed={match.group(1) if match else 'MISSING'}") f"control_expectation={expectation} observed={match.group(1) if match else 'MISSING'}")
@@ -2227,7 +2267,7 @@ def run_gcc_supplement(runner: VerificationRunner) -> None:
if not fixture.is_file() or not layout_path.is_file(): if not fixture.is_file() or not layout_path.is_file():
fixture, layout_path = run_native_caves_field_audit(runner, CLANG) fixture, layout_path = run_native_caves_field_audit(runner, CLANG)
run_caves_determinism(runner, GCC, fixture, layout_path, compare_reference=True) run_caves_determinism(runner, GCC, fixture, layout_path, compare_reference=True)
lattice_fixture = OUT / "fixtures" / "lattice-l58.json" lattice_fixture = OUT / "fixtures" / "lattice-l59.json"
lattice_layout = OUT / "layouts" / "native-lattice-field-clang.json" lattice_layout = OUT / "layouts" / "native-lattice-field-clang.json"
if not lattice_fixture.is_file() or not lattice_layout.is_file(): if not lattice_fixture.is_file() or not lattice_layout.is_file():
lattice_fixture, lattice_layout = run_native_lattice_field_audit(runner, CLANG) lattice_fixture, lattice_layout = run_native_lattice_field_audit(runner, CLANG)