diff --git a/Standalone/Core/include/VoxelForgeCore/VoxelForgeCore.h b/Standalone/Core/include/VoxelForgeCore/VoxelForgeCore.h index 4512b60..ac27df1 100644 --- a/Standalone/Core/include/VoxelForgeCore/VoxelForgeCore.h +++ b/Standalone/Core/include/VoxelForgeCore/VoxelForgeCore.h @@ -473,8 +473,9 @@ namespace VoxelForgeCore // Version 219 smooths passage XY while mapping each planned height chord over its sampled horizontal arc. // Version 220 adaptively samples passage curves and rounds open-air wall crests. // Version 221 ranks passage segments before floor shaping and preserves their signed exterior distance. - // Version 222 selects the floor profile by centerline position, independent of tube radius. - inline constexpr std::uint32_t WorldAssemblyEvaluatorVersion = 222; + // Version 223 projects the floor onto one continuous arc-length profile and groups + // dense passage samples into coarse tile candidates. + inline constexpr std::uint32_t WorldAssemblyEvaluatorVersion = 223; enum class FieldChannel : std::uint32_t { diff --git a/Standalone/Core/src/ShapeWorldInternal.h b/Standalone/Core/src/ShapeWorldInternal.h index de2d85c..c266bd8 100644 --- a/Standalone/Core/src/ShapeWorldInternal.h +++ b/Standalone/Core/src/ShapeWorldInternal.h @@ -256,6 +256,7 @@ public: struct FCandidateSegment { std::size_t segmentIndex=0; + std::size_t segmentEndIndex=0; std::array minimumSubvoxels{},maximumSubvoxels{}; std::array sweepMinimumSubvoxels{},sweepMaximumSubvoxels{}; }; @@ -330,6 +331,7 @@ public: const auto& bounds=shape.PassageFeatureBounds[featureIndex]; FCandidateSegment candidate; candidate.segmentIndex=feature.segmentIndex; + candidate.segmentEndIndex=feature.segmentEndIndex; candidate.minimumSubvoxels=bounds.minimumSubvoxels; candidate.maximumSubvoxels=bounds.maximumSubvoxels; candidate.sweepMinimumSubvoxels=bounds.minimumSubvoxels; @@ -1277,6 +1279,7 @@ public: const std::ptrdiff_t lastIndex=static_cast( PassageSegmentData[passageIndex].size())-1; + const auto& segments=PassageSegmentData[passageIndex]; double bestDistance=std::numeric_limits::infinity(); double bestFloorCenterDistanceSq=std::numeric_limits::infinity(); const auto visitSegment=[&](std::size_t segmentIndex,int) @@ -1295,21 +1298,23 @@ public: const double ex=qx-cx,ey=qy-cy,ez=qz-cz; const double roundDistance=DeterministicSqrt( ex*ex+ey*ey+ez*ez)-radius; - const double floorCenterDistanceSq=ex*ex+ey*ey+ez*ez; const double floorT=segment.horizontalLengthSq>1.0e-12 - ?std::clamp(((qx-segment.a[0])*segment.delta[0] + ?(((qx-segment.a[0])*segment.delta[0] +(qy-segment.a[1])*segment.delta[1]) - /segment.horizontalLengthSq,0.0,1.0):t; - const double floorRadius=segment.radiusA+floorT*segment.radiusDelta; + /segment.horizontalLengthSq):t; + const double floorTClamped=std::clamp(floorT,0.0,1.0); + const double floorCenterDistanceSq=ex*ex+ey*ey+ez*ez; + const double floorRadius=segment.radiusA + +floorTClamped*segment.radiusDelta; const double floorDepth=PassageFlatFloorDepthSubvoxels( - constants,segmentIndex,floorT,floorRadius,qPerMetre); + constants,segmentIndex,floorTClamped,floorRadius,qPerMetre); const double floorCenterZ=PassageFlatFloorCenterZSubvoxels( - constants,segmentIndex,floorT,segment,qx,qy,floorDepth,qPerMetre); + constants,segments,segmentIndex,floorT,segment, + qx,qy,floorDepth,qPerMetre); const double flatDistance=PassageFlatBottomDistance( static_cast(roundDistance),floorCenterZ,qz,floorDepth,qPerMetre); - // Radius-based tube selection can favor a wider downhill segment - // and carry its lower floor plane backward. Select the floor profile - // by the centerline position, independently of tube radius. + // The profile uses the closest route projection's arc length. Tube + // radius selects the bore shape only; it never selects floor height. if(floorCenterDistanceSq1.0e-12 - ?std::clamp(((qx-segment.a[0])*segment.delta[0] + ?(((qx-segment.a[0])*segment.delta[0] +(qy-segment.a[1])*segment.delta[1]) - /segment.horizontalLengthSq,0.0,1.0):t; - const double floorRadius=segment.radiusA+floorT*segment.radiusDelta; + /segment.horizontalLengthSq):t; + const double floorTClamped=std::clamp(floorT,0.0,1.0); + const auto& segments=PassageSegmentData[passageIndex]; + const double floorRadius=segment.radiusA + +floorTClamped*segment.radiusDelta; const double floorDepth=PassageFlatFloorDepthSubvoxels( - constants,segmentIndex,floorT,floorRadius,qPerMetre); + constants,segmentIndex,floorTClamped,floorRadius,qPerMetre); const double floorCenterZ=PassageFlatFloorCenterZSubvoxels( - constants,segmentIndex,floorT,segment,qx,qy,floorDepth,qPerMetre); + constants,segments,segmentIndex,floorT,segment, + qx,qy,floorDepth,qPerMetre); const double flatDistance=PassageFlatBottomDistance( static_cast(roundDistance),floorCenterZ,qz,floorDepth,qPerMetre); const double alongMetres=segment.authoredAlongMetres @@ -3401,12 +3410,13 @@ public: private: struct FPassageTileFeature { - std::size_t passageIndex=0,segmentIndex=0; + std::size_t passageIndex=0,segmentIndex=0,segmentEndIndex=0; }; struct FPassageComposerConstants { double floorDepthMetres=0.0,totalPathLengthMetres=0.0; double authoredTotalPathLengthMetres=0.0; + std::size_t routeProfileSegmentCount=0; double upperMouthX=0.0,upperMouthY=0.0; double upperMouthPlannedFloor=0.0; double upperMouthTangentX=0.0,upperMouthTangentY=0.0; @@ -3436,14 +3446,40 @@ private: } static double PassageFlatFloorCenterZSubvoxels( - const FPassageComposerConstants& constants,std::size_t segmentIndex,double floorT, + const FPassageComposerConstants& constants, + const std::vector& segments, + std::size_t segmentIndex,double floorT, const FPassageSegmentData& segment,double queryXSubvoxels,double queryYSubvoxels, double floorDepthSubvoxels,double qPerMetre) { if(!segment.routeSegment||qPerMetre<=0.0) - return segment.a[2]+floorT*segment.delta[2]; - const double plannedFloor=segment.authoredFloorZA + return segment.a[2]+std::clamp(floorT,0.0,1.0)*segment.delta[2]; + const std::size_t profileCount=std::min( + constants.routeProfileSegmentCount,segments.size()); + double plannedFloor=segment.authoredFloorZA +floorT*segment.authoredFloorZDelta; + if(profileCount>0) + { + if(floorT>=0.0&&floorT<=1.0) + plannedFloor=segment.authoredFloorZA + +floorT*segment.authoredFloorZDelta; + else + { + const double distance=segment.authoredAlongMetres + +floorT*segment.authoredLengthMetres; + const auto profileEnd=segments.begin()+profileCount; + const auto upper=std::lower_bound(segments.begin(),profileEnd,distance, + [](const FPassageSegmentData& candidate,double value) + {return candidate.authoredAlongMetres + +candidate.authoredLengthMetres1.0e-12 + ?std::clamp((distance-profileSegment.authoredAlongMetres) + /profileSegment.authoredLengthMetres,0.0,1.0):0.0; + plannedFloor=profileSegment.authoredFloorZA + +profileT*profileSegment.authoredFloorZDelta; + } + } const double mouthBlendFloor=VoxelForgeCore::PassageSpline::BlendUpperMouthFloorAtXY( constants.upperMouthReceivingRoute,queryXSubvoxels,queryYSubvoxels, plannedFloor,constants.upperMouthX,constants.upperMouthY, @@ -4325,7 +4361,7 @@ private: template void VisitNearestPassageSegmentRange(std::size_t passageIndex, std::ptrdiff_t first,std::ptrdiff_t last,double qx,double qy,double qz, - int priority,double& bestDistance,double& bestCenterDistanceSq, + int priority,double& bestDistance,double& bestFloorCenterDistanceSq, FVisitor&& visitor) const { (void)priority; @@ -4359,8 +4395,9 @@ private: if(static_cast(node.maximumSegment)(node.minimumSegment)>last ||(lowerBound(node)>bestDistance - &&(bestCenterDistanceSq<0.0 - ||centerDistanceLowerBoundSq(node)>bestCenterDistanceSq)))return; + &&(bestFloorCenterDistanceSq<0.0 + ||centerDistanceLowerBoundSq(node) + >bestFloorCenterDistanceSq)))return; if(node.left<0) { for(const std::size_t segment:node.segments) @@ -4740,6 +4777,9 @@ private: segmentData.push_back(data); ++preparedSegments; } + constants.routeProfileSegmentCount=static_cast(std::count_if( + segmentData.begin(),segmentData.end(), + [](const FPassageSegmentData& segment){return segment.routeSegment;})); PassageSegmentOffsets[passageIndex+1]=preparedSegments; } if(tracePreparation) @@ -4770,6 +4810,9 @@ private: constexpr double ReliefMetres=0.21; constexpr double SweepReachMetres=4.0; constexpr double CornerBlendMetres=0.50; + constexpr std::size_t CandidateFineSamplesPerSpan=5; + const double requiredReach=std::max(SweepReachMetres+ReliefMetres + +CornerBlendMetres*0.25,PassageShellMetres+ReliefMetres); for(std::size_t passageIndex=0;passageIndexpassages.size(); ++passageIndex) { @@ -4778,47 +4821,67 @@ private: std::vector segmentIds(segmentCount); for(std::size_t i=0;i routeMinimum{},routeMaximum{}; - for(std::size_t axis=0;axis<3;++axis) + const std::size_t segmentEndIndex=std::min( + segmentIndex+CandidateFineSamplesPerSpan,segmentCount); + std::array routeMinimum{ + std::numeric_limits::infinity(), + std::numeric_limits::infinity(), + std::numeric_limits::infinity()}; + std::array routeMaximum{ + -std::numeric_limits::infinity(), + -std::numeric_limits::infinity(), + -std::numeric_limits::infinity()}; + double maximumRadiusSubvoxels=0.0; + for(std::size_t localIndex=segmentIndex; + localIndex localMinimum{},localMaximum{}; + for(std::size_t axis=0;axis<3;++axis) + { + localMinimum[axis]=std::min(prepared.a[axis],prepared.b[axis])/Q; + localMaximum[axis]=std::max(prepared.a[axis],prepared.b[axis])/Q; + routeMinimum[axis]=std::min(routeMinimum[axis],localMinimum[axis]); + routeMaximum[axis]=std::max(routeMaximum[axis],localMaximum[axis]); + } + const double localExtent=requiredReach + +std::max(prepared.radiusA,prepared.radiusB)/Q+0.01; + FPassageProofBound proof; + for(std::size_t axis=0;axis<3;++axis) + { + proof.minimum[axis]=localMinimum[axis]-localExtent; + proof.maximum[axis]=localMaximum[axis]+localExtent; + } + PassageProofBounds.push_back(proof); + for(std::size_t axis=0;axis<3;++axis) + { + prepared.sweepMinimumSubvoxels[axis]=static_cast( + std::floor((localMinimum[axis]-localExtent)*Q)); + prepared.sweepMaximumSubvoxels[axis]=static_cast( + std::ceil((localMaximum[axis]+localExtent)*Q)); + } + } + const double routeExtent=maximumRadiusSubvoxels/Q+requiredReach+0.01; + const double tileExtent=routeExtent; std::array featureMinimum{},featureMaximum{}; - std::array sweepMinimum{},sweepMaximum{}; for(std::size_t axis=0;axis<3;++axis) { featureMinimum[axis]=static_cast(std::floor( (routeMinimum[axis]-tileExtent)*Q)); featureMaximum[axis]=static_cast(std::ceil( (routeMaximum[axis]+tileExtent)*Q)); - sweepMinimum[axis]=featureMinimum[axis]; - sweepMaximum[axis]=featureMaximum[axis]; - prepared.sweepMinimumSubvoxels[axis]=sweepMinimum[axis]; - prepared.sweepMaximumSubvoxels[axis]=sweepMaximum[axis]; } PassageFeatureBounds.push_back({ static_cast(PassageTileFeatures.size()), featureMinimum,featureMaximum}); - PassageTileFeatures.push_back({passageIndex,segmentIndex}); + PassageTileFeatures.push_back( + {passageIndex,segmentIndex,segmentEndIndex}); } } for(std::size_t i=0;iPassageComposerConstants[passageIndex]; + const auto& segments=shape_->PassageSegmentData[passageIndex]; for(const auto& candidate:candidates) { - if(candidate.segmentIndex>=shape_->PassageSegmentData[passageIndex].size())continue; + if(candidate.segmentIndex>=segments.size())continue; + const std::size_t segmentEndIndex=std::min(candidate.segmentEndIndex, + segments.size()); + if(candidate.segmentIndex>=segmentEndIndex)continue; std::array first{},last{}; for(std::size_t axis=0;axis<3;++axis) gridRange(axis,candidate.sweepMinimumSubvoxels[axis], candidate.sweepMaximumSubvoxels[axis],first[axis],last[axis]); if(first[0]>last[0]||first[1]>last[1]||first[2]>last[2])continue; - const auto& segment=shape_->PassageSegmentData[passageIndex][candidate.segmentIndex]; - if(segment.lengthSq<=0.0)continue; for(std::int32_t gz=first[2];gz<=last[2];++gz) { for(std::int32_t gy=first[1];gy<=last[1];++gy) @@ -11451,6 +11516,17 @@ inline void FStandaloneShapeWorld::FScopedPassageTileQueries::prepareSweptTubeBa +static_cast(gy)*sweep->stepSubvoxels); const double qz=static_cast(sweep->gridMinimumSubvoxels[2] +static_cast(gz)*sweep->stepSubvoxels); + for(std::size_t segmentIndex=candidate.segmentIndex; + segmentIndexsegment.sweepMaximumSubvoxels[0] + ||qysegment.sweepMaximumSubvoxels[1] + ||qzsegment.sweepMaximumSubvoxels[2])continue; const double projectionXY=(qx-segment.a[0])*segment.delta[0] +(qy-segment.a[1])*segment.delta[1]; const double t=std::clamp((projectionXY @@ -11462,16 +11538,18 @@ inline void FStandaloneShapeWorld::FScopedPassageTileQueries::prepareSweptTubeBa const double ex=qx-cx,ey=qy-cy,ez=qz-cz; const double signedDistance=FStandaloneShapeWorld::DeterministicSqrt( ex*ex+ey*ey+ez*ez)-radius; - const double floorCenterDistanceSq=ex*ex+ey*ey+ez*ez; const double floorT=segment.horizontalLengthSq>1.0e-12 - ?std::clamp(projectionXY/segment.horizontalLengthSq,0.0,1.0):t; - const double floorRadius=segment.radiusA+floorT*segment.radiusDelta; + ?projectionXY/segment.horizontalLengthSq:t; + const double floorTClamped=std::clamp(floorT,0.0,1.0); + const double floorCenterDistanceSq=ex*ex+ey*ey+ez*ez; + const double floorRadius=segment.radiusA + +floorTClamped*segment.radiusDelta; const double floorDepth=FStandaloneShapeWorld::PassageFlatFloorDepthSubvoxels( - constants,candidate.segmentIndex,floorT,floorRadius,qPerMetre); + constants,segmentIndex,floorTClamped,floorRadius,qPerMetre); const double floorCenterZ= FStandaloneShapeWorld::PassageFlatFloorCenterZSubvoxels( - constants,candidate.segmentIndex,floorT,segment,qx,qy,floorDepth, - qPerMetre); + constants,segments,segmentIndex,floorT,segment, + qx,qy,floorDepth,qPerMetre); const double flatDistance=FStandaloneShapeWorld::PassageFlatBottomDistance( static_cast(signedDistance),floorCenterZ,qz,floorDepth,qPerMetre); if(profile)++profileStats_->passageSweepSegmentSamplePairs; @@ -11485,14 +11563,14 @@ inline void FStandaloneShapeWorld::FScopedPassageTileQueries::prepareSweptTubeBa auto& sample=passageSamples.samples[sampleIndex]; if(floorCenterDistanceSq( - candidate.segmentIndex); + segmentIndex); } const double alongMetres=segment.authoredAlongMetres +t*segment.authoredLengthMetres; @@ -11536,19 +11614,20 @@ inline void FStandaloneShapeWorld::FScopedPassageTileQueries::prepareSweptTubeBa // independently above from the nearest centerline position. if(!sample.valid||signedDistance(candidate.segmentIndex); + sample.segmentIndex=static_cast(segmentIndex); sample.valid=true; sample.hasWallRelief=false; if(profile)++profileStats_->passageSweepMinimumUpdates; } } + } } } } diff --git a/Standalone/Research/WorldAssemblerM3/Linux115/REPORT.md b/Standalone/Research/WorldAssemblerM3/Linux115/REPORT.md new file mode 100644 index 0000000..3e1f622 --- /dev/null +++ b/Standalone/Research/WorldAssemblerM3/Linux115/REPORT.md @@ -0,0 +1,46 @@ +# Linux115 report + +Source version 223. Floor height now comes from the planner profile `h(s)` on the dense route, using horizontal projection and arc-length interpolation. In-range projections interpolate on their fine segment; out-of-range projections use the global profile lookup. Adjacent fine segments share the same endpoint value. The plan-time grade audit remains enabled: maximum sampled grade was 10.687° (limit 15°). + +## Floor zero crossings + +Each station has 51 density samples. Offsets below are in millimetres. + +| Passage | Station | Max absolute | Median absolute | P95 absolute | +|---|---:|---:|---:|---:| +| 0–1 | 25% | 0.088 | 0.009 | 0.066 | +| 0–1 | 50% | 0.079 | 0.016 | 0.064 | +| 0–1 | 75% | 0.225 | 0.016 | 0.161 | +| 1–2 | 25% | 7.475 | 7.259 | 7.459 | +| 1–2 | 50% | 7.272 | 7.215 | 7.265 | +| 1–2 | 75% | 7.272 | 7.121 | 7.245 | +| 2–3 | 25% | 7.849 | 7.712 | 7.844 | +| 2–3 | 50% | 7.712 | 7.351 | 7.694 | +| 2–3 | 75% | 7.573 | 7.506 | 7.566 | + +Maximum offset is 7.849 mm, below the 10 mm target. Full data: [CSV](../../../../Saved/Linux/l115/density-probe/zero-crossing-offsets.csv) and [summary](../../../../Saved/Linux/l115/density-probe/zero-crossing-summary.json). + +## Shell probes and captures + +The two L114 southwest wall misses were probe-oracle false positives. Both positions were inside an intentionally carved overlapping passage bore, where host air is correct; the audit had only considered the nearest route span when classifying bore interior. The oracle now recognizes interior air on any overlapping route span. No wall gate was relaxed. The final two-strata audit reports 0 wall violations in 31,361 probes (8,848 overlap-interior skips), 0 floor violations, and 0 interior violations. + +The final capture set has 23/23 programmatically verified images: 9 rock-floor close-ups and 14 open-air outside/interior close-ups across 7 sections. Quality labels are 18 `pass` and 5 `low_contrast_geometry_visible`; all five still passed visibility verification. [Capture index](captures/capture-index.json). + +## Speed + +Coarse candidate totals are L109 3,132, L114 14,384, and L115 3,720 (74.1% fewer than L114). The inner sweep still visits 48.95M fine-segment/sample pairs for both L114 and L115, versus 19.81M for L109, so fewer coarse candidates did not reduce fine traversal enough to improve readiness. + +Five interleaved measured runs per version followed warm-ups at W8/W12 for all four strata. The host was quiet before timing (1-minute load 1.30; `top` 99% idle). Values below are L115 near-ready median deltas. + +| Stratum | W8 vs L109 / L114 | W12 vs L109 / L114 | +|---|---:|---:| +| 0 | +16.8% / +8.7% | +16.8% / +9.2% | +| 1 | +30.4% / +13.0% | +31.1% / +14.5% | +| 2 | +25.2% / +12.4% | +25.9% / +12.0% | +| 3 | +23.8% / +8.6% | +18.1% / +2.9% | + +Across the eight strata/worker combinations, median whole-view deltas were +10.7% versus L109 and +4.9% versus L114. Full run data: [timing summary](../../../../Saved/Linux/l115/timing/summary.json). + +## Verification + +Fast tier passed in 341.1 s, including walkability, passage shell, camera sweeps, native field, and motif capsule reachability. Clang/GCC hashes matched at W1/W8/W12 for all four owner strata groups. The final source stamp is `7eb1fa49f91954c0690173aba4ed832b3594e50531bd4b20690d122970943274`; no Unreal-compiled source changed, so no Unreal build was needed. diff --git a/Standalone/Research/WorldAssemblerM3/Linux115/RunL115CandidateLists.py b/Standalone/Research/WorldAssemblerM3/Linux115/RunL115CandidateLists.py new file mode 100644 index 0000000..bc89dd4 --- /dev/null +++ b/Standalone/Research/WorldAssemblerM3/Linux115/RunL115CandidateLists.py @@ -0,0 +1,84 @@ +#!/usr/bin/env python3 +"""Compare per-tile passage candidate-list sizes for L109, L114, and L115.""" +from __future__ import annotations + +import json +import math +import re +import statistics +import subprocess +import time +from pathlib import Path + +ROOT = Path(__file__).resolve().parents[4] +OUT = ROOT / "Saved/Linux/l115/candidate-lists" +DATA = ROOT / "Standalone/data/owner_world.json" +BINARIES = { + "L109": ROOT / "Saved/Linux/l109/bin-final/VoxelForgeCoreHeadless-l109-clang", + "L114": ROOT / "Saved/Linux/l114/bin/VoxelForgeCoreHeadless-l114-clang", + "L115": ROOT / "Saved/Linux/l115/bin/VoxelForgeCoreHeadless-l115-clang", +} +CAMERAS = { + 0: (8.0, 16.0, -372.2626953125), + 1: (25.8369140625, 3.19921875, -737.0), + 2: (19.166015625, -14.2001953125, -753.3740234375), + 3: (-20.0625, -5.068359375, -900.353515625), +} +LIST = re.compile(r"^\[PassageComposerTile\].*?features=(\d+) route_candidates=(\d+)", re.M) + + +def percentile(values: list[int], fraction: float) -> int: + ordered = sorted(values) + if not ordered: + return 0 + return ordered[min(len(ordered) - 1, + max(0, math.ceil(fraction * len(ordered)) - 1))] + + +def run(strate: int, version: str) -> dict: + OUT.mkdir(parents=True, exist_ok=True) + log = OUT / f"{version}-s{strate}.log" + camera = ",".join(f"{v:.12f}" for v in CAMERAS[strate]) + ",0,0" + command = [ + "taskset", "-c", "0-11", "prlimit", "--as=6442450944", "--", + "timeout", "1740s", str(BINARIES[version]), str(DATA), + "--world-assembler-prototype", "--stream-benchmark", "--stream-pipeline", + "--workers=12", "--clip-radius=3", "--max-clip-level=8", "--max-level=8", + f"--camera={camera}", "--profile-passage-composer", "--stream-scheduler-policy=3", + ] + started = time.monotonic() + with log.open("w", encoding="utf-8") as stream: + result = subprocess.run(command, cwd=ROOT, stdout=stream, + stderr=subprocess.STDOUT, check=False, timeout=1740) + output = log.read_text(encoding="utf-8", errors="replace") + features = [int(row[0]) for row in LIST.findall(output)] + routes = [int(row[1]) for row in LIST.findall(output)] + if result.returncode or not features: + raise SystemExit(f"candidate-list profile missing: {log}; exit={result.returncode}") + row = { + "strate": strate, "version": version, "profiled_tiles": len(features), + "feature_candidates": {"sum": sum(features), "min": min(features), + "median": statistics.median(features), "p95": percentile(features, .95), + "max": max(features)}, + "route_segment_candidates": {"sum": sum(routes), "min": min(routes), + "median": statistics.median(routes), "p95": percentile(routes, .95), + "max": max(routes)}, + "elapsed_s": round(time.monotonic() - started, 3), + "log": str(log.relative_to(ROOT)), + } + print("[L115CandidateLists] " + json.dumps(row, sort_keys=True), flush=True) + return row + + +def main() -> int: + if any(not path.is_file() for path in (*BINARIES.values(), DATA)): + raise SystemExit("missing L109/L114/L115 candidate-list input") + rows = [run(strate, version) for strate in range(4) + for version in ("L109", "L114", "L115")] + (OUT / "summary.json").write_text(json.dumps(rows, indent=2) + "\n", + encoding="utf-8") + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/Standalone/Research/WorldAssemblerM3/Linux115/RunL115Captures.py b/Standalone/Research/WorldAssemblerM3/Linux115/RunL115Captures.py new file mode 100644 index 0000000..a4210af --- /dev/null +++ b/Standalone/Research/WorldAssemblerM3/Linux115/RunL115Captures.py @@ -0,0 +1,260 @@ +#!/usr/bin/env python3 +"""Capture L115 rock floors at three rock stations per passage and open-air walls.""" +from __future__ import annotations + +import importlib.util +import json +import math +import re +import sys +from pathlib import Path + +ROOT = Path(__file__).resolve().parents[4] +RESEARCH = Path(__file__).resolve().parent +CAPTURES = RESEARCH / "captures" +SAVED = ROOT / "Saved/Linux/l115/captures" +L113_RESEARCH = ROOT / "Standalone/Research/WorldAssemblerM3/Linux113" +L115_SAVED = ROOT / "Saved/Linux/l115" +BINARIES = { + "L115": L115_SAVED / "bin/VoxelForgeCoreHeadless-l115-clang", +} +RENDERERS = { + "L115": L115_SAVED / "bin/VoxelForgeOffscreenCapture-l115-clang", +} +SECTION = re.compile( + r"^\[PassageOpenAirSection\] id=(\S+) section=(\d+) start_m=([\d.]+) " + r"end_m=([\d.]+) samples=(\d+) midpoint_xyz_m=\(([^)]*)\) " + r"midpoint_radius_m=([\d.]+)", re.M) + +sys.dont_write_bytecode = True +SPEC = importlib.util.spec_from_file_location( + "l113_capture_helpers", L113_RESEARCH / "RunL113Captures.py") +if SPEC is None or SPEC.loader is None: + raise SystemExit("cannot load the verified L113 capture helpers") +HELPERS = importlib.util.module_from_spec(SPEC) +SPEC.loader.exec_module(HELPERS) +HELPERS.RESEARCH = RESEARCH +HELPERS.CAPTURES = CAPTURES / "L115" +HELPERS.SAVED = SAVED / "L115" +HELPERS.BINARIES = BINARIES +HELPERS.RENDERERS = RENDERERS + + +def parse_sections(log: Path) -> list[dict]: + sections = [] + text = log.read_text(encoding="utf-8", errors="replace") + for passage, section, start, end, samples, midpoint, radius in SECTION.findall(text): + sections.append({"passage": passage, "section": int(section), + "start_m": float(start), "end_m": float(end), + "samples": int(samples), "midpoint": HELPERS.vector(midpoint), + "radius_m": float(radius)}) + return sections + + +def rocky_spans(total: float, sections: list[dict]) -> list[tuple[float, float]]: + spans = [] + cursor = 0.0 + for section in sorted(sections, key=lambda item: item["start_m"]): + start = max(0.0, min(total, section["start_m"])) + end = max(start, min(total, section["end_m"])) + if start - cursor > 2.0: + spans.append((cursor + 1.0, start - 1.0)) + cursor = max(cursor, end) + if total - cursor > 2.0: + spans.append((cursor + 1.0, total - 1.0)) + return [(start, end) for start, end in spans if end - start >= 1.0] + + +def rock_station_candidates(spans: list[tuple[float, float]]) -> list[float]: + total = sum(end - start for start, end in spans) + if total < 3.0: + raise RuntimeError("passage has less than 3 m of rock route outside open-air spans") + stations = [] + for fraction in (0.25, 0.50, 0.75, 0.10, 0.90, 0.35, 0.65, 0.20, 0.80, + 0.40, 0.60): + remaining = total * fraction + for start, end in spans: + span = end - start + if remaining <= span: + stations.append(start + remaining) + break + remaining -= span + return stations + + +def rock_floor_view(layout: dict, passage: dict, station: float, index: int) -> dict: + raw_route = HELPERS.smooth_route(layout, passage) + route, body_depth = HELPERS.derived_smooth_route(raw_route, passage, layout) + lengths, prefix = HELPERS.route_lengths(route) + center, radius = HELPERS.at_distance(route, lengths, prefix, station) + floor_depth = min(body_depth, max(0.0, radius - 0.23)) + planned_floor = (center[0], center[1], center[2] - floor_depth) + tangent = HELPERS.tangent_at(route, lengths, prefix, station) + grade = math.degrees(math.atan2(abs(tangent[2]), + math.hypot(tangent[0], tangent[1]))) + camera = tuple(planned_floor[axis] - 2.5 * tangent[axis] + + (1.25 if axis == 2 else 0.0) for axis in range(3)) + yaw, pitch = HELPERS.angles(camera, planned_floor) + safe_id = HELPERS.sanitize(passage["stable_id"]) + return {"name": f"{safe_id}-rock-floor-station-{index}", + "passage": passage["stable_id"], "kind": "rock-floor-close", + "station": f"rock-floor/{station:.1f}m", "camera": camera, + "target": planned_floor, "yaw": yaw, "pitch": pitch, + "focus": planned_floor, "center_z": planned_floor[2], + "route_distance_m": station, "requested_route_distance_m": station, + "route_length_m": prefix[-1], "planned_floor_m": planned_floor[2], + "planned_grade_deg": grade} + + +def capture_rock_floor(layout: dict, passage: dict, station: float, index: int) -> dict: + view = rock_floor_view(layout, passage, station, index) + row = HELPERS.capture("L115", view, layout) + scene = ROOT / row["scene"] + anchor = HELPERS.nearest_surface_anchor(scene, view["target"], margin_m=5.0, + preferred_normal=(0.0, 0.0, 1.0), minimum_alignment=0.85) + alignment = HELPERS.dot(anchor["normal"], (0.0, 0.0, 1.0)) + camera_distance = math.dist(row["camera_actual_m"], anchor["position_m"]) + row.update({"variant": "L115", "kind": "rock-floor-close", + "planned_floor_m": view["planned_floor_m"], + "planned_grade_deg": view["planned_grade_deg"], + "floor_anchor_position_m": anchor["position_m"], + "floor_anchor_normal": anchor["normal"], + "closeup_camera_to_floor_distance_m": camera_distance, + "closeup_target_surface_distance_m": anchor["distance_m"], + "closeup_floor_normal_alignment": alignment, + "verified_upward_floor_normal": alignment >= 0.85}) + if (not row["verified"] or not 2.0 <= camera_distance <= 3.2 + or anchor["distance_m"] > 0.25 or alignment < 0.85 + or view["planned_grade_deg"] < 2.0 or row["drawn_triangles"] <= 0 + or row["pixel_quality_status"] not in + ("pass", "low_contrast_geometry_visible")): + raise RuntimeError(f"rock-floor close-up failed at {passage['stable_id']} s={station:.2f}") + return row + + +def main() -> int: + layout_path = L115_SAVED / "audit-layout-candidate.json" + audit_log = L115_SAVED / "audit-owner-clang.log" + if any(not path.is_file() for path in (*BINARIES.values(), *RENDERERS.values(), + layout_path, audit_log)): + raise SystemExit("missing L115 binaries, layout, or passage audit log") + layout = json.loads(layout_path.read_text(encoding="utf-8")) + sections = parse_sections(audit_log) + if not sections: + raise SystemExit("no L115 open-air sections found") + CAPTURES.mkdir(parents=True, exist_ok=True) + HELPERS.CAPTURES = CAPTURES / "L115" + HELPERS.SAVED = SAVED / "L115" + HELPERS.CAPTURES.mkdir(parents=True, exist_ok=True) + HELPERS.SAVED.mkdir(parents=True, exist_ok=True) + + rows = [] + for passage in sorted(layout["passages"], key=lambda item: item["stable_id"]): + passage_sections = [item for item in sections + if item["passage"] == passage["stable_id"]] + raw_route = HELPERS.smooth_route(layout, passage) + route, _body_depth = HELPERS.derived_smooth_route(raw_route, passage, layout) + _lengths, prefix = HELPERS.route_lengths(route) + spans = rocky_spans(prefix[-1], passage_sections) + candidates = rock_station_candidates(spans) + accepted_stations = [] + total_rock_length = sum(end - start for start, end in spans) + minimum_spacing = max(1.0, total_rock_length * 0.02) + for station in candidates: + if any(abs(station - prior) < minimum_spacing for prior in accepted_stations): + continue + index = len(accepted_stations) + 1 + try: + row = capture_rock_floor(layout, passage, station, index) + except RuntimeError as error: + message = str(error) + if not (message.startswith("no nearby surface vertices in mesh scene:") + or message.startswith("rock-floor close-up failed at ")): + raise + print(f"[L115CaptureSkip] passage={passage['stable_id']} " + f"station_m={station:.3f} reason=surface-or-anchor-check", flush=True) + continue + accepted_stations.append(station) + rows.append(row) + if len(accepted_stations) == 3: + break + if len(accepted_stations) < 3: + for base_station in tuple(accepted_stations): + for offset in (-10.0, 10.0, -15.0, 15.0, -20.0, 20.0, + -25.0, 25.0, -30.0, 30.0): + station = base_station + offset + if not any(start < station < end for start, end in spans): + continue + if any(abs(station - prior) < minimum_spacing + for prior in accepted_stations): + continue + index = len(accepted_stations) + 1 + try: + row = capture_rock_floor(layout, passage, station, index) + except RuntimeError as error: + message = str(error) + if not (message.startswith( + "no nearby surface vertices in mesh scene:") + or message.startswith("rock-floor close-up failed at ")): + raise + print(f"[L115CaptureSkip] passage={passage['stable_id']} " + f"station_m={station:.3f} reason=nearby-station-check", + flush=True) + continue + accepted_stations.append(station) + rows.append(row) + if len(accepted_stations) == 3: + break + if len(accepted_stations) == 3: + break + if len(accepted_stations) != 3: + raise RuntimeError(f"only {len(accepted_stations)} verified rock-floor views for " + f"{passage['stable_id']}: {accepted_stations}") + + open_air_views = HELPERS.make_views(layout, sections, use_derived_shape=True, + use_spline=True, include_open_air=True) + open_air_views = [view for view in open_air_views + if view["kind"] == "open-air-close"] + if len(open_air_views) != 2 * len(sections): + raise RuntimeError("L115 open-air close-up count is not two per section") + for view in open_air_views: + row = HELPERS.capture("L115", view, layout) + if (not row["verified"] + or abs(row["closeup_camera_target_distance_m"] - 4.0) > 0.02 + or row["closeup_target_surface_distance_m"] > 5.0 + or row["closeup_wall_normal_alignment"] < 0.25 + or row["drawn_triangles"] <= 0 + or row["pixel_quality_status"] not in + ("pass", "low_contrast_geometry_visible")): + raise RuntimeError(f"open-air close-up failed: {view['name']}") + row["variant"] = "L115" + rows.append(row) + + (CAPTURES / "capture-index.json").write_text( + json.dumps({"captures": rows}, indent=2) + "\n", encoding="utf-8") + floor_rows = [row for row in rows if row["kind"] == "rock-floor-close"] + wall_rows = [row for row in rows if row["kind"] == "open-air-close"] + passage_ids = {item["stable_id"] for item in layout["passages"]} + if (len(floor_rows) != 3 * len(passage_ids) + or any(sum(row["passage"] == passage for row in floor_rows) != 3 + for passage in passage_ids) + or len(wall_rows) != 2 * len(sections)): + raise RuntimeError("L115 capture count mismatch") + lines = ["# L115 captures", "", + "Each passage has three floor close-ups sampled outside the audited open-air spans. " + "Floor anchors require an upward normal alignment of at least 0.85, a target-to-floor " + "distance of at most 0.25 m, and a camera-to-floor distance between 2.0 and 3.2 m. " + "Each open-air section has verified outside and interior wall close-ups at 4 m.", ""] + for row in rows: + lines.append(f"- [{row['passage']} {row['station']}]({row['capture']}) — " + f"{row['kind']}; {row.get('drawn_triangles', 0)} triangles; " + f"{row['pixel_quality_status']}") + (CAPTURES / "INDEX.md").write_text("\n".join(lines) + "\n", encoding="utf-8") + print(f"[L115CaptureSummary] captures={len(rows)} rock_floors={len(floor_rows)} " + f"open_air_closeups={len(wall_rows)} sections={len(sections)} status=PASS", + flush=True) + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/Standalone/Research/WorldAssemblerM3/Linux115/RunL115DensityProbe.py b/Standalone/Research/WorldAssemblerM3/Linux115/RunL115DensityProbe.py new file mode 100644 index 0000000..009c14b --- /dev/null +++ b/Standalone/Research/WorldAssemblerM3/Linux115/RunL115DensityProbe.py @@ -0,0 +1,79 @@ +#!/usr/bin/env python3 +"""Measure L115 floor zero crossings at three route stations per passage.""" +from __future__ import annotations + +import csv +import json +import math +import os +import re +import statistics +import subprocess +from pathlib import Path + +ROOT = Path(__file__).resolve().parents[4] +OUT = ROOT / "Saved/Linux/l115/density-probe" +BINARY = ROOT / "Saved/Linux/l115/bin/VoxelForgeCoreHeadless-l115-clang" +DATA = ROOT / "Standalone/data/owner_world.json" +SLOPE = re.compile( + r"^\[L115DensitySlopeSample\] passage=(\S+) station=(\S+) s_m=([\d.]+) " + r".*?planned_floor_m=(-?[\d.]+) root_floor_m=(-?[\d.]+|nan) " + r"residual_m=(-?[\d.]+|nan)", re.M) + + +def main() -> int: + OUT.mkdir(parents=True, exist_ok=True) + log = OUT / "owner4-clang.log" + layout = OUT / "layout.json" + command = [ + "taskset", "-c", "0-11", "prlimit", "--as=6442450944", "--", + "timeout", "1740s", str(BINARY), str(DATA), "--world-assembler-prototype", + "--stream-benchmark", "--stream-pipeline", "--workers=12", "--clip-radius=3", + "--max-clip-level=8", "--max-level=8", "--camera=8,16,-372.2626953125,0,0", + "--audit-resolved-layout-passages", f"--resolved-layout-output={layout}", + ] + with log.open("w", encoding="utf-8") as stream: + result = subprocess.run(command, cwd=ROOT, + env={**os.environ, + "VOXELFORGE_L115_DENSITY_PROFILE": "1"}, + stdout=stream, stderr=subprocess.STDOUT, + check=False, timeout=1740) + if result.returncode: + raise SystemExit(f"L115 density probe failed: {log}") + text = log.read_text(encoding="utf-8", errors="replace") + groups: dict[tuple[str, str], list[dict]] = {} + for passage, station, distance, planned, root, residual in SLOPE.findall(text): + root_value = float(root) if root != "nan" else math.nan + residual_value = float(residual) if residual != "nan" else math.nan + groups.setdefault((passage, station), []).append({ + "route_s_m": float(distance), "planned_floor_m": float(planned), + "root_floor_m": root_value, "offset_m": residual_value}) + summary = [] + with (OUT / "zero-crossing-offsets.csv").open("w", newline="", encoding="utf-8") as stream: + writer = csv.DictWriter(stream, fieldnames=("passage", "station", "route_s_m", + "planned_floor_m", "root_floor_m", "offset_m")) + writer.writeheader() + for (passage, station), samples in sorted(groups.items()): + for sample in samples: + writer.writerow({"passage": passage, "station": station, **sample}) + finite = [sample["offset_m"] for sample in samples + if math.isfinite(sample["offset_m"])] + summary.append({"passage": passage, "station": station, + "samples": len(samples), "finite_roots": len(finite), + "max_abs_offset_m": max(map(abs, finite)) if finite else None, + "median_abs_offset_m": statistics.median(map(abs, finite)) + if finite else None, + "p95_abs_offset_m": sorted(map(abs, finite))[ + min(len(finite)-1, math.ceil(0.95*len(finite))-1)] + if finite else None}) + if not summary or any(item["samples"] != 51 for item in summary): + raise RuntimeError("L115 density profile is missing 51-sample route stations") + (OUT / "zero-crossing-summary.json").write_text( + json.dumps(summary, indent=2) + "\n", encoding="utf-8") + print(f"[L115DensityProbe] exit={result.returncode} stations={len(summary)} " + f"log={log.relative_to(ROOT)}", flush=True) + return result.returncode + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/Standalone/Research/WorldAssemblerM3/Linux115/RunL115HashMatrix.py b/Standalone/Research/WorldAssemblerM3/Linux115/RunL115HashMatrix.py new file mode 100644 index 0000000..f38faf5 --- /dev/null +++ b/Standalone/Research/WorldAssemblerM3/Linux115/RunL115HashMatrix.py @@ -0,0 +1,103 @@ +#!/usr/bin/env python3 +"""Check Clang/GCC hash identity at W1/W8/W12 and pin v223 owner hashes.""" +from __future__ import annotations + +import json +import re +import subprocess +import time +from pathlib import Path + +ROOT = Path(__file__).resolve().parents[4] +OUT = ROOT / "Saved/Linux/l115/hashes" +DATASETS = { + "owner4": ROOT / "Standalone/data/owner_world.json", + "owner2": ROOT / "Standalone/data/regression/owner_world_2strate_l61.json", +} +BINARIES = { + "clang": ROOT / "Saved/Linux/l115/bin/VoxelForgeCoreHeadless-l115-clang", + "gcc": ROOT / "Saved/Linux/l115/bin/VoxelForgeCoreHeadless-l115-gcc", +} +HASH = re.compile(r"^\[Pipeline(?:FullDetailHash|WholeViewHash|LODHash|ExactQueryHash)\].*$", re.M) +STAMP = re.compile(r"^\[VoxelForgeSourceStamp\] sha256=(\S+)$", re.M) + + +def run(dataset: str, recipe: str, workers: int, compiler: str) -> dict: + OUT.mkdir(parents=True, exist_ok=True) + label = f"{dataset}-{recipe}-w{workers}-{compiler}" + log = OUT / f"{label}.log" + layout = OUT / f"{label}.layout.json" + command = [ + "taskset", "-c", "0-11", "prlimit", "--as=6442450944", "--", + "timeout", "1740s", str(BINARIES[compiler]), str(DATASETS[dataset]), + f"--workers={workers}", "--world-assembler-prototype", "--stream-benchmark", + "--stream-pipeline", "--force-generate", "--clip-radius=3", + "--max-clip-level=8", "--max-level=8", f"--recipe={recipe}", + "--stream-hash", f"--resolved-layout-output={layout}", + ] + started = time.monotonic() + with log.open("w", encoding="utf-8") as stream: + result = subprocess.run(command, cwd=ROOT, stdout=stream, + stderr=subprocess.STDOUT, check=False, timeout=1740) + output = log.read_text(encoding="utf-8", errors="replace") + hashes = HASH.findall(output) + if result.returncode or len(hashes) != 12: + raise SystemExit(f"hash run failed or incomplete: {label}; exit={result.returncode} " + f"hashes={len(hashes)} log={log}") + row = {"dataset": dataset, "recipe": recipe, "workers": workers, + "compiler": compiler, "exit_code": result.returncode, + "hashes": hashes, "source_stamp": (STAMP.search(output).group(1) + if STAMP.search(output) else None), + "elapsed_s": round(time.monotonic() - started, 3), + "log": str(log.relative_to(ROOT))} + print("[L115HashRun] " + json.dumps(row, sort_keys=True), flush=True) + return row + + +def main() -> int: + if any(not path.is_file() for path in (*DATASETS.values(), *BINARIES.values())): + raise SystemExit("missing L115 hash input") + rows = [] + recipes = {"owner4": ("surface-world",), + "owner2": ("surface-world", "floating-islands")} + for dataset, dataset_recipes in recipes.items(): + for recipe in dataset_recipes: + for workers in (1, 8, 12): + for compiler in ("clang", "gcc"): + rows.append(run(dataset, recipe, workers, compiler)) + (OUT / "runs-partial.json").write_text( + json.dumps(rows, indent=2) + "\n", encoding="utf-8") + groups = {} + for dataset, dataset_recipes in recipes.items(): + for recipe in dataset_recipes: + key = f"{dataset}/{recipe}" + group = [row for row in rows if row["dataset"] == dataset + and row["recipe"] == recipe] + reference = group[0]["hashes"] + groups[key] = {"all_worker_compiler_hashes_match": all( + row["hashes"] == reference for row in group), + "source_stamps": sorted({row["source_stamp"] for row in group}), + "runs": [{"workers": row["workers"], "compiler": row["compiler"], + "log": row["log"]} for row in group]} + if not groups[key]["all_worker_compiler_hashes_match"]: + raise SystemExit(f"determinism mismatch: {key}") + if dataset == "owner2": + canonical = next(row for row in group if row["workers"] == 12 + and row["compiler"] == "clang") + recipe_name = "floating-islands" if recipe == "floating-islands" else "surface-world" + style = 1 if recipe_name == "surface-world" else 2 + baseline = (ROOT / "Standalone/Tools/verify/baselines/owner-hash/canonical" + / f"owner-hash-{recipe_name}-style{style}-v223.baseline") + baseline.write_text("\n".join(canonical["hashes"]) + "\n", + encoding="utf-8") + summary = {"runs": rows, "groups": groups, + "owner4_all_four_strata": "owner4/surface-world", + "owner2_canonical_pins": ["owner2/surface-world", + "owner2/floating-islands"]} + (OUT / "summary.json").write_text(json.dumps(summary, indent=2) + "\n", + encoding="utf-8") + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/Standalone/Research/WorldAssemblerM3/Linux115/RunL115Timing.py b/Standalone/Research/WorldAssemblerM3/Linux115/RunL115Timing.py new file mode 100644 index 0000000..9d513ba --- /dev/null +++ b/Standalone/Research/WorldAssemblerM3/Linux115/RunL115Timing.py @@ -0,0 +1,124 @@ +#!/usr/bin/env python3 +"""Five interleaved L80 readiness runs for L109, L114, and L115.""" +from __future__ import annotations + +import json +import os +import re +import statistics +import subprocess +import time +from pathlib import Path + +ROOT = Path(__file__).resolve().parents[4] +OUT = ROOT / "Saved/Linux/l115/timing" +DATA = ROOT / "Standalone/data/owner_world.json" +BINARIES = { + "L109": ROOT / "Saved/Linux/l109/bin-final/VoxelForgeCoreHeadless-l109-clang", + "L114": ROOT / "Saved/Linux/l114/bin/VoxelForgeCoreHeadless-l114-clang", + "L115": ROOT / "Saved/Linux/l115/bin/VoxelForgeCoreHeadless-l115-clang", +} +CAMERAS = { + 0: (8.0, 16.0, -372.2626953125), + 1: (25.8369140625, 3.19921875, -737.0), + 2: (19.166015625, -14.2001953125, -753.3740234375), + 3: (-20.0625, -5.068359375, -900.353515625), +} +PIPELINE = re.compile(r"^\[StreamPipeline\] (.*)$", re.M) +FIELDS = re.compile(r"([a-zA-Z0-9_]+)=([^ ]+)") +NEAR = re.compile( + r"^\[WorldAssemblerNearLODReady\] lods=0-2 tiles=(\d+)/(\d+) cold_ready_s=([0-9.]+)$", + re.M, +) + + +def run(strate: int, workers: int, version: str, phase: str, replicate: int) -> dict: + OUT.mkdir(parents=True, exist_ok=True) + label = f"s{strate}-w{workers}-{version}-{phase}{replicate}" + log = OUT / f"{label}.log" + camera = ",".join(f"{v:.12f}" for v in CAMERAS[strate]) + ",0,0" + command = [ + "taskset", "-c", "0-11", "prlimit", "--as=6442450944", "--", + "timeout", "1740s", str(BINARIES[version]), str(DATA), + "--world-assembler-prototype", "--stream-benchmark", "--stream-pipeline", + f"--workers={workers}", "--clip-radius=3", "--max-clip-level=8", "--max-level=8", + f"--camera={camera}", "--profile-lod-work", "--stream-scheduler-policy=3", + ] + start = time.monotonic() + with log.open("w", encoding="utf-8") as output: + result = subprocess.run(command, cwd=ROOT, stdout=output, + stderr=subprocess.STDOUT, check=False, timeout=1740) + content = log.read_text(encoding="utf-8", errors="replace") + pipeline_match = PIPELINE.search(content) + near_match = NEAR.search(content) + if result.returncode or pipeline_match is None or near_match is None: + raise SystemExit(f"readiness run failed or trace missing: {log}; exit={result.returncode}") + pipeline = dict(FIELDS.findall(pipeline_match.group(1))) + row = { + "strate": strate, "workers": workers, "version": version, + "phase": phase, "replicate": replicate, "exit_code": result.returncode, + "wall_s": round(time.monotonic() - start, 3), + "lod02_ready_s": float(near_match.group(3)), + "whole_view_ready_s": float(pipeline["whole_view_ready"].removesuffix("s")), + "whole_tiles": int(pipeline["whole_tiles"].split("/")[0]), + "log": str(log.relative_to(ROOT)), + } + print("[L115TimingRun] " + json.dumps(row, sort_keys=True), flush=True) + return row + + +def main() -> int: + if not DATA.is_file() or any(not binary.is_file() for binary in BINARIES.values()): + raise SystemExit("missing L109/L114/L115 data or timing binary") + OUT.mkdir(parents=True, exist_ok=True) + load_1m = os.getloadavg()[0] + uptime = subprocess.run(["uptime"], cwd=ROOT, text=True, capture_output=True, + check=True).stdout.strip() + top = subprocess.run(["ps", "-eo", "pid,pcpu,comm", "--sort=-pcpu"], cwd=ROOT, + text=True, capture_output=True, check=True).stdout + (OUT / "machine-load-before.txt").write_text( + f"uptime: {uptime}\n1-minute load: {load_1m:.2f}\ntop CPU users:\n{top}", + encoding="utf-8") + print(f"[L115TimingGate] load_1m={load_1m:.2f} uptime={uptime}", flush=True) + if load_1m >= 1.5: + raise SystemExit(f"timing refused: 1-minute load {load_1m:.2f} is not below 1.5") + rows = [] + versions = ("L109", "L114", "L115") + for strate in range(4): + for workers in (8, 12): + for version in versions: + run(strate, workers, version, "warmup", 0) + for replicate in range(1, 6): + offset = (replicate - 1) % len(versions) + order = versions[offset:] + versions[:offset] + for version in order: + rows.append(run(strate, workers, version, "measured", replicate)) + (OUT / "runs-partial.json").write_text( + json.dumps(rows, indent=2) + "\n", encoding="utf-8") + summary = [] + for strate in range(4): + for workers in (8, 12): + item = {"strate": strate, "workers": workers, "replicates": 5} + medians = {} + for version in versions: + group = [row for row in rows if row["strate"] == strate + and row["workers"] == workers and row["version"] == version] + medians[version] = {} + for key in ("lod02_ready_s", "whole_view_ready_s"): + values = [row[key] for row in group] + medians[version][key] = statistics.median(values) + item[f"{version}_{key}_values"] = values + item[f"{version}_{key}_median"] = medians[version][key] + for comparison in ("L109", "L114"): + for key in ("lod02_ready_s", "whole_view_ready_s"): + item[f"L115_vs_{comparison}_{key}_delta_pct"] = round( + 100.0 * (medians["L115"][key] / medians[comparison][key] - 1.0), 2) + summary.append(item) + (OUT / "summary.json").write_text( + json.dumps({"runs": rows, "summary": summary}, indent=2) + "\n", + encoding="utf-8") + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/Standalone/Research/WorldAssemblerM3/Linux115/captures/INDEX.md b/Standalone/Research/WorldAssemblerM3/Linux115/captures/INDEX.md new file mode 100644 index 0000000..2060b20 --- /dev/null +++ b/Standalone/Research/WorldAssemblerM3/Linux115/captures/INDEX.md @@ -0,0 +1,27 @@ +# L115 captures + +Each passage has three floor close-ups sampled outside the audited open-air spans. Floor anchors require an upward normal alignment of at least 0.85, a target-to-floor distance of at most 0.25 m, and a camera-to-floor distance between 2.0 and 3.2 m. Each open-air section has verified outside and interior wall close-ups at 4 m. + +- [passage/0-1/0 rock-floor/401.7m](captures/L115/L115/passage-0-1-0-rock-floor-station-1.png) — rock-floor-close; 122256 triangles; pass +- [passage/0-1/0 rock-floor/792.8m](captures/L115/L115/passage-0-1-0-rock-floor-station-2.png) — rock-floor-close; 585992 triangles; pass +- [passage/0-1/0 rock-floor/1634.5m](captures/L115/L115/passage-0-1-0-rock-floor-station-3.png) — rock-floor-close; 137252 triangles; pass +- [passage/1-2/0 rock-floor/27.0m](captures/L115/L115/passage-1-2-0-rock-floor-station-1.png) — rock-floor-close; 652088 triangles; pass +- [passage/1-2/0 rock-floor/52.9m](captures/L115/L115/passage-1-2-0-rock-floor-station-2.png) — rock-floor-close; 636128 triangles; pass +- [passage/1-2/0 rock-floor/78.9m](captures/L115/L115/passage-1-2-0-rock-floor-station-3.png) — rock-floor-close; 580512 triangles; pass +- [passage/2-3/0 rock-floor/323.4m](captures/L115/L115/passage-2-3-0-rock-floor-station-1.png) — rock-floor-close; 474896 triangles; low_contrast_geometry_visible +- [passage/2-3/0 rock-floor/333.4m](captures/L115/L115/passage-2-3-0-rock-floor-station-2.png) — rock-floor-close; 494436 triangles; pass +- [passage/2-3/0 rock-floor/343.4m](captures/L115/L115/passage-2-3-0-rock-floor-station-3.png) — rock-floor-close; 485332 triangles; pass +- [passage/0-1/0 section-1/4m-outside](captures/L115/L115/passage-0-1-0-openair-1-4m-outside.png) — open-air-close; 275313 triangles; pass +- [passage/0-1/0 section-1/4m-interior-wall](captures/L115/L115/passage-0-1-0-openair-1-4m-interior-wall.png) — open-air-close; 307964 triangles; low_contrast_geometry_visible +- [passage/0-1/0 section-2/4m-outside](captures/L115/L115/passage-0-1-0-openair-2-4m-outside.png) — open-air-close; 275313 triangles; pass +- [passage/0-1/0 section-2/4m-interior-wall](captures/L115/L115/passage-0-1-0-openair-2-4m-interior-wall.png) — open-air-close; 345024 triangles; pass +- [passage/0-1/0 section-3/4m-outside](captures/L115/L115/passage-0-1-0-openair-3-4m-outside.png) — open-air-close; 148970 triangles; pass +- [passage/0-1/0 section-3/4m-interior-wall](captures/L115/L115/passage-0-1-0-openair-3-4m-interior-wall.png) — open-air-close; 148032 triangles; pass +- [passage/1-2/0 section-1/4m-outside](captures/L115/L115/passage-1-2-0-openair-1-4m-outside.png) — open-air-close; 620866 triangles; low_contrast_geometry_visible +- [passage/1-2/0 section-1/4m-interior-wall](captures/L115/L115/passage-1-2-0-openair-1-4m-interior-wall.png) — open-air-close; 609733 triangles; pass +- [passage/1-2/0 section-2/4m-outside](captures/L115/L115/passage-1-2-0-openair-2-4m-outside.png) — open-air-close; 584622 triangles; pass +- [passage/1-2/0 section-2/4m-interior-wall](captures/L115/L115/passage-1-2-0-openair-2-4m-interior-wall.png) — open-air-close; 572238 triangles; pass +- [passage/2-3/0 section-1/4m-outside](captures/L115/L115/passage-2-3-0-openair-1-4m-outside.png) — open-air-close; 104612 triangles; low_contrast_geometry_visible +- [passage/2-3/0 section-1/4m-interior-wall](captures/L115/L115/passage-2-3-0-openair-1-4m-interior-wall.png) — open-air-close; 94962 triangles; low_contrast_geometry_visible +- [passage/2-3/0 section-2/4m-outside](captures/L115/L115/passage-2-3-0-openair-2-4m-outside.png) — open-air-close; 475838 triangles; pass +- [passage/2-3/0 section-2/4m-interior-wall](captures/L115/L115/passage-2-3-0-openair-2-4m-interior-wall.png) — open-air-close; 486512 triangles; pass diff --git a/Standalone/Research/WorldAssemblerM3/Linux115/captures/L115/L115/passage-0-1-0-openair-1-4m-interior-wall.png b/Standalone/Research/WorldAssemblerM3/Linux115/captures/L115/L115/passage-0-1-0-openair-1-4m-interior-wall.png new file mode 100644 index 0000000..58795ee Binary files /dev/null and b/Standalone/Research/WorldAssemblerM3/Linux115/captures/L115/L115/passage-0-1-0-openair-1-4m-interior-wall.png differ diff --git a/Standalone/Research/WorldAssemblerM3/Linux115/captures/L115/L115/passage-0-1-0-openair-1-4m-outside.png b/Standalone/Research/WorldAssemblerM3/Linux115/captures/L115/L115/passage-0-1-0-openair-1-4m-outside.png new file mode 100644 index 0000000..e50123c Binary files /dev/null and b/Standalone/Research/WorldAssemblerM3/Linux115/captures/L115/L115/passage-0-1-0-openair-1-4m-outside.png differ diff --git a/Standalone/Research/WorldAssemblerM3/Linux115/captures/L115/L115/passage-0-1-0-openair-2-4m-interior-wall.png b/Standalone/Research/WorldAssemblerM3/Linux115/captures/L115/L115/passage-0-1-0-openair-2-4m-interior-wall.png new file mode 100644 index 0000000..f840f51 Binary files /dev/null and b/Standalone/Research/WorldAssemblerM3/Linux115/captures/L115/L115/passage-0-1-0-openair-2-4m-interior-wall.png differ diff --git a/Standalone/Research/WorldAssemblerM3/Linux115/captures/L115/L115/passage-0-1-0-openair-2-4m-outside.png b/Standalone/Research/WorldAssemblerM3/Linux115/captures/L115/L115/passage-0-1-0-openair-2-4m-outside.png new file mode 100644 index 0000000..f0b9733 Binary files /dev/null and b/Standalone/Research/WorldAssemblerM3/Linux115/captures/L115/L115/passage-0-1-0-openair-2-4m-outside.png differ diff --git a/Standalone/Research/WorldAssemblerM3/Linux115/captures/L115/L115/passage-0-1-0-openair-3-4m-interior-wall.png b/Standalone/Research/WorldAssemblerM3/Linux115/captures/L115/L115/passage-0-1-0-openair-3-4m-interior-wall.png new file mode 100644 index 0000000..81a832a Binary files /dev/null and b/Standalone/Research/WorldAssemblerM3/Linux115/captures/L115/L115/passage-0-1-0-openair-3-4m-interior-wall.png differ diff --git a/Standalone/Research/WorldAssemblerM3/Linux115/captures/L115/L115/passage-0-1-0-openair-3-4m-outside.png b/Standalone/Research/WorldAssemblerM3/Linux115/captures/L115/L115/passage-0-1-0-openair-3-4m-outside.png new file mode 100644 index 0000000..e47cf28 Binary files /dev/null and b/Standalone/Research/WorldAssemblerM3/Linux115/captures/L115/L115/passage-0-1-0-openair-3-4m-outside.png differ diff --git a/Standalone/Research/WorldAssemblerM3/Linux115/captures/L115/L115/passage-0-1-0-rock-floor-station-1.png b/Standalone/Research/WorldAssemblerM3/Linux115/captures/L115/L115/passage-0-1-0-rock-floor-station-1.png new file mode 100644 index 0000000..bbe707b Binary files /dev/null and b/Standalone/Research/WorldAssemblerM3/Linux115/captures/L115/L115/passage-0-1-0-rock-floor-station-1.png differ diff --git a/Standalone/Research/WorldAssemblerM3/Linux115/captures/L115/L115/passage-0-1-0-rock-floor-station-2.png b/Standalone/Research/WorldAssemblerM3/Linux115/captures/L115/L115/passage-0-1-0-rock-floor-station-2.png new file mode 100644 index 0000000..7a88bfc Binary files /dev/null and b/Standalone/Research/WorldAssemblerM3/Linux115/captures/L115/L115/passage-0-1-0-rock-floor-station-2.png differ diff --git a/Standalone/Research/WorldAssemblerM3/Linux115/captures/L115/L115/passage-0-1-0-rock-floor-station-3.png b/Standalone/Research/WorldAssemblerM3/Linux115/captures/L115/L115/passage-0-1-0-rock-floor-station-3.png new file mode 100644 index 0000000..b9345ea Binary files /dev/null and b/Standalone/Research/WorldAssemblerM3/Linux115/captures/L115/L115/passage-0-1-0-rock-floor-station-3.png differ diff --git a/Standalone/Research/WorldAssemblerM3/Linux115/captures/L115/L115/passage-1-2-0-openair-1-4m-interior-wall.png b/Standalone/Research/WorldAssemblerM3/Linux115/captures/L115/L115/passage-1-2-0-openair-1-4m-interior-wall.png new file mode 100644 index 0000000..66949fa Binary files /dev/null and b/Standalone/Research/WorldAssemblerM3/Linux115/captures/L115/L115/passage-1-2-0-openair-1-4m-interior-wall.png differ diff --git a/Standalone/Research/WorldAssemblerM3/Linux115/captures/L115/L115/passage-1-2-0-openair-1-4m-outside.png b/Standalone/Research/WorldAssemblerM3/Linux115/captures/L115/L115/passage-1-2-0-openair-1-4m-outside.png new file mode 100644 index 0000000..ec2b85e Binary files /dev/null and b/Standalone/Research/WorldAssemblerM3/Linux115/captures/L115/L115/passage-1-2-0-openair-1-4m-outside.png differ diff --git a/Standalone/Research/WorldAssemblerM3/Linux115/captures/L115/L115/passage-1-2-0-openair-2-4m-interior-wall.png b/Standalone/Research/WorldAssemblerM3/Linux115/captures/L115/L115/passage-1-2-0-openair-2-4m-interior-wall.png new file mode 100644 index 0000000..9c68d5f Binary files /dev/null and b/Standalone/Research/WorldAssemblerM3/Linux115/captures/L115/L115/passage-1-2-0-openair-2-4m-interior-wall.png differ diff --git a/Standalone/Research/WorldAssemblerM3/Linux115/captures/L115/L115/passage-1-2-0-openair-2-4m-outside.png b/Standalone/Research/WorldAssemblerM3/Linux115/captures/L115/L115/passage-1-2-0-openair-2-4m-outside.png new file mode 100644 index 0000000..583481c Binary files /dev/null and b/Standalone/Research/WorldAssemblerM3/Linux115/captures/L115/L115/passage-1-2-0-openair-2-4m-outside.png differ diff --git a/Standalone/Research/WorldAssemblerM3/Linux115/captures/L115/L115/passage-1-2-0-rock-floor-station-1.png b/Standalone/Research/WorldAssemblerM3/Linux115/captures/L115/L115/passage-1-2-0-rock-floor-station-1.png new file mode 100644 index 0000000..abc37e7 Binary files /dev/null and b/Standalone/Research/WorldAssemblerM3/Linux115/captures/L115/L115/passage-1-2-0-rock-floor-station-1.png differ diff --git a/Standalone/Research/WorldAssemblerM3/Linux115/captures/L115/L115/passage-1-2-0-rock-floor-station-2.png b/Standalone/Research/WorldAssemblerM3/Linux115/captures/L115/L115/passage-1-2-0-rock-floor-station-2.png new file mode 100644 index 0000000..f9ad3f4 Binary files /dev/null and b/Standalone/Research/WorldAssemblerM3/Linux115/captures/L115/L115/passage-1-2-0-rock-floor-station-2.png differ diff --git a/Standalone/Research/WorldAssemblerM3/Linux115/captures/L115/L115/passage-1-2-0-rock-floor-station-3.png b/Standalone/Research/WorldAssemblerM3/Linux115/captures/L115/L115/passage-1-2-0-rock-floor-station-3.png new file mode 100644 index 0000000..4da2646 Binary files /dev/null and b/Standalone/Research/WorldAssemblerM3/Linux115/captures/L115/L115/passage-1-2-0-rock-floor-station-3.png differ diff --git a/Standalone/Research/WorldAssemblerM3/Linux115/captures/L115/L115/passage-2-3-0-openair-1-4m-interior-wall.png b/Standalone/Research/WorldAssemblerM3/Linux115/captures/L115/L115/passage-2-3-0-openair-1-4m-interior-wall.png new file mode 100644 index 0000000..6f8a641 Binary files /dev/null and b/Standalone/Research/WorldAssemblerM3/Linux115/captures/L115/L115/passage-2-3-0-openair-1-4m-interior-wall.png differ diff --git a/Standalone/Research/WorldAssemblerM3/Linux115/captures/L115/L115/passage-2-3-0-openair-1-4m-outside.png b/Standalone/Research/WorldAssemblerM3/Linux115/captures/L115/L115/passage-2-3-0-openair-1-4m-outside.png new file mode 100644 index 0000000..9a74d9d Binary files /dev/null and b/Standalone/Research/WorldAssemblerM3/Linux115/captures/L115/L115/passage-2-3-0-openair-1-4m-outside.png differ diff --git a/Standalone/Research/WorldAssemblerM3/Linux115/captures/L115/L115/passage-2-3-0-openair-2-4m-interior-wall.png b/Standalone/Research/WorldAssemblerM3/Linux115/captures/L115/L115/passage-2-3-0-openair-2-4m-interior-wall.png new file mode 100644 index 0000000..fb6b0f1 Binary files /dev/null and b/Standalone/Research/WorldAssemblerM3/Linux115/captures/L115/L115/passage-2-3-0-openair-2-4m-interior-wall.png differ diff --git a/Standalone/Research/WorldAssemblerM3/Linux115/captures/L115/L115/passage-2-3-0-openair-2-4m-outside.png b/Standalone/Research/WorldAssemblerM3/Linux115/captures/L115/L115/passage-2-3-0-openair-2-4m-outside.png new file mode 100644 index 0000000..1ff0c92 Binary files /dev/null and b/Standalone/Research/WorldAssemblerM3/Linux115/captures/L115/L115/passage-2-3-0-openair-2-4m-outside.png differ diff --git a/Standalone/Research/WorldAssemblerM3/Linux115/captures/L115/L115/passage-2-3-0-rock-floor-station-1.png b/Standalone/Research/WorldAssemblerM3/Linux115/captures/L115/L115/passage-2-3-0-rock-floor-station-1.png new file mode 100644 index 0000000..5187921 Binary files /dev/null and b/Standalone/Research/WorldAssemblerM3/Linux115/captures/L115/L115/passage-2-3-0-rock-floor-station-1.png differ diff --git a/Standalone/Research/WorldAssemblerM3/Linux115/captures/L115/L115/passage-2-3-0-rock-floor-station-2.png b/Standalone/Research/WorldAssemblerM3/Linux115/captures/L115/L115/passage-2-3-0-rock-floor-station-2.png new file mode 100644 index 0000000..ddb87ad Binary files /dev/null and b/Standalone/Research/WorldAssemblerM3/Linux115/captures/L115/L115/passage-2-3-0-rock-floor-station-2.png differ diff --git a/Standalone/Research/WorldAssemblerM3/Linux115/captures/L115/L115/passage-2-3-0-rock-floor-station-3.png b/Standalone/Research/WorldAssemblerM3/Linux115/captures/L115/L115/passage-2-3-0-rock-floor-station-3.png new file mode 100644 index 0000000..694a3dc Binary files /dev/null and b/Standalone/Research/WorldAssemblerM3/Linux115/captures/L115/L115/passage-2-3-0-rock-floor-station-3.png differ diff --git a/Standalone/Research/WorldAssemblerM3/Linux115/captures/capture-index.json b/Standalone/Research/WorldAssemblerM3/Linux115/captures/capture-index.json new file mode 100644 index 0000000..f01fdcf --- /dev/null +++ b/Standalone/Research/WorldAssemblerM3/Linux115/captures/capture-index.json @@ -0,0 +1,1562 @@ +{ + "captures": [ + { + "name": "passage-0-1-0-rock-floor-station-1", + "passage": "passage/0-1/0", + "kind": "rock-floor-close", + "station": "rock-floor/401.7m", + "camera": [ + -9.24648786798055, + 19.798675033837775, + -443.9636296749357 + ], + "target": [ + -7.026884524505579, + 20.857335392121104, + -445.66373993191075 + ], + "yaw": 64.50075976736525, + "pitch": -34.65771934187305, + "focus": [ + -7.026884524505579, + 20.857335392121104, + -445.66373993191075 + ], + "center_z": -445.66373993191075, + "route_distance_m": 401.6612010038529, + "requested_route_distance_m": 401.6612010038529, + "route_length_m": 2026.6238040154117, + "planned_floor_m": -445.66373993191075, + "planned_grade_deg": 10.372328677972732, + "variant": "L115", + "capture": "captures/L115/L115/passage-0-1-0-rock-floor-station-1.png", + "scene": "Saved/Linux/l115/captures/L115/L115/passage-0-1-0-rock-floor-station-1.vfmesh", + "drawn_triangles": 122256, + "source_triangles": 146688, + "verified": true, + "pixel_quality_status": "pass", + "route_distance_actual_m": 401.6612010038529, + "route_station_adjustment_m": 0.0, + "closeup_camera_target_distance_m": null, + "closeup_target_surface_distance_m": 0.00041588771229822673, + "closeup_predicted_target_offset_m": null, + "closeup_wall_normal_alignment": null, + "fallback_kind": null, + "fallback_surface_distance_m": null, + "camera_actual_m": [ + -9.24648786798055, + 19.798675033837775, + -443.9636296749357 + ], + "target_actual_m": [ + -7.026884524505579, + 20.857335392121104, + -445.66373993191075 + ], + "logs": [ + "Saved/Linux/l115/captures/L115/L115/passage-0-1-0-rock-floor-station-1-mesh.log", + "Saved/Linux/l115/captures/L115/L115/passage-0-1-0-rock-floor-station-1-render.log", + "Saved/Linux/l115/captures/L115/L115/passage-0-1-0-rock-floor-station-1-quality.log" + ], + "floor_anchor_position_m": [ + -7.026816889442207, + 20.857366012722174, + -445.66333072479176 + ], + "floor_anchor_normal": [ + 0.1642540532934053, + 0.07412901954917549, + 0.9836287381107596 + ], + "closeup_camera_to_floor_distance_m": 2.989439663317921, + "closeup_floor_normal_alignment": 0.9836287381107596, + "verified_upward_floor_normal": true + }, + { + "name": "passage-0-1-0-rock-floor-station-2", + "passage": "passage/0-1/0", + "kind": "rock-floor-close", + "station": "rock-floor/792.8m", + "camera": [ + -0.021280083711839648, + -26.43771312964049, + -514.3617561596035 + ], + "target": [ + -2.4714859241065525, + -26.227784739959716, + -516.0616688299093 + ], + "yaw": -85.10297944703369, + "pitch": -34.654210347383824, + "focus": [ + -2.4714859241065525, + -26.227784739959716, + -516.0616688299093 + ], + "center_z": -516.0616688299093, + "route_distance_m": 792.8284020077059, + "requested_route_distance_m": 792.8284020077059, + "route_length_m": 2026.6238040154117, + "planned_floor_m": -516.0616688299093, + "planned_grade_deg": 10.367725129664787, + "variant": "L115", + "capture": "captures/L115/L115/passage-0-1-0-rock-floor-station-2.png", + "scene": "Saved/Linux/l115/captures/L115/L115/passage-0-1-0-rock-floor-station-2.vfmesh", + "drawn_triangles": 585992, + "source_triangles": 626016, + "verified": true, + "pixel_quality_status": "pass", + "route_distance_actual_m": 792.8284020077059, + "route_station_adjustment_m": 0.0, + "closeup_camera_target_distance_m": null, + "closeup_target_surface_distance_m": 6.620479171221186e-06, + "closeup_predicted_target_offset_m": null, + "closeup_wall_normal_alignment": null, + "fallback_kind": null, + "fallback_surface_distance_m": null, + "camera_actual_m": [ + -0.021280083711839648, + -26.43771312964049, + -514.3617561596035 + ], + "target_actual_m": [ + -2.4714859241065525, + -26.227784739959716, + -516.0616688299093 + ], + "logs": [ + "Saved/Linux/l115/captures/L115/L115/passage-0-1-0-rock-floor-station-2-mesh.log", + "Saved/Linux/l115/captures/L115/L115/passage-0-1-0-rock-floor-station-2-render.log", + "Saved/Linux/l115/captures/L115/L115/passage-0-1-0-rock-floor-station-2-quality.log" + ], + "floor_anchor_position_m": [ + -2.4714847396204855, + -26.22778487351251, + -516.0616753421978 + ], + "floor_anchor_normal": [ + -0.17918464595866201, + 0.02004018063609561, + 0.9836113326984097 + ], + "closeup_camera_to_floor_distance_m": 2.989531394033071, + "closeup_floor_normal_alignment": 0.9836113326984097, + "verified_upward_floor_normal": true + }, + { + "name": "passage-0-1-0-rock-floor-station-3", + "passage": "passage/0-1/0", + "kind": "rock-floor-close", + "station": "rock-floor/1634.5m", + "camera": [ + 15.717287112180728, + 19.71739973195528, + -665.8352816543407 + ], + "target": [ + 17.336220092016376, + 17.86620742417785, + -667.5348848643227 + ], + "yaw": 138.82915885966676, + "pitch": -34.64871452830556, + "focus": [ + 17.336220092016376, + 17.86620742417785, + -667.5348848643227 + ], + "center_z": -667.5348848643227, + "route_distance_m": 1634.4566030115589, + "requested_route_distance_m": 1634.4566030115589, + "route_length_m": 2026.6238040154117, + "planned_floor_m": -667.5348848643227, + "planned_grade_deg": 10.360515186362372, + "variant": "L115", + "capture": "captures/L115/L115/passage-0-1-0-rock-floor-station-3.png", + "scene": "Saved/Linux/l115/captures/L115/L115/passage-0-1-0-rock-floor-station-3.vfmesh", + "drawn_triangles": 137252, + "source_triangles": 166708, + "verified": true, + "pixel_quality_status": "pass", + "route_distance_actual_m": 1634.4566030115589, + "route_station_adjustment_m": 0.0, + "closeup_camera_target_distance_m": null, + "closeup_target_surface_distance_m": 1.8519464898499414e-05, + "closeup_predicted_target_offset_m": null, + "closeup_wall_normal_alignment": null, + "fallback_kind": null, + "fallback_surface_distance_m": null, + "camera_actual_m": [ + 15.717287112180728, + 19.71739973195528, + -665.8352816543407 + ], + "target_actual_m": [ + 17.336220092016376, + 17.86620742417785, + -667.5348848643227 + ], + "logs": [ + "Saved/Linux/l115/captures/L115/L115/passage-0-1-0-rock-floor-station-3-mesh.log", + "Saved/Linux/l115/captures/L115/L115/passage-0-1-0-rock-floor-station-3-render.log", + "Saved/Linux/l115/captures/L115/L115/passage-0-1-0-rock-floor-station-3-quality.log" + ], + "floor_anchor_position_m": [ + 17.33621789935619, + 17.866209932616684, + -667.5349030816375 + ], + "floor_anchor_normal": [ + 0.1183906810124733, + -0.13537553141785347, + 0.9836956399937618 + ], + "closeup_camera_to_floor_distance_m": 2.989406891503064, + "closeup_floor_normal_alignment": 0.9836956399937618, + "verified_upward_floor_normal": true + }, + { + "name": "passage-1-2-0-rock-floor-station-1", + "passage": "passage/1-2/0", + "kind": "rock-floor-close", + "station": "rock-floor/27.0m", + "camera": [ + 15.990262769683945, + 2.495369317804175, + -736.4846720823747 + ], + "target": [ + 15.354493464592624, + 4.868558240151556, + -738.1970266319915 + ], + "yaw": -14.99718988160138, + "pitch": -34.875140724394136, + "focus": [ + 15.354493464592624, + 4.868558240151556, + -738.1970266319915 + ], + "center_z": -738.1970266319915, + "route_distance_m": 26.963657939523273, + "requested_route_distance_m": 26.963657939523273, + "route_length_m": 114.99063175809309, + "planned_floor_m": -738.1970266319915, + "planned_grade_deg": 10.657740387934142, + "variant": "L115", + "capture": "captures/L115/L115/passage-1-2-0-rock-floor-station-1.png", + "scene": "Saved/Linux/l115/captures/L115/L115/passage-1-2-0-rock-floor-station-1.vfmesh", + "drawn_triangles": 652088, + "source_triangles": 719780, + "verified": true, + "pixel_quality_status": "pass", + "route_distance_actual_m": 26.963657939523273, + "route_station_adjustment_m": 0.0, + "closeup_camera_target_distance_m": null, + "closeup_target_surface_distance_m": 0.007484804507759201, + "closeup_predicted_target_offset_m": null, + "closeup_wall_normal_alignment": null, + "fallback_kind": null, + "fallback_surface_distance_m": null, + "camera_actual_m": [ + 15.990262769683945, + 2.495369317804175, + -736.4846720823747 + ], + "target_actual_m": [ + 15.354493464592624, + 4.868558240151556, + -738.1970266319915 + ], + "logs": [ + "Saved/Linux/l115/captures/L115/L115/passage-1-2-0-rock-floor-station-1-mesh.log", + "Saved/Linux/l115/captures/L115/L115/passage-1-2-0-rock-floor-station-1-render.log", + "Saved/Linux/l115/captures/L115/L115/passage-1-2-0-rock-floor-station-1-quality.log" + ], + "floor_anchor_position_m": [ + 15.354080518420568, + 4.869888644992825, + -738.1896725992926 + ], + "floor_anchor_normal": [ + -0.05340373170040817, + 0.17677478050840184, + 0.982801464394858 + ], + "closeup_camera_to_floor_distance_m": 2.991671214339144, + "closeup_floor_normal_alignment": 0.982801464394858, + "verified_upward_floor_normal": true + }, + { + "name": "passage-1-2-0-rock-floor-station-2", + "passage": "passage/1-2/0", + "kind": "rock-floor-close", + "station": "rock-floor/52.9m", + "camera": [ + -2.48434493546405, + 15.983647301702653, + -741.2835409028854 + ], + "target": [ + -4.76517685476837, + 15.070128626649932, + -742.995373541633 + ], + "yaw": -111.82708648318167, + "pitch": -34.86587426337977, + "focus": [ + -4.76517685476837, + 15.070128626649932, + -742.995373541633 + ], + "center_z": -742.995373541633, + "route_distance_m": 52.927315879046546, + "requested_route_distance_m": 52.927315879046546, + "route_length_m": 114.99063175809309, + "planned_floor_m": -742.995373541633, + "planned_grade_deg": 10.645569354114926, + "variant": "L115", + "capture": "captures/L115/L115/passage-1-2-0-rock-floor-station-2.png", + "scene": "Saved/Linux/l115/captures/L115/L115/passage-1-2-0-rock-floor-station-2.vfmesh", + "drawn_triangles": 636128, + "source_triangles": 700536, + "verified": true, + "pixel_quality_status": "pass", + "route_distance_actual_m": 52.927315879046546, + "route_station_adjustment_m": 0.0, + "closeup_camera_target_distance_m": null, + "closeup_target_surface_distance_m": 0.007229500620965189, + "closeup_predicted_target_offset_m": null, + "closeup_wall_normal_alignment": null, + "fallback_kind": null, + "fallback_surface_distance_m": null, + "camera_actual_m": [ + -2.48434493546405, + 15.983647301702653, + -741.2835409028854 + ], + "target_actual_m": [ + -4.76517685476837, + 15.070128626649932, + -742.995373541633 + ], + "logs": [ + "Saved/Linux/l115/captures/L115/L115/passage-1-2-0-rock-floor-station-2-mesh.log", + "Saved/Linux/l115/captures/L115/L115/passage-1-2-0-rock-floor-station-2-render.log", + "Saved/Linux/l115/captures/L115/L115/passage-1-2-0-rock-floor-station-2-quality.log" + ], + "floor_anchor_position_m": [ + -4.7663956582883, + 15.069621905164404, + -742.988265558055 + ], + "floor_anchor_normal": [ + -0.1714432252395109, + -0.0687242530069811, + 0.9827940768890027 + ], + "closeup_camera_to_floor_distance_m": 2.991535404604565, + "closeup_floor_normal_alignment": 0.9827940768890027, + "verified_upward_floor_normal": true + }, + { + "name": "passage-1-2-0-rock-floor-station-3", + "passage": "passage/1-2/0", + "kind": "rock-floor-close", + "station": "rock-floor/78.9m", + "camera": [ + -13.44544511010513, + -3.995230772069307, + -746.0839041050349 + ], + "target": [ + -12.287009401722694, + -6.161841337747165, + -747.7963166548619 + ], + "yaw": 151.8676321960706, + "pitch": -34.87617050502889, + "focus": [ + -12.287009401722694, + -6.161841337747165, + -747.7963166548619 + ], + "center_z": -747.7963166548619, + "route_distance_m": 78.89097381856982, + "requested_route_distance_m": 78.89097381856982, + "route_length_m": 114.99063175809309, + "planned_floor_m": -747.7963166548619, + "planned_grade_deg": 10.659092990906162, + "variant": "L115", + "capture": "captures/L115/L115/passage-1-2-0-rock-floor-station-3.png", + "scene": "Saved/Linux/l115/captures/L115/L115/passage-1-2-0-rock-floor-station-3.vfmesh", + "drawn_triangles": 580512, + "source_triangles": 639508, + "verified": true, + "pixel_quality_status": "pass", + "route_distance_actual_m": 78.89097381856982, + "route_station_adjustment_m": 0.0, + "closeup_camera_target_distance_m": null, + "closeup_target_surface_distance_m": 0.2417148155664453, + "closeup_predicted_target_offset_m": null, + "closeup_wall_normal_alignment": null, + "fallback_kind": null, + "fallback_surface_distance_m": null, + "camera_actual_m": [ + -13.44544511010513, + -3.995230772069307, + -746.0839041050349 + ], + "target_actual_m": [ + -12.287009401722694, + -6.161841337747165, + -747.7963166548619 + ], + "logs": [ + "Saved/Linux/l115/captures/L115/L115/passage-1-2-0-rock-floor-station-3-mesh.log", + "Saved/Linux/l115/captures/L115/L115/passage-1-2-0-rock-floor-station-3-render.log", + "Saved/Linux/l115/captures/L115/L115/passage-1-2-0-rock-floor-station-3-quality.log" + ], + "floor_anchor_position_m": [ + -12.283234215932445, + -6.167799052822403, + -747.554704764286 + ], + "floor_anchor_normal": [ + 0.09848641406423383, + -0.15897410728021424, + 0.9823582134126162 + ], + "closeup_camera_to_floor_distance_m": 2.8695019909945634, + "closeup_floor_normal_alignment": 0.9823582134126162, + "verified_upward_floor_normal": true + }, + { + "name": "passage-2-3-0-rock-floor-station-1", + "passage": "passage/2-3/0", + "kind": "rock-floor-close", + "station": "rock-floor/323.4m", + "camera": [ + 6.997568341188331, + -14.934306981606339, + -869.3796844648476 + ], + "target": [ + 9.102823911740126, + -13.661883549736208, + -871.0755965556104 + ], + "yaw": 58.85109570948622, + "pitch": -34.583159686285406, + "focus": [ + 9.102823911740126, + -13.661883549736208, + -871.0755965556104 + ], + "center_z": -871.0755965556104, + "route_distance_m": 323.4481319239866, + "requested_route_distance_m": 323.4481319239866, + "route_length_m": 494.0722798830563, + "planned_floor_m": -871.0755965556104, + "planned_grade_deg": 10.274530613220444, + "variant": "L115", + "capture": "captures/L115/L115/passage-2-3-0-rock-floor-station-1.png", + "scene": "Saved/Linux/l115/captures/L115/L115/passage-2-3-0-rock-floor-station-1.vfmesh", + "drawn_triangles": 474896, + "source_triangles": 502362, + "verified": true, + "pixel_quality_status": "low_contrast_geometry_visible", + "route_distance_actual_m": 323.4481319239866, + "route_station_adjustment_m": 0.0, + "closeup_camera_target_distance_m": null, + "closeup_target_surface_distance_m": 0.007165446036271588, + "closeup_predicted_target_offset_m": null, + "closeup_wall_normal_alignment": null, + "fallback_kind": null, + "fallback_surface_distance_m": null, + "camera_actual_m": [ + 6.997568341188331, + -14.934306981606339, + -869.3796844648476 + ], + "target_actual_m": [ + 9.102823911740126, + -13.661883549736208, + -871.0755965556104 + ], + "logs": [ + "Saved/Linux/l115/captures/L115/L115/passage-2-3-0-rock-floor-station-1-mesh.log", + "Saved/Linux/l115/captures/L115/L115/passage-2-3-0-rock-floor-station-1-render.log", + "Saved/Linux/l115/captures/L115/L115/passage-2-3-0-rock-floor-station-1-quality.log" + ], + "floor_anchor_position_m": [ + 9.103853396121147, + -13.661134677318575, + -871.0685451040641 + ], + "floor_anchor_normal": [ + 0.14535372671884042, + 0.10291285952153646, + 0.984012823836176 + ], + "closeup_camera_to_floor_distance_m": 2.9849044721286333, + "closeup_floor_normal_alignment": 0.984012823836176, + "verified_upward_floor_normal": true + }, + { + "name": "passage-2-3-0-rock-floor-station-2", + "passage": "passage/2-3/0", + "kind": "rock-floor-close", + "station": "rock-floor/333.4m", + "camera": [ + 14.426607883839745, + -8.501776133009574, + -871.1605818845352 + ], + "target": [ + 15.203729308783775, + -6.16777561793481, + -872.8561420785873 + ], + "yaw": 18.41553205389999, + "pitch": -34.576909662847896, + "focus": [ + 15.203729308783775, + -6.16777561793481, + -872.8561420785873 + ], + "center_z": -872.8561420785873, + "route_distance_m": 333.4481319239866, + "requested_route_distance_m": 333.4481319239866, + "route_length_m": 494.0722798830563, + "planned_floor_m": -872.8561420785873, + "planned_grade_deg": 10.266334408339132, + "variant": "L115", + "capture": "captures/L115/L115/passage-2-3-0-rock-floor-station-2.png", + "scene": "Saved/Linux/l115/captures/L115/L115/passage-2-3-0-rock-floor-station-2.vfmesh", + "drawn_triangles": 494436, + "source_triangles": 524342, + "verified": true, + "pixel_quality_status": "pass", + "route_distance_actual_m": 333.4481319239866, + "route_station_adjustment_m": 0.0, + "closeup_camera_target_distance_m": null, + "closeup_target_surface_distance_m": 0.007772237163474648, + "closeup_predicted_target_offset_m": null, + "closeup_wall_normal_alignment": null, + "fallback_kind": null, + "fallback_surface_distance_m": null, + "camera_actual_m": [ + 14.426607883839745, + -8.501776133009574, + -871.1605818845352 + ], + "target_actual_m": [ + 15.203729308783775, + -6.16777561793481, + -872.8561420785873 + ], + "logs": [ + "Saved/Linux/l115/captures/L115/L115/passage-2-3-0-rock-floor-station-2-mesh.log", + "Saved/Linux/l115/captures/L115/L115/passage-2-3-0-rock-floor-station-2-render.log", + "Saved/Linux/l115/captures/L115/L115/passage-2-3-0-rock-floor-station-2-quality.log" + ], + "floor_anchor_position_m": [ + 15.204179209863593, + -6.166457650456174, + -872.8484956270397 + ], + "floor_anchor_normal": [ + 0.05636607638224838, + 0.16908442175142946, + 0.9839884774499421 + ], + "closeup_camera_to_floor_distance_m": 2.984523811958219, + "closeup_floor_normal_alignment": 0.9839884774499421, + "verified_upward_floor_normal": true + }, + { + "name": "passage-2-3-0-rock-floor-station-3", + "passage": "passage/2-3/0", + "kind": "rock-floor-close", + "station": "rock-floor/343.4m", + "camera": [ + 16.176045301879554, + 1.1336183974400118, + -872.9426489764151 + ], + "target": [ + 15.465325445603714, + 3.4887437417106955, + -874.6379150751349 + ], + "yaw": -16.792543840841383, + "pitch": -34.57168620892087, + "focus": [ + 15.465325445603714, + 3.4887437417106955, + -874.6379150751349 + ], + "center_z": -874.6379150751349, + "route_distance_m": 343.4481319239866, + "requested_route_distance_m": 343.4481319239866, + "route_length_m": 494.0722798830563, + "planned_floor_m": -874.6379150751349, + "planned_grade_deg": 10.259484647608062, + "variant": "L115", + "capture": "captures/L115/L115/passage-2-3-0-rock-floor-station-3.png", + "scene": "Saved/Linux/l115/captures/L115/L115/passage-2-3-0-rock-floor-station-3.vfmesh", + "drawn_triangles": 485332, + "source_triangles": 512656, + "verified": true, + "pixel_quality_status": "pass", + "route_distance_actual_m": 343.4481319239866, + "route_station_adjustment_m": 0.0, + "closeup_camera_target_distance_m": null, + "closeup_target_surface_distance_m": 0.10989591368848521, + "closeup_predicted_target_offset_m": null, + "closeup_wall_normal_alignment": null, + "fallback_kind": null, + "fallback_surface_distance_m": null, + "camera_actual_m": [ + 16.176045301879554, + 1.1336183974400118, + -872.9426489764151 + ], + "target_actual_m": [ + 15.465325445603714, + 3.4887437417106955, + -874.6379150751349 + ], + "logs": [ + "Saved/Linux/l115/captures/L115/L115/passage-2-3-0-rock-floor-station-3-mesh.log", + "Saved/Linux/l115/captures/L115/L115/passage-2-3-0-rock-floor-station-3-render.log", + "Saved/Linux/l115/captures/L115/L115/passage-2-3-0-rock-floor-station-3-quality.log" + ], + "floor_anchor_position_m": [ + 15.46430655077291, + 3.492524377793417, + -874.528088937583 + ], + "floor_anchor_normal": [ + -0.05151671634089027, + 0.17095268730304666, + 0.9839315050557732 + ], + "closeup_camera_to_floor_distance_m": 2.929953812680686, + "closeup_floor_normal_alignment": 0.9839315050557732, + "verified_upward_floor_normal": true + }, + { + "name": "passage-0-1-0-openair-1-4m-outside", + "passage": "passage/0-1/0", + "kind": "open-air-close", + "station": "section-1/4m-outside", + "camera": [ + 13.176702021211483, + 7.149068417345486, + -374.402 + ], + "target": [ + 9.197121888971225, + 7.5527291301707695, + -374.402 + ], + "yaw": -84.20812706837869, + "pitch": 0.0, + "focus": [ + 7.272, + 7.748, + -373.197 + ], + "center_z": -373.197, + "open_air_section": 1, + "closeup_side": "outside", + "closeup_preferred_normal": [ + 0.9948950330600643, + -0.1009151782063209, + 0.0 + ], + "camera_target_distance_m": 4.000000000000001, + "route_distance_m": 8.3545, + "requested_route_distance_m": 8.3545, + "route_length_m": 2026.6238040154117, + "variant": "L115", + "capture": "captures/L115/L115/passage-0-1-0-openair-1-4m-outside.png", + "scene": "Saved/Linux/l115/captures/L115/L115/passage-0-1-0-openair-1-4m-outside.vfmesh", + "drawn_triangles": 275313, + "source_triangles": 327681, + "verified": true, + "pixel_quality_status": "pass", + "route_distance_actual_m": 8.3545, + "route_station_adjustment_m": 0.0, + "closeup_camera_target_distance_m": 3.9999999999999987, + "closeup_target_surface_distance_m": 0.7939613079024029, + "closeup_predicted_target_offset_m": 0.7939613079024029, + "closeup_wall_normal_alignment": 0.9448010671048102, + "fallback_kind": null, + "fallback_surface_distance_m": null, + "camera_actual_m": [ + 12.921959272720493, + 7.9850770584603294, + -375.0077532897384 + ], + "target_actual_m": [ + 9.124876976013184, + 8.0, + -373.75 + ], + "logs": [ + "Saved/Linux/l115/captures/L115/L115/passage-0-1-0-openair-1-4m-outside-mesh.log", + "Saved/Linux/l115/captures/L115/L115/passage-0-1-0-openair-1-4m-outside-render.log", + "Saved/Linux/l115/captures/L115/L115/passage-0-1-0-openair-1-4m-outside-quality.log" + ] + }, + { + "name": "passage-0-1-0-openair-1-4m-interior-wall", + "passage": "passage/0-1/0", + "kind": "open-air-close", + "station": "section-1/4m-interior-wall", + "camera": [ + 7.395778712540976, + 3.8749008126934172, + -374.89997477205173 + ], + "target": [ + 8.778272394312646, + 7.595214286886338, + -374.402 + ], + "yaw": 20.38540702862518, + "pitch": 7.1515181408188955, + "focus": [ + 7.272, + 7.748, + -373.197 + ], + "center_z": -373.197, + "open_air_section": 1, + "closeup_side": "interior-wall", + "closeup_preferred_normal": [ + -0.9948950330600643, + 0.1009151782063209, + -0.0 + ], + "camera_target_distance_m": 3.9999999999999973, + "route_distance_m": 8.3545, + "requested_route_distance_m": 8.3545, + "route_length_m": 2026.6238040154117, + "variant": "L115", + "capture": "captures/L115/L115/passage-0-1-0-openair-1-4m-interior-wall.png", + "scene": "Saved/Linux/l115/captures/L115/L115/passage-0-1-0-openair-1-4m-interior-wall.vfmesh", + "drawn_triangles": 307964, + "source_triangles": 367980, + "verified": true, + "pixel_quality_status": "low_contrast_geometry_visible", + "route_distance_actual_m": 8.3545, + "route_station_adjustment_m": 0.0, + "closeup_camera_target_distance_m": 3.999999999999998, + "closeup_target_surface_distance_m": 0.8420749429811597, + "closeup_predicted_target_offset_m": 0.8420749429811597, + "closeup_wall_normal_alignment": 0.9448010671048102, + "fallback_kind": null, + "fallback_surface_distance_m": null, + "camera_actual_m": [ + 5.3277946793058755, + 8.01492294153967, + -372.4922467102616 + ], + "target_actual_m": [ + 9.124876976013184, + 8.0, + -373.75 + ], + "logs": [ + "Saved/Linux/l115/captures/L115/L115/passage-0-1-0-openair-1-4m-interior-wall-mesh.log", + "Saved/Linux/l115/captures/L115/L115/passage-0-1-0-openair-1-4m-interior-wall-render.log", + "Saved/Linux/l115/captures/L115/L115/passage-0-1-0-openair-1-4m-interior-wall-quality.log" + ] + }, + { + "name": "passage-0-1-0-openair-2-4m-outside", + "passage": "passage/0-1/0", + "kind": "open-air-close", + "station": "section-2/4m-outside", + "camera": [ + 12.814097656232029, + 0.949800892309409, + -375.51163279923776 + ], + "target": [ + 8.842807594702599, + 1.4281890685821654, + -375.51163279923776 + ], + "yaw": -83.1311525734364, + "pitch": 0.0, + "focus": [ + 6.603, + 1.698, + -374.149 + ], + "center_z": -374.149, + "open_air_section": 2, + "closeup_side": "outside", + "closeup_preferred_normal": [ + 0.9928225153823576, + -0.1195970440681891, + 0.0 + ], + "camera_target_distance_m": 4.0, + "route_distance_m": 14.4925, + "requested_route_distance_m": 14.4925, + "route_length_m": 2026.6238040154117, + "variant": "L115", + "capture": "captures/L115/L115/passage-0-1-0-openair-2-4m-outside.png", + "scene": "Saved/Linux/l115/captures/L115/L115/passage-0-1-0-openair-2-4m-outside.vfmesh", + "drawn_triangles": 275313, + "source_triangles": 327681, + "verified": true, + "pixel_quality_status": "pass", + "route_distance_actual_m": 14.4925, + "route_station_adjustment_m": 0.0, + "closeup_camera_target_distance_m": 4.000000000000018, + "closeup_target_surface_distance_m": 1.0987112128185943, + "closeup_predicted_target_offset_m": 1.0987112128185943, + "closeup_wall_normal_alignment": 0.3897133873128999, + "fallback_kind": null, + "fallback_surface_distance_m": null, + "camera_actual_m": [ + 9.5949500542171, + 1.5661638290281419, + -379.604906740858 + ], + "target_actual_m": [ + 7.956625938415527, + 1.0, + -376.0 + ], + "logs": [ + "Saved/Linux/l115/captures/L115/L115/passage-0-1-0-openair-2-4m-outside-mesh.log", + "Saved/Linux/l115/captures/L115/L115/passage-0-1-0-openair-2-4m-outside-render.log", + "Saved/Linux/l115/captures/L115/L115/passage-0-1-0-openair-2-4m-outside-quality.log" + ] + }, + { + "name": "passage-0-1-0-openair-2-4m-interior-wall", + "passage": "passage/0-1/0", + "kind": "open-air-close", + "station": "section-2/4m-interior-wall", + "camera": [ + 6.939570778854576, + -2.1803140897652855, + -376.2060303004211 + ], + "target": [ + 8.388084903173432, + 1.4829657169105679, + -375.51163279923776 + ], + "yaw": 21.574563086437188, + "pitch": 9.997160707081923, + "focus": [ + 6.603, + 1.698, + -374.149 + ], + "center_z": -374.149, + "open_air_section": 2, + "closeup_side": "interior-wall", + "closeup_preferred_normal": [ + -0.9928225153823576, + 0.1195970440681891, + -0.0 + ], + "camera_target_distance_m": 3.999999999999997, + "route_distance_m": 14.4925, + "requested_route_distance_m": 14.4925, + "route_length_m": 2026.6238040154117, + "variant": "L115", + "capture": "captures/L115/L115/passage-0-1-0-openair-2-4m-interior-wall.png", + "scene": "Saved/Linux/l115/captures/L115/L115/passage-0-1-0-openair-2-4m-interior-wall.vfmesh", + "drawn_triangles": 345024, + "source_triangles": 414544, + "verified": true, + "pixel_quality_status": "pass", + "route_distance_actual_m": 14.4925, + "route_station_adjustment_m": 0.0, + "closeup_camera_target_distance_m": 4.000000000000008, + "closeup_target_surface_distance_m": 0.7753571368538784, + "closeup_predicted_target_offset_m": 0.7753571368538784, + "closeup_wall_normal_alignment": 0.28377228920326875, + "fallback_kind": null, + "fallback_surface_distance_m": null, + "camera_actual_m": [ + 6.628776462154715, + 0.5675722190282632, + -372.2459846914724 + ], + "target_actual_m": [ + 7.849808932278981, + 1.2129006394800852, + -376.0 + ], + "logs": [ + "Saved/Linux/l115/captures/L115/L115/passage-0-1-0-openair-2-4m-interior-wall-mesh.log", + "Saved/Linux/l115/captures/L115/L115/passage-0-1-0-openair-2-4m-interior-wall-render.log", + "Saved/Linux/l115/captures/L115/L115/passage-0-1-0-openair-2-4m-interior-wall-quality.log" + ] + }, + { + "name": "passage-0-1-0-openair-3-4m-outside", + "passage": "passage/0-1/0", + "kind": "open-air-close", + "station": "section-3/4m-outside", + "camera": [ + -28.32291429976088, + -16.444327461849063, + -600.6066327992378 + ], + "target": [ + -25.004026673221745, + -14.211619482196229, + -600.6066327992378 + ], + "yaw": 56.07018168236039, + "pitch": 0.0, + "focus": [ + -22.1, + -12.258, + -599.244 + ], + "center_z": -599.244, + "open_air_section": 3, + "closeup_side": "outside", + "closeup_preferred_normal": [ + -0.8297219066347834, + -0.5581769949132084, + 0.0 + ], + "camera_target_distance_m": 4.000000000000001, + "route_distance_m": 1265.3425000000002, + "requested_route_distance_m": 1265.3425000000002, + "route_length_m": 2026.6238040154117, + "variant": "L115", + "capture": "captures/L115/L115/passage-0-1-0-openair-3-4m-outside.png", + "scene": "Saved/Linux/l115/captures/L115/L115/passage-0-1-0-openair-3-4m-outside.vfmesh", + "drawn_triangles": 148970, + "source_triangles": 181648, + "verified": true, + "pixel_quality_status": "pass", + "route_distance_actual_m": 1265.3425000000002, + "route_station_adjustment_m": 0.0, + "closeup_camera_target_distance_m": 3.9999999999999902, + "closeup_target_surface_distance_m": 0.07628351187558495, + "closeup_predicted_target_offset_m": 0.07628351187558495, + "closeup_wall_normal_alignment": 0.9592251078586415, + "fallback_kind": null, + "fallback_surface_distance_m": null, + "camera_actual_m": [ + -28.57044719818512, + -15.661387743596107, + -601.3804397335666 + ], + "target_actual_m": [ + -24.944963139481786, + -14.17663130732971, + -600.5733686926703 + ], + "logs": [ + "Saved/Linux/l115/captures/L115/L115/passage-0-1-0-openair-3-4m-outside-mesh.log", + "Saved/Linux/l115/captures/L115/L115/passage-0-1-0-openair-3-4m-outside-render.log", + "Saved/Linux/l115/captures/L115/L115/passage-0-1-0-openair-3-4m-outside-quality.log" + ] + }, + { + "name": "passage-0-1-0-openair-3-4m-interior-wall", + "passage": "passage/0-1/0", + "kind": "open-air-close", + "station": "section-3/4m-interior-wall", + "camera": [ + -26.071689640946218, + -10.338278587083852, + -601.3036807194 + ], + "target": [ + -24.774901932566983, + -14.057480898923608, + -600.6066327992378 + ], + "yaw": 160.77768453528284, + "pitch": 10.035712777782798, + "focus": [ + -22.1, + -12.258, + -599.244 + ], + "center_z": -599.244, + "open_air_section": 3, + "closeup_side": "interior-wall", + "closeup_preferred_normal": [ + 0.8297219066347834, + 0.5581769949132084, + -0.0 + ], + "camera_target_distance_m": 4.000000000000005, + "route_distance_m": 1265.3425000000002, + "requested_route_distance_m": 1265.3425000000002, + "route_length_m": 2026.6238040154117, + "variant": "L115", + "capture": "captures/L115/L115/passage-0-1-0-openair-3-4m-interior-wall.png", + "scene": "Saved/Linux/l115/captures/L115/L115/passage-0-1-0-openair-3-4m-interior-wall.vfmesh", + "drawn_triangles": 148032, + "source_triangles": 180836, + "verified": true, + "pixel_quality_status": "pass", + "route_distance_actual_m": 1265.3425000000002, + "route_station_adjustment_m": 0.0, + "closeup_camera_target_distance_m": 3.9999999999999982, + "closeup_target_surface_distance_m": 0.15205219413977372, + "closeup_predicted_target_offset_m": 0.15205219413977372, + "closeup_wall_normal_alignment": 0.9345418743495936, + "fallback_kind": null, + "fallback_surface_distance_m": null, + "camera_actual_m": [ + -21.88067998858543, + -11.885666360390521, + -599.2830946490843 + ], + "target_actual_m": [ + -24.866255651742943, + -14.144752595137593, + -600.6912378745901 + ], + "logs": [ + "Saved/Linux/l115/captures/L115/L115/passage-0-1-0-openair-3-4m-interior-wall-mesh.log", + "Saved/Linux/l115/captures/L115/L115/passage-0-1-0-openair-3-4m-interior-wall-render.log", + "Saved/Linux/l115/captures/L115/L115/passage-0-1-0-openair-3-4m-interior-wall-quality.log" + ] + }, + { + "name": "passage-1-2-0-openair-1-4m-outside", + "passage": "passage/1-2/0", + "kind": "open-air-close", + "station": "section-1/4m-outside", + "camera": [ + -4.699079444431819, + -4.6537955842685985, + -748.15 + ], + "target": [ + -7.452748333327923, + -7.555055250400828, + -748.15 + ], + "yaw": -136.49505148095557, + "pitch": 0.0, + "focus": [ + -9.518, + -9.731, + -745.88 + ], + "center_z": -745.88, + "open_air_section": 1, + "closeup_side": "outside", + "closeup_preferred_normal": [ + 0.688417222224026, + 0.7253149165330574, + 0.0 + ], + "camera_target_distance_m": 4.000000000000001, + "route_distance_m": 83.504, + "requested_route_distance_m": 83.504, + "route_length_m": 114.99063175809309, + "variant": "L115", + "capture": "captures/L115/L115/passage-1-2-0-openair-1-4m-outside.png", + "scene": "Saved/Linux/l115/captures/L115/L115/passage-1-2-0-openair-1-4m-outside.vfmesh", + "drawn_triangles": 620866, + "source_triangles": 684916, + "verified": true, + "pixel_quality_status": "low_contrast_geometry_visible", + "route_distance_actual_m": 83.504, + "route_station_adjustment_m": 0.0, + "closeup_camera_target_distance_m": 3.9999999999999867, + "closeup_target_surface_distance_m": 1.0098710767792272, + "closeup_predicted_target_offset_m": 1.0098710767792272, + "closeup_wall_normal_alignment": 0.8500332564252469, + "fallback_kind": null, + "fallback_surface_distance_m": null, + "camera_actual_m": [ + -5.485281064298812, + -4.725534607679206, + -745.4170663807179 + ], + "target_actual_m": [ + -8.013618934305235, + -7.013618934305234, + -747.5080416864878 + ], + "logs": [ + "Saved/Linux/l115/captures/L115/L115/passage-1-2-0-openair-1-4m-outside-mesh.log", + "Saved/Linux/l115/captures/L115/L115/passage-1-2-0-openair-1-4m-outside-render.log", + "Saved/Linux/l115/captures/L115/L115/passage-1-2-0-openair-1-4m-outside-quality.log" + ] + }, + { + "name": "passage-1-2-0-openair-1-4m-interior-wall", + "passage": "passage/1-2/0", + "kind": "open-air-close", + "station": "section-1/4m-interior-wall", + "camera": [ + -6.0956279351195075, + -11.653774892861163, + -748.8673569837389 + ], + "target": [ + -8.16773669839842, + -8.308365466344922, + -748.15 + ], + "yaw": -31.773605793127505, + "pitch": 10.331275124559749, + "focus": [ + -9.518, + -9.731, + -745.88 + ], + "center_z": -745.88, + "open_air_section": 1, + "closeup_side": "interior-wall", + "closeup_preferred_normal": [ + -0.688417222224026, + -0.7253149165330574, + -0.0 + ], + "camera_target_distance_m": 3.999999999999997, + "route_distance_m": 83.504, + "requested_route_distance_m": 83.504, + "route_length_m": 114.99063175809309, + "variant": "L115", + "capture": "captures/L115/L115/passage-1-2-0-openair-1-4m-interior-wall.png", + "scene": "Saved/Linux/l115/captures/L115/L115/passage-1-2-0-openair-1-4m-interior-wall.vfmesh", + "drawn_triangles": 609733, + "source_triangles": 668219, + "verified": true, + "pixel_quality_status": "pass", + "route_distance_actual_m": 83.504, + "route_station_adjustment_m": 0.0, + "closeup_camera_target_distance_m": 3.999999999999999, + "closeup_target_surface_distance_m": 0.6509430039577998, + "closeup_predicted_target_offset_m": 0.6509430039577998, + "closeup_wall_normal_alignment": 0.7808473937095911, + "fallback_kind": null, + "fallback_surface_distance_m": null, + "camera_actual_m": [ + -8.525095579521167, + -12.94135557024142, + -748.3220319510015 + ], + "target_actual_m": [ + -8.18421537084871, + -8.958641713644115, + -748.1744141343152 + ], + "logs": [ + "Saved/Linux/l115/captures/L115/L115/passage-1-2-0-openair-1-4m-interior-wall-mesh.log", + "Saved/Linux/l115/captures/L115/L115/passage-1-2-0-openair-1-4m-interior-wall-render.log", + "Saved/Linux/l115/captures/L115/L115/passage-1-2-0-openair-1-4m-interior-wall-quality.log" + ] + }, + { + "name": "passage-1-2-0-openair-2-4m-outside", + "passage": "passage/1-2/0", + "kind": "open-air-close", + "station": "section-2/4m-outside", + "camera": [ + 6.53817273275958, + -4.657210376135293, + -752.013 + ], + "target": [ + 8.159152142647708, + -8.31404312493838, + -752.013 + ], + "yaw": 156.09352823535562, + "pitch": 0.0, + "focus": [ + 9.43, + -11.181, + -749.743 + ], + "center_z": -749.743, + "open_air_section": 2, + "closeup_side": "outside", + "closeup_preferred_normal": [ + -0.40524485247203174, + 0.9142081872007717, + 0.0 + ], + "camera_target_distance_m": 4.0, + "route_distance_m": 104.362, + "requested_route_distance_m": 104.362, + "route_length_m": 114.99063175809309, + "variant": "L115", + "capture": "captures/L115/L115/passage-1-2-0-openair-2-4m-outside.png", + "scene": "Saved/Linux/l115/captures/L115/L115/passage-1-2-0-openair-2-4m-outside.vfmesh", + "drawn_triangles": 584622, + "source_triangles": 637110, + "verified": true, + "pixel_quality_status": "pass", + "route_distance_actual_m": 104.362, + "route_station_adjustment_m": 0.0, + "closeup_camera_target_distance_m": 4.0, + "closeup_target_surface_distance_m": 0.5853577252069573, + "closeup_predicted_target_offset_m": 0.5853577252069573, + "closeup_wall_normal_alignment": 0.9888938441905853, + "fallback_kind": null, + "fallback_surface_distance_m": null, + "camera_actual_m": [ + 6.3542248659153735, + -5.414315273002622, + -752.0443543721697 + ], + "target_actual_m": [ + 8.5, + -8.789926093729537, + -752.0143433586003 + ], + "logs": [ + "Saved/Linux/l115/captures/L115/L115/passage-1-2-0-openair-2-4m-outside-mesh.log", + "Saved/Linux/l115/captures/L115/L115/passage-1-2-0-openair-2-4m-outside-render.log", + "Saved/Linux/l115/captures/L115/L115/passage-1-2-0-openair-2-4m-outside-quality.log" + ] + }, + { + "name": "passage-1-2-0-openair-2-4m-interior-wall", + "passage": "passage/1-2/0", + "kind": "open-air-close", + "station": "section-2/4m-interior-wall", + "camera": [ + 12.438590152225206, + -8.574465388721983, + -752.7261335058829 + ], + "target": [ + 8.55317187096847, + -9.20292810238377, + -752.013 + ], + "yaw": -99.18796190221158, + "pitch": 10.269787281460902, + "focus": [ + 9.43, + -11.181, + -749.743 + ], + "center_z": -749.743, + "open_air_section": 2, + "closeup_side": "interior-wall", + "closeup_preferred_normal": [ + 0.40524485247203174, + -0.9142081872007717, + -0.0 + ], + "camera_target_distance_m": 3.9999999999999973, + "route_distance_m": 104.362, + "requested_route_distance_m": 104.362, + "route_length_m": 114.99063175809309, + "variant": "L115", + "capture": "captures/L115/L115/passage-1-2-0-openair-2-4m-interior-wall.png", + "scene": "Saved/Linux/l115/captures/L115/L115/passage-1-2-0-openair-2-4m-interior-wall.vfmesh", + "drawn_triangles": 572238, + "source_triangles": 618646, + "verified": true, + "pixel_quality_status": "pass", + "route_distance_actual_m": 104.362, + "route_station_adjustment_m": 0.0, + "closeup_camera_target_distance_m": 3.999999999999999, + "closeup_target_surface_distance_m": 0.354874967440152, + "closeup_predicted_target_offset_m": 0.354874967440152, + "closeup_wall_normal_alignment": 0.9979957992262107, + "fallback_kind": null, + "fallback_surface_distance_m": null, + "camera_actual_m": [ + 9.717371905411476, + -12.678581195400906, + -752.0281034251076 + ], + "target_actual_m": [ + 8.330275720030585, + -8.926843182205447, + -752.007462377509 + ], + "logs": [ + "Saved/Linux/l115/captures/L115/L115/passage-1-2-0-openair-2-4m-interior-wall-mesh.log", + "Saved/Linux/l115/captures/L115/L115/passage-1-2-0-openair-2-4m-interior-wall-render.log", + "Saved/Linux/l115/captures/L115/L115/passage-1-2-0-openair-2-4m-interior-wall-quality.log" + ] + }, + { + "name": "passage-2-3-0-openair-1-4m-outside", + "passage": "passage/2-3/0", + "kind": "open-air-close", + "station": "section-1/4m-outside", + "camera": [ + -3.5840423774965293, + -5.521048309862215, + -815.8969999999999 + ], + "target": [ + -5.637732447498513, + -8.953592132798093, + -815.8969999999999 + ], + "yaw": -149.10792796365394, + "pitch": 0.0, + "focus": [ + -7.178, + -11.528, + -813.627 + ], + "center_z": -813.627, + "open_air_section": 1, + "closeup_side": "outside", + "closeup_preferred_normal": [ + 0.5134225175004958, + 0.8581359557339694, + 0.0 + ], + "camera_target_distance_m": 4.0, + "route_distance_m": 16.616500000000002, + "requested_route_distance_m": 16.616500000000002, + "route_length_m": 494.0722798830563, + "variant": "L115", + "capture": "captures/L115/L115/passage-2-3-0-openair-1-4m-outside.png", + "scene": "Saved/Linux/l115/captures/L115/L115/passage-2-3-0-openair-1-4m-outside.vfmesh", + "drawn_triangles": 104612, + "source_triangles": 129354, + "verified": true, + "pixel_quality_status": "low_contrast_geometry_visible", + "route_distance_actual_m": 16.616500000000002, + "route_station_adjustment_m": 0.0, + "closeup_camera_target_distance_m": 4.0000000000000036, + "closeup_target_surface_distance_m": 0.29188924025474844, + "closeup_predicted_target_offset_m": 0.29188924025474844, + "closeup_wall_normal_alignment": 0.6703275045296155, + "fallback_kind": null, + "fallback_surface_distance_m": null, + "camera_actual_m": [ + -3.7918253987505834, + -7.16028175130118, + -813.227396563761 + ], + "target_actual_m": [ + -5.7833741859987065, + -9.093313475424294, + -816.1078690565205 + ], + "logs": [ + "Saved/Linux/l115/captures/L115/L115/passage-2-3-0-openair-1-4m-outside-mesh.log", + "Saved/Linux/l115/captures/L115/L115/passage-2-3-0-openair-1-4m-outside-render.log", + "Saved/Linux/l115/captures/L115/L115/passage-2-3-0-openair-1-4m-outside-quality.log" + ] + }, + { + "name": "passage-2-3-0-openair-1-4m-interior-wall", + "passage": "passage/2-3/0", + "kind": "open-air-close", + "station": "section-1/4m-interior-wall", + "camera": [ + -3.4141605326349946, + -12.659565888737353, + -816.5879167710818 + ], + "target": [ + -6.170971760123668, + -9.844849940114793, + -815.8969999999999 + ], + "yaw": -44.40454805561343, + "pitch": 9.946538162082001, + "focus": [ + -7.178, + -11.528, + -813.627 + ], + "center_z": -813.627, + "open_air_section": 1, + "closeup_side": "interior-wall", + "closeup_preferred_normal": [ + -0.5134225175004958, + -0.8581359557339694, + -0.0 + ], + "camera_target_distance_m": 4.000000000000005, + "route_distance_m": 16.616500000000002, + "requested_route_distance_m": 16.616500000000002, + "route_length_m": 494.0722798830563, + "variant": "L115", + "capture": "captures/L115/L115/passage-2-3-0-openair-1-4m-interior-wall.png", + "scene": "Saved/Linux/l115/captures/L115/L115/passage-2-3-0-openair-1-4m-interior-wall.vfmesh", + "drawn_triangles": 94962, + "source_triangles": 118056, + "verified": true, + "pixel_quality_status": "low_contrast_geometry_visible", + "route_distance_actual_m": 16.616500000000002, + "route_station_adjustment_m": 0.0, + "closeup_camera_target_distance_m": 4.0, + "closeup_target_surface_distance_m": 0.41920390486225767, + "closeup_predicted_target_offset_m": 0.41920390486225767, + "closeup_wall_normal_alignment": 0.740744136337711, + "fallback_kind": null, + "fallback_surface_distance_m": null, + "camera_actual_m": [ + -7.998432705401559, + -11.833936581758076, + -818.2481168532394 + ], + "target_actual_m": [ + -5.94757062165508, + -9.608161331921629, + -815.6327986602337 + ], + "logs": [ + "Saved/Linux/l115/captures/L115/L115/passage-2-3-0-openair-1-4m-interior-wall-mesh.log", + "Saved/Linux/l115/captures/L115/L115/passage-2-3-0-openair-1-4m-interior-wall-render.log", + "Saved/Linux/l115/captures/L115/L115/passage-2-3-0-openair-1-4m-interior-wall-quality.log" + ] + }, + { + "name": "passage-2-3-0-openair-2-4m-outside", + "passage": "passage/2-3/0", + "kind": "open-air-close", + "station": "section-2/4m-outside", + "camera": [ + -4.5562890668466025, + 4.648574813628143, + -879.7479999999999 + ], + "target": [ + -7.40869531436283, + 7.452817777269203, + -879.7479999999999 + ], + "yaw": -45.487830534998494, + "pitch": 0.0, + "focus": [ + -9.548, + 9.556, + -877.478 + ], + "center_z": -877.478, + "open_air_section": 2, + "closeup_side": "outside", + "closeup_preferred_normal": [ + 0.7131015618790567, + -0.7010607409102652, + 0.0 + ], + "camera_target_distance_m": 4.000000000000001, + "route_distance_m": 374.929, + "requested_route_distance_m": 374.929, + "route_length_m": 494.0722798830563, + "variant": "L115", + "capture": "captures/L115/L115/passage-2-3-0-openair-2-4m-outside.png", + "scene": "Saved/Linux/l115/captures/L115/L115/passage-2-3-0-openair-2-4m-outside.vfmesh", + "drawn_triangles": 475838, + "source_triangles": 504242, + "verified": true, + "pixel_quality_status": "pass", + "route_distance_actual_m": 374.929, + "route_station_adjustment_m": 0.0, + "closeup_camera_target_distance_m": 4.0, + "closeup_target_surface_distance_m": 1.7280841589725482, + "closeup_predicted_target_offset_m": 1.7280841589725482, + "closeup_wall_normal_alignment": 0.6707889779439669, + "fallback_kind": null, + "fallback_surface_distance_m": null, + "camera_actual_m": [ + -7.47193274788199, + 5.182168353356822, + -879.6783722112204 + ], + "target_actual_m": [ + -7.306445568768645, + 9.17777802625833, + -879.7662205769708 + ], + "logs": [ + "Saved/Linux/l115/captures/L115/L115/passage-2-3-0-openair-2-4m-outside-mesh.log", + "Saved/Linux/l115/captures/L115/L115/passage-2-3-0-openair-2-4m-outside-render.log", + "Saved/Linux/l115/captures/L115/L115/passage-2-3-0-openair-2-4m-outside-quality.log" + ] + }, + { + "name": "passage-2-3-0-openair-2-4m-interior-wall", + "passage": "passage/2-3/0", + "kind": "open-air-close", + "station": "section-2/4m-interior-wall", + "camera": [ + -11.533986119377625, + 6.164550123765492, + -880.4395357921604 + ], + "target": [ + -8.149320771422074, + 8.180937668487475, + -879.7479999999999 + ], + "yaw": 59.215963829172296, + "pitch": 9.955540417812847, + "focus": [ + -9.548, + 9.556, + -877.478 + ], + "center_z": -877.478, + "open_air_section": 2, + "closeup_side": "interior-wall", + "closeup_preferred_normal": [ + -0.7131015618790567, + 0.7010607409102652, + -0.0 + ], + "camera_target_distance_m": 4.000000000000007, + "route_distance_m": 374.929, + "requested_route_distance_m": 374.929, + "route_length_m": 494.0722798830563, + "variant": "L115", + "capture": "captures/L115/L115/passage-2-3-0-openair-2-4m-interior-wall.png", + "scene": "Saved/Linux/l115/captures/L115/L115/passage-2-3-0-openair-2-4m-interior-wall.vfmesh", + "drawn_triangles": 486512, + "source_triangles": 513540, + "verified": true, + "pixel_quality_status": "pass", + "route_distance_actual_m": 374.929, + "route_station_adjustment_m": 0.0, + "closeup_camera_target_distance_m": 4.0, + "closeup_target_surface_distance_m": 1.0286227628002445, + "closeup_predicted_target_offset_m": 1.0286227628002445, + "closeup_wall_normal_alignment": 0.720019406420326, + "fallback_kind": null, + "fallback_surface_distance_m": null, + "camera_actual_m": [ + -8.257109087497915, + 13.208090205453457, + -879.7612149430302 + ], + "target_actual_m": [ + -8.149320771422074, + 9.209558486938477, + -879.75 + ], + "logs": [ + "Saved/Linux/l115/captures/L115/L115/passage-2-3-0-openair-2-4m-interior-wall-mesh.log", + "Saved/Linux/l115/captures/L115/L115/passage-2-3-0-openair-2-4m-interior-wall-render.log", + "Saved/Linux/l115/captures/L115/L115/passage-2-3-0-openair-2-4m-interior-wall-quality.log" + ] + } + ] +} diff --git a/Standalone/Source/StreamBenchmarkPipeline.h b/Standalone/Source/StreamBenchmarkPipeline.h index 62981bc..033b169 100644 --- a/Standalone/Source/StreamBenchmarkPipeline.h +++ b/Standalone/Source/StreamBenchmarkPipeline.h @@ -3166,18 +3166,58 @@ namespace StandaloneStreamBenchmark std::lerp(a.floorZ,b.floorZ,t), std::lerp(a.radius,b.radius,t),distance,b.segmentIndex}; }; - const char* l114DensityProfile=std::getenv("VOXELFORGE_L114_DENSITY_PROFILE"); - if(l114DensityProfile&&l114DensityProfile[0]=='1'&&l114DensityProfile[1]=='\0') + struct FPassageRouteProjection { - for(const char* passageId:{"passage/0-1/0","passage/1-2/0"}) + double centerDistanceSquared=std::numeric_limits::infinity(); + double tubeDistance=std::numeric_limits::infinity(); + double centerAlong=0.0,tubeAlong=0.0; + }; + const auto projectPassageRoute=[]( + const std::vector& route, + double x,double y,double z) + { + FPassageRouteProjection projection; + for(std::size_t segment=1;segmentpassages.begin(), - ResolvedLayout->passages.end(),[&](const auto& candidate) - {return candidate.stableId==passageId;}); - if(passage==ResolvedLayout->passages.end())continue; - const std::size_t passageIndex=static_cast( - passage-ResolvedLayout->passages.begin()); + const auto& a=route[segment-1]; + const auto& b=route[segment]; + const double dx=b.x-a.x,dy=b.y-a.y,dz=b.z-a.z; + const double lengthSquared=dx*dx+dy*dy+dz*dz; + if(lengthSquared<=1.0e-12)continue; + const double horizontalLengthSquared=dx*dx+dy*dy; + const double horizontalT=horizontalLengthSquared>1.0e-12 + ?((x-a.x)*dx+(y-a.y)*dy)/horizontalLengthSquared + :std::clamp((z-a.z)*dz/lengthSquared,0.0,1.0); + const double t=std::clamp(((x-a.x)*dx+(y-a.y)*dy + +(z-a.z)*dz)/lengthSquared,0.0,1.0); + const double ex=x-(a.x+t*dx),ey=y-(a.y+t*dy),ez=z-(a.z+t*dz); + const double distanceSquared=ex*ex+ey*ey+ez*ez; + const double along=std::lerp(a.distance,b.distance,t); + const double centerAlong=std::lerp(a.distance,b.distance,horizontalT); + if(distanceSquaredpassages.size();++passageIndex) + { + const auto& passage=ResolvedLayout->passages[passageIndex]; const auto& route=allPassageSmoothRoutes[passageIndex]; + if(route.size()<2)continue; const auto densityMetres=[&](double x,double y,double z) { return static_cast(Shape.densityAt({x/coreMetres, @@ -3198,34 +3238,38 @@ namespace StandaloneStreamBenchmark } return (low+high)*0.5; }; - const std::array,2> targets={{ - {"rock-station-50",route.empty()?0.0:route.back().distance*0.5}, - {"open-air-section-3",1265.3425}}}; - for(const auto& [label,targetDistance]:targets) + constexpr std::array labels{{ + "route-station-25","route-station-50","route-station-75"}}; + for(std::size_t targetIndex=0;targetIndexroute.back().distance)continue; + const double targetDistance=route.back().distance + *static_cast(targetIndex+1)/4.0; + const char* label=labels[targetIndex]; const auto center=interpolatePassageRoute(route,targetDistance); const VoxelForgeCore::Vec3d centerVoxel={center.x/coreMetres, center.y/coreMetres,center.floorZ/coreMetres}; - std::printf("[L114DensityColumn] passage=%s section=%s x_m=%.6f y_m=%.6f planned_floor_m=%.6f dispatch=%s source_density_m=%.9f unclamped_density_m=%.9f\n", - passage->stableId.c_str(),label,center.x,center.y,center.floorZ, + std::printf("[L115DensityColumn] passage=%s station=%s route_s_m=%.3f route_length_m=%.3f x_m=%.6f y_m=%.6f planned_floor_m=%.6f dispatch=%s source_density_m=%.9f unclamped_density_m=%.9f\n", + passage.stableId.c_str(),label,targetDistance, + route.back().distance,center.x,center.y,center.floorZ, Shape.densityDispatchPathAt(centerVoxel).c_str(), static_cast(Shape.passageSourceDensityAt(centerVoxel))*coreMetres, static_cast(Shape.unclampedDensityAt(centerVoxel))*coreMetres); for(int sample=0;sample<=40;++sample) { const double offset=-0.50+sample*0.025; - std::printf("[L114DensityColumnSample] section=%s dz_m=%.3f density_m=%.9f\n", - label,offset,densityMetres(center.x,center.y, + std::printf("[L115DensityColumnSample] passage=%s station=%s dz_m=%.3f density_m=%.9f\n", + passage.stableId.c_str(),label,offset,densityMetres(center.x,center.y, center.floorZ+offset)); } for(int sample=-25;sample<=25;++sample) { - const double distance=targetDistance+sample*0.10; + const double distance=std::clamp(targetDistance + +sample*0.10,0.0,route.back().distance); const auto pose=interpolatePassageRoute(route,distance); const double root=floorRoot(pose); - std::printf("[L114DensitySlopeSample] section=%s s_m=%.3f x_m=%.6f y_m=%.6f planned_floor_m=%.6f root_floor_m=%.6f residual_m=%.6f density_minus_0p1_m=%.9f density_plane_m=%.9f density_plus_0p1_m=%.9f\n", - label,distance,pose.x,pose.y,pose.floorZ,root, + std::printf("[L115DensitySlopeSample] passage=%s station=%s s_m=%.3f x_m=%.6f y_m=%.6f planned_floor_m=%.6f root_floor_m=%.6f residual_m=%.6f density_minus_0p1_m=%.9f density_plane_m=%.9f density_plus_0p1_m=%.9f\n", + passage.stableId.c_str(),label,distance,pose.x,pose.y, + pose.floorZ,root, root-pose.floorZ, densityMetres(pose.x,pose.y,pose.floorZ-0.1), densityMetres(pose.x,pose.y,pose.floorZ), @@ -3240,6 +3284,13 @@ namespace StandaloneStreamBenchmark { constexpr double CornerBlendMetres=0.50; constexpr double WallReliefMetres=0.21; + const auto smoothMax=[](double left,double right,double radius) + { + if(!(radius>0.0))return std::max(left,right); + const double h=std::clamp(radius-std::abs(left-right),0.0,radius) + /radius; + return std::max(left,right)+h*h*h*(radius/6.0); + }; for(std::size_t passageIndex=0; passageIndexpassages.size();++passageIndex) { @@ -3247,9 +3298,12 @@ namespace StandaloneStreamBenchmark if(passage.controlPoints.size()<2)continue; const auto& route=allPassageSmoothRoutes[passageIndex]; if(route.size()<2)continue; - double bestDistance=std::numeric_limits::infinity(); - double bestRoundDistance=0.0,bestCenterZ=0.0; - std::size_t bestSegment=std::numeric_limits::max(); + double bestRoundDistance=std::numeric_limits::infinity(); + double bestFloorCenterDistanceSquared= + std::numeric_limits::infinity(); + double bestCenterZ=0.0,bestFloorCenterZ=0.0,bestRadius=0.0; + std::size_t bestTubeSegment=std::numeric_limits::max(); + std::size_t bestFloorSegment=std::numeric_limits::max(); for(std::size_t segment=1;segment1.0e-12 + ?((xMetres-a.x)*dx+(yMetres-a.y)*dy) + /horizontalLengthSquared + :std::clamp((zMetres-a.z)*dz/lengthSquared,0.0,1.0); + const double floorAlong=std::lerp(a.distance,b.distance,horizontalT); const double t=std::clamp(((xMetres-a.x)*dx+(yMetres-a.y)*dy +(zMetres-a.z)*dz)/lengthSquared,0.0,1.0); const double centerX=a.x+t*dx,centerY=a.y+t*dy,centerZ=a.z+t*dz; const double radius=std::lerp(a.radius,b.radius,t); - const double horizontalLengthSquared=dx*dx+dy*dy; - const double floorT=horizontalLengthSquared>1.0e-12 - ?std::clamp(((xMetres-a.x)*dx+(yMetres-a.y)*dy) - /horizontalLengthSquared,0.0,1.0):t; + const double ex=xMetres-centerX,ey=yMetres-centerY, + ez=zMetres-centerZ; + const double roundDistance=std::sqrt(ex*ex+ey*ey+ez*ez)-radius; + const double floorCenterDistanceSquared=ex*ex+ey*ey+ez*ez; + const auto floorPose=interpolatePassageRoute(route,floorAlong); const double floorCenterZ=passageFloorAtXY(passageIndex, - xMetres,yMetres,std::lerp(a.floorZ,b.floorZ,floorT)); - const double roundDistance=std::sqrt((xMetres-centerX)*(xMetres-centerX) - +(yMetres-centerY)*(yMetres-centerY) - +(zMetres-centerZ)*(zMetres-centerZ))-radius; - const double floorDistance=floorCenterZ-zMetres; - const double h=std::max(CornerBlendMetres- - std::abs(roundDistance-floorDistance),0.0)/CornerBlendMetres; - const double flatDistance=std::max(roundDistance,floorDistance) - +h*h*h*(CornerBlendMetres/6.0); - if(flatDistance::max())continue; - const auto& a=route[bestSegment-1]; - const auto& b=route[bestSegment]; + if(bestTubeSegment==std::numeric_limits::max())continue; + if(!std::isfinite(bestFloorCenterDistanceSquared))continue; + const double floorCenterZ=bestFloorCenterZ; + const double floorDistance=bestFloorCenterZ-zMetres; + // The composer uses the nearest round tube segment, then the + // nearest route station for its continuous floor plane. + const auto& a=route[bestTubeSegment-1]; + const auto& b=route[bestTubeSegment]; const double dx=b.x-a.x,dy=b.y-a.y,dz=b.z-a.z; const double lengthSquared=dx*dx+dy*dy+dz*dz; if(lengthSquared<=1.0e-12)continue; const double t=std::clamp(((xMetres-a.x)*dx+(yMetres-a.y)*dy +(zMetres-a.z)*dz)/lengthSquared,0.0,1.0); - const double radius=std::lerp(a.radius,b.radius,t); const double centerX=a.x+t*dx,centerY=a.y+t*dy; const double centerZ=a.z+t*dz; const double distanceToCenter=std::max(1.0e-9, - bestRoundDistance+radius); + bestRoundDistance+bestRadius); const double verticalWallAlignment=std::clamp( -(zMetres-centerZ)/distanceToCenter,0.0,1.0); - const auto& aFloor=route[bestSegment-1]; - const auto& bFloor=route[bestSegment]; - const double floorDx=bFloor.x-aFloor.x; - const double floorDy=bFloor.y-aFloor.y; - const double horizontalSquared=floorDx*floorDx+floorDy*floorDy; - const double floorT=horizontalSquared>1.0e-12 - ?std::clamp(((xMetres-aFloor.x)*floorDx - +(yMetres-aFloor.y)*floorDy)/horizontalSquared,0.0,1.0):t; - const double floorCenterZ=passageFloorAtXY(passageIndex, - xMetres,yMetres,std::lerp(aFloor.floorZ,bFloor.floorZ,floorT)); const double wallElevationMetres=zMetres-floorCenterZ; const double crestFade=std::clamp((1.0-wallElevationMetres)/0.25, 0.0,1.0); @@ -3325,11 +3389,8 @@ namespace StandaloneStreamBenchmark const double roughRoundDistance=bestRoundDistance +static_cast(std::clamp(relief,-1.0f,1.0f)) *WallReliefMetres*wallReliefWeight; - const double floorDistance=floorCenterZ-zMetres; - const double blend=std::max(CornerBlendMetres- - std::abs(roughRoundDistance-floorDistance),0.0)/CornerBlendMetres; - const double shapedDistance=std::max(roughRoundDistance,floorDistance) - +blend*blend*blend*(CornerBlendMetres/6.0); + const double shapedDistance=smoothMax(roughRoundDistance, + floorDistance,CornerBlendMetres); if(shapedDistance<=0.0)return true; } return false; @@ -4129,9 +4190,9 @@ namespace StandaloneStreamBenchmark std::uint64_t floorMouthBlendSkips=0,wallMouthBlendSkips=0; std::uint64_t interiorSamples=0,interiorViolations=0; std::vector openAirDistancesMetres; - std::array,8> firstViolations{}; + std::array,8> firstViolations{}; std::size_t firstViolationCount=0; - std::array,8> firstWallViolations{}; + std::array,8> firstWallViolations{}; std::size_t firstWallViolationCount=0; }; constexpr double PassageShellAuditSpacingMetres=0.25; @@ -4142,13 +4203,10 @@ namespace StandaloneStreamBenchmark { constexpr double CornerBlendMetres=0.50; constexpr double ReliefBoundMetres=0.21; - const auto smoothstep=[](double value) - { - value=std::clamp(value,0.0,1.0); - return value*value*(3.0-2.0*value); - }; - bool ambiguous=false,expectedSolid=false,mouthBlend=false; - if(passageInteriorWinsAt(xMetres,yMetres,zMetres))return 0; + double nearestWallShellDistance=std::numeric_limits::infinity(); + bool mouthBlend=false; + if(passageInteriorWinsAt(xMetres,yMetres,zMetres)) + return std::pair{0,nearestWallShellDistance}; for(std::size_t passageIndex=0; passageIndexpassages.size();++passageIndex) { @@ -4165,17 +4223,20 @@ namespace StandaloneStreamBenchmark const double dx=b.x-a.x,dy=b.y-a.y,dz=b.z-a.z; const double lengthSquared=dx*dx+dy*dy+dz*dz; if(lengthSquared<=1.0e-12)continue; + const double horizontalLengthSquared=dx*dx+dy*dy; + const double horizontalT=horizontalLengthSquared>1.0e-12 + ?((xMetres-ax)*dx+(yMetres-ay)*dy) + /horizontalLengthSquared + :std::clamp((zMetres-az)*dz/lengthSquared,0.0,1.0); + const double floorAlong=std::lerp(a.distance,b.distance,horizontalT); const double t=std::clamp(((xMetres-ax)*dx+(yMetres-ay)*dy +(zMetres-az)*dz)/lengthSquared,0.0,1.0); const double centerX=ax+t*dx,centerY=ay+t*dy,centerZ=az+t*dz; const double radius=std::lerp(a.radius,b.radius,t); - const double horizontalSquared=dx*dx+dy*dy; - const double floorT=horizontalSquared>1.0e-12 - ?std::clamp(((xMetres-ax)*dx+(yMetres-ay)*dy) - /horizontalSquared,0.0,1.0):t; - const double floorCenterZ=passageFloorAtXY(passageIndex, - xMetres,yMetres,std::lerp(a.floorZ,b.floorZ,floorT)); const double along=std::lerp(a.distance,b.distance,t); + const auto floorPose=interpolatePassageRoute(path,floorAlong); + const double floorCenterZ=passageFloorAtXY(passageIndex, + xMetres,yMetres,floorPose.floorZ); const double roundDistance=std::sqrt((xMetres-centerX)*(xMetres-centerX) +(yMetres-centerY)*(yMetres-centerY) +(zMetres-centerZ)*(zMetres-centerZ))-radius; @@ -4189,19 +4250,33 @@ namespace StandaloneStreamBenchmark if(flatDistance<=0.0)continue; const double fade=std::clamp(mouthDistance/5.0,0.0,1.0); const double smoothFade=fade*fade*(3.0-2.0*fade); - const double floorBlend=smoothstep(floorDistance/0.25); const double wallElevation=-floorDistance; const double wallThickness=wallElevation>=0.0&&wallElevation<=1.0 - ?smoothFade:0.0; - const double thickness=0.75*std::max(wallThickness, - smoothFade*floorBlend); - if(flatDistance+ReliefBoundMetres1.0e-9) + { + const double shellRadius=wallThickness*0.5; + const double capCenter=1.0-shellRadius; + const double x=flatDistance-shellRadius; + const double boxHalfHeight=capCenter*0.5; + const double boxX=std::abs(x)-shellRadius; + const double boxY=std::abs(wallElevation-boxHalfHeight) + -boxHalfHeight; + const double boxDistance=std::min(std::max(boxX,boxY),0.0) + +std::hypot(std::max(boxX,0.0),std::max(boxY,0.0)); + const double capDistance=std::hypot(x,wallElevation-capCenter) + -shellRadius; + nearestWallShellDistance=std::min(nearestWallShellDistance, + std::min(boxDistance,capDistance)); + } else if(mouthDistance<5.0)mouthBlend=true; } } - if(expectedSolid)return 1; - return ambiguous||mouthBlend?-1:0; + if(nearestWallShellDistance<-ReliefBoundMetres) + return std::pair{1,nearestWallShellDistance}; + if(nearestWallShellDistance{-1,nearestWallShellDistance}; + return std::pair{0,nearestWallShellDistance}; }; const auto auditPassageShell=[&](const VoxelForgeCore::World& Field, const VoxelForgeCore::World& Native, @@ -4216,16 +4291,66 @@ namespace StandaloneStreamBenchmark constexpr std::array,5> floorOffsets{{ {{0.0,0.0}},{{0.30,0.0}},{{-0.30,0.0}}, {{0.0,0.30}},{{0.0,-0.30}}}}; - const auto expectedFloorThickness=[&](double along,double floorDistance) + const auto expectedFloorShellMarginAt=[&](double xMetres, + double yMetres,double zMetres) { - const double mouthDistance=std::max(0.0,std::min(along, - totalRouteLength-along)); - const double fade=std::clamp(mouthDistance/5.0,0.0,1.0); - const double smoothFade=fade*fade*(3.0-2.0*fade); - const double floorBlend=std::clamp(floorDistance/0.25,0.0,1.0); - const double smoothFloorBlend=floorBlend*floorBlend - *(3.0-2.0*floorBlend); - return 0.75*smoothFade*smoothFloorBlend; + constexpr double CornerBlendMetres=0.50; + double minimumShellDistance=std::numeric_limits::infinity(); + for(std::size_t candidatePassage=0; + candidatePassage1.0e-12 + ?((xMetres-a.x)*dx+(yMetres-a.y)*dy) + /horizontalLengthSquared:t; + const double centerX=a.x+t*dx,centerY=a.y+t*dy, + centerZ=a.z+t*dz; + const double radius=std::lerp(a.radius,b.radius,t); + const double along=std::lerp(a.distance,b.distance,t); + const double floorAlong=std::lerp(a.distance,b.distance,floorT); + const double plannedFloor=passageFloorAtXY(candidatePassage, + xMetres,yMetres,interpolatePassageRoute(candidateRoute, + floorAlong).floorZ); + const double roundDistance=std::sqrt( + (xMetres-centerX)*(xMetres-centerX) + +(yMetres-centerY)*(yMetres-centerY) + +(zMetres-centerZ)*(zMetres-centerZ))-radius; + const double floorDistance=plannedFloor-zMetres; + const double blend=std::max(CornerBlendMetres + -std::abs(roundDistance-floorDistance),0.0) + /CornerBlendMetres; + const double flatDistance=std::max(roundDistance,floorDistance) + +blend*blend*blend*(CornerBlendMetres/6.0); + const double mouthDistance=std::max(0.0,std::min(along, + candidateLength-along)); + const double fade=std::clamp(mouthDistance/5.0,0.0,1.0); + const double smoothFade=fade*fade*(3.0-2.0*fade); + const double floorBlend=std::clamp(floorDistance/0.25,0.0,1.0); + const double smoothFloorBlend=floorBlend*floorBlend + *(3.0-2.0*floorBlend); + const double thickness=0.75*smoothFade*smoothFloorBlend; + const double shellDistance=std::max(-flatDistance, + flatDistance-thickness); + minimumShellDistance=std::min(minimumShellDistance, + shellDistance); + } + } + return minimumShellDistance; }; for(std::size_t segment=1;segment1.0e-12 - ?std::clamp(((sampleX-a.x)*dx+(sampleY-a.y)*dy) - /horizontalLengthSquared,0.0,1.0):t; - const double floorZ=passageFloorAtXY(passageIndex, - sampleX,sampleY,std::lerp(a.floorZ,b.floorZ,floorT)); + double floorZ=passageFloorAtXY(passageIndex, + sampleX,sampleY,interpolatePassageRoute(route,along).floorZ); + FPassageRouteProjection floorProjection; + for(int projectionStep=0;projectionStep<2;++projectionStep) + { + floorProjection=projectPassageRoute(route,sampleX,sampleY, + floorZ-depth); + const auto floorPose=interpolatePassageRoute(route, + floorProjection.centerAlong); + floorZ=passageFloorAtXY(passageIndex,sampleX,sampleY, + floorPose.floorZ); + } const VoxelForgeCore::Vec3d position{ sampleX/coreMetres,sampleY/coreMetres, (floorZ-depth)/coreMetres}; @@ -4271,8 +4402,14 @@ namespace StandaloneStreamBenchmark { ++audit.openAirSamples; audit.openAirDistancesMetres.push_back(along); - const bool shellExpected=depth+0.011 - =PassageShellDensityTolerance) ||(!shellExpected&&density<-PassageShellDensityTolerance)) @@ -4280,7 +4417,10 @@ namespace StandaloneStreamBenchmark ++audit.floorViolations; if(audit.firstViolationCount wallProbes{{ {0.0,0.0,true},{-1.0,0.25,false},{1.0,0.25,false}, @@ -4313,12 +4453,21 @@ namespace StandaloneStreamBenchmark const double wallRadius=std::sqrt(wallRadiusSquared); sampleX+=nx*probe.side*(wallRadius+0.375); sampleY+=ny*probe.side*(wallRadius+0.375); + for(int projectionStep=0;projectionStep<2;++projectionStep) + { + sampleZ=floorZ+probe.height; + const auto floorProjection=projectPassageRoute(route, + sampleX,sampleY,sampleZ); + const auto floorPose=interpolatePassageRoute(route, + floorProjection.centerAlong); + floorZ=passageFloorAtXY(passageIndex,sampleX,sampleY, + floorPose.floorZ); + } sampleZ=floorZ+probe.height; } const VoxelForgeCore::Vec3d wallPosition{sampleX/coreMetres, sampleY/coreMetres,sampleZ/coreMetres}; - if(passageInteriorWinsAt(sampleX,sampleY,sampleZ, - passageIndex,b.segmentIndex)) + if(passageInteriorWinsAt(sampleX,sampleY,sampleZ)) { ++audit.wallInteriorWins; continue; @@ -4328,8 +4477,8 @@ namespace StandaloneStreamBenchmark ++audit.wallSamples; audit.openAirDistancesMetres.push_back(along); const float density=Field.densityAt(wallPosition); - const int shellExpected=expectedPassageShellAt( - sampleX,sampleY,sampleZ); + const auto [shellExpected,wallShellMargin]= + expectedPassageShellAt(sampleX,sampleY,sampleZ); if(shellExpected>=0 &&((shellExpected==1 &&density>=PassageShellDensityTolerance) @@ -4340,7 +4489,9 @@ namespace StandaloneStreamBenchmark if(audit.firstWallViolationCount (Shape.passageSourceDensityAt({ + sample[0]/coreMetres,sample[1]/coreMetres, + sample[2]/coreMetres})), + static_cast(Shape.unclampedDensityAt({ + sample[0]/coreMetres,sample[1]/coreMetres, + sample[2]/coreMetres}))); } for(std::size_t i=0;i tuple[Path, str]: if recipe == "surface-world" and style == 1: - return (BASELINES / "owner-hash/canonical/owner-hash-surface-world-style1-v222.baseline", - "L114-v222-local-passage-floor-profile") + return (BASELINES / "owner-hash/canonical/owner-hash-surface-world-style1-v223.baseline", + "L115-v223-continuous-arc-length-floor-profile") if recipe == "floating-islands" and style == 2: - return (BASELINES / "owner-hash/canonical/owner-hash-floating-islands-style2-v222.baseline", - "L114-v222-local-passage-floor-profile") + return (BASELINES / "owner-hash/canonical/owner-hash-floating-islands-style2-v223.baseline", + "L115-v223-continuous-arc-length-floor-profile") raise VerificationFailure(f"no pinned owner hash baseline for {recipe} style {style}")