Files
VoxelForge/Standalone/Source/StreamBenchmarkPipeline.h
T
Fr0zkaandClaude Opus 5.5 ca85e876ad feat(core): ore vein records and a materialAt query, off by default (L50); research R18, R19
Versioned capsule vein records (stable ID, resource ID, endpoints, radius, seeded irregularity) resolved
into the snapshot only when requested, placed beside the route and away from passages, landings and
landmarks (forced-passage control rejected). The bound field table gains materialAt (host + two resource
IDs + Q16 weights) behind a per-tile BVH; mesh export v2 carries per-vertex materials; a measurement-only
yield computes removed resource volume (0 on already-air space). With veins on, every density, mesh,
payload and topology hash is unchanged; demo off: owner hashes identical to L47. fast/medium/full PASS.
Research R18 (cavern-graph planner) and R19 (why FloatingIslands costs ~10x SurfaceWorld).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016dhxM43dnWvUu2B5Ph1iG1
2026-10-24 18:25:03 +02:00

4786 lines
300 KiB
C++

#pragma once
#include "OwnerWorldLoader.h"
#include "StreamingWorld.h"
#include "LinuxScreenSpaceGate.h"
#include <algorithm>
#include <array>
#include <bit>
#include <chrono>
#include <cmath>
#include <cstdint>
#include <ctime>
#include <cstdio>
#include <filesystem>
#include <fstream>
#include <future>
#include <limits>
#include <numeric>
#include <queue>
#include <string_view>
#include <thread>
#include <unordered_map>
#include <unordered_set>
#include <vector>
namespace StandaloneStreamBenchmark
{
struct FRouteDensityComparison
{
std::uint64_t samples=0;
std::uint64_t signMismatches=0;
std::uint64_t crossingEdgeMismatches=0;
std::uint64_t sharedCrossingEdges=0;
std::uint64_t exactQuerySamples=0;
std::uint64_t exactQueryMismatches=0;
double maxAbsoluteDelta=0.0;
double sumAbsoluteDelta=0.0;
double maxSurfaceDisplacementVoxels=0.0;
double sumSurfaceDisplacementVoxels=0.0;
bool valid=false;
};
inline FRouteDensityComparison CompareRouteDensities(
const VoxelForgeCore::TileMesh& A,const VoxelForgeCore::TileMesh& B,
const VoxelForgeCore::World& World)
{
FRouteDensityComparison Result;
if(A.debugDensitySamples.empty()
||A.debugDensitySamples.size()!=B.debugDensitySamples.size())return Result;
const double Root=std::cbrt(static_cast<double>(A.debugDensitySamples.size()));
const std::int32_t Dim=static_cast<std::int32_t>(std::llround(Root));
if(Dim<4||static_cast<std::size_t>(Dim)*Dim*Dim!=A.debugDensitySamples.size())return Result;
const std::int32_t GridDim=Dim-3;
const std::int32_t Extent=CHUNK_SIZE<<A.key.lod;
if(GridDim<=0||Extent%GridDim!=0)return Result;
const std::int32_t Step=Extent/GridDim;
const FVoxelTileKey NativeKey(
FIntVector(A.key.coordinate.x,A.key.coordinate.y,A.key.coordinate.z),A.key.lod);
const FIntVector Origin=NativeKey.OriginVoxels();
const auto Index=[Dim](std::int32_t X,std::int32_t Y,std::int32_t Z)
{return (static_cast<std::size_t>(Z)*Dim+Y)*Dim+X;};
const auto IsSolid=[](float Density){return Density<0.0f;};
const auto EdgeCrosses=[&](const std::vector<float>& Values,
std::int32_t X0,std::int32_t Y0,std::int32_t Z0,
std::int32_t X1,std::int32_t Y1,std::int32_t Z1)
{
return IsSolid(Values[Index(X0,Y0,Z0)])!=IsSolid(Values[Index(X1,Y1,Z1)]);
};
for(std::int32_t Z=0;Z<Dim;++Z)
for(std::int32_t Y=0;Y<Dim;++Y)
for(std::int32_t X=0;X<Dim;++X)
{
const std::size_t I=Index(X,Y,Z);
const float DA=A.debugDensitySamples[I],DB=B.debugDensitySamples[I];
if(!std::isfinite(DA)||!std::isfinite(DB))return Result;
const double Delta=std::abs(static_cast<double>(DA)-DB);
Result.maxAbsoluteDelta=std::max(Result.maxAbsoluteDelta,Delta);
Result.sumAbsoluteDelta+=Delta;
Result.signMismatches+=IsSolid(DA)!=IsSolid(DB)?1u:0u;
++Result.samples;
const std::int32_t WorldX=Origin.X+(X-1)*Step;
const std::int32_t WorldY=Origin.Y+(Y-1)*Step;
const std::int32_t WorldZ=Origin.Z+(Z-1)*Step;
const VoxelForgeCore::Vec3i Lattice{WorldX,WorldY,WorldZ};
const float ExactLattice=World.densityAtLattice(Lattice);
const float ExactPoint=World.densityAt({static_cast<double>(WorldX),
static_cast<double>(WorldY),static_cast<double>(WorldZ)});
++Result.exactQuerySamples;
if(std::bit_cast<std::uint32_t>(DA)!=std::bit_cast<std::uint32_t>(ExactLattice)
||std::bit_cast<std::uint32_t>(DA)!=std::bit_cast<std::uint32_t>(ExactPoint))
++Result.exactQueryMismatches;
}
const auto CompareEdge=[&](std::int32_t X0,std::int32_t Y0,std::int32_t Z0,
std::int32_t X1,std::int32_t Y1,std::int32_t Z1)
{
const bool CrossA=EdgeCrosses(A.debugDensitySamples,X0,Y0,Z0,X1,Y1,Z1);
const bool CrossB=EdgeCrosses(B.debugDensitySamples,X0,Y0,Z0,X1,Y1,Z1);
if(CrossA!=CrossB)++Result.crossingEdgeMismatches;
if(!CrossA||!CrossB)return;
const float A0=A.debugDensitySamples[Index(X0,Y0,Z0)];
const float A1=A.debugDensitySamples[Index(X1,Y1,Z1)];
const float B0=B.debugDensitySamples[Index(X0,Y0,Z0)];
const float B1=B.debugDensitySamples[Index(X1,Y1,Z1)];
const double TA=static_cast<double>(A0)/(static_cast<double>(A0)-A1);
const double TB=static_cast<double>(B0)/(static_cast<double>(B0)-B1);
const double Displacement=std::abs(TA-TB)*Step;
Result.maxSurfaceDisplacementVoxels=std::max(
Result.maxSurfaceDisplacementVoxels,Displacement);
Result.sumSurfaceDisplacementVoxels+=Displacement;
++Result.sharedCrossingEdges;
};
for(std::int32_t Z=0;Z<Dim;++Z)
for(std::int32_t Y=0;Y<Dim;++Y)
for(std::int32_t X=0;X<Dim;++X)
{
if(X+1<Dim)CompareEdge(X,Y,Z,X+1,Y,Z);
if(Y+1<Dim)CompareEdge(X,Y,Z,X,Y+1,Z);
if(Z+1<Dim)CompareEdge(X,Y,Z,X,Y,Z+1);
}
Result.valid=true;
return Result;
}
struct FLandmarkReachabilityResult
{
std::uint64_t pathSamples=0,capsuleSamples=0,blockedCapsuleSamples=0;
std::uint64_t supportSamples=0,unsupportedSamples=0,gradeFailures=0;
double maximumGradeDegrees=0.0,maximumSupportDepthMetres=0.0;
double minimumClearanceMetres=std::numeric_limits<double>::infinity();
double minimumHeadroomMetres=std::numeric_limits<double>::infinity();
double latestPointMinimumClearanceMetres=std::numeric_limits<double>::infinity();
std::array<double,3> latestPointMinimumClearancePosition{};
bool passed=false;
};
inline FLandmarkReachabilityResult AuditLandmarkWalkPath(
const VoxelForgeCore::World& shape,
const VoxelForgeCore::WorldAssemblyManifest* assembly,
const VoxelForgeCore::ResolvedLayoutSnapshotV3& layout,
std::uint32_t coreVoxelSizeMicrometres,std::string_view label)
{
FLandmarkReachabilityResult result;
const auto surface=std::find_if(layout.strates.begin(),layout.strates.end(),
[](const auto& value){return value.generatorKind=="SurfaceWorld";});
if(surface==layout.strates.end())return result;
const auto passage=std::find_if(layout.passages.begin(),layout.passages.end(),
[&](const auto& value){return value.lowerStrateIndex==surface->strateIndex;});
if(passage==layout.passages.end()||assembly==nullptr)return result;
const auto surfacePlan=std::find_if(assembly->plan.strates.begin(),assembly->plan.strates.end(),
[&](const auto& value){return value.strateIndex==surface->strateIndex;});
if(surfacePlan==assembly->plan.strates.end())return result;
const VoxelForgeCore::Heightfield2D surfaceField(assembly->recipe,*surfacePlan);
if(!surfaceField.isValid())return result;
const auto tunnel=std::find_if(layout.cavernEdges.begin(),layout.cavernEdges.end(),
[](const auto& edge)
{return edge.stableId=="landmark/sw-arrival-chamber-tunnel-v1";});
std::vector<const VoxelForgeCore::ResolvedLayoutStampV1*> legacyRamp;
if(tunnel==layout.cavernEdges.end())
{
for(const auto& stamp:layout.stamps)
if(stamp.stableId.starts_with("landmark/sw-arrival-chamber-ramp-"))
legacyRamp.push_back(&stamp);
std::sort(legacyRamp.begin(),legacyRamp.end(),[](const auto* a,const auto* b)
{return a->stableId<b->stableId;});
if(legacyRamp.size()<2)return result;
}
const double voxelMetres=static_cast<double>(std::max<std::uint32_t>(1,
coreVoxelSizeMicrometres))/1000000.0;
const double metresPerSubvoxel=voxelMetres
/VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel;
struct FPathPoint { double x=0.0,y=0.0,z=0.0;bool tunnel=false; };
std::vector<FPathPoint> path;
const auto& arrival=passage->lowerMouthSubvoxels;
const double arrivalX=arrival[0]*metresPerSubvoxel;
const double arrivalY=arrival[1]*metresPerSubvoxel;
const double arrivalCenterZ=arrival[2]*metresPerSubvoxel+0.9;
const auto densityMetres=[&](double x,double y,double z)
{
return static_cast<double>(shape.densityAt({x/voxelMetres,
y/voxelMetres,z/voxelMetres}))*voxelMetres;
};
const auto samplePoint=[&](double x,double y,double centerZ,bool inTunnel,
bool measureHeadroom=false)
{
constexpr double FloorStep=0.01;
double floorZ=centerZ-5.0;
bool foundFloor=false;
if(inTunnel)
{
if(densityMetres(x,y,centerZ)>0.025)
for(double offset=-0.10;offset>=-10.0;offset-=FloorStep)
if(densityMetres(x,y,centerZ+offset)<0.0)
{floorZ=centerZ+offset+FloorStep;foundFloor=true;break;}
}
else
{
const auto xSubvoxels=static_cast<std::int64_t>(std::llround(x/metresPerSubvoxel));
const auto ySubvoxels=static_cast<std::int64_t>(std::llround(y/metresPerSubvoxel));
floorZ=surfaceField.point(xSubvoxels,ySubvoxels,0).groundHeightSubvoxels
*metresPerSubvoxel;
foundFloor=std::isfinite(floorZ);
}
++result.pathSamples;
if(!foundFloor)
{
++result.unsupportedSamples;
return std::pair<double,bool>{floorZ,false};
}
// Reserve a footfall margin above the sampled ground for the vertical
// capsule; it prevents the lower hemisphere from grazing adjacent floor
// samples on a gently sloped ramp.
floorZ+=0.15;
constexpr double CapsuleRadius=0.34;
constexpr double CapsuleHeight=1.76;
constexpr double RequiredClearance=0.025;
constexpr double VerticalStep=0.18;
constexpr double HorizontalStep=0.17;
result.latestPointMinimumClearanceMetres=std::numeric_limits<double>::infinity();
for(double height=0.08;height<=CapsuleHeight;height+=VerticalStep)
{
double capOffset=0.0;
if(height<CapsuleRadius)capOffset=CapsuleRadius-height;
else if(height>CapsuleHeight-CapsuleRadius)
capOffset=height-(CapsuleHeight-CapsuleRadius);
const double radial=std::sqrt(std::max(0.0,
CapsuleRadius*CapsuleRadius-capOffset*capOffset));
for(double oy=-radial;oy<=radial+1.0e-9;oy+=HorizontalStep)
for(double ox=-radial;ox<=radial+1.0e-9;ox+=HorizontalStep)
{
if(ox*ox+oy*oy>radial*radial+1.0e-9)continue;
const double clearance=densityMetres(x+ox,y+oy,floorZ+height);
++result.capsuleSamples;
result.minimumClearanceMetres=std::min(
result.minimumClearanceMetres,clearance);
if(clearance<result.latestPointMinimumClearanceMetres)
{
result.latestPointMinimumClearanceMetres=clearance;
result.latestPointMinimumClearancePosition={x+ox,y+oy,floorZ+height};
}
if(clearance<RequiredClearance)++result.blockedCapsuleSamples;
}
}
if(measureHeadroom)
{
constexpr std::array<std::array<double,2>,5> headOffsets={{{0.0,0.0},
{0.24,0.0},{-0.24,0.0},{0.0,0.24},{0.0,-0.24}}};
constexpr double HeadStep=0.05,HeadLimit=4.0;
for(const auto& offset:headOffsets)
{
double headroom=HeadLimit;
for(double rise=0.0;rise<=HeadLimit;rise+=HeadStep)
if(densityMetres(x+offset[0],y+offset[1],
floorZ+CapsuleHeight+rise)<0.0)
{headroom=std::max(0.0,rise-HeadStep);break;}
result.minimumHeadroomMetres=std::min(
result.minimumHeadroomMetres,headroom);
}
}
const std::array<std::array<double,2>,5> supportOffsets={{{0.0,0.0},
{0.28,0.0},{-0.28,0.0},{0.0,0.28},{0.0,-0.28}}};
std::uint32_t supported=0;
for(const auto& offset:supportOffsets)
{
++result.supportSamples;
bool hit=false;
for(double depth=0.10;depth<=0.55;depth+=0.08)
if(densityMetres(x+offset[0],y+offset[1],floorZ-depth)<0.0)
{hit=true;result.maximumSupportDepthMetres=std::max(
result.maximumSupportDepthMetres,depth);break;}
if(hit)++supported;
}
const bool supportOk=supported>=3;
if(!supportOk)++result.unsupportedSamples;
return std::pair<double,bool>{floorZ,supportOk};
};
// Find a walkable surface route around the passage's support rock. The nearby grid is
// evaluated against the same composed density field as the ramp and both L43/L45 runs.
constexpr int GridRadius=52;
constexpr int GridWidth=GridRadius*2+1;
constexpr double GridStep=0.50;
constexpr double MaximumGradeRadians=15.0*3.14159265358979323846/180.0;
struct FSurfaceNode
{
bool evaluated=false,walkable=false,closed=false;
double floorZ=0.0,cost=std::numeric_limits<double>::infinity();
int parent=-1;
};
const double edgeStartX=tunnel!=layout.cavernEdges.end()
?tunnel->controlPointsMicrometres[0][0]/1000000.0
:legacyRamp.front()->positionMicrometres[0]/1000000.0;
const double edgeStartY=tunnel!=layout.cavernEdges.end()
?tunnel->controlPointsMicrometres[0][1]/1000000.0
:legacyRamp.front()->positionMicrometres[1]/1000000.0;
const int goalX=GridRadius+static_cast<int>(std::llround(
(edgeStartX-arrivalX)/GridStep));
const int goalY=GridRadius+static_cast<int>(std::llround(
(edgeStartY-arrivalY)/GridStep));
const auto nodeIndex=[](int x,int y){return y*GridWidth+x;};
std::vector<FSurfaceNode> surfaceNodes(static_cast<std::size_t>(GridWidth*GridWidth));
std::uint64_t exploredNodes=0;
const auto evaluateNode=[&](int ix,int iy)->FSurfaceNode*
{
if(ix<0||iy<0||ix>=GridWidth||iy>=GridWidth)return nullptr;
auto& node=surfaceNodes[static_cast<std::size_t>(nodeIndex(ix,iy))];
if(node.evaluated)return &node;
node.evaluated=true;++exploredNodes;
const double x=arrivalX+(ix-GridRadius)*GridStep;
const double y=arrivalY+(iy-GridRadius)*GridStep;
const auto blockedBefore=result.blockedCapsuleSamples;
const auto unsupportedBefore=result.unsupportedSamples;
const auto pathBefore=result.pathSamples;
const double scanCenter=arrivalCenterZ;
const auto [floorZ,supported]=samplePoint(x,y,scanCenter,false);
node.floorZ=floorZ;
node.walkable=supported&&result.pathSamples>pathBefore
&&result.blockedCapsuleSamples==blockedBefore
&&result.unsupportedSamples==unsupportedBefore;
return &node;
};
struct FOpenNode { double score=0.0;int index=0; };
const auto farther=[](const FOpenNode& a,const FOpenNode& b)
{return a.score>b.score;};
std::priority_queue<FOpenNode,std::vector<FOpenNode>,decltype(farther)> open(farther);
const int goalIndex=goalX>=0&&goalY>=0&&goalX<GridWidth&&goalY<GridWidth
?nodeIndex(goalX,goalY):-1;
if(goalIndex>=0)
{
constexpr double GroundStartRadius=18.0;
const int sourceRadius=static_cast<int>(std::ceil(GroundStartRadius/GridStep));
for(int iy=GridRadius-sourceRadius;iy<=GridRadius+sourceRadius;++iy)
for(int ix=GridRadius-sourceRadius;ix<=GridRadius+sourceRadius;++ix)
{
const double dx=(ix-GridRadius)*GridStep,dy=(iy-GridRadius)*GridStep;
const double distance=std::hypot(dx,dy);
if(distance>GroundStartRadius)continue;
auto* start=evaluateNode(ix,iy);
if(!start||!start->walkable)continue;
start->cost=distance;start->parent=-1;
open.push({distance+GridStep*std::hypot(goalX-ix,goalY-iy),
nodeIndex(ix,iy)});
}
constexpr std::array<std::array<int,2>,8> neighbours={{{1,0},{-1,0},{0,1},{0,-1},
{1,1},{1,-1},{-1,1},{-1,-1}}};
while(!open.empty())
{
const int currentIndex=open.top().index;open.pop();
auto& current=surfaceNodes[static_cast<std::size_t>(currentIndex)];
if(current.closed)continue;
current.closed=true;
if(currentIndex==goalIndex)break;
const int currentX=currentIndex%GridWidth,currentY=currentIndex/GridWidth;
for(const auto& direction:neighbours)
{
const int nextX=currentX+direction[0],nextY=currentY+direction[1];
auto* next=evaluateNode(nextX,nextY);
if(!next||!next->walkable||next->closed)continue;
const double run=GridStep*std::hypot(direction[0],direction[1]);
const double rise=std::abs(next->floorZ-current.floorZ);
if(std::atan2(rise,run)>MaximumGradeRadians)continue;
if(direction[0]!=0&&direction[1]!=0)
{
const auto* sideA=evaluateNode(currentX+direction[0],currentY);
const auto* sideB=evaluateNode(currentX,currentY+direction[1]);
if(!sideA||!sideA->walkable||!sideB||!sideB->walkable)continue;
}
const double cost=current.cost+run+rise*0.25;
if(cost>=next->cost)continue;
next->cost=cost;next->parent=currentIndex;
const double heuristic=GridStep*std::hypot(goalX-nextX,goalY-nextY);
open.push({cost+heuristic,nodeIndex(nextX,nextY)});
}
}
}
std::vector<int> surfaceRoute;
if(goalIndex>=0&&surfaceNodes[static_cast<std::size_t>(goalIndex)].closed)
{
for(int current=goalIndex;current>=0;current=surfaceNodes[static_cast<std::size_t>(current)].parent)
surfaceRoute.push_back(current);
std::reverse(surfaceRoute.begin(),surfaceRoute.end());
}
const bool surfaceGoalWalkable=goalIndex>=0
&&evaluateNode(goalX,goalY)->walkable;
if(surfaceRoute.size()<2)surfaceRoute.clear();
const auto surfaceRouteSamples=surfaceRoute.size();
double surfaceStartDistance=std::numeric_limits<double>::infinity();
if(!surfaceRoute.empty())
{
path.reserve(surfaceRoute.size()+128);
const int startX=surfaceRoute.front()%GridWidth;
const int startY=surfaceRoute.front()/GridWidth;
surfaceStartDistance=GridStep*std::hypot(startX-GridRadius,startY-GridRadius);
for(const int index:surfaceRoute)
{
const int ix=index%GridWidth,iy=index/GridWidth;
const auto& node=surfaceNodes[static_cast<std::size_t>(index)];
path.push_back({arrivalX+(ix-GridRadius)*GridStep,
arrivalY+(iy-GridRadius)*GridStep,node.floorZ+0.9,false});
}
if(tunnel!=layout.cavernEdges.end())
{
const auto curveValue=[&](double t,std::size_t axis)
{
const double one=1.0-t;
return (one*one*one*tunnel->controlPointsMicrometres[0][axis]
+3.0*one*one*t*tunnel->controlPointsMicrometres[1][axis]
+3.0*one*t*t*tunnel->controlPointsMicrometres[2][axis]
+t*t*t*tunnel->controlPointsMicrometres[3][axis])/1000000.0;
};
double curveLength=0.0,previousCurveX=curveValue(0.0,0),previousCurveY=curveValue(0.0,1);
for(int sample=1;sample<=128;++sample)
{
const double t=static_cast<double>(sample)/128.0;
const double x=curveValue(t,0),y=curveValue(t,1);
curveLength+=std::hypot(x-previousCurveX,y-previousCurveY);
previousCurveX=x;previousCurveY=y;
}
const int curveSteps=std::max(2,static_cast<int>(std::ceil(curveLength/0.60)));
for(int sample=0;sample<=curveSteps;++sample)
{
const double t=static_cast<double>(sample)/curveSteps;
path.push_back({curveValue(t,0),curveValue(t,1),
curveValue(t,2)+0.9,true});
}
}
else
{
for(const auto* stamp:legacyRamp)
path.push_back({stamp->positionMicrometres[0]/1000000.0,
stamp->positionMicrometres[1]/1000000.0,
stamp->positionMicrometres[2]/1000000.0,true});
}
}
std::printf("[LandmarkSurfaceRoute] reachable=%s goal_walkable=%s grid_step_m=%.2f start_offset_m=%.2f explored=%llu surface_points=%zu grade_limit_deg=15.000\n",
surfaceRoute.empty()?"false":"true",surfaceGoalWalkable?"true":"false",GridStep,surfaceStartDistance,
static_cast<unsigned long long>(exploredNodes),surfaceRouteSamples);
result={};
if(path.size()<2)return result;
bool allSupport=true,allGrade=true;
bool havePrior=false;double priorX=0.0,priorY=0.0,priorFloor=0.0;
std::size_t diagnosticCount=0;
for(std::size_t segment=1;segment<path.size();++segment)
{
const auto& from=path[segment-1];const auto& to=path[segment];
const double horizontal=std::hypot(to.x-from.x,to.y-from.y);
const std::size_t steps=std::max<std::size_t>(1,
static_cast<std::size_t>(std::ceil(horizontal/0.8)));
for(std::size_t step=segment==1?0:1;step<=steps;++step)
{
const double t=static_cast<double>(step)/steps;
const double x=from.x+(to.x-from.x)*t;
const double y=from.y+(to.y-from.y)*t;
const double centerZ=from.z+(to.z-from.z)*t;
const auto blockedBefore=result.blockedCapsuleSamples;
const auto capsuleBefore=result.capsuleSamples;
const auto supportBefore=result.supportSamples;
const bool tunnel=from.tunnel&&to.tunnel;
const auto [floorZ,supportOk]=samplePoint(x,y,centerZ,tunnel,true);
allSupport&=supportOk;
double grade=0.0;
if(havePrior)
{
const double run=std::hypot(x-priorX,y-priorY);
grade=run>1.0e-6
?std::atan2(std::abs(floorZ-priorFloor),run)*180.0/3.14159265358979323846
:std::numeric_limits<double>::infinity();
result.maximumGradeDegrees=std::max(result.maximumGradeDegrees,grade);
if(grade>15.0) {++result.gradeFailures;allGrade=false;}
}
if(diagnosticCount<16&&(result.blockedCapsuleSamples>blockedBefore
||!supportOk||grade>15.0))
{
std::printf("[LandmarkWalkPoint] field=%.*s mode=%s x=%.3f y=%.3f center_z=%.3f floor_z=%.3f previous_x=%.3f previous_y=%.3f previous_floor_z=%.3f horizontal_step_m=%.3f blocked=%llu/%llu support_probes=%llu grade_deg=%.3f density_center_m=%.3f capsule_min_m=%.3f capsule_min_at_m=(%.3f,%.3f,%.3f)\n",
static_cast<int>(label.size()),label.data(),tunnel?"tunnel":"surface",x,y,centerZ,floorZ,
priorX,priorY,priorFloor,std::hypot(x-priorX,y-priorY),
static_cast<unsigned long long>(result.blockedCapsuleSamples-blockedBefore),
static_cast<unsigned long long>(result.capsuleSamples-capsuleBefore),
static_cast<unsigned long long>(result.supportSamples-supportBefore),
grade,densityMetres(x,y,centerZ),result.latestPointMinimumClearanceMetres,
result.latestPointMinimumClearancePosition[0],
result.latestPointMinimumClearancePosition[1],
result.latestPointMinimumClearancePosition[2]);
++diagnosticCount;
}
havePrior=true;priorX=x;priorY=y;priorFloor=floorZ;
}
}
result.passed=result.pathSamples>1&&result.capsuleSamples>0
&&result.blockedCapsuleSamples==0&&allSupport&&allGrade
&&result.unsupportedSamples==0&&result.gradeFailures==0
&&result.minimumHeadroomMetres>=0.300;
return result;
}
struct FLandmarkTunnelRippleResult
{
std::size_t floorSamples=0,entranceFloorSamples=0,wallSamples=0;
double floorPeakPeriodMetres=0.0,floorPeakAmplitudeMetres=0.0;
double entranceFloorMaxStepMetres=0.0;
double entranceFloorWorstDistanceMetres=0.0;
double entranceFloorPriorResidualMetres=0.0,entranceFloorCurrentResidualMetres=0.0;
std::size_t entranceFloorWorstTrack=0;
double wallPeakPeriodMetres=0.0,wallPeakAmplitudeMetres=0.0;
bool valid=false,passed=false;
};
inline FLandmarkTunnelRippleResult AuditLandmarkTunnelRipples(
const VoxelForgeCore::World& shape,
const VoxelForgeCore::ResolvedLayoutSnapshotV3& layout,
std::uint32_t coreVoxelSizeMicrometres)
{
FLandmarkTunnelRippleResult result;
const double voxelMetres=static_cast<double>(std::max<std::uint32_t>(1,
coreVoxelSizeMicrometres))/1000000.0;
const auto densityMetres=[&](double x,double y,double z)
{return static_cast<double>(shape.densityAt({x/voxelMetres,y/voxelMetres,
z/voxelMetres}))*voxelMetres;};
struct FRoutePoint { double x=0.0,y=0.0,floor=0.0; };
std::vector<FRoutePoint> route;
const auto edge=std::find_if(layout.cavernEdges.begin(),layout.cavernEdges.end(),
[](const auto& value)
{return value.stableId=="landmark/sw-arrival-chamber-tunnel-v1";});
if(edge!=layout.cavernEdges.end())
{
constexpr int CurveSamples=512;
route.reserve(CurveSamples+1);
for(int index=0;index<=CurveSamples;++index)
{
const double t=static_cast<double>(index)/CurveSamples,one=1.0-t;
const std::array<double,4> weights={one*one*one,3.0*one*one*t,
3.0*one*t*t,t*t*t};
FRoutePoint point;
point.x=point.y=point.floor=0.0;
for(std::size_t control=0;control<4;++control)
{
point.x+=weights[control]*edge->controlPointsMicrometres[control][0]/1e6;
point.y+=weights[control]*edge->controlPointsMicrometres[control][1]/1e6;
point.floor+=weights[control]*edge->controlPointsMicrometres[control][2]/1e6;
}
route.push_back(point);
}
}
else
{
std::vector<const VoxelForgeCore::ResolvedLayoutStampV1*> ramp;
for(const auto& stamp:layout.stamps)
if(stamp.stableId.starts_with("landmark/sw-arrival-chamber-ramp-"))
ramp.push_back(&stamp);
std::sort(ramp.begin(),ramp.end(),[](const auto* a,const auto* b)
{return a->stableId<b->stableId;});
for(const auto* stamp:ramp)
route.push_back({stamp->positionMicrometres[0]/1e6,
stamp->positionMicrometres[1]/1e6,
stamp->positionMicrometres[2]/1e6-1.6});
}
if(route.size()<2)return result;
std::vector<double> arc(route.size(),0.0);
for(std::size_t index=1;index<route.size();++index)
arc[index]=arc[index-1]+std::hypot(route[index].x-route[index-1].x,
route[index].y-route[index-1].y);
const double length=arc.back();
if(length<4.0)return result;
const auto atDistance=[&](double distance)
{
distance=std::clamp(distance,0.0,length);
const auto upper=std::lower_bound(arc.begin(),arc.end(),distance);
const std::size_t hi=std::min<std::size_t>(route.size()-1,
static_cast<std::size_t>(upper-arc.begin()));
const std::size_t lo=hi?hi-1:0;
const double span=arc[hi]-arc[lo];
const double t=span>0.0?(distance-arc[lo])/span:0.0;
return FRoutePoint{std::lerp(route[lo].x,route[hi].x,t),
std::lerp(route[lo].y,route[hi].y,t),
std::lerp(route[lo].floor,route[hi].floor,t)};
};
const auto floorRoot=[&](double x,double y,double expected)->std::optional<double>
{
constexpr double Step=0.025,Below=0.65,Above=0.35;
double priorZ=expected-Below;
double priorDensity=densityMetres(x,y,priorZ);
std::optional<double> closest;
double closestError=std::numeric_limits<double>::infinity();
for(double z=priorZ+Step;z<=expected+Above+1.0e-9;z+=Step)
{
const double density=densityMetres(x,y,z);
if(priorDensity<0.0&&density>=0.0)
{
const double span=density-priorDensity;
const double root=span>0.0?priorZ+Step*(-priorDensity)/span:z;
const double error=std::abs(root-expected);
if(error<closestError){closest=root;closestError=error;}
}
priorZ=z;priorDensity=density;
}
return closest;
};
std::vector<std::pair<double,double>> floorResiduals;
std::array<std::vector<std::pair<double,double>>,3> floorTrackResiduals;
std::array<std::optional<double>,3> previousFloorResiduals;
std::array<double,3> previousFloorDistances{};
constexpr std::array<double,3> FloorTrackOffsets={-1.5,0.0,1.5};
for(double distance=0.0;distance<=length-0.75;distance+=0.125)
{
const auto point=atDistance(distance);
const auto prior=atDistance(std::max(0.0,distance-0.1));
const auto next=atDistance(std::min(length,distance+0.1));
const double tx=next.x-prior.x,ty=next.y-prior.y;
const double tangentLength=std::hypot(tx,ty);
if(tangentLength<1.0e-6)continue;
const double normalX=-ty/tangentLength,normalY=tx/tangentLength;
double offsetSum=0.0;std::size_t offsetCount=0;
for(std::size_t track=0;track<FloorTrackOffsets.size();++track)
{
const double lateral=FloorTrackOffsets[track];
const auto root=floorRoot(point.x+normalX*lateral,
point.y+normalY*lateral,point.floor);
if(!root)continue;
const double residual=*root-point.floor;
floorTrackResiduals[track].push_back({distance,residual});
offsetSum+=residual;++offsetCount;
if(distance<=10.0+1.0e-9)
{
++result.entranceFloorSamples;
if(previousFloorResiduals[track]
&&distance-previousFloorDistances[track]<=0.2)
{
const double step=std::abs(residual-*previousFloorResiduals[track]);
if(step>result.entranceFloorMaxStepMetres)
{
result.entranceFloorMaxStepMetres=step;
result.entranceFloorWorstDistanceMetres=distance;
result.entranceFloorPriorResidualMetres=*previousFloorResiduals[track];
result.entranceFloorCurrentResidualMetres=residual;
result.entranceFloorWorstTrack=track;
}
}
}
previousFloorResiduals[track]=residual;
previousFloorDistances[track]=distance;
}
if(offsetCount)
{floorResiduals.push_back({distance,offsetSum/offsetCount});}
}
result.floorSamples=floorTrackResiduals[0].size()
+floorTrackResiduals[1].size()+floorTrackResiduals[2].size();
const auto peakPeriod=[&](const std::vector<std::pair<double,double>>& samples,
double minimumPeriod,double maximumPeriod,
double& outPeriod)
{
double amplitude=0.0;outPeriod=0.0;
if(samples.size()<16)return amplitude;
for(double period=minimumPeriod;period<=maximumPeriod+1.0e-9;period+=0.125)
{
double cosine=0.0,sine=0.0;
for(const auto& [distance,residual]:samples)
{
const double phase=2.0*3.14159265358979323846*distance/period;
cosine+=residual*std::cos(phase);sine+=residual*std::sin(phase);
}
const double candidate=2.0*std::hypot(cosine,sine)/samples.size();
if(candidate>amplitude){amplitude=candidate;outPeriod=period;}
}
return amplitude;
};
result.floorPeakAmplitudeMetres=peakPeriod(floorResiduals,0.375,
std::min(8.0,length/2.0),result.floorPeakPeriodMetres);
for(const auto& track:floorTrackResiduals)
{
double trackPeriod=0.0;
const double trackAmplitude=peakPeriod(track,0.375,
std::min(8.0,length/2.0),trackPeriod);
if(trackAmplitude>result.floorPeakAmplitudeMetres)
{
result.floorPeakAmplitudeMetres=trackAmplitude;
result.floorPeakPeriodMetres=trackPeriod;
}
}
std::vector<std::pair<double,double>> wallResiduals;
const double expectedWallRadius=edge!=layout.cavernEdges.end()
?edge->boreRadiusMicrometres/1e6*std::sqrt(1.0
-std::pow(2.0/(edge->boreHeightMicrometres/1e6),2.0))
:2.6*std::sqrt(1.0-std::pow(0.4/2.0,2.0));
// Keep the edge audit away from the ground portal and the room union;
// those are transitions between features, not tunnel-wall ripple.
const double wallAuditStart=std::max(4.0,length*0.38);
const double wallAuditEnd=std::min(length*0.55,length-4.0);
for(double distance=wallAuditStart;distance<=wallAuditEnd;distance+=0.0625)
{
const auto point=atDistance(distance);
const auto prior=atDistance(std::max(0.0,distance-0.1));
const auto next=atDistance(std::min(length,distance+0.1));
const double tx=next.x-prior.x,ty=next.y-prior.y;
const double tangentLength=std::hypot(tx,ty);
if(tangentLength<1.0e-6)continue;
const double normalX=-ty/tangentLength,normalY=tx/tangentLength;
const double height=point.floor+2.0;
for(const double sign:{-1.0,1.0})
{
double priorRadius=0.0;
double priorDensity=densityMetres(point.x,point.y,height);
bool found=false;
for(double radius=0.025;radius<=8.0;radius+=0.025)
{
const double density=densityMetres(point.x+normalX*sign*radius,
point.y+normalY*sign*radius,height);
if(priorDensity>=0.0&&density<0.0)
{
const double span=priorDensity-density;
const double root=span>0.0?priorRadius+0.025*priorDensity/span:radius;
wallResiduals.push_back({distance,root-expectedWallRadius});
found=true;break;
}
priorRadius=radius;priorDensity=density;
}
if(!found)continue;
}
}
result.wallSamples=wallResiduals.size();
// Remove the slow wall envelope from the amplitude profile before testing
// for segment-scale ribs. The moving baseline covers 2 m, while the audit
// band covers the shorter repeated seams seen in the L35/L36 controls.
std::vector<std::pair<double,double>> wallRippleResiduals;
wallRippleResiduals.reserve(wallResiduals.size());
for(const auto& sample:wallResiduals)
{
double baseline=0.0;std::size_t neighbours=0;
for(const auto& other:wallResiduals)
if(std::abs(other.first-sample.first)<=1.0)
{baseline+=other.second;++neighbours;}
if(neighbours>0&&sample.first>=wallAuditStart+1.0
&&sample.first<=wallAuditEnd-1.0)
wallRippleResiduals.push_back({sample.first,
sample.second-baseline/static_cast<double>(neighbours)});
}
result.wallPeakAmplitudeMetres=peakPeriod(wallRippleResiduals,0.25,
std::min(1.0,length/2.0),result.wallPeakPeriodMetres);
result.valid=result.floorSamples>=16&&result.entranceFloorSamples>=150
&&result.wallSamples>=16;
result.passed=result.valid&&result.floorPeakAmplitudeMetres<=0.015
&&result.entranceFloorMaxStepMetres<=0.05
&&result.wallPeakAmplitudeMetres<=0.035;
return result;
}
inline bool MakeL43BuriedLandmarkControl(
const VoxelForgeCore::ResolvedLayoutSnapshotV3& source,
VoxelForgeCore::ResolvedLayoutSnapshotV3& control,std::string& error)
{
using namespace VoxelForgeCore;
control=source;control.stamps.clear();control.stampVocabularyVersion=1;
control.cavernGraphVocabularyVersion=0;
control.cavernRooms.clear();control.cavernEdges.clear();
const auto add=[&](std::string id,ResolvedSdfStampKindV1 kind,
std::array<std::int64_t,3> position,
std::array<std::int64_t,3> half,std::int64_t smooth,
std::int64_t rough,std::int64_t wavelength,std::uint64_t seed,
std::uint8_t yaw)
{
ResolvedLayoutStampV1 stamp;stamp.stableId=std::move(id);
stamp.strateIndex=1;stamp.kind=kind;stamp.positionMicrometres=position;
stamp.halfExtentsMicrometres=half;stamp.smoothWidthMicrometres=smooth;
stamp.irregularityAmplitudeMicrometres=rough;
stamp.irregularityWavelengthMicrometres=wavelength;
stamp.irregularitySeed=seed;stamp.yawQuarterTurns=yaw;
const std::int64_t pad=smooth+rough;
const std::array<std::int64_t,3> bounds={
half[yaw%2?1:0]+pad,half[yaw%2?0:1]+pad,half[2]+pad};
for(std::size_t axis=0;axis<3;++axis)
{stamp.boundsMinimumMicrometres[axis]=position[axis]-bounds[axis];
stamp.boundsMaximumMicrometres[axis]=position[axis]+bounds[axis];}
control.stamps.push_back(std::move(stamp));
};
add("landmark/sw-arrival-chamber-v1",ResolvedSdfStampKindV1::carveEllipsoid,
{-8917798,31949858,-513083425},{8500000,7500000,6000000},
800000,700000,4800000,4704841454711558ull,0);
add("landmark/sw-arrival-chamber-entrance-v1",ResolvedSdfStampKindV1::carveArch,
{-12289139,37026886,-513310578},{2600000,4200000,3200000},
350000,250000,2600000,2371181934872559ull,0);
add("landmark/sw-arrival-chamber-dais-v1",ResolvedSdfStampKindV1::fillDais,
{-7489021,30688194,-515838454},{3200000,2800000,900000},
300000,180000,2200000,7240637434535735ull,0);
if(!control.finalize(error))return false;
std::vector<ResolvedLayoutIssueV2> issues;
return control.validate(ResolvedLayoutValidationModeV3::strict,issues,error);
}
inline bool SameTileOutput(const VoxelForgeCore::TileMesh& A,
const VoxelForgeCore::TileMesh& B)
{
return A.hasDensityHash&&B.hasDensityHash&&A.hasMeshHash&&B.hasMeshHash
&&A.hasPayloadHash&&B.hasPayloadHash&&A.hasTopologyHash&&B.hasTopologyHash
&&A.densityHash==B.densityHash&&A.meshHash==B.meshHash
&&A.payloadHash==B.payloadHash&&A.topologyHash==B.topologyHash;
}
struct FSceneExportWriter
{
std::ofstream File;
bool bGood=true;
bool bIncludeMaterialAttributes=false;
std::uint32_t TileCount=0;
template<typename T> void Write(const T& Value)
{
File.write(reinterpret_cast<const char*>(&Value),sizeof(Value));
bGood=bGood&&static_cast<bool>(File);
}
bool Open(const std::filesystem::path& Path,std::uint32_t VoxelSizeMicrons,
const FVector& CameraVoxels,float YawDegrees,float PitchDegrees,
std::uint32_t ExpectedTiles,bool IncludeMaterialAttributes)
{
std::error_code Error;
if(!Path.parent_path().empty())
std::filesystem::create_directories(Path.parent_path(),Error);
if(Error)return false;
File.open(Path,std::ios::binary|std::ios::trunc);
if(!File)return false;
bIncludeMaterialAttributes=IncludeMaterialAttributes;
const char Magic[8]={'V','F','M','S','H','0','0',
static_cast<char>(bIncludeMaterialAttributes?'2':'1')};
File.write(Magic,sizeof(Magic));
const std::uint32_t Version=bIncludeMaterialAttributes?2u:1u;
Write(Version);Write(VoxelSizeMicrons);Write(ExpectedTiles);
const double MicronsToMeters=static_cast<double>(VoxelSizeMicrons)/1000000.0;
const double Camera[3]={CameraVoxels.X*MicronsToMeters,
CameraVoxels.Y*MicronsToMeters,CameraVoxels.Z*MicronsToMeters};
for(const double Value:Camera)Write(Value);
const double Yaw=YawDegrees,Pitch=PitchDegrees;
Write(Yaw);Write(Pitch);
return bGood;
}
void Add(const FStandaloneCpuTile& Tile)
{
const std::int32_t Key[4]={Tile.Key.Coord.X,Tile.Key.Coord.Y,
Tile.Key.Coord.Z,Tile.Key.Level};
for(const auto Value:Key)Write(Value);
const std::uint32_t SurfaceVertexCount=Tile.SurfaceVertexCount;
const std::uint32_t SkirtTriangleCount=Tile.SkirtTriangleCount;
const std::uint32_t VertexCount=static_cast<std::uint32_t>(Tile.Vertices.size());
const std::uint32_t IndexCount=static_cast<std::uint32_t>(Tile.Indices.size());
const std::uint32_t MaskCount=static_cast<std::uint32_t>(Tile.TriangleSkirtFaceMasks.size());
Write(SurfaceVertexCount);Write(SkirtTriangleCount);
Write(VertexCount);Write(IndexCount);Write(MaskCount);
for(const FStandaloneCpuVertex& Vertex:Tile.Vertices)
for(const float Value:Vertex.Position)Write(Value);
for(const FStandaloneCpuVertex& Vertex:Tile.Vertices)
for(const float Value:Vertex.Normal)Write(Value);
if(bIncludeMaterialAttributes)
for(const FStandaloneCpuVertex& Vertex:Tile.Vertices)
{
Write(Vertex.HostMaterialId);
for(const std::uint16_t id:Vertex.ResourceMaterialIds)Write(id);
for(const std::uint16_t weight:Vertex.ResourceWeightsQ16)Write(weight);
}
if(IndexCount)
File.write(reinterpret_cast<const char*>(Tile.Indices.data()),
static_cast<std::streamsize>(sizeof(std::uint32_t)*Tile.Indices.size()));
if(MaskCount)
File.write(reinterpret_cast<const char*>(Tile.TriangleSkirtFaceMasks.data()),
static_cast<std::streamsize>(Tile.TriangleSkirtFaceMasks.size()));
bGood=bGood&&static_cast<bool>(File);
++TileCount;
}
bool Close(std::uint32_t ExpectedTiles)
{
File.flush();
const bool bComplete=bGood&&static_cast<bool>(File)&&TileCount==ExpectedTiles;
File.close();
return bComplete;
}
};
inline void HashWord(uint64& Hash,uint64 Word,int32 Bytes=8)
{
for(int32 I=0;I<Bytes;++I)
{
Hash^=static_cast<uint8>(Word>>(I*8));
Hash*=1099511628211ull;
}
}
struct FHashedTile
{
FVoxelTileKey Key;
uint64 Hash=14695981039346656037ull;
};
inline bool TileKeyLessForHash(const FVoxelTileKey& A,const FVoxelTileKey& B)
{
if(A.Level!=B.Level)return A.Level<B.Level;
if(A.Coord.Z!=B.Coord.Z)return A.Coord.Z<B.Coord.Z;
if(A.Coord.Y!=B.Coord.Y)return A.Coord.Y<B.Coord.Y;
return A.Coord.X<B.Coord.X;
}
inline uint64 HashTileRows(std::vector<FHashedTile>& Rows)
{
std::sort(Rows.begin(),Rows.end(),[](const FHashedTile& A,const FHashedTile& B)
{return TileKeyLessForHash(A.Key,B.Key);});
uint64 Hash=14695981039346656037ull;
for(const FHashedTile& Row:Rows)
{
HashWord(Hash,static_cast<uint32>(Row.Key.Level),4);
HashWord(Hash,static_cast<uint32>(Row.Key.Coord.X),4);
HashWord(Hash,static_cast<uint32>(Row.Key.Coord.Y),4);
HashWord(Hash,static_cast<uint32>(Row.Key.Coord.Z),4);
HashWord(Hash,Row.Hash);
}
return Hash;
}
inline bool AuditResolvedStrateTransitions(const VoxelForgeCore::World& Field,
const FStandaloneOwnerWorld& Owner,
const VoxelForgeCore::ResolvedLayoutSnapshotV3& Layout)
{
constexpr std::int64_t XYExtentMicrometres=256000000;
constexpr std::int64_t XYStepMicrometres=8000000;
const std::int64_t coreMicrometres=std::max<std::uint32_t>(1,Owner.CoreVoxelSizeMicrons);
const std::int64_t zStepMicrometres=std::max<std::int64_t>(1,coreMicrometres/2);
const std::int64_t minimumBandMicrometres=2*coreMicrometres;
std::uint64_t interfacesPassed=0,totalColumns=0,passageColumnsSkipped=0;
std::uint64_t holeColumns=0,airSamples=0,solidSamples=0;
bool negativeWidthRejected=false,negativeThinBandRejected=false;
for(std::size_t interfaceIndex=0;interfaceIndex+1<Layout.strates.size();++interfaceIndex)
{
const auto& upper=Layout.strates[interfaceIndex];
const auto& lower=Layout.strates[interfaceIndex+1];
std::int64_t minimumOffset=std::numeric_limits<std::int64_t>::max();
std::int64_t maximumOffset=std::numeric_limits<std::int64_t>::min();
std::int64_t maximumCrossingDepth=0;
std::int64_t minimumUpperThickness=std::numeric_limits<std::int64_t>::max();
std::int64_t minimumLowerThickness=std::numeric_limits<std::int64_t>::max();
std::uint64_t columns=0,skipped=0,holes=0,air=0,solid=0;
bool firstHoleReported=false;
const std::int64_t seam=upper.bedrock.bottomMicrometres;
const auto passageCoversColumn=[&](std::int64_t xUm,std::int64_t yUm,
std::int64_t zMinimumUm,std::int64_t zMaximumUm)
{
constexpr double Q=VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel;
for(const auto& passage:Layout.passages)
{
if(passage.upperStrateIndex!=upper.strateIndex
||passage.lowerStrateIndex!=lower.strateIndex)continue;
for(std::size_t pointIndex=1;pointIndex<passage.controlPoints.size();++pointIndex)
{
const auto& a=passage.controlPoints[pointIndex-1];
const auto& b=passage.controlPoints[pointIndex];
const double ax=a.positionSubvoxels[0]*coreMicrometres/Q;
const double ay=a.positionSubvoxels[1]*coreMicrometres/Q;
const double az=a.positionSubvoxels[2]*coreMicrometres/Q;
const double bx=b.positionSubvoxels[0]*coreMicrometres/Q;
const double by=b.positionSubvoxels[1]*coreMicrometres/Q;
const double bz=b.positionSubvoxels[2]*coreMicrometres/Q;
const double radius=std::max(a.radiusSubvoxels,b.radiusSubvoxels)
*coreMicrometres/Q+750000.0;
if(std::max(az,bz)+radius<zMinimumUm
||std::min(az,bz)-radius>zMaximumUm)continue;
const double dx=bx-ax,dy=by-ay;
const double lengthSquared=dx*dx+dy*dy;
const double t=lengthSquared>0.0
?std::clamp(((xUm-ax)*dx+(yUm-ay)*dy)/lengthSquared,0.0,1.0):0.0;
const double ex=xUm-(ax+t*dx),ey=yUm-(ay+t*dy);
if(ex*ex+ey*ey<=radius*radius)return true;
}
}
return false;
};
for(std::int64_t iy=-XYExtentMicrometres/XYStepMicrometres;
iy<=XYExtentMicrometres/XYStepMicrometres;++iy)
for(std::int64_t ix=-XYExtentMicrometres/XYStepMicrometres;
ix<=XYExtentMicrometres/XYStepMicrometres;++ix)
{
const std::int64_t xUm=ix*XYStepMicrometres;
const std::int64_t yUm=iy*XYStepMicrometres;
const auto bands=VoxelForgeCore::EvaluateResolvedLayoutTransitionBandsV1(
upper,lower,Owner.Seed,Layout.strateLayoutChunkSizeMicrometres,xUm,yUm);
const std::int64_t offset=bands.upperBedrockBottomMicrometres-seam;
minimumOffset=std::min(minimumOffset,offset);
maximumOffset=std::max(maximumOffset,offset);
maximumCrossingDepth=std::max(maximumCrossingDepth,
bands.crossingDepthMicrometres);
minimumUpperThickness=std::min(minimumUpperThickness,
bands.upperBedrockTopMicrometres-bands.upperBedrockBottomMicrometres);
minimumLowerThickness=std::min(minimumLowerThickness,
bands.lowerCeilingTopMicrometres-bands.lowerCeilingBottomMicrometres);
const std::int64_t zMinimum=std::min(bands.upperBedrockBottomMicrometres,
bands.lowerCeilingBottomMicrometres);
const std::int64_t zMaximum=std::max(bands.upperBedrockTopMicrometres,
bands.lowerCeilingTopMicrometres);
if(passageCoversColumn(xUm,yUm,zMinimum,zMaximum)){++skipped;continue;}
++columns;
bool hasHole=false;
for(std::int64_t zUm=zMinimum+zStepMicrometres/2;
zUm<zMaximum-zStepMicrometres/2;zUm+=zStepMicrometres)
{
const VoxelForgeCore::Vec3d point{
static_cast<double>(xUm)/coreMicrometres,
static_cast<double>(yUm)/coreMicrometres,
static_cast<double>(zUm)/coreMicrometres};
const float density=Field.densityAt(point);
if(!std::isfinite(density)||density>=0.0f)
{
if(!firstHoleReported)
{
std::printf("[StrateTransitionFirstHole] x_um=%lld y_um=%lld z_um=%lld z_min_um=%lld z_max_um=%lld density=%.9g dispatch=%s\n",
static_cast<long long>(xUm),static_cast<long long>(yUm),
static_cast<long long>(zUm),static_cast<long long>(zMinimum),
static_cast<long long>(zMaximum),density,
Field.densityDispatchPathAt(point).c_str());
firstHoleReported=true;
}
hasHole=true;++air;
}
else ++solid;
}
if(hasHole)++holes;
}
const std::int64_t boundaryPeakToPeak=maximumOffset-minimumOffset;
const std::int64_t allowedWidth=upper.transitionMode=="Hard"
||upper.transitionFallsBackToHard?0:upper.transitionWidthMicrometres;
if(interfaceIndex==0)
{
auto wide=Layout;
wide.strates[0].transitionMode="Interleaved";
wide.strates[0].transitionFallsBackToHard=false;
wide.strates[0].transitionWidthMicrometres=8000000;
wide.strates[0].transitionInterpenetrationMicrometres=8000001;
std::vector<VoxelForgeCore::ResolvedLayoutIssueV2> issues;
std::string error;
negativeWidthRejected=!wide.validate(
VoxelForgeCore::ResolvedLayoutValidationModeV3::strict,issues,error);
auto thin=Layout;
auto& bedrock=thin.strates[0].bedrock;
bedrock.topMicrometres=bedrock.bottomMicrometres+minimumBandMicrometres-1;
thin.strates[0].content.bottomMicrometres=bedrock.topMicrometres;
negativeThinBandRejected=!thin.validate(
VoxelForgeCore::ResolvedLayoutValidationModeV3::strict,issues,error);
}
const bool passed=columns>0&&holes==0&&maximumCrossingDepth<=allowedWidth
&&minimumUpperThickness>=minimumBandMicrometres
&&minimumLowerThickness>=minimumBandMicrometres;
interfacesPassed+=passed?1u:0u;
totalColumns+=columns;passageColumnsSkipped+=skipped;
holeColumns+=holes;airSamples+=air;solidSamples+=solid;
std::printf("[StrateTransitionInterface] upper=%d lower=%d mode=%s width_um=%lld max_crossing_depth_um=%lld boundary_peak_to_peak_um=%lld allowed_um=%lld upper_min_band_um=%lld lower_min_band_um=%lld columns=%llu passage_columns=%llu hole_columns=%llu air_samples=%llu status=%s\n",
upper.strateIndex,lower.strateIndex,upper.transitionMode.c_str(),
static_cast<long long>(upper.transitionWidthMicrometres),
static_cast<long long>(maximumCrossingDepth),
static_cast<long long>(boundaryPeakToPeak),static_cast<long long>(allowedWidth),
static_cast<long long>(minimumUpperThickness),static_cast<long long>(minimumLowerThickness),
static_cast<unsigned long long>(columns),static_cast<unsigned long long>(skipped),
static_cast<unsigned long long>(holes),static_cast<unsigned long long>(air),
passed?"PASS":"FAIL");
}
const bool controlsPassed=negativeWidthRejected&&negativeThinBandRejected;
std::printf("[StrateTransitionNegativeControls] wider_than_declared=%s thinner_than_minimum=%s minimum_band_um=%lld status=%s\n",
negativeWidthRejected?"REJECTED":"ACCEPTED",
negativeThinBandRejected?"REJECTED":"ACCEPTED",
static_cast<long long>(minimumBandMicrometres),controlsPassed?"PASS":"FAIL");
const bool passed=!Layout.strates.empty()&&interfacesPassed+1==Layout.strates.size()
&&holeColumns==0&&airSamples==0&&controlsPassed;
std::printf("[StrateTransitionAuditSummary] interfaces=%llu passed=%llu columns=%llu skipped_passage_columns=%llu hole_columns=%llu air_samples=%llu solid_samples=%llu status=%s\n",
static_cast<unsigned long long>(Layout.strates.size()-1),
static_cast<unsigned long long>(interfacesPassed),
static_cast<unsigned long long>(totalColumns),
static_cast<unsigned long long>(passageColumnsSkipped),
static_cast<unsigned long long>(holeColumns),
static_cast<unsigned long long>(airSamples),
static_cast<unsigned long long>(solidSamples),passed?"PASS":"FAIL");
return passed;
}
inline int RunPipelinedStreamingBenchmark(std::shared_ptr<FStandaloneOwnerWorld> OwnerWorld,
const VoxelForgeCore::ResolvedWorldSnapshot& CoreSnapshot,
const FVector& CameraPositionVoxels,int32 WorkerCount,int32 MaxLevel,
VoxelForgeCore::DetailVariant DetailVariant,const VoxelForgeCore::JobScheduler& Scheduler,
bool bHashDensity,bool bSkipUvAndColors,bool bSkipMaterialGroups,bool bSkipUV,bool bSkipColors,
std::chrono::steady_clock::time_point ColdStart,bool bProfileColumnOverlap,
int32 FarHorizonLOD8InteriorStepVoxels,bool bReportMeshCoverage=false,
const std::filesystem::path& MeshExportPath={},float CameraYawDegrees=0.0f,
float CameraPitchDegrees=0.0f,bool bScreenSpaceGate=false,
bool bUseSharedColumnCache=true,FVector CameraStepVoxels=FVector::ZeroVector,
bool bAuditUniformBlockProofs=false,bool bReportLodWorkProfile=false,
bool bRegionCrossing=false,
bool bAuditTileShapeReadiness=false,int DiagnosticSlowShapeCompileMs=0,
bool bAuditBasePageEquivalence=false,bool bAuditRouteParity=false,
bool bAuditResolvedLayoutBoundaries=false,
bool bAuditResolvedLayoutPassages=false,
bool bAuditStrateTransitions=false,
const VoxelForgeCore::ResolvedLayoutSnapshotV3* ResolvedLayout=nullptr,
bool bPrintTileHashes=false,bool bAuditLandmarkReachability=false,
bool bAuditOreVeinYield=false)
{
using Clock=std::chrono::steady_clock;
FStandaloneOwnerWorld& World=*OwnerWorld;
const VoxelForgeCore::WorldAssemblyManifest* Assembly=CoreSnapshot.worldAssembly();
std::array<double,9> ClosestDisplayDistances{};
std::array<std::int64_t,9> PixelBudgetsSubvoxels{};
if(bScreenSpaceGate)
{
ClosestDisplayDistances=StandaloneScreenSpaceGate::ClosestDisplayedDistancesMeters(
World,CameraPositionVoxels,World.CoreVoxelSizeMicrons);
const double VoxelMeters=static_cast<double>(World.CoreVoxelSizeMicrons)/1000000.0;
for(int32 Lod=3;Lod<=World.MaxClipLevel&&Lod<9;++Lod)
PixelBudgetsSubvoxels[static_cast<std::size_t>(Lod)]=static_cast<std::int64_t>(std::floor(
ClosestDisplayDistances[static_cast<std::size_t>(Lod)]
*StandaloneScreenSpaceGate::OnePixelRadians/VoxelMeters
*VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel));
}
const bool bRoundTunnels=World.Generator->bStandaloneResearchRoundTunnels;
const bool bEnhancedTunnelWalls=World.Generator->bStandaloneResearchEnhancedWalls;
VoxelForgeCore::World Shape(CoreSnapshot);
FStandaloneDesiredTileSet Desired=StandaloneWorldMesher::BuildDesiredSet(World,CameraPositionVoxels);
const auto CoreTiles=Shape.desiredTiles(
{CameraPositionVoxels.X,CameraPositionVoxels.Y,CameraPositionVoxels.Z});
Desired.Tiles.clear();Desired.Tiles.reserve(CoreTiles.size());
for(const auto& Key:CoreTiles)
Desired.Tiles.emplace_back(FIntVector(Key.coordinate.x,Key.coordinate.y,Key.coordinate.z),Key.lod);
if(MaxLevel>=0)
Desired.Tiles.erase(std::remove_if(Desired.Tiles.begin(),Desired.Tiles.end(),
[&](const FVoxelTileKey& Tile){return Tile.Level>MaxLevel;}),Desired.Tiles.end());
const bool bHasCameraStep=std::abs(CameraStepVoxels.X)+std::abs(CameraStepVoxels.Y)
+std::abs(CameraStepVoxels.Z)>1.0e-6f;
FStandaloneDesiredTileSet MovedDesired;
if(bHasCameraStep)
{
const FVector MovedCamera=CameraPositionVoxels+CameraStepVoxels;
MovedDesired=StandaloneWorldMesher::BuildDesiredSet(World,MovedCamera);
const auto MovedCoreTiles=Shape.desiredTiles({MovedCamera.X,MovedCamera.Y,MovedCamera.Z});
MovedDesired.Tiles.clear();MovedDesired.Tiles.reserve(MovedCoreTiles.size());
for(const auto& Key:MovedCoreTiles)
MovedDesired.Tiles.emplace_back(FIntVector(Key.coordinate.x,Key.coordinate.y,Key.coordinate.z),Key.lod);
if(MaxLevel>=0)
MovedDesired.Tiles.erase(std::remove_if(MovedDesired.Tiles.begin(),MovedDesired.Tiles.end(),
[&](const FVoxelTileKey& Tile){return Tile.Level>MaxLevel;}),MovedDesired.Tiles.end());
}
if(!Desired.Tiles.empty())
{
FIntVector volumeMin(INT32_MAX,INT32_MAX,INT32_MAX);
FIntVector volumeMax(INT32_MIN,INT32_MIN,INT32_MIN);
int32 minimumLod=INT32_MAX,maximumLod=INT32_MIN;
for(const FVoxelTileKey& tile:Desired.Tiles)
{
const FIntVector origin=tile.OriginVoxels();
const int32 extent=tile.ExtentVoxels();
volumeMin.X=std::min(volumeMin.X,origin.X);
volumeMin.Y=std::min(volumeMin.Y,origin.Y);
volumeMin.Z=std::min(volumeMin.Z,origin.Z);
volumeMax.X=std::max(volumeMax.X,origin.X+extent);
volumeMax.Y=std::max(volumeMax.Y,origin.Y+extent);
volumeMax.Z=std::max(volumeMax.Z,origin.Z+extent);
minimumLod=std::min(minimumLod,tile.Level);
maximumLod=std::max(maximumLod,tile.Level);
}
std::printf("[PipelineVolume] tiles=%zu lod=%d..%d min_voxel=(%d,%d,%d) max_voxel=(%d,%d,%d)\n",
Desired.Tiles.size(),minimumLod,maximumLod,volumeMin.X,volumeMin.Y,volumeMin.Z,
volumeMax.X,volumeMax.Y,volumeMax.Z);
}
FIntVector FineMin(INT32_MAX,INT32_MAX,INT32_MAX),FineMax(INT32_MIN,INT32_MIN,INT32_MIN);
FIntVector ClipMin(INT32_MAX,INT32_MAX,INT32_MAX),ClipMax(INT32_MIN,INT32_MIN,INT32_MIN);
const auto AccumulateBounds=[&](const std::vector<FVoxelTileKey>& Tiles)
{
for(const FVoxelTileKey& Tile:Tiles)
{
const FIntVector Origin=Tile.OriginVoxels();const int32 Extent=Tile.ExtentVoxels();
ClipMin.X=std::min(ClipMin.X,Origin.X);ClipMin.Y=std::min(ClipMin.Y,Origin.Y);ClipMin.Z=std::min(ClipMin.Z,Origin.Z);
ClipMax.X=std::max(ClipMax.X,Origin.X+Extent);ClipMax.Y=std::max(ClipMax.Y,Origin.Y+Extent);ClipMax.Z=std::max(ClipMax.Z,Origin.Z+Extent);
if(Tile.Level<World.FullResClipLevels)
{
FineMin.X=std::min(FineMin.X,Origin.X);FineMin.Y=std::min(FineMin.Y,Origin.Y);FineMin.Z=std::min(FineMin.Z,Origin.Z);
FineMax.X=std::max(FineMax.X,Origin.X+Extent);FineMax.Y=std::max(FineMax.Y,Origin.Y+Extent);FineMax.Z=std::max(FineMax.Z,Origin.Z+Extent);
}
}
};
AccumulateBounds(Desired.Tiles);
if(bHasCameraStep&&!bRegionCrossing)AccumulateBounds(MovedDesired.Tiles);
if(FineMin.X==INT32_MAX||ClipMin.X==INT32_MAX)
{std::fprintf(stderr,"[StreamPipeline] no desired detail or clipmap tiles.\n");return 7;}
const FIntVector CenterChunk=Desired.CenterChunk;
std::unordered_set<FVoxelTileKey,FStandaloneTileKeyHash> Neighborhood;
Neighborhood.reserve(32);
for(const FVoxelTileKey& Tile:Desired.Tiles)
if(Tile.Level==0&&std::abs(Tile.Coord.X-CenterChunk.X)<=1
&&std::abs(Tile.Coord.Y-CenterChunk.Y)<=1&&std::abs(Tile.Coord.Z-CenterChunk.Z)<=1)
Neighborhood.insert(Tile);
if(Neighborhood.size()!=27)
{std::fprintf(stderr,"[StreamPipeline] expected 27 player-neighborhood tiles, found %zu.\n",Neighborhood.size());return 7;}
FStandaloneDesiredTileSet ShapeFreeDesired=Desired;
ShapeFreeDesired.Tiles.clear();
std::vector<FVoxelTileKey> ShapeFreeTiles;
ShapeFreeTiles.reserve(Neighborhood.size());
int32 ShapeFreeNeighborhood=0;
for(const FVoxelTileKey& Tile:Desired.Tiles)
{
if(!Neighborhood.contains(Tile))continue;
const VoxelForgeCore::TileKey CoreKey{{Tile.Coord.X,Tile.Coord.Y,Tile.Coord.Z},Tile.Level};
if(!Shape.isTileShapeFree(CoreKey))continue;
ShapeFreeDesired.Tiles.push_back(Tile);
ShapeFreeTiles.push_back(Tile);
if(Neighborhood.contains(Tile))++ShapeFreeNeighborhood;
}
if(bAuditTileShapeReadiness)
{
FVoxelTileKey DeliberatelyWrong(FIntVector(0,0,31250),0);
for(int32 Z=100000;Z<100100;++Z)
{
DeliberatelyWrong=FVoxelTileKey(FIntVector(0,0,Z),0);
if(!Shape.isTileShapeFree({{0,0,Z},0}))break;
}
VoxelForgeCore::TileGenerationOptions NegativeControlOptions;
NegativeControlOptions.diagnosticForceNativeOnly=true;
std::string NegativeControlError;
const auto MisMarked=Shape.generateTile(
{{DeliberatelyWrong.Coord.X,DeliberatelyWrong.Coord.Y,DeliberatelyWrong.Coord.Z},0},
NegativeControlOptions,NegativeControlError);
const bool bGuardCaught=!MisMarked
&&NegativeControlError.find("shape-free guard")!=std::string::npos;
std::printf("[ShapeReadinessNegativeControl] deliberately_mismarked=(%d,%d,%d,lod0) result=%s guard_caught=%d error=%s\n",
DeliberatelyWrong.Coord.X,DeliberatelyWrong.Coord.Y,DeliberatelyWrong.Coord.Z,
MisMarked?"generated":"rejected",bGuardCaught?1:0,
NegativeControlError.c_str());
if(!bGuardCaught)
{std::fprintf(stderr,"[StreamPipeline] shape-free guard did not reject the deliberately mis-marked tile.\n");return 9;}
}
std::printf("[ShapeReadiness] shape_free_desired=%zu/%zu near_ring=%d/27 proof=single_SurfaceWorld_plan_no_features_routes_passages_edits_or_owner_primitive_overlap\n",
ShapeFreeTiles.size(),Desired.Tiles.size(),ShapeFreeNeighborhood);
// The initial desired set now owns all clipmap metadata needed by this Core-only run.
// Release the separate compatibility-world generation graph before compiling Core.
World.Generator.reset();
World.Manager.reset();
World.DefinitionStorage.clear();
World.BiomeStorage.clear();
World.OperationStorage.clear();
World.DensitySamples.clear();
const bool bIncludeFarWorld=MaxLevel<0||MaxLevel>=World.FullResClipLevels;
VoxelForgeCore::ShapeBuildRequest ShapeRequest;
ShapeRequest.minVoxel={FineMin.X,FineMin.Y,FineMin.Z};
ShapeRequest.maxVoxel={FineMax.X,FineMax.Y,FineMax.Z};
ShapeRequest.clipMinVoxel={ClipMin.X,ClipMin.Y,ClipMin.Z};
ShapeRequest.clipMaxVoxel={ClipMax.X,ClipMax.Y,ClipMax.Z};
ShapeRequest.workerLimit=static_cast<uint32>(std::clamp(WorkerCount,1,16));
ShapeRequest.detail=DetailVariant;ShapeRequest.includeFarWorld=bIncludeFarWorld;
ShapeRequest.roundTunnels=bRoundTunnels;
ShapeRequest.enhancedTunnelWalls=bEnhancedTunnelWalls;
FStandaloneStreamingGenerator Streamer(World,WorkerCount,bHashDensity,nullptr,MaxLevel,
bSkipUvAndColors,bSkipMaterialGroups,bSkipUV,bSkipColors,&Shape,bProfileColumnOverlap,
FarHorizonLOD8InteriorStepVoxels,bUseSharedColumnCache);
Streamer.SetUniformBlockProofAuditEnabled(bAuditUniformBlockProofs);
if(bScreenSpaceGate||bReportLodWorkProfile)Streamer.SetMesherStageProfilingEnabled(true);
const auto StreamStart=Clock::now();
const FStandaloneStreamingUpdate EarlyUpdate=Streamer.StartWithDesired(ShapeFreeDesired);
if(EarlyUpdate.DesiredTiles!=static_cast<int32>(ShapeFreeDesired.Tiles.size()))
{
Streamer.Stop();
std::fprintf(stderr,"[StreamPipeline] expected %zu shape-free tiles but queued %d.\n",
ShapeFreeDesired.Tiles.size(),EarlyUpdate.DesiredTiles);return 7;
}
const auto ShapeBuildStart=Clock::now();
auto ShapeBuildFuture=std::async(std::launch::async,
[&Shape,&Scheduler,ShapeRequest,DiagnosticSlowShapeCompileMs]() mutable
{
if(DiagnosticSlowShapeCompileMs>0)
std::this_thread::sleep_for(std::chrono::milliseconds(DiagnosticSlowShapeCompileMs));
std::string Error;
const bool bCompiled=Shape.compile(ShapeRequest,Scheduler,Error);
return std::pair<bool,std::string>{bCompiled,std::move(Error)};
});
const auto [bShapeCompiled,BuildError]=ShapeBuildFuture.get();
if(!bShapeCompiled)
{
Streamer.Stop();
std::fprintf(stderr,"[StreamPipeline] full shape build failed: %s\n",BuildError.c_str());return 2;
}
if(bAuditOreVeinYield)
{
if(!ResolvedLayout||ResolvedLayout->oreVeins.empty())
{std::fprintf(stderr,"[OreMiningYield] missing resolved ore-vein records\n");return 2;}
const auto vein=std::find_if(ResolvedLayout->oreVeins.begin(),
ResolvedLayout->oreVeins.end(),[](const auto& value)
{return value.stableId.find("arrival-route-copper")!=std::string::npos;});
const auto& selected=vein==ResolvedLayout->oreVeins.end()
?ResolvedLayout->oreVeins.front():*vein;
const auto micrometresToVoxel=[&](const std::array<std::int64_t,3>& point)
{
const double size=static_cast<double>(World.CoreVoxelSizeMicrons);
return VoxelForgeCore::Vec3d{point[0]/size,point[1]/size,point[2]/size};
};
const std::array<std::int64_t,3> editCenterMicrometres={
(selected.endpointsMicrometres[0][0]+selected.endpointsMicrometres[1][0])/2,
(selected.endpointsMicrometres[0][1]+selected.endpointsMicrometres[1][1])/2,
(selected.endpointsMicrometres[0][2]+selected.endpointsMicrometres[1][2])/2};
const VoxelForgeCore::Vec3d editCenter=micrometresToVoxel(editCenterMicrometres);
const auto mined=Shape.measureOreMiningYieldForSphere(editCenter,1.25,0.25);
std::uint64_t weightedSamples=0;double resourceVolume=0.0;
for(const auto& resource:mined.resources)
{weightedSamples+=resource.weightedSamplesQ16;resourceVolume+=resource.volumeCubicMetres;}
const bool yieldPassed=weightedSamples>0&&resourceVolume>0.0;
std::printf("[OreMiningYield] edit=sphere record=%s center_voxel=(%.3f,%.3f,%.3f) radius_m=1.250 resolution_m=%.3f removed_solid_samples=%llu resource_volume_m3=%.6f status=%s\n",
selected.stableId.c_str(),editCenter.x,editCenter.y,editCenter.z,
mined.sampleSpacingMetres,static_cast<unsigned long long>(mined.solidSamplesRemoved),
resourceVolume,yieldPassed?"PASS":"FAIL");
for(const auto& resource:mined.resources)
std::printf("[OreMiningYieldResource] id=%u volume_m3=%.6f weighted_samples_q16=%llu\n",
resource.resourceMaterialId,resource.volumeCubicMetres,
static_cast<unsigned long long>(resource.weightedSamplesQ16));
VoxelForgeCore::Vec3d airCenter{};
if(!ResolvedLayout->cavernEdges.empty())
{
const auto& edge=ResolvedLayout->cavernEdges.front();
airCenter=micrometresToVoxel(edge.controlPointsMicrometres[0]);
airCenter.z+=edge.boreHeightMicrometres*0.5
/static_cast<double>(World.CoreVoxelSizeMicrons);
}
else if(!ResolvedLayout->passages.empty())
{
const auto& mouth=ResolvedLayout->passages.front().lowerMouthSubvoxels;
const double divisor=static_cast<double>(
VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel);
airCenter={mouth[0]/divisor,mouth[1]/divisor,mouth[2]/divisor};
}
const auto air=Shape.measureOreMiningYieldForSphere(airCenter,1.0,0.25);
std::uint64_t airWeightedSamples=0;
double airResourceVolume=0.0;
for(const auto& resource:air.resources)
{airWeightedSamples+=resource.weightedSamplesQ16;airResourceVolume+=resource.volumeCubicMetres;}
const bool airPassed=airWeightedSamples==0&&airResourceVolume==0.0;
std::printf("[OreMiningYieldControl] case=already-air center_voxel=(%.3f,%.3f,%.3f) radius_m=1.000 resolution_m=0.250 removed_solid_samples=%llu resource_volume_m3=%.6f status=%s\n",
airCenter.x,airCenter.y,airCenter.z,
static_cast<unsigned long long>(air.solidSamplesRemoved),
airResourceVolume,airPassed?"PASS":"FAIL");
if(!yieldPassed||!airPassed)return 14;
}
if(bAuditLandmarkReachability)
{
Streamer.Stop();
if(ResolvedLayout==nullptr||!CoreSnapshot.resolvedLayout())
{std::fprintf(stderr,"[LandmarkReachabilityAudit] missing resolved layout\n");return 2;}
if(ResolvedLayout->cavernEdges.empty())
{
const auto control=AuditLandmarkTunnelRipples(Shape,*ResolvedLayout,
World.CoreVoxelSizeMicrons);
const bool expectedFail=control.valid
&&control.floorPeakAmplitudeMetres>0.015;
std::printf("[CavernTunnelRippleControl] layout=L45-ramp floor_samples=%zu floor_peak_period_m=%.3f floor_peak_amplitude_m=%.4f floor_limit_m=0.015 wall_samples=%zu wall_peak_period_m=%.3f wall_peak_amplitude_m=%.4f wall_limit_m=0.035 observed=%s expected=FAIL status=%s\n",
control.floorSamples,control.floorPeakPeriodMetres,
control.floorPeakAmplitudeMetres,control.wallSamples,
control.wallPeakPeriodMetres,control.wallPeakAmplitudeMetres,
expectedFail?"FAIL":"PASS",expectedFail?"PASS":"FAIL");
return expectedFail?0:14;
}
if(ResolvedLayout->cavernRooms.empty())
{std::fprintf(stderr,"[LandmarkReachabilityAudit] missing cavern room node\n");return 2;}
const auto ripples=AuditLandmarkTunnelRipples(Shape,*ResolvedLayout,
World.CoreVoxelSizeMicrons);
const bool entranceFloorPassed=ripples.entranceFloorSamples>=150
&&ripples.entranceFloorMaxStepMetres<=0.05
&&ripples.floorPeakAmplitudeMetres<=0.015;
std::printf("[CavernEntranceFloorAudit] layout=L46 samples=%zu distance_m=0.000..10.000 rails=3 max_step_m=%.4f step_limit_m=0.050 ripple_peak_m=%.4f ripple_limit_m=0.015 status=%s\n",
ripples.entranceFloorSamples,ripples.entranceFloorMaxStepMetres,
ripples.floorPeakAmplitudeMetres,entranceFloorPassed?"PASS":"FAIL");
std::printf("[CavernEntranceFloorStepDetail] rail=%zu distance_m=%.3f residual_m=%.4f->%.4f\n",
ripples.entranceFloorWorstTrack,ripples.entranceFloorWorstDistanceMetres,
ripples.entranceFloorPriorResidualMetres,
ripples.entranceFloorCurrentResidualMetres);
std::printf("[CavernTunnelRipple] layout=L46 floor_samples=%zu floor_peak_period_m=%.3f floor_peak_amplitude_m=%.4f floor_limit_m=0.015 wall_samples=%zu wall_peak_period_m=%.3f wall_peak_amplitude_m=%.4f wall_period_band_m=0.250..1.000 wall_detrend_window_m=2.000 wall_limit_m=0.035 status=%s\n",
ripples.floorSamples,ripples.floorPeakPeriodMetres,
ripples.floorPeakAmplitudeMetres,ripples.wallSamples,
ripples.wallPeakPeriodMetres,ripples.wallPeakAmplitudeMetres,
ripples.passed?"PASS":"FAIL");
const auto candidate=AuditLandmarkWalkPath(Shape,Assembly,*ResolvedLayout,
World.CoreVoxelSizeMicrons,"L46");
const auto daisStamp=std::find_if(ResolvedLayout->stamps.begin(),
ResolvedLayout->stamps.end(),[](const auto& stamp)
{return stamp.stableId=="landmark/sw-arrival-chamber-v1-dais";});
if(daisStamp!=ResolvedLayout->stamps.end())
{
const double voxelMetres=std::max<std::uint32_t>(1,
World.CoreVoxelSizeMicrons)/1000000.0;
for(const double offset:{-0.5,0.0,0.5,0.9,1.2})
{
const double x=daisStamp->positionMicrometres[0]/1000000.0;
const double y=daisStamp->positionMicrometres[1]/1000000.0;
const double z=daisStamp->positionMicrometres[2]/1000000.0+offset;
const double density=Shape.densityAt({x/voxelMetres,y/voxelMetres,
z/voxelMetres})*voxelMetres;
std::printf("[LandmarkDaisProfile] offset_m=%.2f sample_z_m=%.3f density_m=%.4f\n",
offset,z,density);
}
}
VoxelForgeCore::ResolvedLayoutSnapshotV3 oldLayout;
std::string oldError;
if(!MakeL43BuriedLandmarkControl(*ResolvedLayout,oldLayout,oldError))
{std::fprintf(stderr,"[LandmarkReachabilityAudit] L43 control layout failed: %s\n",
oldError.c_str());return 2;}
auto oldSnapshot=CoreSnapshot.withResolvedLayout(oldLayout);
if(!oldSnapshot)
{std::fprintf(stderr,"[LandmarkReachabilityAudit] could not construct L43 control snapshot\n");return 2;}
VoxelForgeCore::World oldShape(oldSnapshot);
std::string oldBuildError;
if(!oldShape.compile(ShapeRequest,Scheduler,oldBuildError))
{std::fprintf(stderr,"[LandmarkReachabilityAudit] L43 control field build failed: %s\n",
oldBuildError.c_str());return 2;}
const auto buried=AuditLandmarkWalkPath(oldShape,Assembly,*ResolvedLayout,
World.CoreVoxelSizeMicrons,"L43");
std::printf("[LandmarkWalkability] layout=L46 path_samples=%llu capsule_samples=%llu blocked=%llu support_samples=%llu unsupported=%llu grade_failures=%llu max_grade_deg=%.3f limit_deg=15.000 min_clearance_m=%.3f max_support_depth_m=%.3f min_headroom_m=%.3f headroom_required_m=0.300 status=%s\n",
static_cast<unsigned long long>(candidate.pathSamples),
static_cast<unsigned long long>(candidate.capsuleSamples),
static_cast<unsigned long long>(candidate.blockedCapsuleSamples),
static_cast<unsigned long long>(candidate.supportSamples),
static_cast<unsigned long long>(candidate.unsupportedSamples),
static_cast<unsigned long long>(candidate.gradeFailures),
candidate.maximumGradeDegrees,candidate.minimumClearanceMetres,
candidate.maximumSupportDepthMetres,candidate.minimumHeadroomMetres,
candidate.passed?"PASS":"FAIL");
std::printf("[LandmarkHeadroom] minimum_m=%.3f required_m=0.300 status=%s\n",
candidate.minimumHeadroomMetres,
candidate.minimumHeadroomMetres>=0.300?"PASS":"FAIL");
std::printf("[LandmarkReachabilityControl] layout=L43-buried path_samples=%llu blocked=%llu unsupported=%llu grade_failures=%llu result=%s expected=FAIL status=%s\n",
static_cast<unsigned long long>(buried.pathSamples),
static_cast<unsigned long long>(buried.blockedCapsuleSamples),
static_cast<unsigned long long>(buried.unsupportedSamples),
static_cast<unsigned long long>(buried.gradeFailures),
buried.passed?"PASS":"FAIL",buried.passed?"FAIL":"PASS");
const bool passed=ripples.passed&&entranceFloorPassed
&&candidate.passed&&!buried.passed;
std::printf("[LandmarkReachabilityAudit] positive=PASS control=%s status=%s\n",
buried.passed?"FAILED":"EXPECTED_FAIL",passed?"PASS":"FAIL");
return passed?0:13;
}
if(bAuditStrateTransitions)
{
if(ResolvedLayout==nullptr||!CoreSnapshot.resolvedLayout())
{Streamer.Stop();std::fprintf(stderr,"[StrateTransitionAudit] missing resolved-layout snapshot\n");return 2;}
const bool passed=AuditResolvedStrateTransitions(Shape,World,*ResolvedLayout);
Streamer.Stop();
return passed?0:11;
}
if(bAuditResolvedLayoutPassages)
{
if(ResolvedLayout==nullptr||!CoreSnapshot.resolvedLayout())
{Streamer.Stop();std::fprintf(stderr,"[ResolvedPassageAudit] missing resolved-layout snapshot\n");return 2;}
struct FWalkAudit
{
std::uint64_t segments=0,centers=0,capsuleSamples=0,blocked=0;
std::uint64_t supportSamples=0,unsupported=0,gradeFailures=0;
std::array<std::array<double,4>,8> firstBlocked{};
std::array<std::array<double,4>,8> firstUnsupported{};
std::array<std::array<bool,5>,8> firstSupportMasks{};
std::size_t firstBlockedCount=0,firstUnsupportedCount=0;
std::array<double,4> firstDeepUnsupported{};
std::array<bool,5> firstDeepSupportMask{};
bool hasDeepUnsupported=false;
bool passed=false;
};
struct FPassageSegmentSupportAudit
{
std::uint64_t centers=0,unsupported=0,nativeUnsupported=0;
std::array<double,3> firstUnsupported{};
std::array<double,4> firstNativeDensities{};
std::uint32_t firstNativeSupportedProbes=0;
bool hasUnsupported=false;
};
const double coreMetres=static_cast<double>(World.CoreVoxelSizeMicrons)/1000000.0;
const auto auditPlayerPath=[&](const VoxelForgeCore::World& Field,
const std::vector<std::array<double,3>>& path,
double supportStartMetres,double supportStepMetres,
double supportMaximumMetres,std::uint32_t minimumSupportProbes,
double supportProbeRadiusMetres,
const VoxelForgeCore::World* nativeField=nullptr,
std::vector<FPassageSegmentSupportAudit>* segmentSupport=nullptr)
{
FWalkAudit audit;
if(path.size()<2)return audit;
if(segmentSupport)segmentSupport->assign(path.size()-1,{});
constexpr std::array<double,7> heights{{-0.84,-0.60,-0.30,0.0,0.30,0.60,0.84}};
constexpr std::array<std::array<double,2>,8> directions{{
{{1.0,0.0}},{{0.7071067811865475,0.7071067811865475}},{{0.0,1.0}},
{{-0.7071067811865475,0.7071067811865475}},{{-1.0,0.0}},
{{-0.7071067811865475,-0.7071067811865475}},{{0.0,-1.0}},
{{0.7071067811865475,-0.7071067811865475}}}};
const auto solidAt=[&](double xMetres,double yMetres,double zMetres)
{
++audit.capsuleSamples;
const VoxelForgeCore::Vec3d position{xMetres/coreMetres,yMetres/coreMetres,zMetres/coreMetres};
const float density=Field.densityAt(position);
if(density<0.0f)
{
if(audit.firstBlockedCount<audit.firstBlocked.size())
{
audit.firstBlocked[audit.firstBlockedCount++]={xMetres,yMetres,zMetres,density};
std::printf("[ResolvedWalkDispatch] kind=blocked xyz_m=(%.3f,%.3f,%.3f) path=%s\n",
xMetres,yMetres,zMetres,Field.densityDispatchPathAt(position).c_str());
}
++audit.blocked;return true;
}
return false;
};
for(std::size_t segment=1;segment<path.size();++segment)
{
++audit.segments;
const auto& a=path[segment-1];const auto& b=path[segment];
const double dx=b[0]-a[0],dy=b[1]-a[1],dz=b[2]-a[2];
const double horizontal=std::hypot(dx,dy)*coreMetres;
const double vertical=std::abs(dz)*coreMetres;
if(horizontal<=1.0e-6||vertical>horizontal*0.2679491924311227)
++audit.gradeFailures;
const double length=std::sqrt(dx*dx+dy*dy+dz*dz)*coreMetres;
const std::uint64_t intervals=std::max<std::uint64_t>(1,
static_cast<std::uint64_t>(std::ceil(length/0.5)));
for(std::uint64_t step=0;step<=intervals;++step)
{
if(segment>1&&step==0)continue;
const double t=static_cast<double>(step)/intervals;
const double x=(a[0]+dx*t)*coreMetres;
const double y=(a[1]+dy*t)*coreMetres;
const double z=(a[2]+dz*t)*coreMetres;
++audit.centers;
FPassageSegmentSupportAudit* segmentAudit=segmentSupport
?&(*segmentSupport)[segment-1]:nullptr;
if(segmentAudit)++segmentAudit->centers;
for(const double h:heights)
{
const double capOffset=std::max(0.0,std::abs(h)-0.54);
const double radial=std::abs(h)<=0.54?0.34
:std::sqrt(std::max(0.0,0.34*0.34-capOffset*capOffset));
solidAt(x,y,z+h);
for(const auto& direction:directions)
solidAt(x+direction[0]*radial,y+direction[1]*radial,z+h);
}
const double footZ=z-0.88;
const std::array<std::array<double,2>,5> supportOffsets{{
{{0.0,0.0}},{{supportProbeRadiusMetres,0.0}},
{{-supportProbeRadiusMetres,0.0}},
{{0.0,supportProbeRadiusMetres}},
{{0.0,-supportProbeRadiusMetres}}}};
std::uint32_t supportedProbes=0;
std::uint32_t nativeSupportedProbes=0;
double firstUnsupportedX=x,firstUnsupportedY=y,lastUnsupportedDensity=0.0;
std::array<bool,5> supportMask{};
for(std::size_t offsetIndex=0;offsetIndex<supportOffsets.size();++offsetIndex)
{
const auto& offset=supportOffsets[offsetIndex];
const double supportX=x+offset[0],supportY=y+offset[1];
bool supported=false;
for(double depth=supportStartMetres;
depth<=supportMaximumMetres+1.0e-6;depth+=supportStepMetres)
{
++audit.supportSamples;
lastUnsupportedDensity=Field.densityAt({supportX/coreMetres,
supportY/coreMetres,(footZ-depth)/coreMetres});
if(lastUnsupportedDensity<0.0)
{
supported=true;break;
}
}
if(nativeField)
{
for(double depth=supportStartMetres;
depth<=supportMaximumMetres+1.0e-6;depth+=supportStepMetres)
if(nativeField->densityAt({supportX/coreMetres,
supportY/coreMetres,(footZ-depth)/coreMetres})<0.0f)
{++nativeSupportedProbes;break;}
}
if(supported){++supportedProbes;supportMask[offsetIndex]=true;}
else{firstUnsupportedX=supportX;firstUnsupportedY=supportY;}
}
if(nativeField&&segmentAudit
&&nativeSupportedProbes<minimumSupportProbes)
++segmentAudit->nativeUnsupported;
if(supportedProbes<minimumSupportProbes)
{
++audit.unsupported;
if(segmentAudit)
{
++segmentAudit->unsupported;
if(!segmentAudit->hasUnsupported)
{
segmentAudit->hasUnsupported=true;
segmentAudit->firstUnsupported={x,y,footZ};
segmentAudit->firstNativeSupportedProbes=nativeSupportedProbes;
if(nativeField)
{
constexpr std::array<double,4> depths{{0.125,1.0,2.0,4.0}};
for(std::size_t depthIndex=0;depthIndex<depths.size();++depthIndex)
segmentAudit->firstNativeDensities[depthIndex]=nativeField->densityAt({
x/coreMetres,y/coreMetres,
(footZ-depths[depthIndex])/coreMetres});
}
}
}
if(!audit.hasDeepUnsupported&&footZ<-80.0)
{
audit.hasDeepUnsupported=true;
audit.firstDeepUnsupported={firstUnsupportedX,firstUnsupportedY,
footZ,lastUnsupportedDensity};
audit.firstDeepSupportMask=supportMask;
}
if(audit.firstUnsupportedCount<audit.firstUnsupported.size())
{
const std::size_t sample=audit.firstUnsupportedCount++;
audit.firstUnsupported[sample]={
firstUnsupportedX,firstUnsupportedY,footZ,lastUnsupportedDensity};
audit.firstSupportMasks[sample]=supportMask;
std::printf("[ResolvedWalkDispatch] kind=unsupported xyz_m=(%.3f,%.3f,%.3f) support_probes=%u/5 mask=%d%d%d%d%d path=%s\n",
firstUnsupportedX,firstUnsupportedY,footZ,supportedProbes,
supportMask[0],supportMask[1],supportMask[2],supportMask[3],supportMask[4],
Field.densityDispatchPathAt({firstUnsupportedX/coreMetres,
firstUnsupportedY/coreMetres,footZ/coreMetres}).c_str());
}
}
}
}
audit.passed=audit.centers>0&&audit.blocked==0&&audit.unsupported==0
&&audit.gradeFailures==0;
return audit;
};
const auto qToMetres=[&](std::int64_t q)
{return static_cast<double>(q)*World.CoreVoxelSizeMicrons
/(VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel*1000000.0);};
struct FPassageNaturalnessAudit
{
double maximumFlatRunMetres=0.0;
double wallReliefPeakToPeakMetres=0.0;
std::uint64_t wallSamples=0,missingWallSamples=0;
bool passed=false;
};
struct FPassageMouthProfileAudit
{
double floorFlatStepRunMetres=0.0,floorStepMetres=0.0;
double wallFlatStepRunMetres=0.0,wallStepMetres=0.0;
std::uint64_t floorSamples=0,wallSamples=0,missingFloorSamples=0,missingWallSamples=0;
bool passed=false;
};
struct FPassageRippleAudit
{
double periodMetres=0.0,amplitudeMetres=0.0,localPeakAmplitudeMetres=0.0;
double coherentPeriodMetres=0.0,coherentAmplitudeMetres=0.0;
double controlAmplitudeMetres=0.0;
double floorPeriodMetres=0.0,floorAmplitudeMetres=0.0;
double floorControlAmplitudeMetres=0.0;
double floorCoherentPeriodMetres=0.0,floorCoherentAmplitudeMetres=0.0;
std::vector<std::array<double,6>> floorPeakProfile;
double floorPeakWindowStartMetres=0.0;
std::uint64_t samples=0,expectedSamples=0;
std::uint64_t floorSamples=0,floorExpectedSamples=0;
bool controlDetected=false,passed=false;
bool floorControlDetected=false;
};
constexpr double MaximumFlatRunMetres=8.0;
constexpr double MinimumWallReliefMetres=0.20;
constexpr double PassageProfileSpacingMetres=0.125;
constexpr double PassageProfilePlateauMinimumMetres=0.50;
constexpr double PassageProfilePlateauEpsilonMetres=0.020;
constexpr double PassageProfileStepThresholdMetres=0.100;
constexpr double PassageMouthProfileReachMetres=12.0;
const auto auditProfilePlateaus=[&](const std::vector<std::array<double,2>>& profile)
{
std::pair<double,double> result{};
if(profile.size()<2)return result;
std::size_t runStart=0;
for(std::size_t i=1;i<profile.size();++i)
{
if(profile[i][0]-profile[i-1][0]
>PassageProfileSpacingMetres*1.5)
{runStart=i;continue;}
if(std::abs(profile[i][1]-profile[runStart][1])
<=PassageProfilePlateauEpsilonMetres)continue;
const double flatLength=profile[i-1][0]-profile[runStart][0];
const double step=std::abs(profile[i][1]-profile[i-1][1]);
if(flatLength>=PassageProfilePlateauMinimumMetres
&&step>=PassageProfileStepThresholdMetres)
{
result.first=std::max(result.first,flatLength);
result.second=std::max(result.second,step);
}
runStart=i;
}
return result;
};
const auto auditPassageMouthProfiles=[&](const VoxelForgeCore::World& Field,
const VoxelForgeCore::ResolvedLayoutPassageV1& passage)
{
FPassageMouthProfileAudit audit;
if(passage.controlPoints.size()<2)return audit;
const std::size_t end=std::min(passage.lowerMouthControlIndex,
passage.controlPoints.size()-1);
if(end<1)return audit;
struct FProfilePose
{
double distance=0.0,x=0.0,y=0.0,z=0.0,radius=0.0;
};
std::vector<FProfilePose> path;
path.reserve(end*8+1);
double distance=0.0;
for(std::size_t segment=0;segment<end;++segment)
{
const auto& a=passage.controlPoints[segment];
const auto& b=passage.controlPoints[segment+1];
const double ax=qToMetres(a.positionSubvoxels[0]);
const double ay=qToMetres(a.positionSubvoxels[1]);
const double az=qToMetres(a.positionSubvoxels[2]);
const double bx=qToMetres(b.positionSubvoxels[0]);
const double by=qToMetres(b.positionSubvoxels[1]);
const double bz=qToMetres(b.positionSubvoxels[2]);
const double ar=qToMetres(a.radiusSubvoxels);
const double br=qToMetres(b.radiusSubvoxels);
const double length=std::sqrt((bx-ax)*(bx-ax)+(by-ay)*(by-ay)+(bz-az)*(bz-az));
if(!(length>1.0e-8))continue;
const std::size_t steps=std::max<std::size_t>(1,
static_cast<std::size_t>(std::ceil(length/PassageProfileSpacingMetres)));
for(std::size_t step=segment==0?0:1;step<=steps;++step)
{
const double t=static_cast<double>(step)/steps;
path.push_back({distance+length*t,std::lerp(ax,bx,t),
std::lerp(ay,by,t),std::lerp(az,bz,t),std::lerp(ar,br,t)});
}
distance+=length;
}
if(path.size()<3)return audit;
const double lowerMouthDistance=distance;
constexpr double DensitySearchStepMetres=0.0625;
const auto densityMetres=[&](double x,double y,double z)
{
const float value=Field.densityAt({x/coreMetres,y/coreMetres,z/coreMetres});
return std::isfinite(value)?static_cast<double>(value)*coreMetres
:std::numeric_limits<double>::quiet_NaN();
};
const auto firstFloorCrossing=[&](const FProfilePose& pose,double x,double y)->double
{
const double expectedFloor=pose.z-pose.radius;
const double maximumRise=std::min(2.0*pose.radius-0.25,
std::max(0.75,pose.radius-1.20+0.50));
double previousZ=expectedFloor-1.50;
double previous=densityMetres(x,y,previousZ);
if(!std::isfinite(previous))return std::numeric_limits<double>::quiet_NaN();
double highestFloor=std::numeric_limits<double>::quiet_NaN();
for(double z=previousZ+DensitySearchStepMetres;
z<=expectedFloor+maximumRise+DensitySearchStepMetres*0.25;
z+=DensitySearchStepMetres)
{
const double current=densityMetres(x,y,z);
if(!std::isfinite(current))return std::numeric_limits<double>::quiet_NaN();
if(previous<=0.0&&current>=0.0)
{
const double denominator=current-previous;
const double t=std::abs(denominator)>1.0e-12
?std::clamp(-previous/denominator,0.0,1.0):0.0;
highestFloor=std::lerp(z-DensitySearchStepMetres,z,t);
}
previous=current;
}
return highestFloor;
};
const auto findWallRadius=[&](const FProfilePose& pose,double nx,double ny)
{
const double maximum=pose.radius+2.0;
double previousRadius=0.0;
double previous=densityMetres(pose.x,pose.y,pose.z);
if(!std::isfinite(previous)||previous<0.0)
return std::numeric_limits<double>::quiet_NaN();
for(double radius=DensitySearchStepMetres;radius<=maximum;
radius+=DensitySearchStepMetres)
{
const double current=densityMetres(pose.x+nx*radius,
pose.y+ny*radius,pose.z);
if(!std::isfinite(current))return std::numeric_limits<double>::quiet_NaN();
if(previous>=0.0&&current<=0.0)
{
const double denominator=previous-current;
const double t=std::abs(denominator)>1.0e-12
?std::clamp(previous/denominator,0.0,1.0):0.0;
return std::lerp(previousRadius,radius,t);
}
previous=current;previousRadius=radius;
}
return std::numeric_limits<double>::quiet_NaN();
};
std::array<std::array<std::vector<std::array<double,2>>,3>,2> floorProfiles;
std::array<std::array<std::vector<std::array<double,2>>,2>,2> wallProfiles;
std::array<double,2> endpointFloorCounts{};
for(std::size_t i=0;i<path.size();++i)
{
const auto& pose=path[i];
const bool inUpperWindow=pose.distance<=PassageMouthProfileReachMetres;
const bool inLowerWindow=lowerMouthDistance-pose.distance
<=PassageMouthProfileReachMetres;
if(!inUpperWindow&&!inLowerWindow)continue;
for(std::size_t endpoint=0;endpoint<2;++endpoint)
{
if((endpoint==0&&!inUpperWindow)||(endpoint==1&&!inLowerWindow))continue;
const double localDistance=endpoint==0?pose.distance
:lowerMouthDistance-pose.distance;
const double tangentX=i==0?path[i+1].x-path[i].x
:i+1>=path.size()?path[i].x-path[i-1].x
:path[i+1].x-path[i-1].x;
const double tangentY=i==0?path[i+1].y-path[i].y
:i+1>=path.size()?path[i].y-path[i-1].y
:path[i+1].y-path[i-1].y;
const double tangentLength=std::hypot(tangentX,tangentY);
if(tangentLength<=1.0e-6)
{audit.missingFloorSamples+=3;audit.missingWallSamples+=2;continue;}
const double nx=-tangentY/tangentLength,ny=tangentX/tangentLength;
for(std::size_t lane=0;lane<3;++lane)
{
const double lateral=lane==0?0.0:lane==1?0.75:-0.75;
const double floor=firstFloorCrossing(pose,
pose.x+nx*lateral,pose.y+ny*lateral);
if(lane!=0&&localDistance>=4.0&&localDistance<=5.5)
std::printf("[PassageMouthProfileProbe] id=%s endpoint=%s d_m=%.3f lane_m=%.2f x_m=%.3f y_m=%.3f route_floor_m=%.3f field_floor_m=%.3f\n",
passage.stableId.c_str(),endpoint==0?"upper":"lower",
localDistance,lateral,pose.x+nx*lateral,
pose.y+ny*lateral,pose.z-pose.radius,floor);
if(std::isfinite(floor))
{
floorProfiles[endpoint][lane].push_back({localDistance,floor});
++endpointFloorCounts[endpoint];++audit.floorSamples;
}
else ++audit.missingFloorSamples;
}
if(i%4!=0)continue;
for(std::size_t side=0;side<2;++side)
{
const double sign=side==0?-1.0:1.0;
const double radius=findWallRadius(pose,sign*nx,sign*ny);
if(std::isfinite(radius))
{
wallProfiles[endpoint][side].push_back({localDistance,radius});
++audit.wallSamples;
}
else ++audit.missingWallSamples;
}
}
}
double worstEndpointFloorCoverage=1.0;
for(std::size_t endpoint=0;endpoint<2;++endpoint)
{
for(std::size_t lane=0;lane<3;++lane)
std::sort(floorProfiles[endpoint][lane].begin(),
floorProfiles[endpoint][lane].end(),
[](const auto& a,const auto& b){return a[0]<b[0];});
for(std::size_t side=0;side<2;++side)
std::sort(wallProfiles[endpoint][side].begin(),
wallProfiles[endpoint][side].end(),
[](const auto& a,const auto& b){return a[0]<b[0];});
const double expectedFloor=std::min<double>(path.size(),
PassageMouthProfileReachMetres/PassageProfileSpacingMetres)+1.0;
worstEndpointFloorCoverage=std::min(worstEndpointFloorCoverage,
expectedFloor>0?endpointFloorCounts[endpoint]/expectedFloor:0.0);
// Lateral probes confirm floor coverage, but do not define a longitudinal
// floor profile: the normal rotates around tight bends and can jump across
// unrelated terrain. The centerline is the stable passage-floor trace.
const auto floorStep=auditProfilePlateaus(floorProfiles[endpoint][0]);
audit.floorFlatStepRunMetres=std::max(audit.floorFlatStepRunMetres,
floorStep.first);
audit.floorStepMetres=std::max(audit.floorStepMetres,floorStep.second);
for(std::size_t side=0;side<2;++side)
{
const auto wallStep=auditProfilePlateaus(wallProfiles[endpoint][side]);
audit.wallFlatStepRunMetres=std::max(audit.wallFlatStepRunMetres,wallStep.first);
audit.wallStepMetres=std::max(audit.wallStepMetres,wallStep.second);
}
}
audit.passed=worstEndpointFloorCoverage>=0.75
&&audit.wallSamples>=8
&&audit.floorFlatStepRunMetres==0.0&&audit.wallFlatStepRunMetres==0.0;
return audit;
};
std::vector<std::array<double,2>> l23TerracedControl;
for(std::size_t tread=0;tread<8;++tread)
for(std::size_t sample=0;sample<=16;++sample)
l23TerracedControl.push_back({(tread*16+sample)*PassageProfileSpacingMetres,
static_cast<double>(tread)*0.25});
const auto l23TerraceControlResult=auditProfilePlateaus(l23TerracedControl);
const bool l23TerraceControlDetected=l23TerraceControlResult.first
>=PassageProfilePlateauMinimumMetres
&&l23TerraceControlResult.second>=PassageProfileStepThresholdMetres;
const auto auditPassageNaturalness=[&](const VoxelForgeCore::World& Field,
const VoxelForgeCore::ResolvedLayoutPassageV1& passage)
{
FPassageNaturalnessAudit audit;
const std::size_t end=std::min<std::size_t>(passage.lowerMouthControlIndex,
passage.controlPoints.size()-1);
double flatRun=0.0;
for(std::size_t i=1;i<=end;++i)
{
const auto& a=passage.controlPoints[i-1];
const auto& b=passage.controlPoints[i];
const double dx=qToMetres(b.positionSubvoxels[0]-a.positionSubvoxels[0]);
const double dy=qToMetres(b.positionSubvoxels[1]-a.positionSubvoxels[1]);
const double floorA=qToMetres(a.positionSubvoxels[2]-a.radiusSubvoxels)+1.13;
const double floorB=qToMetres(b.positionSubvoxels[2]-b.radiusSubvoxels)+1.13;
const double dz=floorB-floorA;
const double horizontal=std::hypot(dx,dy);
if(horizontal>1.0e-6&&std::abs(dz)/horizontal
<std::tan(0.5*3.14159265358979323846/180.0))
{flatRun+=horizontal;audit.maximumFlatRunMetres=std::max(
audit.maximumFlatRunMetres,flatRun);}
else flatRun=0.0;
}
if(end>=6)
{
const std::size_t sampleCount=std::min<std::size_t>(64,end-4);
double minimumRadius=std::numeric_limits<double>::infinity();
double maximumRadius=-std::numeric_limits<double>::infinity();
for(std::size_t sample=0;sample<sampleCount;++sample)
{
const std::size_t index=2+(sample*(end-4))
/std::max<std::size_t>(1,sampleCount-1);
const auto& point=passage.controlPoints[index];
const auto& before=passage.controlPoints[index-1];
const auto& after=passage.controlPoints[index+1];
const double tangentX=qToMetres(after.positionSubvoxels[0]-before.positionSubvoxels[0]);
const double tangentY=qToMetres(after.positionSubvoxels[1]-before.positionSubvoxels[1]);
const double tangentLength=std::hypot(tangentX,tangentY);
if(tangentLength<=1.0e-6){++audit.missingWallSamples;continue;}
const double radiusMetres=qToMetres(point.radiusSubvoxels);
const double sampleRadius=std::max(0.20,radiusMetres-0.18);
const double centerX=qToMetres(point.positionSubvoxels[0]);
const double centerY=qToMetres(point.positionSubvoxels[1]);
const double centerZ=qToMetres(point.positionSubvoxels[2]);
const double nx=-tangentY/tangentLength,ny=tangentX/tangentLength;
for(const double side:{-1.0,1.0})
{
const VoxelForgeCore::Vec3d probe{
(centerX+side*nx*sampleRadius)/coreMetres,
(centerY+side*ny*sampleRadius)/coreMetres,
centerZ/coreMetres};
const double density=Field.densityAt(probe);
if(!std::isfinite(density)){++audit.missingWallSamples;continue;}
const double densityMetres=density*coreMetres;
if(densityMetres< -0.75||densityMetres>0.75)
{++audit.missingWallSamples;continue;}
// For the carved SDF, r + density is the wall radius. Its
// variation along the passage measures the applied rock relief.
const double wallRadius=sampleRadius+densityMetres;
minimumRadius=std::min(minimumRadius,wallRadius);
maximumRadius=std::max(maximumRadius,wallRadius);
++audit.wallSamples;
}
}
if(audit.wallSamples>0&&std::isfinite(minimumRadius)
&&std::isfinite(maximumRadius))
audit.wallReliefPeakToPeakMetres=maximumRadius-minimumRadius;
}
audit.passed=audit.maximumFlatRunMetres<=MaximumFlatRunMetres
&&audit.wallReliefPeakToPeakMetres>=MinimumWallReliefMetres
&&audit.wallSamples>=8;
return audit;
};
const auto auditPassageRipples=[&](const VoxelForgeCore::World& Field,
const VoxelForgeCore::ResolvedLayoutPassageV1& passage)
{
FPassageRippleAudit audit;
constexpr double SampleSpacingMetres=0.125;
constexpr double WindowLengthMetres=32.0;
constexpr double MinimumPeriodMetres=0.5;
constexpr double MaximumPeriodMetres=8.0;
constexpr double PeriodStepMetres=0.0625;
constexpr double RippleAmplitudeLimitMetres=0.035;
constexpr double FloorRippleAmplitudeLimitMetres=0.015;
struct FPathPoint
{
double x=0.0,y=0.0,z=0.0,radius=0.0,distance=0.0;
};
const std::size_t end=std::min<std::size_t>(passage.lowerMouthControlIndex,
passage.controlPoints.size()-1);
if(end<2)return audit;
std::vector<FPathPoint> path;
path.reserve(end+1);
for(std::size_t i=0;i<=end;++i)
{
const auto& point=passage.controlPoints[i];
FPathPoint value{qToMetres(point.positionSubvoxels[0]),
qToMetres(point.positionSubvoxels[1]),
qToMetres(point.positionSubvoxels[2]),
qToMetres(point.radiusSubvoxels),0.0};
if(!path.empty())
{
const auto& previous=path.back();
value.distance=previous.distance+std::sqrt(
(value.x-previous.x)*(value.x-previous.x)
+(value.y-previous.y)*(value.y-previous.y)
+(value.z-previous.z)*(value.z-previous.z));
}
path.push_back(value);
}
const double total=path.back().distance;
if(total<WindowLengthMetres)return audit;
const auto interpolate=[&](double distance)
{
distance=std::clamp(distance,0.0,total);
const auto upper=std::lower_bound(path.begin()+1,path.end(),distance,
[](const FPathPoint& point,double value){return point.distance<value;});
const auto& b=*upper;
const auto& a=*(upper-1);
const double length=b.distance-a.distance;
const double t=length>1.0e-9?(distance-a.distance)/length:0.0;
return FPathPoint{std::lerp(a.x,b.x,t),std::lerp(a.y,b.y,t),
std::lerp(a.z,b.z,t),std::lerp(a.radius,b.radius,t),distance};
};
const auto sinusoidAmplitude=[&](const std::vector<std::array<double,2>>& samples,
double& bestPeriod)
{
if(samples.size()<64)return 0.0;
double best=0.0;
for(double period=MinimumPeriodMetres;
period<=MaximumPeriodMetres+1.0e-9;period+=PeriodStepMetres)
{
const double angular=6.2831853071795864769/period;
double cc=0.0,ss=0.0,cs=0.0,yc=0.0,ys=0.0;
for(const auto& sample:samples)
{
const double phase=angular*sample[0];
const double c=std::cos(phase),s=std::sin(phase);
cc+=c*c;ss+=s*s;cs+=c*s;
yc+=sample[1]*c;ys+=sample[1]*s;
}
const double determinant=cc*ss-cs*cs;
if(determinant<=1.0e-9)continue;
const double cosine=(yc*ss-ys*cs)/determinant;
const double sine=(ys*cc-yc*cs)/determinant;
const double amplitude=std::hypot(cosine,sine);
if(amplitude>best){best=amplitude;bestPeriod=period;}
}
return best;
};
const auto appendDetrendedProfile=[&](const std::vector<double>& values,
double startDistance,std::vector<std::array<double,2>>& output)
{
if(values.size()<64)return;
const double meanIndex=0.5*static_cast<double>(values.size()-1);
double mean=0.0,xy=0.0,xx=0.0;
for(double value:values)mean+=value;
mean/=static_cast<double>(values.size());
for(std::size_t i=0;i<values.size();++i)
{
const double x=(static_cast<double>(i)-meanIndex)*SampleSpacingMetres;
xy+=x*(values[i]-mean);xx+=x*x;
}
const double slope=xx>0.0?xy/xx:0.0;
for(std::size_t i=0;i<values.size();++i)
{
const double x=(static_cast<double>(i)-meanIndex)*SampleSpacingMetres;
output.push_back({startDistance+static_cast<double>(i)*SampleSpacingMetres,
values[i]-mean-slope*x});
}
};
const auto appendDetrendedPairs=[](
const std::vector<std::array<double,2>>& values,
std::vector<std::array<double,2>>& output)
{
if(values.size()<64)return;
double meanX=0.0,meanY=0.0;
for(const auto& value:values){meanX+=value[0];meanY+=value[1];}
meanX/=static_cast<double>(values.size());
meanY/=static_cast<double>(values.size());
double xy=0.0,xx=0.0;
for(const auto& value:values)
{
const double x=value[0]-meanX;
xy+=x*(value[1]-meanY);xx+=x*x;
}
const double slope=xx>0.0?xy/xx:0.0;
for(const auto& value:values)
output.push_back({value[0],value[1]-meanY
-slope*(value[0]-meanX)});
};
std::vector<double> beadControl;
beadControl.reserve(static_cast<std::size_t>(WindowLengthMetres/SampleSpacingMetres)+1);
constexpr double BeadSpacingMetres=1.5;
constexpr double BeadSphereRadiusMetres=2.0;
for(std::size_t i=0;i<=static_cast<std::size_t>(WindowLengthMetres/SampleSpacingMetres);++i)
{
const double x=static_cast<double>(i)*SampleSpacingMetres;
const double nearest=std::abs(std::remainder(x,BeadSpacingMetres));
beadControl.push_back(std::sqrt(std::max(0.0,
BeadSphereRadiusMetres*BeadSphereRadiusMetres-nearest*nearest)));
}
std::vector<std::array<double,2>> beadSamples;
appendDetrendedProfile(beadControl,0.0,beadSamples);
double ignoredPeriod=0.0;
audit.controlAmplitudeMetres=sinusoidAmplitude(beadSamples,ignoredPeriod);
audit.controlDetected=audit.controlAmplitudeMetres>=RippleAmplitudeLimitMetres;
audit.floorControlAmplitudeMetres=audit.controlAmplitudeMetres;
audit.floorControlDetected=audit.floorControlAmplitudeMetres
>=FloorRippleAmplitudeLimitMetres;
const std::array<double,5> windowStarts{{0.03,0.31,0.457,0.61,0.91}};
std::vector<std::array<double,2>> coherentSamples;
std::vector<std::array<double,2>> coherentFloorSamples;
for(const double fraction:windowStarts)
{
const double start=(total-WindowLengthMetres)*fraction;
std::vector<double> radii;
radii.reserve(static_cast<std::size_t>(WindowLengthMetres/SampleSpacingMetres)+1);
std::vector<std::array<double,2>> floorResiduals;
floorResiduals.reserve(static_cast<std::size_t>(WindowLengthMetres/
SampleSpacingMetres)+1);
std::vector<std::array<double,6>> floorDebugSamples;
floorDebugSamples.reserve(static_cast<std::size_t>(WindowLengthMetres/
SampleSpacingMetres)+1);
for(std::size_t sample=0;
sample<=static_cast<std::size_t>(WindowLengthMetres/SampleSpacingMetres);
++sample)
{
++audit.expectedSamples;
++audit.floorExpectedSamples;
const double distance=start+static_cast<double>(sample)*SampleSpacingMetres;
const auto pose=interpolate(distance);
// Recover the composed walk surface from its zero crossing.
// The support strip is segment-built and is not itself a true
// signed-distance field, so a fixed centerline radius misses
// the stepped top that the player actually walks on.
const double expectedFloor=pose.z-pose.radius+0.20;
constexpr double FloorProbeStepMetres=0.25;
constexpr int FloorProbeCount=7;
double previousDensity=0.0,previousZ=0.0;
bool havePrevious=false,haveFloor=false;
double bestFloor=0.0,bestDistance=std::numeric_limits<double>::infinity();
for(int vertical=0;vertical<FloorProbeCount;++vertical)
{
const double z=expectedFloor-1.0+vertical*FloorProbeStepMetres;
const double density=static_cast<double>(Field.densityAt({
pose.x/coreMetres,pose.y/coreMetres,z/coreMetres}))*coreMetres;
if(havePrevious&&previousDensity<0.0&&density>=0.0)
{
const double denominator=density-previousDensity;
const double crossing=denominator>1.0e-12
?previousZ+(z-previousZ)*(-previousDensity)/denominator:z;
const double candidateDistance=std::abs(crossing-expectedFloor);
if(candidateDistance<bestDistance)
{bestDistance=candidateDistance;bestFloor=crossing;haveFloor=true;}
}
previousDensity=density;previousZ=z;havePrevious=true;
}
if(haveFloor)
{
floorResiduals.push_back({distance,bestFloor-expectedFloor});
floorDebugSamples.push_back({distance,expectedFloor,bestFloor,
pose.x,pose.y,pose.z});
++audit.floorSamples;
}
const auto before=interpolate(std::max(0.0,distance-0.25));
const auto after=interpolate(std::min(total,distance+0.25));
const double tangentX=after.x-before.x,tangentY=after.y-before.y;
const double tangentLength=std::hypot(tangentX,tangentY);
if(tangentLength<=1.0e-6)continue;
const double nx=-tangentY/tangentLength,ny=tangentX/tangentLength;
const double sampleRadius=std::max(0.20,pose.radius-0.18);
const double x0=pose.x/coreMetres,y0=pose.y/coreMetres,z0=pose.z/coreMetres;
const double offset=sampleRadius/coreMetres;
const double left=static_cast<double>(Field.densityAt(
{x0+nx*offset,y0+ny*offset,z0}))*coreMetres;
const double right=static_cast<double>(Field.densityAt(
{x0-nx*offset,y0-ny*offset,z0}))*coreMetres;
if(!std::isfinite(left)||!std::isfinite(right)
||left< -0.75||left>0.75||right< -0.75||right>0.75)continue;
radii.push_back(sampleRadius+0.5*(left+right));
++audit.samples;
}
if(radii.size()<static_cast<std::size_t>(WindowLengthMetres/
SampleSpacingMetres)*3/4)continue;
std::vector<std::array<double,2>> windowSamples;
appendDetrendedProfile(radii,start,windowSamples);
double localPeriod=0.0;
const double localAmplitude=sinusoidAmplitude(windowSamples,localPeriod);
if(localAmplitude>audit.localPeakAmplitudeMetres)
{
audit.localPeakAmplitudeMetres=localAmplitude;
audit.periodMetres=localPeriod;
}
coherentSamples.insert(coherentSamples.end(),windowSamples.begin(),
windowSamples.end());
double floorWindowPeriod=0.0,floorWindowAmplitude=0.0;
if(floorResiduals.size()>=static_cast<std::size_t>(WindowLengthMetres/
SampleSpacingMetres)*3/4)
{
std::vector<std::array<double,2>> floorWindowSamples;
appendDetrendedPairs(floorResiduals,floorWindowSamples);
floorWindowAmplitude=sinusoidAmplitude(floorWindowSamples,
floorWindowPeriod);
if(floorWindowAmplitude>audit.floorAmplitudeMetres)
{
audit.floorAmplitudeMetres=floorWindowAmplitude;
audit.floorPeriodMetres=floorWindowPeriod;
audit.floorPeakWindowStartMetres=start;
audit.floorPeakProfile=std::move(floorDebugSamples);
}
coherentFloorSamples.insert(coherentFloorSamples.end(),
floorWindowSamples.begin(),floorWindowSamples.end());
}
const double floorWindowCoverage=static_cast<double>(floorResiduals.size())
/(WindowLengthMetres/SampleSpacingMetres+1.0);
double floorResidualMinimum=0.0,floorResidualMaximum=0.0;
if(!floorResiduals.empty())
{
const auto extrema=std::minmax_element(floorResiduals.begin(),
floorResiduals.end(),[](const auto& a,const auto& b)
{return a[1]<b[1];});
floorResidualMinimum=(*extrema.first)[1];
floorResidualMaximum=(*extrema.second)[1];
}
std::printf("[PassageFloorRippleWindow] id=%s start_m=%.3f "
"period_m=%.3f amplitude_m=%.4f coverage=%.3f "
"residual_range_m=%.4f..%.4f threshold_m=0.015\n",
passage.stableId.c_str(),start,floorWindowPeriod,floorWindowAmplitude,
floorWindowCoverage,floorResidualMinimum,floorResidualMaximum);
}
audit.coherentAmplitudeMetres=sinusoidAmplitude(coherentSamples,
audit.coherentPeriodMetres);
audit.floorCoherentAmplitudeMetres=sinusoidAmplitude(coherentFloorSamples,
audit.floorCoherentPeriodMetres);
audit.amplitudeMetres=audit.localPeakAmplitudeMetres;
const double coverage=audit.expectedSamples>0
?static_cast<double>(audit.samples)/audit.expectedSamples:0.0;
const double floorCoverage=audit.floorExpectedSamples>0
?static_cast<double>(audit.floorSamples)/audit.floorExpectedSamples:0.0;
audit.passed=audit.controlDetected&&coverage>=0.75
&&audit.localPeakAmplitudeMetres<RippleAmplitudeLimitMetres
&&audit.floorControlDetected&&floorCoverage>=0.75
&&audit.floorAmplitudeMetres<FloorRippleAmplitudeLimitMetres;
return audit;
};
const auto looksNatural=[&](double flatRun,double reliefPeakToPeak)
{return flatRun<=MaximumFlatRunMetres
&&reliefPeakToPeak>=MinimumWallReliefMetres;};
const auto findStratum=[&](std::int32_t index)->const VoxelForgeCore::ResolvedLayoutStratumV2*
{
const auto it=std::find_if(ResolvedLayout->strates.begin(),ResolvedLayout->strates.end(),
[index](const auto& s){return s.strateIndex==index;});
return it==ResolvedLayout->strates.end()?nullptr:&*it;
};
const auto controlSnapshot=CoreSnapshot.withoutResolvedLayoutPassages();
VoxelForgeCore::World blockedWorld(controlSnapshot);
std::string blockedCompileError;
const bool blockedCompiled=controlSnapshot
&&blockedWorld.compile(ShapeRequest,Scheduler,blockedCompileError);
if(!blockedCompiled)
{
Streamer.Stop();
std::fprintf(stderr,"[ResolvedPassageBlockedControl] compile_failed=%s\n",
blockedCompileError.c_str());
return 10;
}
struct FPassageOpenAirAudit
{
std::uint64_t supportSamples=0,violations=0,legacyViolations=0;
std::uint64_t columnSamples=0,shortSpanSamples=0;
std::uint64_t routeSupportSamples=0,routeSupportViolations=0;
std::array<std::array<double,4>,8> firstViolations{};
std::size_t firstViolationCount=0;
};
constexpr double PassageSupportAuditSpacingMetres=0.25;
constexpr std::array<double,2> PassageSupportAuditDepthsMetres{{0.125,0.375}};
constexpr std::array<std::array<double,2>,16> PassageSupportAuditDirections{{
{{1.0000000000000000,0.0000000000000000}},
{{0.9238795325112867,0.3826834323650898}},
{{0.7071067811865476,0.7071067811865476}},
{{0.3826834323650898,0.9238795325112867}},
{{0.0000000000000000,1.0000000000000000}},
{{-0.3826834323650898,0.9238795325112867}},
{{-0.7071067811865476,0.7071067811865476}},
{{-0.9238795325112867,0.3826834323650898}},
{{-1.0000000000000000,0.0000000000000000}},
{{-0.9238795325112867,-0.3826834323650898}},
{{-0.7071067811865476,-0.7071067811865476}},
{{-0.3826834323650898,-0.9238795325112867}},
{{0.0000000000000000,-1.0000000000000000}},
{{0.3826834323650898,-0.9238795325112867}},
{{0.7071067811865476,-0.7071067811865476}},
{{0.9238795325112867,-0.3826834323650898}}}};
const auto auditPassageOpenAir=[&](const VoxelForgeCore::World& Field,
const VoxelForgeCore::World& Native,
const VoxelForgeCore::ResolvedLayoutPassageV1& passage,
std::size_t passageIndex)
{
FPassageOpenAirAudit audit;
const auto inspect=[&](double xMetres,double yMetres,double floorMetres,
double depthMetres,double supportThicknessMetres,bool routeSupport=false,
std::size_t passageSegment=std::numeric_limits<std::size_t>::max())
{
if(depthMetres<=0.0||depthMetres>supportThicknessMetres+1.0e-6)return;
++audit.supportSamples;
audit.routeSupportSamples+=routeSupport;
const VoxelForgeCore::Vec3d sample{xMetres/coreMetres,yMetres/coreMetres,
(floorMetres-depthMetres)/coreMetres};
const float nativeDensity=Native.densityAt(sample);
const float passageDensity=Field.densityAt(sample);
const float legacySupportDensity=std::min(nativeDensity,
static_cast<float>(-depthMetres/coreMetres));
if(nativeDensity>=0.0f&&legacySupportDensity<0.0f)
++audit.legacyViolations;
if(nativeDensity>=0.0f&&passageDensity<0.0f)
{
const bool connectedColumn=!routeSupport
&&passageSegment!=std::numeric_limits<std::size_t>::max()
&&Field.isPassageColumnSample(passageIndex,passageSegment,sample);
if(connectedColumn){++audit.columnSamples;return;}
const bool groundedShortSpan=!routeSupport
&&passageSegment!=std::numeric_limits<std::size_t>::max()
&&Field.isPassageShortSpanSample(passageIndex,passageSegment,sample);
if(groundedShortSpan){++audit.shortSpanSamples;return;}
audit.routeSupportViolations+=routeSupport;
if(audit.firstViolationCount<audit.firstViolations.size())
audit.firstViolations[audit.firstViolationCount++]={xMetres,yMetres,
floorMetres-depthMetres,passageDensity};
++audit.violations;
}
};
const auto inspectFloorDisc=[&](double xMetres,double yMetres,double floorMetres,
double supportRadiusMetres,double depthMetres,double supportThicknessMetres,
bool routeSupport=false,
std::size_t passageSegment=std::numeric_limits<std::size_t>::max())
{
const std::size_t radialSteps=static_cast<std::size_t>(std::ceil(
supportRadiusMetres/PassageSupportAuditSpacingMetres));
for(std::size_t radialStep=0;radialStep<=radialSteps;++radialStep)
{
const double radial=std::min(supportRadiusMetres,
radialStep*PassageSupportAuditSpacingMetres);
for(const auto& direction:PassageSupportAuditDirections)
inspect(xMetres+direction[0]*radial,yMetres+direction[1]*radial,
floorMetres,depthMetres,supportThicknessMetres,routeSupport,
passageSegment);
}
};
for(std::size_t segment=1;segment<passage.controlPoints.size();++segment)
{
const auto& a=passage.controlPoints[segment-1];
const auto& b=passage.controlPoints[segment];
const double ax=qToMetres(a.positionSubvoxels[0]);
const double ay=qToMetres(a.positionSubvoxels[1]);
const double az=qToMetres(a.positionSubvoxels[2]);
const double bx=qToMetres(b.positionSubvoxels[0]);
const double by=qToMetres(b.positionSubvoxels[1]);
const double bz=qToMetres(b.positionSubvoxels[2]);
const double length=std::sqrt((bx-ax)*(bx-ax)+(by-ay)*(by-ay)+(bz-az)*(bz-az));
const std::size_t intervals=std::max<std::size_t>(1,static_cast<std::size_t>(
std::ceil(length/PassageSupportAuditSpacingMetres)));
for(std::size_t sample=0;sample<=intervals;++sample)
{
if(segment>1&&sample==0)continue;
const double t=static_cast<double>(sample)/intervals;
const double centerX=ax+(bx-ax)*t,centerY=ay+(by-ay)*t;
const double centerZ=az+(bz-az)*t;
const double radius=qToMetres(a.radiusSubvoxels)
+(qToMetres(b.radiusSubvoxels)-qToMetres(a.radiusSubvoxels))*t;
const double floorZ=centerZ-radius+0.20;
for(const double depth:PassageSupportAuditDepthsMetres)
inspectFloorDisc(centerX,centerY,floorZ,radius,depth,1.0,
false,segment-1);
}
}
const auto upperStratum=std::find_if(ResolvedLayout->strates.begin(),
ResolvedLayout->strates.end(),[&](const auto& value)
{return value.strateIndex==passage.upperStrateIndex;});
if(upperStratum!=ResolvedLayout->strates.end())
{
std::array<const VoxelForgeCore::ResolvedLayoutAnchorV2*,5> route{};
std::size_t routeCount=0;
for(const auto& anchor:upperStratum->anchors)
if(anchor.kind=="route_point"&&anchor.values.size()>=3)
{
if(routeCount<route.size())route[routeCount++]=&anchor;
else
{
std::move(route.begin()+1,route.end(),route.begin());
route.back()=&anchor;
}
}
const double mouthX=qToMetres(passage.upperMouthSubvoxels[0]);
const double mouthY=qToMetres(passage.upperMouthSubvoxels[1]);
constexpr double RouteSupportReachMetres=13.0;
constexpr double RouteFloorOffsetMetres=1.20;
constexpr double RouteSupportThicknessMetres=1.0;
constexpr double RouteSupportDepthStepMetres=0.125;
for(std::size_t segment=1;segment<routeCount;++segment)
{
const auto& a=*route[segment-1];
const auto& b=*route[segment];
const double ax=qToMetres(a.values[0]),ay=qToMetres(a.values[1]);
const double az=qToMetres(a.values[2]);
const double bx=qToMetres(b.values[0]),by=qToMetres(b.values[1]);
const double bz=qToMetres(b.values[2]);
const double dx=bx-ax,dy=by-ay,dz=bz-az;
const double length=std::sqrt(dx*dx+dy*dy+dz*dz);
const std::size_t intervals=std::max<std::size_t>(1,
static_cast<std::size_t>(std::ceil(length
/PassageSupportAuditSpacingMetres)));
const double routeRadius=a.values.size()>=4
?std::max(0.75,qToMetres(a.values[3])):0.75;
for(std::size_t sample=0;sample<=intervals;++sample)
{
if(segment>1&&sample==0)continue;
const double t=static_cast<double>(sample)/intervals;
const double centerX=ax+dx*t,centerY=ay+dy*t;
const double centerZ=az+dz*t;
for(std::size_t radialStep=0;radialStep<=static_cast<std::size_t>(
std::ceil(routeRadius/PassageSupportAuditSpacingMetres));++radialStep)
{
const double radial=std::min(routeRadius,
radialStep*PassageSupportAuditSpacingMetres);
for(const auto& direction:PassageSupportAuditDirections)
{
const double x=centerX+direction[0]*radial;
const double y=centerY+direction[1]*radial;
if(std::hypot(x-mouthX,y-mouthY)>RouteSupportReachMetres)continue;
const double floorZ=centerZ-RouteFloorOffsetMetres;
for(double depth=RouteSupportDepthStepMetres;
depth<=RouteSupportThicknessMetres+1.0e-6;
depth+=RouteSupportDepthStepMetres)
inspect(x,y,floorZ,depth,RouteSupportThicknessMetres,true);
}
}
}
}
}
return audit;
};
struct FPassageColumnAudit
{
std::uint64_t columns=0,shortSpans=0,connectedEnds=0,routeSections=0;
std::uint64_t routeSectionFailures=0,wallSections=0,wallFailures=0;
double minimumWallMetres=std::numeric_limits<double>::infinity();
double minimumSurfaceRadiusMetres=std::numeric_limits<double>::infinity();
double maximumSurfaceRadiusMetres=0.0;
double surfaceRadiusReliefMetres=0.0;
double longestShortSpanMetres=0.0;
bool passed=true;
bool disconnectedEndControlApplicable=false;
bool disconnectedEndControlDetected=false;
};
const auto auditPassageColumns=[&](const VoxelForgeCore::World& Field,
const VoxelForgeCore::World& Native,
const VoxelForgeCore::ResolvedLayoutPassageV1& passage,
std::size_t passageIndex)
{
FPassageColumnAudit audit;
const double qMetres=coreMetres
/VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel;
constexpr std::array<std::array<double,2>,5> supportOffsets{{
{{0.0,0.0}},{{0.45,0.0}},{{-0.45,0.0}},{{0.0,0.45}},{{0.0,-0.45}}}};
const auto endpointSupportCount=[&](const std::array<double,4>& point)
{
const double x=point[0]*qMetres,y=point[1]*qMetres;
const double floor=point[2]*qMetres-point[3]*qMetres+0.13;
std::uint32_t supported=0;
for(const auto& offset:supportOffsets)
{
bool solid=false;
for(const double depth:{0.125,0.25})
if(Native.densityAt({(x+offset[0])/coreMetres,
(y+offset[1])/coreMetres,(floor-depth)/coreMetres})<0.0f)
{solid=true;break;}
supported+=solid;
}
return supported;
};
const auto endpointConnected=[&](const std::array<double,4>& point)
{return endpointSupportCount(point)>=3;};
struct FColumnCapProbe
{
std::uint64_t columnSamples=0,nativeOverlapSamples=0;
double firstOverlapDepthMetres=std::numeric_limits<double>::infinity();
double minimumNativeDensity=std::numeric_limits<double>::infinity();
};
const auto probeColumnCap=[&](const VoxelForgeCore::PassageVoidCrossingAuditV1& crossing,
std::size_t segment,double capZMetres,bool upperCap,double depthLimitMetres)
{
FColumnCapProbe probe;
constexpr double DepthStepMetres=0.25;
constexpr double RadialStepMetres=0.50;
constexpr std::size_t DirectionCount=16;
const double axisX=qToMetres(crossing.columnAxisSubvoxels[0]);
const double axisY=qToMetres(crossing.columnAxisSubvoxels[1]);
for(double depth=DepthStepMetres;depth<=depthLimitMetres+1.0e-6;
depth+=DepthStepMetres)
{
const double z=capZMetres+(upperCap?-depth:depth);
const double maxRadius=qToMetres(crossing.columnMaximumRadiusSubvoxels);
const std::size_t radialSteps=static_cast<std::size_t>(
std::ceil(maxRadius/RadialStepMetres));
for(std::size_t radialStep=0;radialStep<=radialSteps;++radialStep)
{
const double radius=std::min(maxRadius,
radialStep*RadialStepMetres);
for(std::size_t direction=0;direction<DirectionCount;++direction)
{
const double angle=2.0*3.14159265358979323846
*direction/DirectionCount;
const VoxelForgeCore::Vec3d sample{
(axisX+radius*std::cos(angle))/coreMetres,
(axisY+radius*std::sin(angle))/coreMetres,z/coreMetres};
if(!Field.isPassageColumnSample(passageIndex,segment,sample))continue;
++probe.columnSamples;
const double nativeDensity=Native.densityAt(sample);
probe.minimumNativeDensity=std::min(probe.minimumNativeDensity,
nativeDensity);
if(nativeDensity<0.0)
{
++probe.nativeOverlapSamples;
probe.firstOverlapDepthMetres=std::min(
probe.firstOverlapDepthMetres,depth);
}
}
}
}
return probe;
};
const auto columnSolidAt=[&](std::size_t segment,double x,double y,double z)
{
return Field.isPassageColumnSample(passageIndex,segment,
{x/coreMetres,y/coreMetres,z/coreMetres});
};
const auto shortSpanSolidAt=[&](std::size_t segment,double x,double y,double z)
{
return Field.isPassageShortSpanSample(passageIndex,segment,
{x/coreMetres,y/coreMetres,z/coreMetres});
};
const auto crossings=Field.passageVoidCrossings();
double controlLowestRouteZ=std::numeric_limits<double>::infinity();
bool disconnectedEndControlApplicable=false;
bool disconnectedEndControlDetected=false;
for(const auto& crossing:crossings)
{
if(crossing.passageIndex!=passageIndex)continue;
const bool connectedStart=endpointConnected(crossing.startPointSubvoxels);
const bool connectedEnd=endpointConnected(crossing.endPointSubvoxels);
if(!crossing.needsColumn)
{
++audit.shortSpans;
audit.longestShortSpanMetres=std::max(audit.longestShortSpanMetres,
crossing.unsupportedLengthMetres);
const bool shortSpanPass=connectedStart&&connectedEnd
&&crossing.unsupportedLengthMetres<=12.5
&&crossing.lastSegment+1<passage.controlPoints.size();
audit.passed&=shortSpanPass;
std::printf("[PassageGroundedShortSpanAudit] id=%s segments=%zu..%zu length_m=%.3f threshold_m=12.500 connected=%d/2 status=%s\n",
passage.stableId.c_str(),crossing.firstSegment,crossing.lastSegment,
crossing.unsupportedLengthMetres,
static_cast<int>(connectedStart)+static_cast<int>(connectedEnd),
shortSpanPass?"PASS":"FAIL");
const std::size_t segment=std::min(crossing.firstSegment,
passage.controlPoints.size()-2);
const auto& a=passage.controlPoints[segment];
const auto& b=passage.controlPoints[segment+1];
const double x=(qToMetres(a.positionSubvoxels[0])
+qToMetres(b.positionSubvoxels[0]))*0.5;
const double y=(qToMetres(a.positionSubvoxels[1])
+qToMetres(b.positionSubvoxels[1]))*0.5;
const double z=(qToMetres(a.positionSubvoxels[2])
+qToMetres(b.positionSubvoxels[2]))*0.5
-qToMetres(a.radiusSubvoxels+b.radiusSubvoxels)*0.5+0.13;
audit.passed&=shortSpanSolidAt(segment,x,y,z-0.25);
continue;
}
if(crossing.lastSegment+1>=passage.controlPoints.size())
{audit.passed=false;continue;}
const double capTopMetres=qToMetres(crossing.columnTopZSubvoxels);
const double capBottomMetres=qToMetres(crossing.columnBottomZSubvoxels);
const auto topCap=probeColumnCap(crossing,crossing.firstSegment,
capTopMetres,true,6.0);
const auto bottomCap=probeColumnCap(crossing,crossing.lastSegment,
capBottomMetres,false,6.0);
const bool topCapConnected=topCap.nativeOverlapSamples>0;
const bool bottomCapConnected=bottomCap.nativeOverlapSamples>0;
const std::uint32_t routeStartSupport=endpointSupportCount(
crossing.startPointSubvoxels);
const std::uint32_t routeEndSupport=endpointSupportCount(
crossing.endPointSubvoxels);
std::printf("[PassageColumnRouteEndpointSupport] id=%s start=%u/5 start_z_m=%.3f end=%u/5 end_z_m=%.3f threshold=3/5\n",
passage.stableId.c_str(),routeStartSupport,
qToMetres(crossing.startPointSubvoxels[2]),routeEndSupport,
qToMetres(crossing.endPointSubvoxels[2]));
const auto printCap=[&](const char* endName,const char* side,double capZ,
const FColumnCapProbe& probe,bool connected)
{
std::printf("[PassageColumnCapAudit] id=%s end=%s side=%s cap_z_m=%.3f column_samples=%llu native_overlap_samples=%llu first_overlap_depth_m=%.3f minimum_native_density=%.6f search_depth_m=6.000 status=%s\n",
passage.stableId.c_str(),endName,side,capZ,
static_cast<unsigned long long>(probe.columnSamples),
static_cast<unsigned long long>(probe.nativeOverlapSamples),
probe.firstOverlapDepthMetres,probe.minimumNativeDensity,
connected?"PASS":"FAIL");
};
printCap("top","upper",capTopMetres,topCap,topCapConnected);
printCap("bottom","lower",capBottomMetres,bottomCap,bottomCapConnected);
const auto upper=std::find_if(ResolvedLayout->strates.begin(),
ResolvedLayout->strates.end(),[&](const auto& value)
{return value.strateIndex==passage.upperStrateIndex;});
const double startRouteZ=qToMetres(crossing.startPointSubvoxels[2]);
const double endRouteZ=qToMetres(crossing.endPointSubvoxels[2]);
const double lowerRouteZ=std::min(startRouteZ,endRouteZ);
if(upper!=ResolvedLayout->strates.end()
&&upper->generatorKind=="FloatingIslands"
&&lowerRouteZ<controlLowestRouteZ)
{
controlLowestRouteZ=lowerRouteZ;
// Move the hypothetical lower cap 20 m upward into the FI air gap.
// Its first 2 m are still inside the original column bounds, but a
// truncated column there has no native substrate to join.
const double hypotheticalBottomZ=lowerRouteZ+20.0;
const auto disconnectedControl=probeColumnCap(crossing,
crossing.lastSegment,hypotheticalBottomZ,false,2.0);
disconnectedEndControlApplicable=disconnectedControl.columnSamples>0;
disconnectedEndControlDetected=disconnectedEndControlApplicable
&&disconnectedControl.nativeOverlapSamples==0;
std::printf("[PassageColumnDisconnectedEndControl] source=air_gap_truncated_lower_cap cap_z_m=%.3f column_samples=%llu native_overlap_samples=%llu minimum_native_density=%.6f detected=%s\n",
hypotheticalBottomZ,
static_cast<unsigned long long>(disconnectedControl.columnSamples),
static_cast<unsigned long long>(disconnectedControl.nativeOverlapSamples),
disconnectedControl.minimumNativeDensity,
disconnectedEndControlDetected?"true":"false");
}
++audit.columns;
audit.connectedEnds+=topCapConnected+bottomCapConnected;
const double axisX=qToMetres(crossing.columnAxisSubvoxels[0]);
const double axisY=qToMetres(crossing.columnAxisSubvoxels[1]);
const double minimumRadius=qToMetres(crossing.columnMinimumRadiusSubvoxels);
const double maximumRadius=qToMetres(crossing.columnMaximumRadiusSubvoxels);
const double minimumWall=minimumRadius-crossing.maximumRouteOffsetMetres
-crossing.maximumBoreRadiusMetres-0.50;
audit.minimumWallMetres=std::min(audit.minimumWallMetres,minimumWall);
const std::size_t segmentCount=crossing.lastSegment-crossing.firstSegment+1;
const std::size_t probeCount=std::min<std::size_t>(128,segmentCount);
std::uint64_t crossingRouteFailures=0,crossingWallFailures=0;
for(std::size_t probe=0;probe<probeCount;++probe)
{
const std::size_t segment=crossing.firstSegment
+std::min(segmentCount-1,(probe*segmentCount)/probeCount);
const auto& a=passage.controlPoints[segment];
const auto& b=passage.controlPoints[segment+1];
const double ax=qToMetres(a.positionSubvoxels[0]);
const double ay=qToMetres(a.positionSubvoxels[1]);
const double az=qToMetres(a.positionSubvoxels[2]);
const double bx=qToMetres(b.positionSubvoxels[0]);
const double by=qToMetres(b.positionSubvoxels[1]);
const double bz=qToMetres(b.positionSubvoxels[2]);
const double x=(ax+bx)*0.5,y=(ay+by)*0.5;
const double z=(az+bz)*0.5;
const double radius=(qToMetres(a.radiusSubvoxels)
+qToMetres(b.radiusSubvoxels))*0.5;
const double floor=z-radius+0.13;
const VoxelForgeCore::Vec3d supportPoint{
x/coreMetres,y/coreMetres,(floor-2.0)/coreMetres};
const bool solidUnderRoute=columnSolidAt(segment,x,y,floor-2.0)
||Native.densityAt(supportPoint)<0.0f;
++audit.routeSections;
audit.routeSectionFailures+=!solidUnderRoute;
crossingRouteFailures+=!solidUnderRoute;
const double radial=std::hypot(x-axisX,y-axisY);
const double wallRadius=radial+radius+1.5;
const double outwardX=radial>1.0e-6?(x-axisX)/radial:1.0;
const double outwardY=radial>1.0e-6?(y-axisY)/radial:0.0;
const bool wallSolid=columnSolidAt(segment,
axisX+outwardX*wallRadius,axisY+outwardY*wallRadius,z);
++audit.wallSections;
audit.wallFailures+=!wallSolid;
crossingWallFailures+=!wallSolid;
if(!wallSolid&&crossingWallFailures<=8)
std::printf("[PassageRockColumnWallProbe] id=%s segment=%zu xyz_m=(%.3f,%.3f,%.3f) axis_m=(%.3f,%.3f) centerline_radius_m=%.3f bore_radius_m=%.3f wall_probe_radius_m=%.3f\n",
passage.stableId.c_str(),segment,x,y,z,axisX,axisY,radial,radius,wallRadius);
}
double crossingMinimumSurfaceRadius=std::numeric_limits<double>::infinity();
double crossingMaximumSurfaceRadius=0.0;
std::array<double,6> meanRadiusByHeight{};
std::size_t heightSamples=0;
constexpr double RayStepMetres=0.25;
constexpr std::array<double,6> HeightFractions{{0.25,0.35,0.45,0.55,0.65,0.75}};
constexpr std::size_t DirectionCount=16;
const double topMetres=qToMetres(crossing.columnTopZSubvoxels);
const double bottomMetres=qToMetres(crossing.columnBottomZSubvoxels);
const double rayStart=crossing.maximumRouteOffsetMetres
+crossing.maximumBoreRadiusMetres+0.75;
for(const double heightFraction:HeightFractions)
{
const double z=topMetres+(bottomMetres-topMetres)*heightFraction;
double heightMeanRadius=0.0;
std::uint64_t heightRayCount=0;
for(std::size_t direction=0;direction<DirectionCount;++direction)
{
const double angle=2.0*3.14159265358979323846
*direction/DirectionCount;
double lastSolidRadius=0.0;
bool enteredColumn=false;
const std::size_t raySteps=static_cast<std::size_t>(std::ceil(
(maximumRadius+2.0-rayStart)/RayStepMetres));
for(std::size_t step=0;step<=raySteps;++step)
{
const double rayRadius=rayStart+step*RayStepMetres;
const VoxelForgeCore::Vec3d point{
(axisX+rayRadius*std::cos(angle))/coreMetres,
(axisY+rayRadius*std::sin(angle))/coreMetres,
z/coreMetres};
if(Field.densityAt(point)<0.0f)
{enteredColumn=true;lastSolidRadius=rayRadius;}
else if(enteredColumn)break;
}
if(!enteredColumn)continue;
heightMeanRadius+=lastSolidRadius;
++heightRayCount;
crossingMinimumSurfaceRadius=std::min(crossingMinimumSurfaceRadius,
lastSolidRadius);
crossingMaximumSurfaceRadius=std::max(crossingMaximumSurfaceRadius,
lastSolidRadius);
}
if(heightRayCount==0)continue;
meanRadiusByHeight[heightSamples++]=heightMeanRadius/heightRayCount;
}
const double crossingSurfaceRelief=heightSamples>=2
?*std::max_element(meanRadiusByHeight.begin(),
meanRadiusByHeight.begin()+heightSamples)
-*std::min_element(meanRadiusByHeight.begin(),
meanRadiusByHeight.begin()+heightSamples):0.0;
audit.minimumSurfaceRadiusMetres=std::min(audit.minimumSurfaceRadiusMetres,
crossingMinimumSurfaceRadius);
audit.maximumSurfaceRadiusMetres=std::max(audit.maximumSurfaceRadiusMetres,
crossingMaximumSurfaceRadius);
audit.surfaceRadiusReliefMetres=std::max(audit.surfaceRadiusReliefMetres,
crossingSurfaceRelief);
const double measuredWall=crossingMinimumSurfaceRadius
-crossing.maximumRouteOffsetMetres-crossing.maximumBoreRadiusMetres;
const bool columnPass=topCapConnected&&bottomCapConnected
&&minimumWall>=1.50&&crossingRouteFailures==0
&&crossingWallFailures==0&&std::isfinite(measuredWall)
&&measuredWall>=1.50&&crossingSurfaceRelief>=0.20;
audit.passed&=columnPass;
std::printf("[PassageRockColumnAudit] id=%s segments=%zu..%zu span_m=%.3f axis_m=(%.3f,%.3f) connected=%d/2 route_support=%llu/%llu wall_failures=%llu wall_margin_m=%.3f threshold_m=1.500 radii_m=%.3f..%.3f relief_p2p_m=%.3f nominal_radius_m=%.3f status=%s\n",
passage.stableId.c_str(),crossing.firstSegment,crossing.lastSegment,
crossing.unsupportedLengthMetres,axisX,axisY,
static_cast<int>(topCapConnected)+static_cast<int>(bottomCapConnected),
static_cast<unsigned long long>(probeCount-crossingRouteFailures),
static_cast<unsigned long long>(probeCount),
static_cast<unsigned long long>(crossingWallFailures),measuredWall,
crossingMinimumSurfaceRadius,crossingMaximumSurfaceRadius,
crossingSurfaceRelief,qToMetres(crossing.columnNominalRadiusSubvoxels),
columnPass?"PASS":"FAIL");
}
audit.disconnectedEndControlApplicable|=disconnectedEndControlApplicable;
audit.disconnectedEndControlDetected|=disconnectedEndControlDetected;
if(disconnectedEndControlApplicable&&!disconnectedEndControlDetected)
audit.passed=false;
return audit;
};
if(Assembly)
for(const auto& stratum:ResolvedLayout->strates)
{
if(stratum.generatorKind!="FloatingIslands")continue;
const auto anchor=std::find_if(stratum.anchors.begin(),stratum.anchors.end(),
[](const auto& value){return value.kind=="passage_anchor"&&value.values.size()>=7;});
const auto islandPlan=std::find_if(Assembly->floatingIslands.begin(),
Assembly->floatingIslands.end(),[&](const auto& value)
{return value.strateIndex==stratum.strateIndex;});
if(anchor==stratum.anchors.end()||islandPlan==Assembly->floatingIslands.end())continue;
if(islandPlan->manifest.recipe.geometryVersion>=8)continue;
const auto ordinal=islandPlan->manifest.recipe.anchorIslandOrdinal;
if(ordinal>=islandPlan->manifest.plan.islands.size())continue;
const auto& anchorIsland=islandPlan->manifest.plan.islands[ordinal];
const double axisX=qToMetres(anchor->values[0]);
const double axisY=qToMetres(anchor->values[1]);
const double rootBottom=qToMetres(anchor->values[5]);
const auto& islandRecipe=islandPlan->manifest.recipe;
const std::int64_t crustRatioQ16=islandRecipe.thicknessRatioQ16
+islandRecipe.crustDepthBonusQ16;
const std::int64_t crustDepthQ=(anchorIsland.radiusSubvoxels*crustRatioQ16
+32768)/65536;
const double rootTop=qToMetres(anchorIsland.topZSubvoxels-crustDepthQ);
const double nominalRootRadius=qToMetres(anchor->values[2]);
double helixMinimumRadius=std::numeric_limits<double>::infinity();
double helixMaximumRadius=0.0;
for(const auto& passage:ResolvedLayout->passages)
if(passage.upperStrateIndex==stratum.strateIndex)
for(const auto& point:passage.controlPoints)
{
const double z=qToMetres(point.positionSubvoxels[2]);
if(z<rootBottom||z>rootTop)continue;
const double radial=std::hypot(
qToMetres(point.positionSubvoxels[0]-anchor->values[0]),
qToMetres(point.positionSubvoxels[1]-anchor->values[1]));
helixMinimumRadius=std::min(helixMinimumRadius,radial);
helixMaximumRadius=std::max(helixMaximumRadius,radial);
}
if(!std::isfinite(helixMinimumRadius))continue;
double minimumMeasuredRootRadius=std::numeric_limits<double>::infinity();
std::uint64_t rootRaySamples=0;
constexpr std::array<double,5> RootHeightFractions{{0.01,0.25,0.5,0.75,0.99}};
for(const double fraction:RootHeightFractions)
{
const double z=rootTop+(rootBottom-rootTop)*fraction;
double minimumRadius=std::numeric_limits<double>::infinity();
double maximumRadius=0.0,meanRadius=0.0;
constexpr std::size_t DirectionCount=32;
constexpr double RayStepMetres=0.125;
const std::size_t raySteps=static_cast<std::size_t>(std::ceil(
(nominalRootRadius+2.0)/RayStepMetres));
for(std::size_t direction=0;direction<DirectionCount;++direction)
{
const double angle=2.0*3.14159265358979323846*direction/DirectionCount;
double radius=0.0;
for(std::size_t step=0;step<=raySteps;++step)
{
const double probeRadius=step*RayStepMetres;
const VoxelForgeCore::Vec3d probe{
(axisX+probeRadius*std::cos(angle))/coreMetres,
(axisY+probeRadius*std::sin(angle))/coreMetres,z/coreMetres};
if(blockedWorld.densityAt(probe)>=0.0f)break;
radius=probeRadius;
}
minimumRadius=std::min(minimumRadius,radius);
maximumRadius=std::max(maximumRadius,radius);
meanRadius+=radius;
++rootRaySamples;
}
meanRadius/=DirectionCount;
minimumMeasuredRootRadius=std::min(minimumMeasuredRootRadius,minimumRadius);
std::printf("[PassageRootRadiusMeasure] strate=%d z_m=%.3f solid_radius_min_m=%.3f mean_m=%.3f max_m=%.3f nominal_root_m=%.3f rays=%zu\n",
stratum.strateIndex,z,minimumRadius,meanRadius,maximumRadius,
nominalRootRadius,DirectionCount);
}
const auto firstRootPassage=std::find_if(ResolvedLayout->passages.begin(),
ResolvedLayout->passages.end(),[&](const auto& passage)
{return passage.upperStrateIndex==stratum.strateIndex;});
const double mouthBoreRadius=firstRootPassage==ResolvedLayout->passages.end()?0.0
:qToMetres(firstRootPassage->mouthRadiusSubvoxels);
const double midBoreRadius=firstRootPassage==ResolvedLayout->passages.end()?0.0
:qToMetres(firstRootPassage->midRadiusSubvoxels);
const double maximumBoreRadius=std::max(mouthBoreRadius,midBoreRadius);
std::printf("[PassageRootMeasure] strate=%d axis_m=(%.3f,%.3f) helix_centerline_radius_min_m=%.3f max_m=%.3f mouth_bore_radius_m=%.3f mid_bore_radius_m=%.3f nominal_root_m=%.3f measured_min_root_m=%.3f minimum_wall_m=%.3f samples=%llu\n",
stratum.strateIndex,axisX,axisY,helixMinimumRadius,helixMaximumRadius,
mouthBoreRadius,midBoreRadius,nominalRootRadius,minimumMeasuredRootRadius,
minimumMeasuredRootRadius-helixMaximumRadius-maximumBoreRadius,
static_cast<unsigned long long>(rootRaySamples));
}
const auto mouthInContent=[&](std::int32_t index,const std::array<std::int64_t,3>& mouth)
{
const auto* stratum=findStratum(index);if(!stratum)return false;
const std::int64_t zUm=static_cast<std::int64_t>(std::llround(
static_cast<double>(mouth[2])*World.CoreVoxelSizeMicrons
/VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel));
return zUm>=stratum->content.bottomMicrometres&&zUm<stratum->content.topMicrometres;
};
std::uint64_t passageCount=0,passagePasses=0,blockedControls=0,naturalPasses=0;
std::uint64_t mouthProfilePasses=0,ripplePasses=0,rippleControlsDetected=0;
std::uint64_t floorRippleControlsDetected=0;
std::uint64_t openAirViolations=0,openAirLegacyViolations=0,openAirSamples=0;
std::uint64_t openAirAudits=0,openAirColumnSamples=0,openAirShortSpanSamples=0;
std::uint64_t columnCrossings=0,shortGroundedSpans=0,columnConnectedEnds=0;
std::uint64_t columnRouteFailures=0,columnWallFailures=0;
double longestUncolumnedSpanMetres=0.0,longestShortSpanMetres=0.0;
double l26LegacyBridgeSpanMetres=0.0;
bool columnAuditsPassed=true,noLongBridgeAuditPassed=true;
bool columnDisconnectedEndControlApplicable=false;
bool columnDisconnectedEndControlDetected=false;
bool l26NegativeControlApplicable=false;
const auto plannedVoidCrossings=Shape.passageVoidCrossings();
for(const auto& crossing:plannedVoidCrossings)
{
if(crossing.needsColumn)continue;
longestUncolumnedSpanMetres=std::max(longestUncolumnedSpanMetres,
crossing.unsupportedLengthMetres);
}
for(std::size_t passageIndex=0;passageIndex<ResolvedLayout->passages.size();
++passageIndex)
{
const auto& passage=ResolvedLayout->passages[passageIndex];
const auto* upper=findStratum(passage.upperStrateIndex);
const auto* lower=findStratum(passage.lowerStrateIndex);
if(!upper||!lower||lower->generatorKind!="SurfaceWorld"
||upper->generatorKind=="FloatingIslands")continue;
l26NegativeControlApplicable=true;
for(const auto& crossing:plannedVoidCrossings)
if(crossing.passageIndex==passageIndex)
l26LegacyBridgeSpanMetres=std::max(l26LegacyBridgeSpanMetres,
crossing.unsupportedLengthMetres);
}
for(std::size_t passageIndex=0;passageIndex<ResolvedLayout->passages.size();++passageIndex)
{
const auto& passage=ResolvedLayout->passages[passageIndex];
std::vector<std::array<double,3>> path;path.reserve(passage.controlPoints.size());
for(const auto& point:passage.controlPoints)
{
const double playerZ=static_cast<double>(point.positionSubvoxels[2]
-point.radiusSubvoxels)+1.13*VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel
*1000000.0/World.CoreVoxelSizeMicrons;
path.push_back({qToMetres(point.positionSubvoxels[0])/coreMetres,
qToMetres(point.positionSubvoxels[1])/coreMetres,playerZ/256.0});
}
std::vector<FPassageSegmentSupportAudit> segmentSupport;
const FWalkAudit passageAudit=auditPlayerPath(Shape,path,0.125,0.125,0.25,3,0.45,
&blockedWorld,&segmentSupport);
const FPassageNaturalnessAudit naturalAudit=auditPassageNaturalness(Shape,passage);
const FPassageMouthProfileAudit mouthProfileAudit=
auditPassageMouthProfiles(Shape,passage);
const FPassageRippleAudit rippleAudit=auditPassageRipples(Shape,passage);
const FPassageOpenAirAudit openAirAudit=auditPassageOpenAir(Shape,blockedWorld,
passage,passageIndex);
const FPassageColumnAudit columnAudit=auditPassageColumns(Shape,blockedWorld,
passage,passageIndex);
openAirSamples+=openAirAudit.supportSamples;
openAirViolations+=openAirAudit.violations;
openAirLegacyViolations+=openAirAudit.legacyViolations;
openAirColumnSamples+=openAirAudit.columnSamples;
openAirShortSpanSamples+=openAirAudit.shortSpanSamples;
columnCrossings+=columnAudit.columns;
shortGroundedSpans+=columnAudit.shortSpans;
columnConnectedEnds+=columnAudit.connectedEnds;
columnRouteFailures+=columnAudit.routeSectionFailures;
columnWallFailures+=columnAudit.wallFailures;
longestShortSpanMetres=std::max(longestShortSpanMetres,
columnAudit.longestShortSpanMetres);
columnAuditsPassed&=columnAudit.passed;
columnDisconnectedEndControlApplicable|=columnAudit.disconnectedEndControlApplicable;
columnDisconnectedEndControlDetected|=columnAudit.disconnectedEndControlDetected;
++openAirAudits;
const auto radialSquared=[](const std::array<std::int64_t,3>& p)
{return p[0]*p[0]+p[1]*p[1];};
const bool mouthsInRadius=radialSquared(passage.upperMouthSubvoxels)
<=passage.placementRadiusSubvoxels*passage.placementRadiusSubvoxels
&&radialSquared(passage.lowerMouthSubvoxels)
<=passage.placementRadiusSubvoxels*passage.placementRadiusSubvoxels;
const bool mouthsInContent=mouthInContent(passage.upperStrateIndex,passage.upperMouthSubvoxels)
&&mouthInContent(passage.lowerStrateIndex,passage.lowerMouthSubvoxels);
++passageCount;naturalPasses+=naturalAudit.passed;
mouthProfilePasses+=mouthProfileAudit.passed;
ripplePasses+=rippleAudit.passed;
rippleControlsDetected+=rippleAudit.controlDetected;
floorRippleControlsDetected+=rippleAudit.floorControlDetected;
passagePasses+=passageAudit.passed&&mouthsInRadius&&mouthsInContent
&&naturalAudit.passed&&mouthProfileAudit.passed&&rippleAudit.passed;
std::printf("[ResolvedPassageAudit] id=%s interface=%d-%d control_points=%zu center_samples=%llu capsule_samples=%llu blocked=%llu support_samples=%llu unsupported=%llu grade_failures=%llu mouth_content=%d/2 mouth_radius=%d/2 walkability=%s\n",
passage.stableId.c_str(),passage.upperStrateIndex,passage.lowerStrateIndex,
passage.controlPoints.size(),static_cast<unsigned long long>(passageAudit.centers),
static_cast<unsigned long long>(passageAudit.capsuleSamples),
static_cast<unsigned long long>(passageAudit.blocked),
static_cast<unsigned long long>(passageAudit.supportSamples),
static_cast<unsigned long long>(passageAudit.unsupported),
static_cast<unsigned long long>(passageAudit.gradeFailures),mouthsInContent?2:0,
mouthsInRadius?2:0,passageAudit.passed?"PASS":"FAIL");
std::printf("[PassageNaturalnessAudit] id=%s flat_run_max_m=%.3f limit_m=%.3f wall_relief_p2p_m=%.3f minimum_m=%.3f samples=%llu missing=%llu status=%s\n",
passage.stableId.c_str(),naturalAudit.maximumFlatRunMetres,MaximumFlatRunMetres,
naturalAudit.wallReliefPeakToPeakMetres,MinimumWallReliefMetres,
static_cast<unsigned long long>(naturalAudit.wallSamples),
static_cast<unsigned long long>(naturalAudit.missingWallSamples),
naturalAudit.passed?"PASS":"FAIL");
std::printf("[PassageMouthProfileAudit] id=%s floor_samples=%llu floor_missing=%llu wall_samples=%llu wall_missing=%llu floor_step_scan=centerline floor_flat_step_run_m=%.3f floor_step_m=%.3f wall_flat_step_run_m=%.3f wall_step_m=%.3f spacing_m=%.3f plateau=(%.3f,%.3f) status=%s\n",
passage.stableId.c_str(),static_cast<unsigned long long>(mouthProfileAudit.floorSamples),
static_cast<unsigned long long>(mouthProfileAudit.missingFloorSamples),
static_cast<unsigned long long>(mouthProfileAudit.wallSamples),
static_cast<unsigned long long>(mouthProfileAudit.missingWallSamples),
mouthProfileAudit.floorFlatStepRunMetres,mouthProfileAudit.floorStepMetres,
mouthProfileAudit.wallFlatStepRunMetres,mouthProfileAudit.wallStepMetres,
PassageProfileSpacingMetres,PassageProfilePlateauMinimumMetres,
PassageProfileStepThresholdMetres,mouthProfileAudit.passed?"PASS":"FAIL");
std::printf("[PassageRippleAudit] id=%s window_m=32.000 spacing_m=0.125 period_m=%.3f amplitude_m=%.4f amplitude_cm=%.2f coherent_period_m=%.3f coherent_amplitude_m=%.4f coherent_amplitude_cm=%.2f local_peak_amplitude_m=%.4f coverage=%llu/%llu threshold_m=0.035 synthetic_spheres_period_m=1.500 synthetic_spheres_amplitude_m=%.4f synthetic_spheres_detected=%s floor_period_m=%.3f floor_amplitude_m=%.4f floor_amplitude_cm=%.2f floor_coherent_period_m=%.3f floor_coherent_amplitude_m=%.4f floor_coverage=%llu/%llu floor_threshold_m=0.015 floor_beaded_control_amplitude_m=%.4f floor_beaded_control_detected=%s status=%s\n",
passage.stableId.c_str(),rippleAudit.periodMetres,
rippleAudit.amplitudeMetres,rippleAudit.amplitudeMetres*100.0,
rippleAudit.coherentPeriodMetres,rippleAudit.coherentAmplitudeMetres,
rippleAudit.coherentAmplitudeMetres*100.0,
rippleAudit.localPeakAmplitudeMetres,
static_cast<unsigned long long>(rippleAudit.samples),
static_cast<unsigned long long>(rippleAudit.expectedSamples),
rippleAudit.controlAmplitudeMetres,rippleAudit.controlDetected?"true":"false",
rippleAudit.floorPeriodMetres,rippleAudit.floorAmplitudeMetres,
rippleAudit.floorAmplitudeMetres*100.0,
rippleAudit.floorCoherentPeriodMetres,rippleAudit.floorCoherentAmplitudeMetres,
static_cast<unsigned long long>(rippleAudit.floorSamples),
static_cast<unsigned long long>(rippleAudit.floorExpectedSamples),
rippleAudit.floorControlAmplitudeMetres,
rippleAudit.floorControlDetected?"true":"false",
rippleAudit.passed?"PASS":"FAIL");
for(std::size_t sample=0;sample<rippleAudit.floorPeakProfile.size();sample+=4)
{
const auto& value=rippleAudit.floorPeakProfile[sample];
std::printf("[PassageFloorRippleSample] id=%s distance_m=%.3f "
"expected_floor_m=%.4f sampled_floor_m=%.4f residual_m=%.4f "
"route_xyz_m=(%.3f,%.3f,%.3f)\n",
passage.stableId.c_str(),value[0],value[1],value[2],value[2]-value[1],
value[3],value[4],value[5]);
}
std::printf("[PassageOpenAirAudit] id=%s support_samples=%llu violations=%llu column_samples=%llu short_span_samples=%llu l24_ungated_violations=%llu route_support_samples=%llu route_support_violations=%llu spacing_m=%.3f status=%s\n",
passage.stableId.c_str(),static_cast<unsigned long long>(openAirAudit.supportSamples),
static_cast<unsigned long long>(openAirAudit.violations),
static_cast<unsigned long long>(openAirAudit.columnSamples),
static_cast<unsigned long long>(openAirAudit.shortSpanSamples),
static_cast<unsigned long long>(openAirAudit.legacyViolations),
static_cast<unsigned long long>(openAirAudit.routeSupportSamples),
static_cast<unsigned long long>(openAirAudit.routeSupportViolations),
PassageSupportAuditSpacingMetres,
openAirAudit.violations==0?"PASS":"FAIL");
for(std::size_t i=0;i<openAirAudit.firstViolationCount;++i)
std::printf("[PassageOpenAirAuditSample] id=%s kind=unsupported_support xyz_m=(%.3f,%.3f,%.3f) density=%.6f\n",
passage.stableId.c_str(),openAirAudit.firstViolations[i][0],
openAirAudit.firstViolations[i][1],openAirAudit.firstViolations[i][2],
openAirAudit.firstViolations[i][3]);
for(std::size_t i=0;i<passageAudit.firstBlockedCount;++i)
{
const auto& sample=passageAudit.firstBlocked[i];
double nearestDistanceSquared=std::numeric_limits<double>::infinity();
std::size_t nearestSegment=0;
double nearestT=0.0;
double nearestPassageSdf=std::numeric_limits<double>::infinity();
std::size_t nearestPassageSegment=0;
for(std::size_t segment=0;segment+1<path.size();++segment)
{
const auto& a=path[segment];const auto& b=path[segment+1];
const double dx=b[0]-a[0],dy=b[1]-a[1],dz=b[2]-a[2];
const double lengthSquared=dx*dx+dy*dy+dz*dz;
const double t=lengthSquared>0.0?std::clamp(
((sample[0]/coreMetres-a[0])*dx+(sample[1]/coreMetres-a[1])*dy
+(sample[2]/coreMetres-a[2])*dz)/lengthSquared,0.0,1.0):0.0;
const double ex=sample[0]/coreMetres-(a[0]+t*dx);
const double ey=sample[1]/coreMetres-(a[1]+t*dy);
const double ez=sample[2]/coreMetres-(a[2]+t*dz);
const double distanceSquared=ex*ex+ey*ey+ez*ez;
if(distanceSquared<nearestDistanceSquared)
{nearestDistanceSquared=distanceSquared;nearestSegment=segment;nearestT=t;}
}
for(std::size_t segment=0;segment+1<passage.controlPoints.size();++segment)
{
const auto& a=passage.controlPoints[segment];
const auto& b=passage.controlPoints[segment+1];
const double ax=qToMetres(a.positionSubvoxels[0]);
const double ay=qToMetres(a.positionSubvoxels[1]);
const double az=qToMetres(a.positionSubvoxels[2]);
const double dx=qToMetres(b.positionSubvoxels[0]-a.positionSubvoxels[0]);
const double dy=qToMetres(b.positionSubvoxels[1]-a.positionSubvoxels[1]);
const double dz=qToMetres(b.positionSubvoxels[2]-a.positionSubvoxels[2]);
const double lengthSquared=dx*dx+dy*dy+dz*dz;
const double t=lengthSquared>0.0?std::clamp(
((sample[0]-ax)*dx+(sample[1]-ay)*dy+(sample[2]-az)*dz)
/lengthSquared,0.0,1.0):0.0;
const double ex=sample[0]-(ax+t*dx),ey=sample[1]-(ay+t*dy),
ez=sample[2]-(az+t*dz);
const double radius=qToMetres(a.radiusSubvoxels)
+(qToMetres(b.radiusSubvoxels)-qToMetres(a.radiusSubvoxels))*t;
const double signedDistance=std::sqrt(ex*ex+ey*ey+ez*ez)-radius;
if(signedDistance<nearestPassageSdf)
{nearestPassageSdf=signedDistance;nearestPassageSegment=segment;}
}
const VoxelForgeCore::Vec3d nativePosition{sample[0]/coreMetres,
sample[1]/coreMetres,sample[2]/coreMetres};
const float nativeDensity=blockedWorld.densityAt(nativePosition);
const bool passageColumn=Shape.isPassageColumnSample(passageIndex,
nearestSegment,nativePosition);
std::printf("[ResolvedPassageAuditSample] id=%s kind=blocked xyz_m=(%.3f,%.3f,%.3f) density=%.6f native_density=%.6f segment=%zu t=%.3f passage_segment=%zu passage_sdf_m=%.3f passage_column=%d native_path=%s\n",
passage.stableId.c_str(),sample[0],sample[1],sample[2],sample[3],
nativeDensity,nearestSegment,nearestT,nearestPassageSegment,
nearestPassageSdf,passageColumn?1:0,
blockedWorld.densityDispatchPathAt(nativePosition).c_str());
}
for(std::size_t i=0;i<passageAudit.firstUnsupportedCount;++i)
{
std::printf("[ResolvedPassageAuditSample] id=%s kind=unsupported xyz_m=(%.3f,%.3f,%.3f) density=%.6f\n",
passage.stableId.c_str(),passageAudit.firstUnsupported[i][0],
passageAudit.firstUnsupported[i][1],passageAudit.firstUnsupported[i][2],
passageAudit.firstUnsupported[i][3]);
}
for(std::size_t segment=0;segment<segmentSupport.size();++segment)
{
const auto& item=segmentSupport[segment];
if(!item.hasUnsupported)continue;
const auto& a=path[segment];const auto& b=path[segment+1];
const auto& sample=item.firstUnsupported;
const double firstX=sample[0]/coreMetres;
const double firstY=sample[1]/coreMetres;
const double firstZ=(sample[2]-0.125)/coreMetres;
const VoxelForgeCore::Vec3d bridgeProbe{sample[0]/coreMetres,
sample[1]/coreMetres,(sample[2]-0.25)/coreMetres};
const bool columnAtSupport=Shape.isPassageColumnSample(passageIndex,
segment,bridgeProbe);
std::printf("[ResolvedPassageSupportSegment] id=%s segment=%zu route_z_m=%.3f..%.3f centers=%llu unsupported=%llu native_unsupported=%llu first_foot_m=(%.3f,%.3f,%.3f) column_at_d025=%d native_support_probes=%u/5 native_density_d0125_d1_d2_d4=(%.6f,%.6f,%.6f,%.6f) native_path=%s\n",
passage.stableId.c_str(),segment,
std::min(a[2],b[2])*coreMetres,std::max(a[2],b[2])*coreMetres,
static_cast<unsigned long long>(item.centers),
static_cast<unsigned long long>(item.unsupported),
static_cast<unsigned long long>(item.nativeUnsupported),
sample[0],sample[1],sample[2],columnAtSupport?1:0,
item.firstNativeSupportedProbes,item.firstNativeDensities[0],item.firstNativeDensities[1],
item.firstNativeDensities[2],item.firstNativeDensities[3],
blockedWorld.densityDispatchPathAt({firstX,firstY,firstZ}).c_str());
}
}
std::uint64_t routePoints=0,routePasses=0,routeWalkPasses=0,routeBindings=0,routeBindingFailures=0;
struct FRouteAuditInput
{
std::int32_t strateIndex=0;
std::vector<std::array<double,3>> path;
double supportStart=0.125,supportStep=0.125,supportMaximum=0.25,
supportProbeRadius=0.45;
std::uint32_t minimumSupportProbes=3;
};
std::vector<FRouteAuditInput> routeAuditInputs;
for(const auto& stratum:ResolvedLayout->strates)
{
std::vector<const VoxelForgeCore::ResolvedLayoutAnchorV2*> anchors;
for(const auto& anchor:stratum.anchors)
if(anchor.kind=="route_point"&&anchor.values.size()>=3)anchors.push_back(&anchor);
if(anchors.size()<2)continue;
std::vector<std::array<double,3>> route;route.reserve(anchors.size());
for(const auto* anchor:anchors)
{
route.push_back({qToMetres(anchor->values[0])/coreMetres,
qToMetres(anchor->values[1])/coreMetres,
qToMetres(anchor->values[2])/coreMetres});
++routePoints;
}
double supportStartMetres=0.125,supportStepMetres=0.125,
supportMaximumMetres=0.25,supportProbeRadiusMetres=0.45;
std::uint32_t minimumSupportProbes=3;
const VoxelForgeCore::WorldAssemblyRouteConstraintsV1* routeConstraints=nullptr;
if(Assembly)
{
const auto worldRoute=std::find_if(Assembly->plan.strates.begin(),
Assembly->plan.strates.end(),[&](const auto& candidate)
{return candidate.strateIndex==stratum.strateIndex;});
if(worldRoute!=Assembly->plan.strates.end()
&&worldRoute->routeConstraints.version==1)
routeConstraints=&worldRoute->routeConstraints;
const auto islandRoute=std::find_if(Assembly->floatingIslands.begin(),
Assembly->floatingIslands.end(),[&](const auto& candidate)
{return candidate.strateIndex==stratum.strateIndex;});
if(islandRoute!=Assembly->floatingIslands.end()
&&islandRoute->manifest.recipe.routeConstraints.version==1)
routeConstraints=&islandRoute->manifest.recipe.routeConstraints;
}
if(routeConstraints)
{
const double qMetres=coreMetres
/VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel;
minimumSupportProbes=std::clamp<std::uint32_t>(
routeConstraints->minimumSupportProbes,1,5);
supportProbeRadiusMetres=routeConstraints->supportProbeRadiusSubvoxels*qMetres;
if(stratum.generatorKind=="FloatingIslands")
{
supportStartMetres=(routeConstraints->minimumClearanceSubvoxels
+VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel/2)*qMetres;
supportStepMetres=VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel
*0.5*qMetres;
supportMaximumMetres=(routeConstraints->minimumClearanceSubvoxels
+routeConstraints->supportSearchDepthSubvoxels)*qMetres;
}
else
{
const std::int64_t spacing=std::min<std::int64_t>(
routeConstraints->sweepSpacingSubvoxels,
VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel/4);
supportStepMetres=std::max<std::int64_t>(1,spacing)*qMetres;
supportStartMetres=supportStepMetres;
supportMaximumMetres=routeConstraints->supportSearchDepthSubvoxels*qMetres;
}
}
const FWalkAudit routeAudit=auditPlayerPath(Shape,route,supportStartMetres,
supportStepMetres,supportMaximumMetres,minimumSupportProbes,
supportProbeRadiusMetres,nullptr,nullptr);
routeAuditInputs.push_back({stratum.strateIndex,route,supportStartMetres,
supportStepMetres,supportMaximumMetres,supportProbeRadiusMetres,
minimumSupportProbes});
bool binding=true;
for(const auto& passage:ResolvedLayout->passages)
{
const auto equalPosition=[](const auto& a,const auto& b)
{return a[0]==b[0]&&a[1]==b[1]&&a[2]==b[2];};
if(passage.upperStrateIndex==stratum.strateIndex)
{
const auto rootedMouth=std::find_if(stratum.anchors.begin(),
stratum.anchors.end(),[](const auto& anchor)
{return anchor.kind=="passage_anchor"&&anchor.values.size()>=10;});
const std::array<std::int64_t,3> departure=
rootedMouth!=stratum.anchors.end()
?std::array<std::int64_t,3>{{rootedMouth->values[7],
rootedMouth->values[8],rootedMouth->values[9]}}
:std::array<std::int64_t,3>{{anchors.back()->values[0],
anchors.back()->values[1],anchors.back()->values[2]}};
binding&=equalPosition(passage.upperMouthSubvoxels,
departure);
}
if(passage.lowerStrateIndex==stratum.strateIndex)
{
const auto passageArrival=std::find_if(stratum.anchors.begin(),
stratum.anchors.end(),[](const auto& anchor)
{return anchor.kind=="passage_arrival"&&anchor.values.size()>=3;});
const std::array<std::int64_t,3> arrival=passageArrival!=stratum.anchors.end()
?std::array<std::int64_t,3>{{passageArrival->values[0],
passageArrival->values[1],passageArrival->values[2]}}
:std::array<std::int64_t,3>{{anchors.front()->values[0],
anchors.front()->values[1],anchors.front()->values[2]}};
binding&=equalPosition(passage.lowerMouthSubvoxels,
arrival);
}
}
++routePasses;routeWalkPasses+=routeAudit.passed;
routeBindings+=binding;routeBindingFailures+=!binding;
std::printf("[ResolvedStrateRouteAudit] strate=%d route_points=%zu center_samples=%llu capsule_samples=%llu blocked=%llu support_samples=%llu unsupported=%llu grade_failures=%llu mouth_binding=%s status=%s\n",
stratum.strateIndex,anchors.size(),static_cast<unsigned long long>(routeAudit.centers),
static_cast<unsigned long long>(routeAudit.capsuleSamples),
static_cast<unsigned long long>(routeAudit.blocked),
static_cast<unsigned long long>(routeAudit.supportSamples),
static_cast<unsigned long long>(routeAudit.unsupported),
static_cast<unsigned long long>(routeAudit.gradeFailures),binding?"PASS":"FAIL",
routeAudit.passed&&binding?"PASS":"FAIL");
for(std::size_t i=0;i<routeAudit.firstBlockedCount;++i)
std::printf("[ResolvedStrateRouteAuditSample] strate=%d kind=blocked xyz_m=(%.3f,%.3f,%.3f) density=%.6f\n",
stratum.strateIndex,routeAudit.firstBlocked[i][0],routeAudit.firstBlocked[i][1],
routeAudit.firstBlocked[i][2],routeAudit.firstBlocked[i][3]);
for(std::size_t i=0;i<routeAudit.firstUnsupportedCount;++i)
std::printf("[ResolvedStrateRouteAuditSample] strate=%d kind=unsupported xyz_m=(%.3f,%.3f,%.3f) density=%.6f\n",
stratum.strateIndex,routeAudit.firstUnsupported[i][0],
routeAudit.firstUnsupported[i][1],routeAudit.firstUnsupported[i][2],
routeAudit.firstUnsupported[i][3]);
}
for(const auto& passage:ResolvedLayout->passages)
{
std::vector<std::array<double,3>> path;path.reserve(passage.controlPoints.size());
for(const auto& point:passage.controlPoints)
{
const double playerZ=static_cast<double>(point.positionSubvoxels[2]
-point.radiusSubvoxels)+1.13*VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel
*1000000.0/World.CoreVoxelSizeMicrons;
path.push_back({qToMetres(point.positionSubvoxels[0])/coreMetres,
qToMetres(point.positionSubvoxels[1])/coreMetres,playerZ/256.0});
}
const FWalkAudit blockedAudit=auditPlayerPath(blockedWorld,path,
0.125,0.125,0.25,3,0.45,nullptr,nullptr);
blockedControls+=blockedAudit.blocked>0&&!blockedAudit.passed;
std::printf("[ResolvedPassageBlockedControl] id=%s blocked_capsule_samples=%llu detected=%s\n",
passage.stableId.c_str(),static_cast<unsigned long long>(blockedAudit.blocked),
blockedAudit.blocked>0&&!blockedAudit.passed?"true":"false");
}
for(const auto& input:routeAuditInputs)
{
const FWalkAudit controlRoute=auditPlayerPath(blockedWorld,input.path,
input.supportStart,input.supportStep,input.supportMaximum,
input.minimumSupportProbes,input.supportProbeRadius,nullptr,nullptr);
std::printf("[ResolvedStrateRouteBlockedControl] strate=%d blocked=%llu unsupported=%llu status=%s\n",
input.strateIndex,static_cast<unsigned long long>(controlRoute.blocked),
static_cast<unsigned long long>(controlRoute.unsupported),
controlRoute.passed?"PASS":"FAIL");
}
const bool l24OpenAirControlDetected=openAirLegacyViolations>0;
std::printf("[PassageOpenAirNegativeControl] source=L24_ungated_support unsupported_samples=%llu detected=%s\n",
static_cast<unsigned long long>(openAirLegacyViolations),
l24OpenAirControlDetected?"true":"false");
std::printf("[PassageOpenAirAuditSummary] interfaces=%llu samples=%llu violations=%llu column_samples=%llu short_span_samples=%llu l24_negative_control=%s status=%s\n",
static_cast<unsigned long long>(openAirAudits),
static_cast<unsigned long long>(openAirSamples),
static_cast<unsigned long long>(openAirViolations),
static_cast<unsigned long long>(openAirColumnSamples),
static_cast<unsigned long long>(openAirShortSpanSamples),
l24OpenAirControlDetected?"DETECTED":"MISSED",
openAirAudits==passageCount&&openAirViolations==0&&l24OpenAirControlDetected
?"PASS":"FAIL");
const bool l26NoLongBridgeControlDetected=l26NegativeControlApplicable
&&l26LegacyBridgeSpanMetres>12.5;
const bool l26NoLongBridgeControlPass=!l26NegativeControlApplicable
||l26NoLongBridgeControlDetected;
noLongBridgeAuditPassed=longestUncolumnedSpanMetres<=12.5
&&l26NoLongBridgeControlPass;
std::printf("[PassageNoLongBridgeNegativeControl] source=L26_SurfaceWorld_bridge applicable=%s longest_uncolumned_m=%.3f threshold_m=12.500 detected=%s\n",
l26NegativeControlApplicable?"true":"false",l26LegacyBridgeSpanMetres,
l26NoLongBridgeControlDetected?"true":"false");
std::printf("[PassageNoLongBridgeAudit] columns=%llu short_grounded_spans=%llu longest_uncolumned_m=%.3f threshold_m=12.500 longest_short_span_m=%.3f l26_negative_control=%s status=%s\n",
static_cast<unsigned long long>(columnCrossings),
static_cast<unsigned long long>(shortGroundedSpans),longestUncolumnedSpanMetres,
longestShortSpanMetres,l26NegativeControlApplicable
?(l26NoLongBridgeControlDetected?"DETECTED":"MISSED"):"NOT_APPLICABLE",
noLongBridgeAuditPassed?"PASS":"FAIL");
std::printf("[PassageRockColumnAuditSummary] columns=%llu connected_ends=%llu/%llu short_spans=%llu wall_or_support_failures=%llu disconnected_end_control=%s status=%s\n",
static_cast<unsigned long long>(columnCrossings),
static_cast<unsigned long long>(columnConnectedEnds),
static_cast<unsigned long long>(columnCrossings*2),
static_cast<unsigned long long>(shortGroundedSpans),
static_cast<unsigned long long>(columnRouteFailures+columnWallFailures),
columnDisconnectedEndControlApplicable
?(columnDisconnectedEndControlDetected?"DETECTED":"MISSED")
:"NOT_APPLICABLE",
columnAuditsPassed?"PASS":"FAIL");
const bool l23SmoothWallDetected=!looksNatural(0.0,0.0);
std::printf("[PassageNaturalnessNegativeControl] source=L23_smooth_unrelieved_wall relief_p2p_m=0.000 threshold_m=%.3f detected=%s\n",
MinimumWallReliefMetres,l23SmoothWallDetected?"true":"false");
std::printf("[PassageMouthProfileNegativeControl] source=L23_terraced_geometry flat_run_m=%.3f following_step_m=%.3f thresholds=(%.3f,%.3f) detected=%s\n",
l23TerraceControlResult.first,l23TerraceControlResult.second,
PassageProfilePlateauMinimumMetres,PassageProfileStepThresholdMetres,
l23TerraceControlDetected?"true":"false");
std::printf("[PassageNaturalnessSummary] passed=%llu/%llu l23_negative_control=%s flat_run_limit_m=%.3f wall_relief_min_m=%.3f status=%s\n",
static_cast<unsigned long long>(naturalPasses),static_cast<unsigned long long>(passageCount),
l23SmoothWallDetected?"DETECTED":"MISSED",MaximumFlatRunMetres,
MinimumWallReliefMetres,naturalPasses==passageCount&&l23SmoothWallDetected?"PASS":"FAIL");
std::printf("[PassageMouthProfileSummary] passed=%llu/%llu spacing_m=%.3f plateau_min_m=%.3f following_step_min_m=%.3f l23_terrace_negative_control=%s status=%s\n",
static_cast<unsigned long long>(mouthProfilePasses),
static_cast<unsigned long long>(passageCount),PassageProfileSpacingMetres,
PassageProfilePlateauMinimumMetres,PassageProfileStepThresholdMetres,
l23TerraceControlDetected?"DETECTED":"MISSED",
mouthProfilePasses==passageCount&&l23TerraceControlDetected?"PASS":"FAIL");
std::printf("[PassageRippleAuditSummary] passed=%llu/%llu synthetic_spheres_negative_control=%s max_amplitude_m=0.035 floor_beaded_negative_control=%s max_floor_amplitude_m=0.015 status=%s\n",
static_cast<unsigned long long>(ripplePasses),
static_cast<unsigned long long>(passageCount),
rippleControlsDetected==passageCount?"DETECTED":"MISSED",
floorRippleControlsDetected==passageCount?"DETECTED":"MISSED",
ripplePasses==passageCount?"PASS":"FAIL");
const bool auditPassed=passageCount>0&&passagePasses==passageCount
&&naturalPasses==passageCount&&l23SmoothWallDetected
&&mouthProfilePasses==passageCount&&l23TerraceControlDetected
&&ripplePasses==passageCount
&&openAirAudits==passageCount&&openAirViolations==0&&l24OpenAirControlDetected
&&columnAuditsPassed&&noLongBridgeAuditPassed
&&routePasses>0&&routePasses==routeWalkPasses&&routePasses==routeBindings
&&routeBindingFailures==0
&&blockedCompiled&&blockedControls==passageCount;
std::printf("[ResolvedPassageAuditSummary] interfaces=%llu passed=%llu natural=%llu/%llu strate_routes=%llu route_walkable=%llu route_points=%llu route_bindings=%llu route_binding_failures=%llu blocked_controls=%llu/%llu status=%s\n",
static_cast<unsigned long long>(passageCount),static_cast<unsigned long long>(passagePasses),
static_cast<unsigned long long>(naturalPasses),static_cast<unsigned long long>(passageCount),
static_cast<unsigned long long>(routePasses),static_cast<unsigned long long>(routeWalkPasses),
static_cast<unsigned long long>(routePoints),
static_cast<unsigned long long>(routeBindings),static_cast<unsigned long long>(routeBindingFailures),
static_cast<unsigned long long>(blockedControls),static_cast<unsigned long long>(passageCount),
auditPassed?"PASS":"FAIL");
if(!auditPassed)
{Streamer.Stop();return 10;}
}
if(bAuditResolvedLayoutBoundaries)
{
if(ResolvedLayout==nullptr)
{Streamer.Stop();std::fprintf(stderr,"[ResolvedLayoutProbe] missing plan-time snapshot\n");return 2;}
std::vector<std::int64_t> endpoints;
for(const auto& Stratum:ResolvedLayout->strates)
{
endpoints.push_back(Stratum.interiorBottomMicrometres);
endpoints.push_back(Stratum.interiorTopMicrometres);
endpoints.push_back(Stratum.ceiling.bottomMicrometres);
endpoints.push_back(Stratum.ceiling.topMicrometres);
endpoints.push_back(Stratum.bedrock.bottomMicrometres);
endpoints.push_back(Stratum.bedrock.topMicrometres);
}
for(std::size_t StratumIndex=0;StratumIndex+1<ResolvedLayout->strates.size();++StratumIndex)
{
const auto& Upper=ResolvedLayout->strates[StratumIndex];
if(Upper.transitionMode=="Hard"||Upper.transitionWidthMicrometres<=0)continue;
endpoints.push_back(Upper.interiorBottomMicrometres-Upper.transitionWidthMicrometres);
endpoints.push_back(Upper.interiorBottomMicrometres+Upper.transitionWidthMicrometres);
}
std::sort(endpoints.begin(),endpoints.end());
endpoints.erase(std::unique(endpoints.begin(),endpoints.end()),endpoints.end());
std::uint64_t probes=0,disagreements=0;
const double CoreVoxelMicrometres=std::max<std::uint32_t>(1,World.CoreVoxelSizeMicrons);
const auto expectedAt=[&](std::int64_t zMicrometres)
{
std::vector<std::string> candidates;
for(const auto& Stratum:ResolvedLayout->strates)
{
const auto contains=[zMicrometres](const VoxelForgeCore::ResolvedLayoutBandV2& Band)
{return Band.presentInCurrentField&&zMicrometres>=Band.bottomMicrometres
&&zMicrometres<Band.topMicrometres;};
if(contains(Stratum.ceiling))candidates.push_back(Stratum.generatorKind+"/ceiling");
if(contains(Stratum.content))candidates.push_back(Stratum.generatorKind+"/content");
if(contains(Stratum.bedrock))candidates.push_back(Stratum.generatorKind+"/bedrock");
}
return candidates;
};
const std::array<std::int64_t,3> offsets{{
-static_cast<std::int64_t>(World.CoreVoxelSizeMicrons),0,
static_cast<std::int64_t>(World.CoreVoxelSizeMicrons)}};
const std::int64_t stackMinimum=std::min_element(ResolvedLayout->strates.begin(),
ResolvedLayout->strates.end(),[](const auto& A,const auto& B)
{return A.bedrock.bottomMicrometres<B.bedrock.bottomMicrometres;})
->bedrock.bottomMicrometres;
const std::int64_t stackMaximum=std::max_element(ResolvedLayout->strates.begin(),
ResolvedLayout->strates.end(),[](const auto& A,const auto& B)
{return A.ceiling.topMicrometres<B.ceiling.topMicrometres;})
->ceiling.topMicrometres;
for(const std::int64_t Endpoint:endpoints)
for(const std::int64_t Offset:offsets)
{
const std::int64_t zMicrometres=Endpoint+Offset;
const double zVoxel=static_cast<double>(zMicrometres)/CoreVoxelMicrometres;
const VoxelForgeCore::Vec3d position{0.0,0.0,zVoxel};
const std::string actual=Shape.densityDispatchPathAt(position);
const auto expected=expectedAt(zMicrometres);
std::string expectedLabel;
std::vector<std::string> expectedGenerators;
for(const auto& Candidate:expected)
{
if(!expectedLabel.empty())expectedLabel+=',';
expectedLabel+=Candidate;
const auto Separator=Candidate.find('/');
const std::string Kind=Candidate.substr(0,Separator);
if(std::find(expectedGenerators.begin(),expectedGenerators.end(),Kind)==expectedGenerators.end())
expectedGenerators.push_back(Kind);
}
const float density=Shape.densityAt(position);
const bool solid=density<0.0f;
const bool outsideStack=zMicrometres<stackMinimum||zMicrometres>=stackMaximum;
if(expected.empty())expectedLabel=outsideStack?"outside-stack/air":"uncovered";
std::string actualGenerator;
if(actual=="SurfaceWorld-native"||actual=="SurfaceWorld-legacy")actualGenerator="SurfaceWorld";
else if(actual=="FloatingIslands-native")actualGenerator="FloatingIslands";
else if(actual.rfind("compiled-analytic/",0)==0)actualGenerator=actual.substr(18);
const bool mismatch=expected.empty()
?(!outsideStack||solid)
:std::find(expectedGenerators.begin(),expectedGenerators.end(),actualGenerator)==expectedGenerators.end();
++probes;disagreements+=mismatch?1u:0u;
std::printf("[ResolvedLayoutProbe] endpoint_um=%lld offset_um=%lld z_m=%.3f expected=%s actual=%s density=%.7g occupancy=%s disagreement=%s\n",
static_cast<long long>(Endpoint),static_cast<long long>(Offset),
static_cast<double>(zMicrometres)/1000000.0,expectedLabel.c_str(),actual.c_str(),density,
solid?"solid":"air",mismatch?"YES":"no");
}
std::printf("[ResolvedLayoutProbeSummary] probes=%llu disagreements=%llu status=%s\n",
static_cast<unsigned long long>(probes),static_cast<unsigned long long>(disagreements),
disagreements==0?"PASS":"DEVIATIONS_RECORDED");
Streamer.Stop();
return 0;
}
const auto ShapeReady=Clock::now();
const double ShapeSeconds=std::chrono::duration<double>(ShapeReady-ShapeBuildStart).count();
if(bAuditTileShapeReadiness)
{
VoxelForgeCore::TileGenerationOptions CompiledOptions;
VoxelForgeCore::TileGenerationOptions NativeOnlyOptions;
CompiledOptions.hashDensity=true;
NativeOnlyOptions.hashDensity=true;
NativeOnlyOptions.diagnosticForceNativeOnly=true;
int32 Compared=0,Mismatched=0;
for(const FVoxelTileKey& Tile:ShapeFreeTiles)
{
if(!Neighborhood.contains(Tile))continue;
const VoxelForgeCore::TileKey CoreKey{{Tile.Coord.X,Tile.Coord.Y,Tile.Coord.Z},Tile.Level};
std::string CompiledError,NativeOnlyError;
const auto Compiled=Shape.generateTile(CoreKey,CompiledOptions,CompiledError);
const auto NativeOnly=Shape.generateTile(CoreKey,NativeOnlyOptions,NativeOnlyError);
++Compared;
const bool bSame=Compiled&&NativeOnly
&&Compiled->densityHash==NativeOnly->densityHash
&&Compiled->meshHash==NativeOnly->meshHash
&&Compiled->payloadHash==NativeOnly->payloadHash
&&Compiled->topologyHash==NativeOnly->topologyHash;
if(!bSame)
{
++Mismatched;
std::printf("[ShapeReadinessEquivalence] key=(%d,%d,%d,lod%d) match=0 compiled=%s native_only=%s density=%s mesh=%s\n",
Tile.Coord.X,Tile.Coord.Y,Tile.Coord.Z,Tile.Level,
Compiled?"ok":CompiledError.c_str(),NativeOnly?"ok":NativeOnlyError.c_str(),
Compiled&&NativeOnly&&Compiled->densityHash==NativeOnly->densityHash?"same":"different",
Compiled&&NativeOnly&&Compiled->meshHash==NativeOnly->meshHash?"same":"different");
}
}
std::printf("[ShapeReadinessEquivalence] compared_near_ring=%d mismatches=%d status=%s\n",
Compared,Mismatched,Mismatched==0?"PASS":"FAIL");
if(Mismatched!=0)
{
Streamer.Stop();
std::fprintf(stderr,"[StreamPipeline] native-only tile generation differs from compiled generation.\n");
return 9;
}
}
if(bAuditBasePageEquivalence)
{
std::vector<VoxelForgeCore::TileKey> AuditKeys;
AuditKeys.reserve(48);
const auto AddAuditCandidates=[&](int32 PreferredLOD)
{
const std::size_t ExistingCount=AuditKeys.size();
for(const FVoxelTileKey& Tile:Desired.Tiles)
{
if(Tile.Level!=PreferredLOD)continue;
const VoxelForgeCore::TileKey Key{{Tile.Coord.X,Tile.Coord.Y,Tile.Coord.Z},
Tile.Level};
if(Shape.isTileShapeFree(Key)||Shape.needsTileRegion(Key))continue;
if(std::find(AuditKeys.begin(),AuditKeys.end(),Key)==AuditKeys.end())
AuditKeys.push_back(Key);
if(AuditKeys.size()>=48||AuditKeys.size()-ExistingCount>=4)return;
}
};
for(int32 PreferredLOD:{1,0,2,3,4,5,6,7,8})
{
AddAuditCandidates(PreferredLOD);
if(AuditKeys.size()>=48)break;
}
if(AuditKeys.empty())
{
std::printf("[BasePageTileEquivalence] status=UNAVAILABLE reason=no_tile_reachable_through_both_routes\n");
Streamer.Stop();
return 9;
}
VoxelForgeCore::TileGenerationOptions HashOptions;
HashOptions.hashDensity=true;
HashOptions.profileMesherStages=true;
bool bFoundEquivalentTile=false;
std::size_t CandidatesTried=0;
VoxelForgeCore::TileKey EquivalentKey{};
for(const VoxelForgeCore::TileKey& AuditKey:AuditKeys)
{
++CandidatesTried;
std::string BaseError,PageError,CompileError;
const auto BaseGenerationStart=Clock::now();
const auto BaseTile=Shape.generateTile(AuditKey,HashOptions,BaseError);
const double BaseGenerationSeconds=std::chrono::duration<double>(
Clock::now()-BaseGenerationStart).count();
if(!BaseTile)
{
std::printf("[BasePageTileEquivalenceCandidate] key=(%d,%d,%d,lod%d) base=FAIL reason=%s\n",
AuditKey.coordinate.x,AuditKey.coordinate.y,AuditKey.coordinate.z,
AuditKey.lod,BaseError.c_str());
continue;
}
const std::array<VoxelForgeCore::TileKey,1> AuditTiles={AuditKey};
VoxelForgeCore::TileRegionCompileStats PageBuildStats;
std::size_t PageTileCount=0;
const auto PageCompileStart=Clock::now();
const bool bPageBuilt=Shape.compileTileRegion(AuditTiles,
static_cast<std::uint32_t>(std::clamp(WorkerCount,1,16)),Scheduler,
CompileError,&PageTileCount,&PageBuildStats,true,true);
const double PageCompileSeconds=std::chrono::duration<double>(
Clock::now()-PageCompileStart).count();
const auto PageGenerationStart=Clock::now();
const auto PageTile=bPageBuilt?Shape.generateTile(AuditKey,HashOptions,PageError)
:std::optional<VoxelForgeCore::TileMesh>{};
const double PageGenerationSeconds=std::chrono::duration<double>(
Clock::now()-PageGenerationStart).count();
const bool bDensitySame=PageTile&&BaseTile->densityHash==PageTile->densityHash;
const bool bMeshSame=PageTile&&BaseTile->meshHash==PageTile->meshHash;
const bool bPayloadSame=PageTile&&BaseTile->payloadHash==PageTile->payloadHash;
const bool bTopologySame=PageTile&&BaseTile->topologyHash==PageTile->topologyHash;
const bool bActualPage=PageTile&&PageTile->diagnostics.analyticRegionPageRoute;
const int32 Matches=static_cast<int32>(bDensitySame)+static_cast<int32>(bMeshSame)
+static_cast<int32>(bPayloadSame)+static_cast<int32>(bTopologySame);
const bool bSame=bActualPage&&Matches==4;
std::printf("[BasePageTileEquivalenceCandidate] key=(%d,%d,%d,lod%d) page_built=%d page_route_verified=%d page_keys=%zu page_nodes=%llu base_route=base-shape page_route=analytic-page base_generation_ms=%.3f page_compile_ms=%.3f page_generation_ms=%.3f density=%s mesh=%s payload=%s topology=%s base_density=0x%016llx page_density=0x%016llx status=%s error=%s\n",
AuditKey.coordinate.x,AuditKey.coordinate.y,AuditKey.coordinate.z,AuditKey.lod,
bPageBuilt?1:0,bActualPage?1:0,PageTileCount,
static_cast<unsigned long long>(PageBuildStats.latticeNodes),
BaseGenerationSeconds*1000.0,PageCompileSeconds*1000.0,
PageGenerationSeconds*1000.0,
bDensitySame?"same":"DIFF",bMeshSame?"same":"DIFF",
bPayloadSame?"same":"DIFF",bTopologySame?"same":"DIFF",
static_cast<unsigned long long>(BaseTile->densityHash),
static_cast<unsigned long long>(PageTile?PageTile->densityHash:0),
bSame?"PASS":"DIFF",bPageBuilt?PageError.c_str():CompileError.c_str());
if(bSame)
{
bFoundEquivalentTile=true;
EquivalentKey=AuditKey;
break;
}
}
std::printf("[BasePageTileEquivalence] candidates=%zu tried=%zu matching_key=(%d,%d,%d,lod%d) status=%s\n",
AuditKeys.size(),CandidatesTried,EquivalentKey.coordinate.x,
EquivalentKey.coordinate.y,EquivalentKey.coordinate.z,EquivalentKey.lod,
bFoundEquivalentTile?"PASS":"FAIL");
if(!bFoundEquivalentTile)
{
Streamer.Stop();
return 9;
}
}
if(bAuditRouteParity)
{
struct FRouteAuditCandidate
{
VoxelForgeCore::TileKey Key;
bool bWouldRequestPage=false;
};
struct FRouteAuditRow
{
FRouteAuditCandidate Candidate;
std::optional<VoxelForgeCore::TileMesh> Base;
};
VoxelForgeCore::TileGenerationOptions CaptureOptions;
CaptureOptions.hashDensity=true;
CaptureOptions.captureDensitySamples=true;
CaptureOptions.forceFullDensityCapture=true;
CaptureOptions.profileMesherStages=true;
std::vector<FRouteAuditRow> Rows;
Rows.reserve(static_cast<std::size_t>(World.FullResClipLevels)*8);
std::vector<VoxelForgeCore::TileKey> PageKeys;
PageKeys.reserve(Rows.capacity());
const int32 AuditPageLODs=std::min(World.FullResClipLevels,3);
std::vector<const FStandaloneDesiredTileSet*> CandidateSets{&Desired};
if(bHasCameraStep)CandidateSets.push_back(&MovedDesired);
for(int32 LOD=0;LOD<AuditPageLODs;++LOD)
{
for(const bool bPageRequested:{true,false})
{
int32 SurfaceCandidates=0;
bool bHaveFlatCandidate=false;
int32 Inspected=0;
for(const FStandaloneDesiredTileSet* CandidateSet:CandidateSets)
{
for(const FVoxelTileKey& Tile:CandidateSet->Tiles)
{
if(Tile.Level!=LOD)continue;
const VoxelForgeCore::TileKey Key{{Tile.Coord.X,Tile.Coord.Y,Tile.Coord.Z},Tile.Level};
if(Shape.isTileShapeFree(Key)
||Shape.needsTileRegion(Key)!=bPageRequested)continue;
if(Inspected++>=256)break;
std::string BaseError;
auto Base=Shape.generateTile(Key,CaptureOptions,BaseError);
if(!Base)
{
std::printf("[RouteParityCandidate] route=%s key=(%d,%d,%d,lod%d) base=FAIL error=%s\n",
bPageRequested?"actual-page":"base-covered-page",Key.coordinate.x,
Key.coordinate.y,Key.coordinate.z,Key.lod,BaseError.c_str());
continue;
}
const bool bHasSurface=!Base->vertices.empty()&&!Base->indices.empty();
if(bHasSurface&&SurfaceCandidates<3)
{
Rows.push_back({{Key,bPageRequested},std::move(Base)});
PageKeys.push_back(Key);
++SurfaceCandidates;
}
else if(!bHasSurface&&!bHaveFlatCandidate)
{
Rows.push_back({{Key,bPageRequested},std::move(Base)});
PageKeys.push_back(Key);
bHaveFlatCandidate=true;
}
if(SurfaceCandidates>=3&&bHaveFlatCandidate)break;
}
if(SurfaceCandidates>=3&&bHaveFlatCandidate)break;
}
}
}
if(Rows.empty())
{
std::printf("[RouteParityAudit] status=UNAVAILABLE reason=no_page_route_candidates\n");
Streamer.Stop();
return 9;
}
VoxelForgeCore::TileGenerationOptions PageOptions=CaptureOptions;
PageOptions.auditUniformBlockProofs=true;
int32 BasePageMismatches=0,PageRoutesVerified=0;
std::uint64_t PageProofBlocks=0,PageProofSamples=0,PageProofFallbacks=0,
PageProofUnknown=0,PageProofViolations=0;
std::uint64_t PageExactSamples=0,PageExactMismatches=0;
double MaxDensityDelta=0.0,SumDensityDelta=0.0;
std::uint64_t ComparedDensitySamples=0,SignMismatches=0,
CrossingEdgeMismatches=0,SharedCrossingEdges=0;
double MaxSurfaceDisplacement=0.0,SumSurfaceDisplacement=0.0;
for(const FRouteAuditRow& Row:Rows)
if(Row.Base)
{
const FRouteDensityComparison Query=CompareRouteDensities(
*Row.Base,*Row.Base,Shape);
PageExactSamples+=Query.exactQuerySamples;
PageExactMismatches+=Query.exactQueryMismatches;
}
else ++BasePageMismatches;
VoxelForgeCore::TileRegionCompileStats PageStats;
std::size_t CoveredPageKeys=0;
std::string PageCompileError;
const bool bPagesCompiled=Shape.compileTileRegion(PageKeys,
static_cast<std::uint32_t>(std::clamp(WorkerCount,1,16)),Scheduler,
PageCompileError,&CoveredPageKeys,&PageStats,true,true);
if(!bPagesCompiled)
{
std::printf("[RouteParityAudit] page_compile=FAIL error=%s\n",PageCompileError.c_str());
Streamer.Stop();
return 9;
}
for(FRouteAuditRow& Row:Rows)
{
std::string Error;
const auto Page=Shape.generateTile(Row.Candidate.Key,PageOptions,Error);
const bool bVerifiedPage=Page&&Page->diagnostics.analyticRegionPageRoute;
PageRoutesVerified+=bVerifiedPage?1:0;
const bool bSame=Row.Base&&bVerifiedPage&&SameTileOutput(*Row.Base,*Page);
const FRouteDensityComparison Comparison=Page&&Row.Base
?CompareRouteDensities(*Page,*Row.Base,Shape):FRouteDensityComparison{};
if(!bSame||!Comparison.valid||Comparison.exactQueryMismatches!=0)
++BasePageMismatches;
PageExactSamples+=Comparison.exactQuerySamples;
PageExactMismatches+=Comparison.exactQueryMismatches;
MaxDensityDelta=std::max(MaxDensityDelta,Comparison.maxAbsoluteDelta);
SumDensityDelta+=Comparison.sumAbsoluteDelta;
ComparedDensitySamples+=Comparison.samples;
SignMismatches+=Comparison.signMismatches;
CrossingEdgeMismatches+=Comparison.crossingEdgeMismatches;
SharedCrossingEdges+=Comparison.sharedCrossingEdges;
MaxSurfaceDisplacement=std::max(MaxSurfaceDisplacement,
Comparison.maxSurfaceDisplacementVoxels);
SumSurfaceDisplacement+=Comparison.sumSurfaceDisplacementVoxels;
if(Page)
{
PageProofBlocks+=Page->diagnostics.uniformBlockProofsChecked;
PageProofSamples+=Page->diagnostics.uniformBlockProofSamplesChecked;
PageProofFallbacks+=Page->diagnostics.uniformBlockProofFallbackBlocks;
PageProofUnknown+=Page->diagnostics.uniformBlockProofUnknownBlocks;
PageProofViolations+=Page->diagnostics.uniformBlockProofViolations;
}
std::printf("[RouteParityPair] route=base/page key=(%d,%d,%d,lod%d) page_requested=%d page_verified=%d same_density=%d same_mesh=%d same_payload=%d same_topology=%d samples=%llu max_abs_density_delta=%.9g sign_mismatches=%llu edge_crossing_mismatches=%llu shared_surface_edges=%llu max_surface_delta_vox=%.9g exact_query_mismatches=%llu base_native_float=%llu page_native_float=%llu first_density=(%.9g,%.9g) status=%s error=%s\n",
Row.Candidate.Key.coordinate.x,Row.Candidate.Key.coordinate.y,
Row.Candidate.Key.coordinate.z,Row.Candidate.Key.lod,
Row.Candidate.bWouldRequestPage?1:0,bVerifiedPage?1:0,
Row.Base&&Page&&Row.Base->densityHash==Page->densityHash?1:0,
Row.Base&&Page&&Row.Base->meshHash==Page->meshHash?1:0,
Row.Base&&Page&&Row.Base->payloadHash==Page->payloadHash?1:0,
Row.Base&&Page&&Row.Base->topologyHash==Page->topologyHash?1:0,
static_cast<unsigned long long>(Comparison.samples),
Comparison.maxAbsoluteDelta,
static_cast<unsigned long long>(Comparison.signMismatches),
static_cast<unsigned long long>(Comparison.crossingEdgeMismatches),
static_cast<unsigned long long>(Comparison.sharedCrossingEdges),
Comparison.maxSurfaceDisplacementVoxels,
static_cast<unsigned long long>(Comparison.exactQueryMismatches),
static_cast<unsigned long long>(Row.Base?Row.Base->diagnostics.floatFieldCalls:0),
static_cast<unsigned long long>(Page?Page->diagnostics.floatFieldCalls:0),
Row.Base&&!Row.Base->debugDensitySamples.empty()
?Row.Base->debugDensitySamples.front():0.0f,
Page&&!Page->debugDensitySamples.empty()?Page->debugDensitySamples.front():0.0f,
bSame&&Comparison.valid&&Comparison.exactQueryMismatches==0?"PASS":"FAIL",
Page?Error.c_str():Error.c_str());
}
int32 NativeMismatches=0,NativeRoutesVerified=0;
std::uint64_t NativeExactSamples=0,NativeExactMismatches=0;
int32 NativePairs=0;
VoxelForgeCore::TileGenerationOptions NativeOptions=CaptureOptions;
NativeOptions.diagnosticForceNativeOnly=true;
for(const FVoxelTileKey& Tile:ShapeFreeTiles)
{
if(NativePairs>=9)break;
if(!Neighborhood.contains(Tile))continue;
const VoxelForgeCore::TileKey Key{{Tile.Coord.X,Tile.Coord.Y,Tile.Coord.Z},Tile.Level};
std::string BaseError,NativeError;
const auto Base=Shape.generateTile(Key,CaptureOptions,BaseError);
const auto Native=Shape.generateTile(Key,NativeOptions,NativeError);
++NativePairs;
const bool bVerifiedNative=Native&&Native->diagnostics.nativeOnlyRoute;
NativeRoutesVerified+=bVerifiedNative?1:0;
const bool bSame=Base&&bVerifiedNative&&SameTileOutput(*Base,*Native);
const FRouteDensityComparison Comparison=Base&&Native
?CompareRouteDensities(*Native,*Base,Shape):FRouteDensityComparison{};
NativeExactSamples+=Comparison.exactQuerySamples;
NativeExactMismatches+=Comparison.exactQueryMismatches;
if(!bSame||!Comparison.valid||Comparison.exactQueryMismatches!=0)
++NativeMismatches;
std::printf("[RouteParityPair] route=compiled/native-only key=(%d,%d,%d,lod%d) native_verified=%d same_density=%d same_mesh=%d same_payload=%d same_topology=%d samples=%llu exact_query_mismatches=%llu status=%s error=%s\n",
Key.coordinate.x,Key.coordinate.y,Key.coordinate.z,Key.lod,
bVerifiedNative?1:0,Base&&Native&&Base->densityHash==Native->densityHash?1:0,
Base&&Native&&Base->meshHash==Native->meshHash?1:0,
Base&&Native&&Base->payloadHash==Native->payloadHash?1:0,
Base&&Native&&Base->topologyHash==Native->topologyHash?1:0,
static_cast<unsigned long long>(Comparison.samples),
static_cast<unsigned long long>(Comparison.exactQueryMismatches),
bSame&&Comparison.valid&&Comparison.exactQueryMismatches==0?"PASS":"FAIL",
Native?NativeError.c_str():NativeError.c_str());
}
int32 ExactQueryPairs=0,ExactQueryMismatches=0;
std::uint64_t ExactQuerySamples=0;
for(int32 LOD=World.FullResClipLevels;LOD<=World.MaxClipLevel&&LOD<9;++LOD)
{
int32 Added=0;
for(const FVoxelTileKey& Tile:Desired.Tiles)
{
if(Tile.Level!=LOD||Added>=2)continue;
const VoxelForgeCore::TileKey Key{{Tile.Coord.X,Tile.Coord.Y,Tile.Coord.Z},Tile.Level};
std::string Error;
const auto Mesh=Shape.generateTile(Key,CaptureOptions,Error);
const FRouteDensityComparison Comparison=Mesh
?CompareRouteDensities(*Mesh,*Mesh,Shape):FRouteDensityComparison{};
++ExactQueryPairs;++Added;
ExactQuerySamples+=Comparison.exactQuerySamples;
if(!Mesh||!Comparison.valid||Comparison.exactQueryMismatches!=0)
++ExactQueryMismatches;
std::printf("[RouteParityPair] route=tile/exact-query key=(%d,%d,%d,lod%d) samples=%llu exact_query_mismatches=%llu status=%s error=%s\n",
Key.coordinate.x,Key.coordinate.y,Key.coordinate.z,Key.lod,
static_cast<unsigned long long>(Comparison.exactQuerySamples),
static_cast<unsigned long long>(Comparison.exactQueryMismatches),
Mesh&&Comparison.valid&&Comparison.exactQueryMismatches==0?"PASS":"FAIL",
Error.c_str());
}
}
int32 EditPairs=0,EditMismatches=0;
const auto EditRow=std::find_if(Rows.begin(),Rows.end(),[](const FRouteAuditRow& Row)
{
return Row.Base&&!Row.Candidate.bWouldRequestPage&&Row.Candidate.Key.lod<=1
&&!Row.Base->vertices.empty()&&!Row.Base->indices.empty();
});
if(EditRow!=Rows.end())
{
VoxelForgeCore::World EditWorld(CoreSnapshot);
std::string EditCompileError;
if(!EditWorld.compile(ShapeRequest,Scheduler,EditCompileError))
{
++EditMismatches;
std::printf("[RouteParityEdit] status=FAIL stage=compile error=%s\n",
EditCompileError.c_str());
}
else
{
const VoxelForgeCore::TileKey Key=EditRow->Candidate.Key;
const std::int32_t Extent=CHUNK_SIZE<<Key.lod;
const std::array<VoxelForgeCore::TileKey,1> EditKeys={Key};
VoxelForgeCore::TileGenerationOptions EditOptions=CaptureOptions;
EditOptions.auditUniformBlockProofs=true;
std::string BeforeError,ApplyError,BaseError,PageCompileError,PageError;
const auto Before=EditWorld.generateTile(Key,EditOptions,BeforeError);
VoxelForgeCore::EditTransaction Transaction;
Transaction.sequence=1;
VoxelForgeCore::EditBrush Brush;
Brush.shape=VoxelForgeCore::EditBrush::Shape::sphere;
Brush.operation=VoxelForgeCore::EditBrush::Operation::densityOffset;
bool bSurfaceCenterFound=false;
if(Before&&!Before->debugDensitySamples.empty())
{
const std::int32_t Dim=static_cast<std::int32_t>(std::llround(
std::cbrt(static_cast<double>(Before->debugDensitySamples.size()))));
const std::int32_t GridDim=Dim-3;
if(Dim>=4&&static_cast<std::size_t>(Dim)*Dim*Dim
==Before->debugDensitySamples.size()&&GridDim>0&&Extent%GridDim==0)
{
const std::int32_t Step=Extent/GridDim;
const std::int32_t OriginX=Key.coordinate.x*Extent;
const std::int32_t OriginY=Key.coordinate.y*Extent;
const std::int32_t OriginZ=Key.coordinate.z*Extent;
const auto Index=[Dim](std::int32_t X,std::int32_t Y,std::int32_t Z)
{return (static_cast<std::size_t>(Z)*Dim+Y)*Dim+X;};
for(std::int32_t Z=0;Z<Dim&&!bSurfaceCenterFound;++Z)
for(std::int32_t Y=0;Y<Dim&&!bSurfaceCenterFound;++Y)
for(std::int32_t X=0;X<Dim&&!bSurfaceCenterFound;++X)
{
for(const std::array<std::int32_t,3>& Delta:
{std::array<std::int32_t,3>{1,0,0},
std::array<std::int32_t,3>{0,1,0},
std::array<std::int32_t,3>{0,0,1}})
{
const std::int32_t NX=X+Delta[0],NY=Y+Delta[1],NZ=Z+Delta[2];
if(NX>=Dim||NY>=Dim||NZ>=Dim)continue;
const float D0=Before->debugDensitySamples[Index(X,Y,Z)];
const float D1=Before->debugDensitySamples[Index(NX,NY,NZ)];
if((D0<0.0f)==(D1<0.0f))continue;
const double T=static_cast<double>(D0)
/(static_cast<double>(D0)-D1);
Brush.a={OriginX+(X-1+T*Delta[0])*Step,
OriginY+(Y-1+T*Delta[1])*Step,
OriginZ+(Z-1+T*Delta[2])*Step};
bSurfaceCenterFound=true;
break;
}
}
}
}
if(!bSurfaceCenterFound)
Brush.a={static_cast<double>(Key.coordinate.x*Extent)+Extent*0.5,
static_cast<double>(Key.coordinate.y*Extent)+Extent*0.5,
static_cast<double>(Key.coordinate.z*Extent)+Extent*0.5};
Brush.radius=10.0;
Brush.strength=-48.0f;
Transaction.brushes.push_back(Brush);
const auto Applied=Before?EditWorld.applyEditTransaction(Transaction,
EditKeys,ApplyError):std::optional<VoxelForgeCore::EditResult>{};
const auto EditedBase=Applied
?EditWorld.generateTile(Key,EditOptions,BaseError)
:std::optional<VoxelForgeCore::TileMesh>{};
VoxelForgeCore::TileRegionCompileStats EditPageStats;
std::size_t EditPageKeys=0;
const bool bEditPageBuilt=EditedBase&&EditWorld.compileTileRegion(EditKeys,
static_cast<std::uint32_t>(std::clamp(WorkerCount,1,16)),Scheduler,
PageCompileError,&EditPageKeys,&EditPageStats,true,true);
const auto EditedPage=bEditPageBuilt
?EditWorld.generateTile(Key,EditOptions,PageError)
:std::optional<VoxelForgeCore::TileMesh>{};
const FRouteDensityComparison EditComparison=EditedBase&&EditedPage
?CompareRouteDensities(*EditedPage,*EditedBase,EditWorld)
:FRouteDensityComparison{};
const bool bEditChanged=Before&&EditedBase
&&Before->densityHash!=EditedBase->densityHash;
const bool bEditPageVerified=EditedPage
&&EditedPage->diagnostics.analyticRegionPageRoute;
const bool bEditSame=EditedBase&&EditedPage&&bEditPageVerified
&&SameTileOutput(*EditedBase,*EditedPage);
const bool bEditPass=Before&&Applied&&EditedBase&&bEditPageBuilt
&&bEditPageVerified&&bEditChanged&&bEditSame&&EditComparison.valid
&&EditComparison.exactQueryMismatches==0;
++EditPairs;
if(!bEditPass)++EditMismatches;
if(EditedPage)
{
PageProofBlocks+=EditedPage->diagnostics.uniformBlockProofsChecked;
PageProofSamples+=EditedPage->diagnostics.uniformBlockProofSamplesChecked;
PageProofFallbacks+=EditedPage->diagnostics.uniformBlockProofFallbackBlocks;
PageProofUnknown+=EditedPage->diagnostics.uniformBlockProofUnknownBlocks;
PageProofViolations+=EditedPage->diagnostics.uniformBlockProofViolations;
}
std::printf("[RouteParityEdit] key=(%d,%d,%d,lod%d) sequence=%llu before_hash=0x%016llx edited_base_hash=0x%016llx edited_page_hash=0x%016llx edit_changed=%d page_verified=%d same_mesh=%d same_payload=%d same_topology=%d samples=%llu exact_query_mismatches=%llu status=%s error=%s\n",
Key.coordinate.x,Key.coordinate.y,Key.coordinate.z,Key.lod,
static_cast<unsigned long long>(Transaction.sequence),
static_cast<unsigned long long>(Before?Before->densityHash:0),
static_cast<unsigned long long>(EditedBase?EditedBase->densityHash:0),
static_cast<unsigned long long>(EditedPage?EditedPage->densityHash:0),
bEditChanged?1:0,bEditPageVerified?1:0,
EditedBase&&EditedPage&&EditedBase->meshHash==EditedPage->meshHash?1:0,
EditedBase&&EditedPage&&EditedBase->payloadHash==EditedPage->payloadHash?1:0,
EditedBase&&EditedPage&&EditedBase->topologyHash==EditedPage->topologyHash?1:0,
static_cast<unsigned long long>(EditComparison.samples),
static_cast<unsigned long long>(EditComparison.exactQueryMismatches),
bEditPass?"PASS":"FAIL",
!Before?BeforeError.c_str():!Applied?ApplyError.c_str():
!EditedBase?BaseError.c_str():!bEditPageBuilt?PageCompileError.c_str():
PageError.c_str());
}
}
int32 HistoryPairs=0,HistoryMismatches=0;
if(bHasCameraStep&&bRegionCrossing)
{
const auto MovedAnchor=std::find_if(MovedDesired.Tiles.begin(),MovedDesired.Tiles.end(),
[](const FVoxelTileKey& Tile){return Tile.Level==0;});
const auto HistoryRow=std::find_if(Rows.begin(),Rows.end(),
[&](const FRouteAuditRow& Row)
{
if(!Row.Base||Row.Candidate.bWouldRequestPage)return false;
return std::none_of(MovedDesired.Tiles.begin(),MovedDesired.Tiles.end(),
[&](const FVoxelTileKey& Tile)
{
return Tile.Level==Row.Candidate.Key.lod
&&Tile.Coord.X==Row.Candidate.Key.coordinate.x
&&Tile.Coord.Y==Row.Candidate.Key.coordinate.y
&&Tile.Coord.Z==Row.Candidate.Key.coordinate.z;
});
});
if(HistoryRow!=Rows.end()&&MovedAnchor!=MovedDesired.Tiles.end())
{
VoxelForgeCore::ShapeBuildRequest MovedShapeRequest=ShapeRequest;
const FIntVector MovedOrigin=MovedAnchor->OriginVoxels();
const std::int32_t MovedExtent=MovedAnchor->ExtentVoxels();
MovedShapeRequest.minVoxel={MovedOrigin.X,MovedOrigin.Y,MovedOrigin.Z};
MovedShapeRequest.maxVoxel={MovedOrigin.X+MovedExtent,
MovedOrigin.Y+MovedExtent,MovedOrigin.Z+MovedExtent};
MovedShapeRequest.clipMinVoxel=MovedShapeRequest.minVoxel;
MovedShapeRequest.clipMaxVoxel=MovedShapeRequest.maxVoxel;
VoxelForgeCore::World MovedWorld(CoreSnapshot);
std::string MovedShapeError,MovedTileError;
const bool bMovedCompiled=MovedWorld.compile(MovedShapeRequest,Scheduler,
MovedShapeError);
const auto MovedTile=bMovedCompiled
?MovedWorld.generateTile(HistoryRow->Candidate.Key,CaptureOptions,MovedTileError)
:std::optional<VoxelForgeCore::TileMesh>{};
const FRouteDensityComparison HistoryComparison=MovedTile
?CompareRouteDensities(*MovedTile,*HistoryRow->Base,MovedWorld)
:FRouteDensityComparison{};
const bool bHistorySame=MovedTile
&&SameTileOutput(*MovedTile,*HistoryRow->Base)
&&HistoryComparison.valid&&HistoryComparison.exactQueryMismatches==0;
++HistoryPairs;
if(!bHistorySame)++HistoryMismatches;
std::printf("[RouteParityHistory] from=initial_base to=moved_world key=(%d,%d,%d,lod%d) same_density=%d same_mesh=%d same_payload=%d same_topology=%d samples=%llu max_abs_density_delta=%.9g exact_query_mismatches=%llu status=%s error=%s\n",
HistoryRow->Candidate.Key.coordinate.x,HistoryRow->Candidate.Key.coordinate.y,
HistoryRow->Candidate.Key.coordinate.z,HistoryRow->Candidate.Key.lod,
MovedTile&&MovedTile->densityHash==HistoryRow->Base->densityHash?1:0,
MovedTile&&MovedTile->meshHash==HistoryRow->Base->meshHash?1:0,
MovedTile&&MovedTile->payloadHash==HistoryRow->Base->payloadHash?1:0,
MovedTile&&MovedTile->topologyHash==HistoryRow->Base->topologyHash?1:0,
static_cast<unsigned long long>(HistoryComparison.samples),
HistoryComparison.maxAbsoluteDelta,
static_cast<unsigned long long>(HistoryComparison.exactQueryMismatches),
bHistorySame?"PASS":"FAIL",
!bMovedCompiled?MovedShapeError.c_str():MovedTileError.c_str());
}
}
const double MeanDensityDelta=ComparedDensitySamples
?SumDensityDelta/static_cast<double>(ComparedDensitySamples):0.0;
const double MeanSurfaceDisplacement=SharedCrossingEdges
?SumSurfaceDisplacement/static_cast<double>(SharedCrossingEdges):0.0;
const bool bRouteParityPassing=BasePageMismatches==0&&NativeMismatches==0
&&ExactQueryMismatches==0&&EditPairs==1&&EditMismatches==0
&&HistoryPairs==(bHasCameraStep&&bRegionCrossing?1:0)&&HistoryMismatches==0
&&PageRoutesVerified==static_cast<int32>(Rows.size())
&&NativeRoutesVerified==NativePairs&&PageProofViolations==0
&&PageExactMismatches==0&&NativeExactMismatches==0;
std::printf("[RouteParityAudit] seed=%d page_pairs=%zu page_verified=%d page_mismatches=%d native_only_pairs=%d native_verified=%d native_mismatches=%d higher_lod_exact_pairs=%d higher_lod_exact_mismatches=%d edit_pairs=%d edit_mismatches=%d history_pairs=%d history_mismatches=%d exact_query_samples=%llu exact_query_mismatches=%llu page_density_samples=%llu max_abs_density_delta=%.9g mean_abs_density_delta=%.9g sign_mismatches=%llu edge_crossing_mismatches=%llu shared_surface_edges=%llu max_surface_delta_vox=%.9g mean_surface_delta_vox=%.9g page_proof_blocks=%llu page_proof_samples=%llu page_proof_fallbacks=%llu page_proof_unknown=%llu page_proof_violations=%llu status=%s\n",
World.Seed,Rows.size(),PageRoutesVerified,BasePageMismatches,
NativePairs,NativeRoutesVerified,NativeMismatches,ExactQueryPairs,
ExactQueryMismatches,EditPairs,EditMismatches,HistoryPairs,HistoryMismatches,
static_cast<unsigned long long>(PageExactSamples
+NativeExactSamples+ExactQuerySamples),
static_cast<unsigned long long>(PageExactMismatches
+NativeExactMismatches+ExactQueryMismatches),
static_cast<unsigned long long>(ComparedDensitySamples),MaxDensityDelta,
MeanDensityDelta,static_cast<unsigned long long>(SignMismatches),
static_cast<unsigned long long>(CrossingEdgeMismatches),
static_cast<unsigned long long>(SharedCrossingEdges),MaxSurfaceDisplacement,
MeanSurfaceDisplacement,static_cast<unsigned long long>(PageProofBlocks),
static_cast<unsigned long long>(PageProofSamples),
static_cast<unsigned long long>(PageProofFallbacks),
static_cast<unsigned long long>(PageProofUnknown),
static_cast<unsigned long long>(PageProofViolations),
bRouteParityPassing?"PASS":"FAIL");
if(!bRouteParityPassing)
{
Streamer.Stop();
return 9;
}
}
const FStandaloneStreamingUpdate Update=Streamer.UpdateDesiredWithSet(Desired,{},0);
if(Update.DesiredTiles!=static_cast<int32>(Desired.Tiles.size()))
{
Streamer.Stop();
std::fprintf(stderr,"[StreamPipeline] expected %zu tiles after shape publication but queued %d.\n",
Desired.Tiles.size(),Update.DesiredTiles);return 7;
}
FSceneExportWriter SceneExport;
const bool bExportRequested=!MeshExportPath.empty();
bool bSceneExportPassing=true;
if(bExportRequested)
{
bSceneExportPassing=SceneExport.Open(MeshExportPath,World.CoreVoxelSizeMicrons,
CameraPositionVoxels,CameraYawDegrees,CameraPitchDegrees,
static_cast<std::uint32_t>(Update.DesiredTiles),
ResolvedLayout&&!ResolvedLayout->oreVeins.empty());
if(!bSceneExportPassing)
{
Streamer.Stop();
std::fprintf(stderr,"[MeshSceneExport] FAIL: could not open %s\n",
MeshExportPath.string().c_str());
return 8;
}
}
std::vector<FHashedTile> DensityRows,MeshRows,PayloadRows,TopologyRows,MaterialRows;
std::uint64_t MaterialQueries=0,MaterialCandidateChecks=0,MaterialOutsideTiles=0;
double MaterialQueryMilliseconds=0.0;
int32 Finished=0,NeighborhoodFinished=0,FullDetailFinished=0;
int32 FullDetailExpected=0;
uint64 WholeNonEmptyMeshTiles=0,WholeTriangleCount=0;
struct FColumnXY
{
std::int64_t X=0,Y=0;
bool operator==(const FColumnXY&)const=default;
};
struct FColumnXYHash
{
std::size_t operator()(const FColumnXY& Value)const noexcept
{
const std::size_t X=std::hash<std::int64_t>{}(Value.X);
const std::size_t Y=std::hash<std::int64_t>{}(Value.Y);
return X^(Y+static_cast<std::size_t>(0x9E3779B9u)+(X<<6)+(X>>2));
}
};
struct FColumnEvaluationEvent
{
FColumnXY XY;
FVoxelTileKey Tile;
std::uint64_t WorkerHash=0;
std::uint64_t Sequence=0;
bool bOutsideTileFootprint=false;
};
std::array<std::vector<FColumnEvaluationEvent>,9> ColumnEventsByLOD;
std::array<std::uint64_t,9> ColumnEvaluationEventsByLOD{},UniqueColumnCoordinatesByLOD{};
std::array<std::uint64_t,9> ColumnDuplicateEventsByLOD{},SameWorkerEvictedRepeatsByLOD{};
std::array<std::uint64_t,9> DifferentWorkerRepeatsByLOD{},HaloNormalRepeatsByLOD{};
std::array<std::uint64_t,9> HaloNormalEvaluationsByLOD{},NeighbourDuplicateEventsByLOD{};
std::array<std::uint64_t,9> CrossWorkerNeighbourDuplicateEventsByLOD{};
std::array<std::uint64_t,9> ColumnCaptureTilesByLOD{},ExpectedTilesByLOD{};
std::array<bool,9> ColumnCaptureCompleteByLOD{};
ColumnCaptureCompleteByLOD.fill(true);
std::array<double,9> WorkerSecondsByLOD{};
std::array<double,9> BaseRouteWorkerSecondsByLOD{},PageRouteWorkerSecondsByLOD{};
std::array<double,9> ColumnEvalMsByLOD{},MarchingExclusiveMsByLOD{};
std::array<double,9> GroundRefineExclusiveMsByLOD{},CapRefineExclusiveMsByLOD{};
std::array<double,9> MeshAssemblyMsByLOD{};
std::array<double,9> SkirtMsByLOD{};
struct FFarLODProfile
{
std::array<std::uint64_t,9> ColumnCalls{},ColumnHits{},ColumnMisses{};
std::array<std::uint64_t,9> ColumnConflictMisses{},SharedColumnHits{},ColumnEvaluations{};
std::array<double,9> McColumnMs{},GroundColumnMs{},CapColumnMs{};
std::array<double,9> McGridMs{},McCellClassMs{},McGradientMs{};
std::array<double,9> McInterpolationMs{},McDedupMs{},McOtherMs{};
std::array<double,9> StratumShellMs{},ConnectorShellMs{};
std::array<std::uint64_t,9> StratumFieldCalls{},ConnectorFieldCalls{},FarShellTriangles{};
std::array<std::uint64_t,9> StratumColumnPointCalls{},StratumColumnHits{};
std::array<std::uint64_t,9> StratumColumnMisses{},StratumSharedColumnHits{},StratumColumnEvaluations{};
std::array<std::uint64_t,9> ConnectorColumnPointCalls{},ConnectorColumnHits{};
std::array<std::uint64_t,9> ConnectorColumnMisses{},ConnectorSharedColumnHits{},ConnectorColumnEvaluations{};
std::array<double,9> StratumColumnComputeMs{},ConnectorColumnComputeMs{};
};
std::unique_ptr<FFarLODProfile> FarLODProfile;
if(bReportLodWorkProfile)FarLODProfile=std::make_unique<FFarLODProfile>();
std::array<std::uint64_t,9> DensitySamplesByLOD{};
std::array<std::uint64_t,9> SkirtTrianglesByLOD{};
std::array<std::uint64_t,9> TileCountByLOD{};
std::array<std::uint64_t,9> BaseRouteTilesByLOD{},PageRouteTilesByLOD{};
for(const FVoxelTileKey& Tile:Desired.Tiles)
if(Tile.Level>=0&&Tile.Level<static_cast<int32>(ExpectedTilesByLOD.size()))
++ExpectedTilesByLOD[static_cast<std::size_t>(Tile.Level)];
const auto AreSameLODNeighbours=[](const FVoxelTileKey& A,const FVoxelTileKey& B)
{
if(A.Level!=B.Level)return false;
const std::int64_t DX=std::abs(static_cast<std::int64_t>(A.Coord.X)-B.Coord.X);
const std::int64_t DY=std::abs(static_cast<std::int64_t>(A.Coord.Y)-B.Coord.Y);
const std::int64_t DZ=std::abs(static_cast<std::int64_t>(A.Coord.Z)-B.Coord.Z);
return std::max({DX,DY,DZ})<=1&&(DX+DY+DZ)>0;
};
uint64 NativeSolidBoxes=0,NativeAirBoxes=0,NativeMixedBoxes=0,NativeUnknownBoxes=0;
uint64 NativeFieldCalls=0,NativeColumnHits=0,NativeColumnMisses=0,NativeMeshingSkips=0;
double NativeClassificationMilliseconds=0.0,NativeColumnComputeMilliseconds=0.0;
double NativeMeshingMilliseconds=0.0;
for(const FVoxelTileKey& Tile:Desired.Tiles)
if(Tile.Level<World.FullResClipLevels)++FullDetailExpected;
std::array<std::optional<FStandaloneCpuTile>,9> GateSampleTiles{};
std::array<double,9> GateSampleDistances{};
GateSampleDistances.fill(std::numeric_limits<double>::infinity());
Clock::time_point FirstTileReady{},NeighborhoodReady{},FullDetailReady{},WholeViewReady{};
bool bFirstTileReported=false,bNeighborhoodReported=false,bFullDetailReported=false;
uint64 BlockProofBlocksChecked=0,BlockProofSamplesChecked=0;
uint64 BlockProofFallbackBlocks=0,BlockProofUnknownBlocks=0,BlockProofViolations=0;
while(Finished<Update.DesiredTiles)
{
std::vector<FStandaloneCpuTile> Ready=Streamer.TakeReady();
if(Ready.empty()){std::this_thread::sleep_for(std::chrono::milliseconds(1));continue;}
for(const FStandaloneCpuTile& Tile:Ready)
{
if(Tile.bGenerationFailed)
{
Streamer.Stop();
std::fprintf(stderr,"[StreamPipeline] a tile failed generation; refusing a partial result.\n");
return 9;
}
if(bExportRequested)SceneExport.Add(Tile);
++Finished;
if(bReportMeshCoverage)
{
const uint64 TileTriangleCount=static_cast<uint64>(Tile.Indices.size()/3);
WholeTriangleCount+=TileTriangleCount;
if(TileTriangleCount>0)++WholeNonEmptyMeshTiles;
}
if(Tile.Key.Level>=0&&Tile.Key.Level<static_cast<int32>(TileCountByLOD.size()))
{
const std::size_t LOD=static_cast<std::size_t>(Tile.Key.Level);
++TileCountByLOD[LOD];
WorkerSecondsByLOD[LOD]+=Tile.WorkerSeconds;
if(bReportLodWorkProfile)
{
if(Tile.CoreDiagnostics.analyticRegionPageRoute)
{
++PageRouteTilesByLOD[LOD];
PageRouteWorkerSecondsByLOD[LOD]+=Tile.WorkerSeconds;
}
else
{
++BaseRouteTilesByLOD[LOD];
BaseRouteWorkerSecondsByLOD[LOD]+=Tile.WorkerSeconds;
}
}
ColumnEvalMsByLOD[LOD]+=Tile.CoreDiagnostics.columnEvaluationExclusiveMilliseconds;
MarchingExclusiveMsByLOD[LOD]+=Tile.CoreDiagnostics.marchingCubesExclusiveMilliseconds;
GroundRefineExclusiveMsByLOD[LOD]+=Tile.CoreDiagnostics.groundRefinementExclusiveMilliseconds;
CapRefineExclusiveMsByLOD[LOD]+=Tile.CoreDiagnostics.capRefinementExclusiveMilliseconds;
MeshAssemblyMsByLOD[LOD]+=Tile.CoreDiagnostics.meshAssemblyMilliseconds;
SkirtMsByLOD[LOD]+=Tile.CoreDiagnostics.marchingCubesSkirtMilliseconds;
SkirtTrianglesByLOD[LOD]+=Tile.SkirtTriangleCount;
if(bReportLodWorkProfile)
{
DensitySamplesByLOD[LOD]+=Tile.DensitySamples;
const auto& D=Tile.CoreDiagnostics;
FarLODProfile->ColumnCalls[LOD]+=D.fieldCalls;
FarLODProfile->ColumnHits[LOD]+=D.columnCacheHits;
FarLODProfile->ColumnMisses[LOD]+=D.columnCacheMisses;
FarLODProfile->ColumnConflictMisses[LOD]+=D.columnCacheConflictMisses;
FarLODProfile->SharedColumnHits[LOD]+=D.sharedColumnCacheHits;
FarLODProfile->ColumnEvaluations[LOD]+=D.columnEvaluations;
FarLODProfile->McColumnMs[LOD]+=D.marchingCubesColumnComputeMilliseconds;
FarLODProfile->GroundColumnMs[LOD]+=D.groundRefinementColumnComputeMilliseconds;
FarLODProfile->CapColumnMs[LOD]+=D.capRefinementColumnComputeMilliseconds;
FarLODProfile->McGridMs[LOD]+=D.marchingCubesDensityGridMilliseconds;
FarLODProfile->McCellClassMs[LOD]+=D.marchingCubesCellClassificationMilliseconds;
FarLODProfile->McGradientMs[LOD]+=D.marchingCubesGradientNormalsMilliseconds;
FarLODProfile->McInterpolationMs[LOD]+=D.marchingCubesEdgeInterpolationMilliseconds;
FarLODProfile->McDedupMs[LOD]+=D.marchingCubesVertexDedupStreamMilliseconds;
FarLODProfile->McOtherMs[LOD]+=D.marchingCubesOtherMilliseconds;
FarLODProfile->StratumShellMs[LOD]+=D.farStratumShellMilliseconds;
FarLODProfile->ConnectorShellMs[LOD]+=D.farConnectorShellMilliseconds;
FarLODProfile->StratumFieldCalls[LOD]+=D.farStratumFieldCalls;
FarLODProfile->ConnectorFieldCalls[LOD]+=D.farConnectorFieldCalls;
FarLODProfile->FarShellTriangles[LOD]+=D.farShellTrianglesAdded;
FarLODProfile->StratumColumnPointCalls[LOD]+=D.farStratumColumnPointCalls;
FarLODProfile->StratumColumnHits[LOD]+=D.farStratumColumnCacheHits;
FarLODProfile->StratumColumnMisses[LOD]+=D.farStratumColumnCacheMisses;
FarLODProfile->StratumSharedColumnHits[LOD]+=D.farStratumSharedColumnCacheHits;
FarLODProfile->StratumColumnEvaluations[LOD]+=D.farStratumColumnEvaluations;
FarLODProfile->ConnectorColumnPointCalls[LOD]+=D.farConnectorColumnPointCalls;
FarLODProfile->ConnectorColumnHits[LOD]+=D.farConnectorColumnCacheHits;
FarLODProfile->ConnectorColumnMisses[LOD]+=D.farConnectorColumnCacheMisses;
FarLODProfile->ConnectorSharedColumnHits[LOD]+=D.farConnectorSharedColumnCacheHits;
FarLODProfile->ConnectorColumnEvaluations[LOD]+=D.farConnectorColumnEvaluations;
FarLODProfile->StratumColumnComputeMs[LOD]+=D.farStratumColumnComputeMilliseconds;
FarLODProfile->ConnectorColumnComputeMs[LOD]+=D.farConnectorColumnComputeMilliseconds;
}
if(bAuditUniformBlockProofs)
{
BlockProofBlocksChecked+=Tile.CoreDiagnostics.uniformBlockProofsChecked;
BlockProofSamplesChecked+=Tile.CoreDiagnostics.uniformBlockProofSamplesChecked;
BlockProofFallbackBlocks+=Tile.CoreDiagnostics.uniformBlockProofFallbackBlocks;
BlockProofUnknownBlocks+=Tile.CoreDiagnostics.uniformBlockProofUnknownBlocks;
BlockProofViolations+=Tile.CoreDiagnostics.uniformBlockProofViolations;
}
if(bScreenSpaceGate&&Assembly&&Tile.Key.Level>=3&&Tile.Key.Level<9
&&!Tile.Vertices.empty()
&&StandaloneScreenSpaceGate::TileHasNativeSurface(Tile.Key,*Assembly,
static_cast<double>(World.CoreVoxelSizeMicrons)/1000000.0))
{
const double Distance=StandaloneScreenSpaceGate::TileAabbDistanceMeters(
Tile.Key,CameraPositionVoxels,
static_cast<double>(World.CoreVoxelSizeMicrons)/1000000.0);
const bool bCloser=Distance<GateSampleDistances[LOD]-1e-9;
const bool bTied=std::abs(Distance-GateSampleDistances[LOD])<=1e-9;
const bool bKeyLess=!GateSampleTiles[LOD]
||TileKeyLessForHash(Tile.Key,GateSampleTiles[LOD]->Key);
if(bCloser||(bTied&&bKeyLess))
{GateSampleDistances[LOD]=Distance;GateSampleTiles[LOD]=Tile;}
}
}
if(bProfileColumnOverlap&&Tile.Key.Level>=0
&&Tile.Key.Level<static_cast<int32>(ColumnCaptureTilesByLOD.size()))
{
const std::size_t LOD=static_cast<std::size_t>(Tile.Key.Level);
++ColumnCaptureTilesByLOD[LOD];
ColumnCaptureCompleteByLOD[LOD]=ColumnCaptureCompleteByLOD[LOD]
&&Tile.CoreDiagnostics.columnCoordinateCaptureComplete;
auto& Events=ColumnEventsByLOD[LOD];
for(const auto& Coordinate:Tile.CoreDiagnostics.evaluatedColumnCoordinates)
{
Events.push_back({{Coordinate.x,Coordinate.y},Tile.Key,
Tile.CoreDiagnostics.columnEvaluationWorkerHash,Coordinate.sequence,
Coordinate.outsideTileFootprint});
}
}
WholeViewReady=std::max(WholeViewReady,Tile.CompletedAt);
if(FirstTileReady.time_since_epoch().count()==0||Tile.CompletedAt<FirstTileReady)
FirstTileReady=Tile.CompletedAt;
if(Neighborhood.contains(Tile.Key))
{
++NeighborhoodFinished;
NeighborhoodReady=std::max(NeighborhoodReady,Tile.CompletedAt);
}
if(Tile.Key.Level<World.FullResClipLevels)
{
++FullDetailFinished;
FullDetailReady=std::max(FullDetailReady,Tile.CompletedAt);
NativeSolidBoxes+=Tile.CoreDiagnostics.solidBoxes;
NativeAirBoxes+=Tile.CoreDiagnostics.airBoxes;
NativeMixedBoxes+=Tile.CoreDiagnostics.mixedBoxes;
NativeUnknownBoxes+=Tile.CoreDiagnostics.unknownBoxes;
NativeFieldCalls+=Tile.CoreDiagnostics.fieldCalls;
NativeColumnHits+=Tile.CoreDiagnostics.columnCacheHits;
NativeColumnMisses+=Tile.CoreDiagnostics.columnCacheMisses;
NativeMeshingSkips+=Tile.CoreDiagnostics.meshingSkipped?1u:0u;
NativeClassificationMilliseconds+=Tile.CoreDiagnostics.classificationMilliseconds;
NativeColumnComputeMilliseconds+=Tile.CoreDiagnostics.columnComputeMilliseconds;
NativeMeshingMilliseconds+=Tile.CoreDiagnostics.meshingMilliseconds;
}
MaterialQueries+=Tile.CoreDiagnostics.materialQueries;
MaterialCandidateChecks+=Tile.CoreDiagnostics.materialCandidateChecks;
MaterialOutsideTiles+=Tile.CoreDiagnostics.materialTileOutsideEveryVein?1u:0u;
MaterialQueryMilliseconds+=Tile.CoreDiagnostics.materialQueryMilliseconds;
if(bHashDensity)
{
if(Tile.bHasDensityHash)DensityRows.push_back({Tile.Key,Tile.DensityHash});
if(Tile.bHasMeshHash)MeshRows.push_back({Tile.Key,Tile.MeshHash});
if(Tile.bHasPayloadHash)PayloadRows.push_back({Tile.Key,Tile.PayloadHash});
if(Tile.bHasTopologyHash)TopologyRows.push_back({Tile.Key,Tile.TopologyHash});
if(Tile.bHasMaterialHash)MaterialRows.push_back({Tile.Key,Tile.MaterialHash});
}
}
if(!bFirstTileReported&&FirstTileReady.time_since_epoch().count()!=0)
{
std::printf("[PipelineMilestone] first_tile_ready=%.3fs\n",
std::chrono::duration<double>(FirstTileReady-ColdStart).count());
bFirstTileReported=true;
}
if(!bNeighborhoodReported&&NeighborhoodFinished==static_cast<int32>(Neighborhood.size()))
{
std::printf("[PipelineMilestone] neighborhood_ready=%.3fs generated=%d/27\n",
std::chrono::duration<double>(NeighborhoodReady-ColdStart).count(),NeighborhoodFinished);
bNeighborhoodReported=true;
}
if(!bFullDetailReported&&FullDetailFinished==FullDetailExpected)
{
std::printf("[PipelineMilestone] full_detail_ready=%.3fs generated=%d/%d\n",
std::chrono::duration<double>(FullDetailReady-ColdStart).count(),
FullDetailFinished,FullDetailExpected);
bFullDetailReported=true;
}
}
if(bHasCameraStep)
{
const auto MovingStart=Clock::now();
double RegionCompileWallSeconds=0.0;
double RegionCompileCpuSeconds=0.0;
std::size_t RegionCompileRequested=0,RegionCompileCovered=0;
VoxelForgeCore::TileRegionCompileStats RegionCompileStats;
if(bRegionCrossing)
{
std::unordered_set<FVoxelTileKey,FStandaloneTileKeyHash> InitialKeys;
InitialKeys.reserve(Desired.Tiles.size()*2+1);
for(const FVoxelTileKey& Key:Desired.Tiles)InitialKeys.insert(Key);
std::vector<VoxelForgeCore::TileKey> EnteringCoreTiles;
EnteringCoreTiles.reserve(MovedDesired.Tiles.size());
for(const FVoxelTileKey& Key:MovedDesired.Tiles)
{
if(InitialKeys.contains(Key))continue;
EnteringCoreTiles.push_back({{Key.Coord.X,Key.Coord.Y,Key.Coord.Z},Key.Level});
}
RegionCompileRequested=EnteringCoreTiles.size();
const auto RegionCompileStart=Clock::now();
const std::clock_t RegionCompileCpuStart=std::clock();
std::string RegionCompileError;
if(!Shape.compileTileRegion(EnteringCoreTiles,
static_cast<uint32>(std::clamp(WorkerCount,1,16)),Scheduler,
RegionCompileError,&RegionCompileCovered,&RegionCompileStats,true))
{
Streamer.Stop();
std::fprintf(stderr,"[MovingRegionCompile] failed: %s\n",RegionCompileError.c_str());
return 2;
}
RegionCompileWallSeconds=std::chrono::duration<double>(
Clock::now()-RegionCompileStart).count();
RegionCompileCpuSeconds=static_cast<double>(std::clock()-RegionCompileCpuStart)
/CLOCKS_PER_SEC;
const std::size_t ParallelWorkers=RegionCompileStats.regionsBuilt>1
?std::min<std::size_t>(8,RegionCompileStats.regionsBuilt):0;
std::printf("[MovingRegionCompile] distance_m=%.3f entering_tiles=%zu covered_tiles=%zu regions=%zu lattice_nodes=%llu wall_s=%.6f cpu_s=%.6f worker_threads=%zu mode=analytic-shape-pages\n",
std::sqrt(static_cast<double>(CameraStepVoxels.X)*CameraStepVoxels.X
+static_cast<double>(CameraStepVoxels.Y)*CameraStepVoxels.Y
+static_cast<double>(CameraStepVoxels.Z)*CameraStepVoxels.Z)
*static_cast<double>(World.CoreVoxelSizeMicrons)/1000000.0,
RegionCompileRequested,RegionCompileCovered,RegionCompileStats.regionsBuilt,
static_cast<unsigned long long>(RegionCompileStats.latticeNodes),
RegionCompileWallSeconds,RegionCompileCpuSeconds,ParallelWorkers);
}
const auto MovingTileStart=Clock::now();
const auto MovingUpdate=Streamer.UpdateDesiredWithSet(MovedDesired,Desired.Tiles,1);
std::array<std::uint64_t,9> MovingTilesByLOD{};
std::array<double,9> MovingWorkerSecondsByLOD{};
std::array<std::uint64_t,9> MovingSamplesByLOD{},MovingNativeFloatCallsByLOD{},
MovingNativeLatticeCallsByLOD{},MovingNativeOnlyTilesByLOD{},
MovingAnalyticPageTilesByLOD{},MovingNativeSurfaceTilesByLOD{};
std::array<std::uint64_t,9> MovingBaseRouteTilesByLOD{};
std::array<double,9> MovingBaseRouteWorkerSecondsByLOD{},
MovingPageRouteWorkerSecondsByLOD{};
std::array<double,9> MovingColumnComputeMsByLOD{},MovingClassificationMsByLOD{},
MovingMcExclusiveMsByLOD{},MovingMcDensityGridMsByLOD{},
MovingMcCellClassMsByLOD{},MovingMcGradientMsByLOD{},
MovingMcInterpolationMsByLOD{},MovingMcDedupMsByLOD{},MovingMcOtherMsByLOD{};
std::vector<FHashedTile> MovingDensityRows,MovingMeshRows,
MovingPayloadRows,MovingTopologyRows;
int32 MovingFinished=0;
while(MovingFinished<MovingUpdate.NewJobs)
{
std::vector<FStandaloneCpuTile> Ready=Streamer.TakeReady();
if(Ready.empty())
{std::this_thread::sleep_for(std::chrono::milliseconds(1));continue;}
for(const FStandaloneCpuTile& Tile:Ready)
{
++MovingFinished;
if(Tile.Key.Level>=0&&Tile.Key.Level<static_cast<int32>(MovingTilesByLOD.size()))
{
const std::size_t LOD=static_cast<std::size_t>(Tile.Key.Level);
++MovingTilesByLOD[LOD];
MovingWorkerSecondsByLOD[LOD]+=Tile.WorkerSeconds;
if(bReportLodWorkProfile)
{
const auto& D=Tile.CoreDiagnostics;
MovingSamplesByLOD[LOD]+=Tile.DensitySamples;
MovingNativeFloatCallsByLOD[LOD]+=D.floatFieldCalls;
MovingNativeLatticeCallsByLOD[LOD]+=D.latticeFieldCalls;
MovingNativeOnlyTilesByLOD[LOD]+=D.nativeOnlyRoute?1u:0u;
MovingAnalyticPageTilesByLOD[LOD]+=D.analyticRegionPageRoute?1u:0u;
MovingNativeSurfaceTilesByLOD[LOD]+=D.nativeSurfaceTile?1u:0u;
if(D.analyticRegionPageRoute)
MovingPageRouteWorkerSecondsByLOD[LOD]+=Tile.WorkerSeconds;
else
{
++MovingBaseRouteTilesByLOD[LOD];
MovingBaseRouteWorkerSecondsByLOD[LOD]+=Tile.WorkerSeconds;
}
MovingColumnComputeMsByLOD[LOD]+=D.columnEvaluationExclusiveMilliseconds;
MovingClassificationMsByLOD[LOD]+=D.classificationExclusiveMilliseconds;
MovingMcExclusiveMsByLOD[LOD]+=D.marchingCubesExclusiveMilliseconds;
MovingMcDensityGridMsByLOD[LOD]+=D.marchingCubesDensityGridMilliseconds;
MovingMcCellClassMsByLOD[LOD]+=D.marchingCubesCellClassificationMilliseconds;
MovingMcGradientMsByLOD[LOD]+=D.marchingCubesGradientNormalsMilliseconds;
MovingMcInterpolationMsByLOD[LOD]+=D.marchingCubesEdgeInterpolationMilliseconds;
MovingMcDedupMsByLOD[LOD]+=D.marchingCubesVertexDedupStreamMilliseconds;
MovingMcOtherMsByLOD[LOD]+=D.marchingCubesOtherMilliseconds;
}
}
if(bHashDensity)
{
if(Tile.bHasDensityHash)MovingDensityRows.push_back({Tile.Key,Tile.DensityHash});
if(Tile.bHasMeshHash)MovingMeshRows.push_back({Tile.Key,Tile.MeshHash});
if(Tile.bHasPayloadHash)MovingPayloadRows.push_back({Tile.Key,Tile.PayloadHash});
if(Tile.bHasTopologyHash)MovingTopologyRows.push_back({Tile.Key,Tile.TopologyHash});
}
}
}
const double MovingTileWallSeconds=std::chrono::duration<double>(
Clock::now()-MovingTileStart).count();
const double MovingWallSeconds=std::chrono::duration<double>(Clock::now()-MovingStart).count();
const double StepDistanceMeters=std::sqrt(
static_cast<double>(CameraStepVoxels.X)*CameraStepVoxels.X
+static_cast<double>(CameraStepVoxels.Y)*CameraStepVoxels.Y
+static_cast<double>(CameraStepVoxels.Z)*CameraStepVoxels.Z)
*static_cast<double>(World.CoreVoxelSizeMicrons)/1000000.0;
std::printf("[MovingCameraStep] step_voxels=(%.3f,%.3f,%.3f) distance_m=%.3f desired_tiles=%zu new_tiles=%d completed=%d wall_s=%.6f shared_column_cache=%s\n",
CameraStepVoxels.X,CameraStepVoxels.Y,CameraStepVoxels.Z,StepDistanceMeters,
MovedDesired.Tiles.size(),MovingUpdate.NewJobs,MovingFinished,MovingWallSeconds,
bUseSharedColumnCache?"on":"off");
std::printf("[MovingTileWork] tiles=%d wall_s=%.6f worker_sum_s=%.6f region_compile_wall_s=%.6f crossing_total_s=%.6f\n",
MovingFinished,MovingTileWallSeconds,
std::accumulate(MovingWorkerSecondsByLOD.begin(),MovingWorkerSecondsByLOD.end(),0.0),
RegionCompileWallSeconds,MovingWallSeconds);
if(bHashDensity)
std::printf("[MovingTileHash] tiles=%d rows=(%zu,%zu,%zu,%zu) density=0x%016llx mesh=0x%016llx payload=0x%016llx topology=0x%016llx status=%s\n",
MovingFinished,MovingDensityRows.size(),MovingMeshRows.size(),
MovingPayloadRows.size(),MovingTopologyRows.size(),
static_cast<unsigned long long>(HashTileRows(MovingDensityRows)),
static_cast<unsigned long long>(HashTileRows(MovingMeshRows)),
static_cast<unsigned long long>(HashTileRows(MovingPayloadRows)),
static_cast<unsigned long long>(HashTileRows(MovingTopologyRows)),
MovingDensityRows.size()==static_cast<std::size_t>(MovingFinished)
&&MovingMeshRows.size()==static_cast<std::size_t>(MovingFinished)
&&MovingPayloadRows.size()==static_cast<std::size_t>(MovingFinished)
&&MovingTopologyRows.size()==static_cast<std::size_t>(MovingFinished)
?"PASS":"FAIL");
for(std::size_t LOD=0;LOD<MovingTilesByLOD.size();++LOD)
if(MovingTilesByLOD[LOD]!=0)
{
std::printf("[MovingCameraStepLOD] lod=%zu tiles=%llu worker_sum_s=%.6f\n",
LOD,static_cast<unsigned long long>(MovingTilesByLOD[LOD]),
MovingWorkerSecondsByLOD[LOD]);
if(bReportLodWorkProfile)
std::printf("[MovingCameraStepLODProfile] lod=%zu density_samples=%llu samples_per_tile=%.1f native_float_calls=%llu native_lattice_calls=%llu native_surface_tiles=%llu native_only_tiles=%llu analytic_page_tiles=%llu base_route_tiles=%llu base_route_avg_ms=%.3f page_route_avg_ms=%.3f column_compute_ms=%.3f classification_ms=%.3f mc_exclusive_ms=%.3f mc_density_grid_ms=%.3f mc_cell_class_ms=%.3f mc_gradient_ms=%.3f mc_interpolation_ms=%.3f mc_dedup_ms=%.3f mc_other_ms=%.3f\n",
LOD,static_cast<unsigned long long>(MovingSamplesByLOD[LOD]),
static_cast<double>(MovingSamplesByLOD[LOD])/MovingTilesByLOD[LOD],
static_cast<unsigned long long>(MovingNativeFloatCallsByLOD[LOD]),
static_cast<unsigned long long>(MovingNativeLatticeCallsByLOD[LOD]),
static_cast<unsigned long long>(MovingNativeSurfaceTilesByLOD[LOD]),
static_cast<unsigned long long>(MovingNativeOnlyTilesByLOD[LOD]),
static_cast<unsigned long long>(MovingAnalyticPageTilesByLOD[LOD]),
static_cast<unsigned long long>(MovingBaseRouteTilesByLOD[LOD]),
MovingBaseRouteTilesByLOD[LOD]
?MovingBaseRouteWorkerSecondsByLOD[LOD]*1000.0
/MovingBaseRouteTilesByLOD[LOD]:0.0,
MovingAnalyticPageTilesByLOD[LOD]
?MovingPageRouteWorkerSecondsByLOD[LOD]*1000.0
/MovingAnalyticPageTilesByLOD[LOD]:0.0,
MovingColumnComputeMsByLOD[LOD],MovingClassificationMsByLOD[LOD],
MovingMcExclusiveMsByLOD[LOD],MovingMcDensityGridMsByLOD[LOD],
MovingMcCellClassMsByLOD[LOD],MovingMcGradientMsByLOD[LOD],
MovingMcInterpolationMsByLOD[LOD],MovingMcDedupMsByLOD[LOD],
MovingMcOtherMsByLOD[LOD]);
}
}
Streamer.Stop();
bool bScreenSpaceGatePassing=true;
if(bScreenSpaceGate)
{
if(Assembly)
bScreenSpaceGatePassing=StandaloneScreenSpaceGate::Run(GateSampleTiles,
Streamer,*Assembly,ClosestDisplayDistances,World.CoreVoxelSizeMicrons,
World.MaxClipLevel,PixelBudgetsSubvoxels,CameraYawDegrees,
CameraPitchDegrees);
else
{std::fprintf(stderr,"[ScreenSpaceGateResult] no-world-assembly status=REJECT\n");bScreenSpaceGatePassing=false;}
}
if(bExportRequested)
{
bSceneExportPassing=SceneExport.Close(static_cast<std::uint32_t>(Update.DesiredTiles));
std::error_code FileSizeError;
const std::uintmax_t ExportBytes=std::filesystem::file_size(MeshExportPath,FileSizeError);
std::printf("[MeshSceneExport] tiles=%u expected=%d bytes=%llu status=%s path=%s\n",
SceneExport.TileCount,Update.DesiredTiles,
static_cast<unsigned long long>(FileSizeError?0:ExportBytes),
bSceneExportPassing?"PASS":"FAIL",MeshExportPath.string().c_str());
bSceneExportPassing=bSceneExportPassing&&!FileSizeError;
}
if(bProfileColumnOverlap)
{
struct FColumnPriorUse
{
FVoxelTileKey Tile;
std::uint64_t WorkerHash=0;
};
for(std::size_t LOD=0;LOD<ColumnEventsByLOD.size();++LOD)
{
auto& Events=ColumnEventsByLOD[LOD];
std::sort(Events.begin(),Events.end(),[](const FColumnEvaluationEvent& A,
const FColumnEvaluationEvent& B){return A.Sequence<B.Sequence;});
std::unordered_map<FColumnXY,std::vector<FColumnPriorUse>,FColumnXYHash> UsesByXY;
UsesByXY.reserve(Events.size());
for(const FColumnEvaluationEvent& Event:Events)
{
++ColumnEvaluationEventsByLOD[LOD];
if(Event.bOutsideTileFootprint)++HaloNormalEvaluationsByLOD[LOD];
auto [Found,Inserted]=UsesByXY.try_emplace(Event.XY);
auto& PriorUses=Found->second;
if(Inserted)
{
++UniqueColumnCoordinatesByLOD[LOD];
PriorUses.push_back({Event.Tile,Event.WorkerHash});
continue;
}
++ColumnDuplicateEventsByLOD[LOD];
if(Event.bOutsideTileFootprint)
++HaloNormalRepeatsByLOD[LOD];
else
{
const bool bSameWorkerSeen=std::any_of(PriorUses.begin(),PriorUses.end(),
[&](const FColumnPriorUse& Prior)
{return Prior.WorkerHash==Event.WorkerHash;});
if(bSameWorkerSeen)++SameWorkerEvictedRepeatsByLOD[LOD];
else ++DifferentWorkerRepeatsByLOD[LOD];
}
bool bHasNeighbourDuplicate=false,bHasCrossWorkerNeighbourDuplicate=false;
for(const FColumnPriorUse& Prior:PriorUses)
{
if(!AreSameLODNeighbours(Prior.Tile,Event.Tile))continue;
bHasNeighbourDuplicate=true;
bHasCrossWorkerNeighbourDuplicate=bHasCrossWorkerNeighbourDuplicate
||Prior.WorkerHash!=Event.WorkerHash;
}
if(bHasNeighbourDuplicate)++NeighbourDuplicateEventsByLOD[LOD];
if(bHasCrossWorkerNeighbourDuplicate)
++CrossWorkerNeighbourDuplicateEventsByLOD[LOD];
PriorUses.push_back({Event.Tile,Event.WorkerHash});
}
}
}
bool bColumnOverlapCapturePassing=true;
if(bProfileColumnOverlap)
{
for(std::size_t LOD=0;LOD<ColumnCaptureTilesByLOD.size();++LOD)
{
const bool bLODComplete=ColumnCaptureCompleteByLOD[LOD]
&&ColumnCaptureTilesByLOD[LOD]==ExpectedTilesByLOD[LOD];
bColumnOverlapCapturePassing=bColumnOverlapCapturePassing&&bLODComplete;
std::printf("[WorldAssemblerLODColumnOverlap] lod=%zu tiles=%llu expected_tiles=%llu total_column_evaluations=%llu unique_xy_columns=%llu repeated_column_evaluations=%llu same_worker_evicted_repeats=%llu different_worker_repeats=%llu halo_normal_repeats=%llu halo_normal_evaluations=%llu neighbouring_duplicate_evaluations=%llu cross_worker_neighbouring_duplicates=%llu capture_complete=%d\n",
LOD,static_cast<unsigned long long>(ColumnCaptureTilesByLOD[LOD]),
static_cast<unsigned long long>(ExpectedTilesByLOD[LOD]),
static_cast<unsigned long long>(ColumnEvaluationEventsByLOD[LOD]),
static_cast<unsigned long long>(UniqueColumnCoordinatesByLOD[LOD]),
static_cast<unsigned long long>(ColumnDuplicateEventsByLOD[LOD]),
static_cast<unsigned long long>(SameWorkerEvictedRepeatsByLOD[LOD]),
static_cast<unsigned long long>(DifferentWorkerRepeatsByLOD[LOD]),
static_cast<unsigned long long>(HaloNormalRepeatsByLOD[LOD]),
static_cast<unsigned long long>(HaloNormalEvaluationsByLOD[LOD]),
static_cast<unsigned long long>(NeighbourDuplicateEventsByLOD[LOD]),
static_cast<unsigned long long>(CrossWorkerNeighbourDuplicateEventsByLOD[LOD]),
bLODComplete?1:0);
}
}
for(std::size_t LOD=0;LOD<TileCountByLOD.size();++LOD)
{
std::printf("[WorldAssemblerLODWorker] lod=%zu tiles=%llu worker_sum_s=%.6f column_eval_exclusive_ms=%.3f mc_exclusive_ms=%.3f ground_refine_exclusive_ms=%.3f cap_refine_exclusive_ms=%.3f skirt_ms=%.3f skirt_triangles=%llu mesh_assembly_ms=%.3f\n",
LOD,static_cast<unsigned long long>(TileCountByLOD[LOD]),WorkerSecondsByLOD[LOD],
ColumnEvalMsByLOD[LOD],MarchingExclusiveMsByLOD[LOD],
GroundRefineExclusiveMsByLOD[LOD],CapRefineExclusiveMsByLOD[LOD],
SkirtMsByLOD[LOD],static_cast<unsigned long long>(SkirtTrianglesByLOD[LOD]),
MeshAssemblyMsByLOD[LOD]);
if(bReportLodWorkProfile)
{
const auto& Detail=*FarLODProfile;
const double SamplesPerTile=TileCountByLOD[LOD]
?static_cast<double>(DensitySamplesByLOD[LOD])/TileCountByLOD[LOD]:0.0;
std::printf("[WorldAssemblerLODSamples] lod=%zu samples=%llu samples_per_tile=%.1f\n",
LOD,static_cast<unsigned long long>(DensitySamplesByLOD[LOD]),SamplesPerTile);
std::printf("[WorldAssemblerLODRouteProfile] lod=%zu base_shape_tiles=%llu base_shape_avg_ms=%.3f analytic_page_tiles=%llu analytic_page_avg_ms=%.3f\n",
LOD,static_cast<unsigned long long>(BaseRouteTilesByLOD[LOD]),
BaseRouteTilesByLOD[LOD]
?BaseRouteWorkerSecondsByLOD[LOD]*1000.0/BaseRouteTilesByLOD[LOD]:0.0,
static_cast<unsigned long long>(PageRouteTilesByLOD[LOD]),
PageRouteTilesByLOD[LOD]
?PageRouteWorkerSecondsByLOD[LOD]*1000.0/PageRouteTilesByLOD[LOD]:0.0);
const double TileDivisor=TileCountByLOD[LOD]
?static_cast<double>(TileCountByLOD[LOD]):1.0;
std::printf("[WorldAssemblerLODCostDetail] lod=%zu tiles=%llu density_samples=%llu column_point_calls=%llu column_local_hits=%llu column_local_misses=%llu column_conflict_misses=%llu column_shared_hits=%llu column_formula_evaluations=%llu column_compute_ms=%.3f mc_column_ms=%.3f mc_exclusive_ms=%.3f mc_grid_ms=%.3f mc_cell_class_ms=%.3f mc_gradient_ms=%.3f mc_interpolation_ms=%.3f mc_dedup_stream_ms=%.3f mc_other_ms=%.3f ground_column_ms=%.3f ground_exclusive_ms=%.3f cap_column_ms=%.3f cap_exclusive_ms=%.3f stratum_shell_ms=%.3f stratum_field_calls=%llu stratum_column_calls=%llu stratum_column_hits=%llu stratum_column_misses=%llu stratum_shared_hits=%llu stratum_column_evaluations=%llu stratum_column_compute_ms=%.3f connector_shell_ms=%.3f connector_field_calls=%llu connector_column_calls=%llu connector_column_hits=%llu connector_column_misses=%llu connector_shared_hits=%llu connector_column_evaluations=%llu connector_column_compute_ms=%.3f far_shell_triangles=%llu skirt_ms=%.3f mesh_assembly_ms=%.3f worker_ms_per_tile=%.3f column_formula_evals_per_tile=%.1f connector_calls_per_tile=%.1f\n",
LOD,static_cast<unsigned long long>(TileCountByLOD[LOD]),
static_cast<unsigned long long>(DensitySamplesByLOD[LOD]),
static_cast<unsigned long long>(Detail.ColumnCalls[LOD]),
static_cast<unsigned long long>(Detail.ColumnHits[LOD]),
static_cast<unsigned long long>(Detail.ColumnMisses[LOD]),
static_cast<unsigned long long>(Detail.ColumnConflictMisses[LOD]),
static_cast<unsigned long long>(Detail.SharedColumnHits[LOD]),
static_cast<unsigned long long>(Detail.ColumnEvaluations[LOD]),
ColumnEvalMsByLOD[LOD],Detail.McColumnMs[LOD],MarchingExclusiveMsByLOD[LOD],
Detail.McGridMs[LOD],Detail.McCellClassMs[LOD],Detail.McGradientMs[LOD],
Detail.McInterpolationMs[LOD],Detail.McDedupMs[LOD],Detail.McOtherMs[LOD],
Detail.GroundColumnMs[LOD],GroundRefineExclusiveMsByLOD[LOD],
Detail.CapColumnMs[LOD],CapRefineExclusiveMsByLOD[LOD],
Detail.StratumShellMs[LOD],
static_cast<unsigned long long>(Detail.StratumFieldCalls[LOD]),
static_cast<unsigned long long>(Detail.StratumColumnPointCalls[LOD]),
static_cast<unsigned long long>(Detail.StratumColumnHits[LOD]),
static_cast<unsigned long long>(Detail.StratumColumnMisses[LOD]),
static_cast<unsigned long long>(Detail.StratumSharedColumnHits[LOD]),
static_cast<unsigned long long>(Detail.StratumColumnEvaluations[LOD]),
Detail.StratumColumnComputeMs[LOD],
Detail.ConnectorShellMs[LOD],
static_cast<unsigned long long>(Detail.ConnectorFieldCalls[LOD]),
static_cast<unsigned long long>(Detail.ConnectorColumnPointCalls[LOD]),
static_cast<unsigned long long>(Detail.ConnectorColumnHits[LOD]),
static_cast<unsigned long long>(Detail.ConnectorColumnMisses[LOD]),
static_cast<unsigned long long>(Detail.ConnectorSharedColumnHits[LOD]),
static_cast<unsigned long long>(Detail.ConnectorColumnEvaluations[LOD]),
Detail.ConnectorColumnComputeMs[LOD],
static_cast<unsigned long long>(Detail.FarShellTriangles[LOD]),
SkirtMsByLOD[LOD],MeshAssemblyMsByLOD[LOD],
WorkerSecondsByLOD[LOD]*1000.0/TileDivisor,
static_cast<double>(Detail.ColumnEvaluations[LOD])/TileDivisor,
static_cast<double>(Detail.ConnectorFieldCalls[LOD])/TileDivisor);
}
}
const double NeighborhoodSeconds=std::chrono::duration<double>(NeighborhoodReady-ColdStart).count();
const double NeighborhoodMeshSeconds=std::max(0.0,
std::chrono::duration<double>(NeighborhoodReady-ShapeReady).count());
const double FullDetailSeconds=std::chrono::duration<double>(FullDetailReady-ColdStart).count();
const double WholeViewSeconds=std::chrono::duration<double>(WholeViewReady-ColdStart).count();
const double StreamSeconds=std::chrono::duration<double>(WholeViewReady-StreamStart).count();
const double FirstTileSeconds=std::chrono::duration<double>(FirstTileReady-ColdStart).count();
std::printf("[StreamPipeline] workers=%d shape=%.3fs first_tile_ready=%.3fs neighborhood_mesh=%.3fs neighborhood_ready=%.3fs full_detail_ready=%.3fs whole_view_ready=%.3fs neighborhood_tiles=%d/27 full_detail_tiles=%d/%d whole_tiles=%d/%zu stream_wall=%.3fs cache_hits=0 full_payload=1\n",
WorkerCount,ShapeSeconds,FirstTileSeconds,NeighborhoodMeshSeconds,NeighborhoodSeconds,
FullDetailSeconds,WholeViewSeconds,NeighborhoodFinished,
FullDetailFinished,FullDetailExpected,Finished,Desired.Tiles.size(),StreamSeconds);
if(bReportMeshCoverage)
std::printf("[PipelineMeshCoverage] tiles=%d nonempty_mesh_tiles=%llu indexed_triangles=%llu\n",
Finished,static_cast<unsigned long long>(WholeNonEmptyMeshTiles),
static_cast<unsigned long long>(WholeTriangleCount));
std::printf("[WorldAssemblerTilePipeline] full_detail_tiles=%d solid_boxes=%llu air_boxes=%llu mixed_boxes=%llu unknown_boxes=%llu whole_tile_skips=%llu field_calls=%llu column_cache_hits=%llu column_cache_misses=%llu column_compute_worker_ms=%.3f classification_worker_ms=%.3f meshing_worker_ms=%.3f\n",
FullDetailExpected,static_cast<unsigned long long>(NativeSolidBoxes),
static_cast<unsigned long long>(NativeAirBoxes),
static_cast<unsigned long long>(NativeMixedBoxes),
static_cast<unsigned long long>(NativeUnknownBoxes),
static_cast<unsigned long long>(NativeMeshingSkips),
static_cast<unsigned long long>(NativeFieldCalls),
static_cast<unsigned long long>(NativeColumnHits),
static_cast<unsigned long long>(NativeColumnMisses),
NativeColumnComputeMilliseconds,NativeClassificationMilliseconds,
NativeMeshingMilliseconds);
std::printf("[MaterialQueryCost] queries=%llu candidate_checks=%llu outside_vein_tiles=%llu tiles=%d elapsed_ms=%.3f outside_query_ms=0 status=%s\n",
static_cast<unsigned long long>(MaterialQueries),
static_cast<unsigned long long>(MaterialCandidateChecks),
static_cast<unsigned long long>(MaterialOutsideTiles),Finished,
MaterialQueryMilliseconds,MaterialQueries==0?"zero":"measured");
if(bAuditUniformBlockProofs)
std::printf("[UniformBlockProofAudit] checked_blocks=%llu checked_samples=%llu fallback_blocks=%llu unknown_blocks=%llu violations=%llu\n",
static_cast<unsigned long long>(BlockProofBlocksChecked),
static_cast<unsigned long long>(BlockProofSamplesChecked),
static_cast<unsigned long long>(BlockProofFallbackBlocks),
static_cast<unsigned long long>(BlockProofUnknownBlocks),
static_cast<unsigned long long>(BlockProofViolations));
bool bHashesPassing=true;
if(bHashDensity)
{
bHashesPassing=DensityRows.size()==Desired.Tiles.size()
&&MeshRows.size()==Desired.Tiles.size()
&&PayloadRows.size()==Desired.Tiles.size()
&&TopologyRows.size()==Desired.Tiles.size()
&&MaterialRows.size()==Desired.Tiles.size();
if(bPrintTileHashes)
{
const auto makeHashIndex=[](const std::vector<FHashedTile>& rows)
{
std::unordered_map<FVoxelTileKey,uint64,FStandaloneTileKeyHash> index;
index.reserve(rows.size());
for(const FHashedTile& row:rows)index.emplace(row.Key,row.Hash);
return index;
};
const auto MeshIndex=makeHashIndex(MeshRows);
const auto PayloadIndex=makeHashIndex(PayloadRows);
const auto TopologyIndex=makeHashIndex(TopologyRows);
const auto MaterialIndex=makeHashIndex(MaterialRows);
const auto findHash=[](const auto& index,const FVoxelTileKey& key)
{
const auto found=index.find(key);
return found==index.end()?uint64{0}:found->second;
};
for(const FHashedTile& row:DensityRows)
std::printf("[PipelineTileHash] lod=%d x=%d y=%d z=%d density=0x%016llx mesh=0x%016llx payload=0x%016llx topology=0x%016llx\n",
row.Key.Level,row.Key.Coord.X,row.Key.Coord.Y,row.Key.Coord.Z,
static_cast<unsigned long long>(row.Hash),
static_cast<unsigned long long>(findHash(MeshIndex,row.Key)),
static_cast<unsigned long long>(findHash(PayloadIndex,row.Key)),
static_cast<unsigned long long>(findHash(TopologyIndex,row.Key)));
for(const FHashedTile& row:MaterialRows)
std::printf("[PipelineTileMaterialHash] lod=%d x=%d y=%d z=%d material=0x%016llx\n",
row.Key.Level,row.Key.Coord.X,row.Key.Coord.Y,row.Key.Coord.Z,
static_cast<unsigned long long>(row.Hash));
}
std::vector<FHashedTile> FullDensity,FullMesh,FullPayload,FullTopology;
for(const FHashedTile& Row:DensityRows)if(Row.Key.Level<World.FullResClipLevels)FullDensity.push_back(Row);
for(const FHashedTile& Row:MeshRows)if(Row.Key.Level<World.FullResClipLevels)FullMesh.push_back(Row);
for(const FHashedTile& Row:PayloadRows)if(Row.Key.Level<World.FullResClipLevels)FullPayload.push_back(Row);
for(const FHashedTile& Row:TopologyRows)if(Row.Key.Level<World.FullResClipLevels)FullTopology.push_back(Row);
std::printf("[PipelineFullDetailHash] tiles=%d density=0x%016llx mesh=0x%016llx payload=0x%016llx topology=0x%016llx\n",
FullDetailExpected,static_cast<unsigned long long>(HashTileRows(FullDensity)),
static_cast<unsigned long long>(HashTileRows(FullMesh)),
static_cast<unsigned long long>(HashTileRows(FullPayload)),
static_cast<unsigned long long>(HashTileRows(FullTopology)));
std::printf("[PipelineWholeViewHash] tiles=%zu density=0x%016llx mesh=0x%016llx payload=0x%016llx topology=0x%016llx\n",
Desired.Tiles.size(),static_cast<unsigned long long>(HashTileRows(DensityRows)),
static_cast<unsigned long long>(HashTileRows(MeshRows)),
static_cast<unsigned long long>(HashTileRows(PayloadRows)),
static_cast<unsigned long long>(HashTileRows(TopologyRows)));
std::printf("[PipelineMaterialHash] tiles=%zu material=0x%016llx\n",
MaterialRows.size(),static_cast<unsigned long long>(HashTileRows(MaterialRows)));
for(std::size_t LOD=0;LOD<TileCountByLOD.size();++LOD)
{
const auto FilterLOD=[LOD](const std::vector<FHashedTile>& Rows)
{
std::vector<FHashedTile> Selected;
for(const FHashedTile& Row:Rows)
if(Row.Key.Level==static_cast<int32>(LOD))Selected.push_back(Row);
return Selected;
};
auto LodDensity=FilterLOD(DensityRows),LodMesh=FilterLOD(MeshRows);
auto LodPayload=FilterLOD(PayloadRows),LodTopology=FilterLOD(TopologyRows);
std::printf("[PipelineLODHash] lod=%zu tiles=%llu density=0x%016llx mesh=0x%016llx payload=0x%016llx topology=0x%016llx\n",
LOD,static_cast<unsigned long long>(TileCountByLOD[LOD]),
static_cast<unsigned long long>(HashTileRows(LodDensity)),
static_cast<unsigned long long>(HashTileRows(LodMesh)),
static_cast<unsigned long long>(HashTileRows(LodPayload)),
static_cast<unsigned long long>(HashTileRows(LodTopology)));
}
const std::array<VoxelForgeCore::Vec3d,9> QueryPoints={{
{CameraPositionVoxels.X,CameraPositionVoxels.Y,CameraPositionVoxels.Z},
{CameraPositionVoxels.X+8.0,CameraPositionVoxels.Y,CameraPositionVoxels.Z},
{CameraPositionVoxels.X-8.0,CameraPositionVoxels.Y,CameraPositionVoxels.Z},
{CameraPositionVoxels.X,CameraPositionVoxels.Y+8.0,CameraPositionVoxels.Z},
{CameraPositionVoxels.X,CameraPositionVoxels.Y-8.0,CameraPositionVoxels.Z},
{CameraPositionVoxels.X,CameraPositionVoxels.Y,CameraPositionVoxels.Z+8.0},
{CameraPositionVoxels.X,CameraPositionVoxels.Y,CameraPositionVoxels.Z-8.0},
{CameraPositionVoxels.X+64.0,CameraPositionVoxels.Y-32.0,CameraPositionVoxels.Z+16.0},
{CameraPositionVoxels.X-128.0,CameraPositionVoxels.Y+96.0,CameraPositionVoxels.Z-64.0}}};
uint64 ExactDensityHash=14695981039346656037ull;
uint64 ExactUnclampedHash=14695981039346656037ull;
uint64 ExactDetailHash=14695981039346656037ull;
uint64 ExactCollisionHash=14695981039346656037ull;
for(const auto& Point:QueryPoints)
{
const float Density=Shape.densityAt(Point);
const float Unclamped=Shape.unclampedDensityAt(Point);
const auto Detail=Shape.detailSampleAt(Point);
HashWord(ExactDensityHash,std::bit_cast<uint32>(Density),4);
HashWord(ExactUnclampedHash,std::bit_cast<uint32>(Unclamped),4);
HashWord(ExactDetailHash,std::bit_cast<uint32>(Detail.displacement),4);
HashWord(ExactDetailHash,std::bit_cast<uint32>(Detail.caveInfluence),4);
HashWord(ExactDetailHash,std::bit_cast<uint32>(Detail.floorInfluence),4);
HashWord(ExactCollisionHash,Shape.isSolidAt(Point)?1u:0u,1);
}
std::printf("[PipelineExactQueryHash] probes=%zu density=0x%016llx unclamped=0x%016llx detail=0x%016llx collision=0x%016llx path=direct-Core-queries\n",
QueryPoints.size(),static_cast<unsigned long long>(ExactDensityHash),
static_cast<unsigned long long>(ExactUnclampedHash),
static_cast<unsigned long long>(ExactDetailHash),
static_cast<unsigned long long>(ExactCollisionHash));
}
return NeighborhoodFinished==static_cast<int32>(Neighborhood.size())
&&FullDetailFinished==FullDetailExpected&&Finished==Update.DesiredTiles&&bHashesPassing
&&(!bProfileColumnOverlap||bColumnOverlapCapturePassing)
&&(!bExportRequested||bSceneExportPassing)&&bScreenSpaceGatePassing
&&(!bAuditUniformBlockProofs||BlockProofViolations==0)?0:6;
}
} // namespace StandaloneStreamBenchmark