Files
VoxelForge/Standalone/Research/WorldAssemblerM3/Linux156/l156-headroom-landing.patch
T
Fr0zkaandClaude Opus 5.5 a751a01b11 research: headroom-only landings, band fit, bore exemption (L156; last landing round, kept as patch)
Band fit works (all chambers inside host bands, 16/16 seeds both sweeps); chamber support exemption + open-floor
control work; found a metres/subvoxel mix in the shell-opening predicate. Still fails: upper landing evaluated grade
22.85 deg over native ground; TN and VS sweeps 0/16; UE 30 m/s near coverage 39.0% vs 45.5%. Owner: stop forcing
landings after this round.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016dhxM43dnWvUu2B5Ph1iG1
2026-11-02 02:31:04 +01:00

842 lines
52 KiB
Diff

diff --git a/Standalone/Core/include/VoxelForgeCore/VoxelForgeCore.h b/Standalone/Core/include/VoxelForgeCore/VoxelForgeCore.h
index 4799b9e..82bc9e1 100644
--- a/Standalone/Core/include/VoxelForgeCore/VoxelForgeCore.h
+++ b/Standalone/Core/include/VoxelForgeCore/VoxelForgeCore.h
@@ -512,7 +512,8 @@ namespace VoxelForgeCore
// boundary-blended host rock from widening the authored passage wall.
// v238 plans one resolved passage spline with explicit landing chambers.
// v239 plans their floor planes as the passage's continuous floor profile.
- inline constexpr std::uint32_t WorldAssemblyEvaluatorVersion = 239;
+ // v240 treats SurfaceWorld landings as headroom above max(planned floor,native ground).
+ inline constexpr std::uint32_t WorldAssemblyEvaluatorVersion = 240;
enum class FieldChannel : std::uint32_t
{
@@ -1212,8 +1213,9 @@ namespace VoxelForgeCore
struct ResolvedLayoutPassageLandingChamberV1
{
- // The chamber floor plane passes through this point. Gradient is dz/dx,
- // dz/dy in Q16 so the chamber continues the passage's authored h(s) grade.
+ // The planned chamber floor passes through this point. SurfaceWorld adds
+ // native ground where it lies within the clear-height envelope. Gradient is
+ // dz/dx,dy in Q16 and continues the passage's authored h(s) grade.
std::array<std::int64_t, 3> floorCenterSubvoxels{};
std::array<std::int64_t, 2> floorGradientQ16{};
std::int64_t radiusSubvoxels = 0;
@@ -2009,6 +2011,9 @@ namespace VoxelForgeCore
ShapeBuildStats buildStats() const;
float densityAt(Vec3d voxelPosition) const;
+ // Deterministic native SurfaceWorld or receiving-route ground in Core voxels.
+ bool nativeSurfaceGroundHeightAt(Vec3d voxelPosition,
+ double& groundHeightVoxels) const;
// Companion material query for the bound strate evaluator; coordinates use Core voxels.
MaterialSampleV1 materialAt(Vec3d voxelPosition) const;
// Measure-only carve estimate. This does not apply an edit or grant inventory.
diff --git a/Standalone/Core/src/ResolvedLayoutInternal.h b/Standalone/Core/src/ResolvedLayoutInternal.h
index 7ea6c8c..c80b95d 100644
--- a/Standalone/Core/src/ResolvedLayoutInternal.h
+++ b/Standalone/Core/src/ResolvedLayoutInternal.h
@@ -3993,6 +3993,72 @@ bool PlanResolvedLayoutPassagesV1(ResolvedLayoutSnapshotV3& layout,std::int32_t
reach/static_cast<double>(qPerMetre));
}
}
+ // Reserve each landing envelope inside its host band before building h(s).
+ // SurfaceWorld can raise its floor by at most the 4.5 m headroom allowance,
+ // so include that bounded rise as well as the grade reach and floor shell.
+ constexpr std::int64_t MaximumLandingGradeQ16=17560;
+ const std::int64_t landingRadius=mouthRadius+3*qPerMetre;
+ const std::int64_t landingClearHeight=static_cast<std::int64_t>(
+ std::llround(4.5*qPerMetre));
+ const std::int64_t landingShell=static_cast<std::int64_t>(
+ std::llround(0.75*qPerMetre));
+ const std::int64_t landingPlaneReach=(landingRadius
+ *MaximumLandingGradeQ16+65535)/65536;
+ const std::array<std::int64_t,3> upperMouthBeforeBandFit=upperMouth;
+ const std::array<std::int64_t,3> lowerMouthBeforeBandFit=lowerMouth;
+ const auto fitMouth=[&](std::array<std::int64_t,3>& mouth,
+ const ResolvedLayoutStratumV2& host,std::int64_t playerHeightQ,
+ const char* side)
+ {
+ if(!host.content.presentInCurrentField)return true;
+ const std::int64_t minimumFloor=contentZQ(host.content.bottomMicrometres)
+ +landingPlaneReach+landingShell;
+ const std::int64_t nativeFloorRise=host.generatorKind=="SurfaceWorld"
+ ?landingClearHeight:0;
+ const std::int64_t maximumFloor=contentZQ(host.content.topMicrometres)
+ -landingPlaneReach-landingShell-landingClearHeight-nativeFloorRise;
+ if(maximumFloor<minimumFloor)
+ {error=passage.stableId+" "+side
+ +" landing chamber envelope is taller than its host content band";return false;}
+ const std::int64_t requestedFloor=mouth[2]-playerHeightQ;
+ const std::int64_t fittedFloor=std::clamp(requestedFloor,
+ minimumFloor,maximumFloor);
+ if(fittedFloor!=requestedFloor)
+ {
+ mouth[2]=fittedFloor+playerHeightQ;
+ std::printf("[PassageLandingChamberPlacement] id=%s side=%s floor_shift_m=%.3f grade_bound_deg=15.000 clear_height_m=4.500 shell_m=0.750 status=PASS\n",
+ passage.stableId.c_str(),side,
+ (fittedFloor-requestedFloor)/static_cast<double>(qPerMetre));
+ }
+ return true;
+ };
+ if(!fitMouth(upperMouth,upper,upperPlayerCenterAboveFloorQ,"upper")
+ ||!fitMouth(lowerMouth,lower,playerCenterAboveFloorQ,"lower"))return false;
+ const auto bindFittedMouthAnchor=[&](
+ const ResolvedLayoutStratumV2& host,
+ const std::array<std::int64_t,3>& before,
+ const std::array<std::int64_t,3>& after,const char* side)
+ {
+ if(before==after)return;
+ auto mutableHost=std::find_if(layout.strates.begin(),layout.strates.end(),
+ [&](const auto& stratum)
+ {return stratum.strateIndex==host.strateIndex;});
+ if(mutableHost!=layout.strates.end())
+ for(auto& anchor:mutableHost->anchors)
+ if((anchor.kind=="passage_arrival"
+ ||anchor.kind=="passage_departure")
+ &&anchor.values.size()>=3
+ &&anchor.values[0]==after[0]
+ &&anchor.values[1]==after[1])
+ {
+ anchor.values[2]=after[2];
+ std::printf("[PassageLandingChamberArrivalBinding] id=%s side=%s anchor=%s status=PASS\n",
+ passage.stableId.c_str(),side,anchor.stableId.c_str());
+ break;
+ }
+ };
+ bindFittedMouthAnchor(upper,upperMouthBeforeBandFit,upperMouth,"upper");
+ bindFittedMouthAnchor(lower,lowerMouthBeforeBandFit,lowerMouth,"lower");
if(!radialWithin(upperMouth,placementRadius)||!radialWithin(lowerMouth,placementRadius))
{error=passage.stableId+" route mouth is outside the resolved PassageConfig.DistanceMax radius";return false;}
passage.upperMouthSubvoxels=upperMouth;passage.lowerMouthSubvoxels=lowerMouth;
@@ -5048,6 +5114,91 @@ bool PlanResolvedLayoutPassagesV1(ResolvedLayoutSnapshotV3& layout,std::int32_t
surfaceHorizontalSquared)};
}
}
+ if(host.generatorKind=="FloatingIslands"&&side[0]=='u')
+ {
+ // The island route is authored as player-center heights. Keep
+ // the chamber center bound to passage h(s), while selecting the
+ // closest grade plane that leaves the audited lower capsule arc
+ // above every receiving route point under the chamber footprint.
+ const auto route=routePoints(host);
+ const std::int64_t routeRadius=chamber.radiusSubvoxels
+ +static_cast<std::int64_t>(std::llround(0.34*qPerMetre));
+ const std::int64_t routeRadiusSquared=routeRadius*routeRadius;
+ const std::int64_t footClearanceQ=static_cast<std::int64_t>(
+ std::llround((0.84+0.025)*qPerMetre));
+ struct FRouteFloorConstraint
+ {
+ std::int64_t dx=0,dy=0,maximumRiseQ16=0;
+ };
+ std::vector<FRouteFloorConstraint> constraints;
+ constraints.reserve(route.size());
+ for(const auto& point:route)
+ {
+ const auto dx=static_cast<std::int64_t>(std::llround(
+ point[0]-chamber.floorCenterSubvoxels[0]));
+ const auto dy=static_cast<std::int64_t>(std::llround(
+ point[1]-chamber.floorCenterSubvoxels[1]));
+ if(dx*dx+dy*dy>routeRadiusSquared)continue;
+ const auto routeFloorMaximum=static_cast<std::int64_t>(
+ std::llround(point[2]))-footClearanceQ;
+ constraints.push_back({dx,dy,
+ (routeFloorMaximum-chamber.floorCenterSubvoxels[2])*65536});
+ }
+ const auto originalGradient=chamber.floorGradientQ16;
+ for(std::size_t pass=0;pass<256&&!constraints.empty();++pass)
+ {
+ bool adjusted=false;
+ for(const auto& constraint:constraints)
+ {
+ const std::int64_t distanceSquared=constraint.dx*constraint.dx
+ +constraint.dy*constraint.dy;
+ if(distanceSquared<=0)continue;
+ const std::int64_t rise=
+ static_cast<std::int64_t>(chamber.floorGradientQ16[0])
+ *constraint.dx
+ +static_cast<std::int64_t>(chamber.floorGradientQ16[1])
+ *constraint.dy;
+ const std::int64_t excess=rise-constraint.maximumRiseQ16;
+ if(excess<=0)continue;
+ const auto correction=[&](std::int64_t delta)
+ {
+ if(delta==0)return std::int64_t{0};
+ const std::uint64_t product=static_cast<std::uint64_t>(excess)
+ *static_cast<std::uint64_t>(std::abs(delta));
+ return static_cast<std::int64_t>((product
+ +static_cast<std::uint64_t>(distanceSquared)-1)
+ /static_cast<std::uint64_t>(distanceSquared));
+ };
+ const auto correctionX=correction(constraint.dx);
+ const auto correctionY=correction(constraint.dy);
+ chamber.floorGradientQ16[0]-=static_cast<std::int32_t>(
+ constraint.dx<0?-correctionX:correctionX);
+ chamber.floorGradientQ16[1]-=static_cast<std::int32_t>(
+ constraint.dy<0?-correctionY:correctionY);
+ adjusted|=correctionX!=0||correctionY!=0;
+ }
+ if(!adjusted)break;
+ }
+ for(const auto& constraint:constraints)
+ {
+ const std::int64_t rise=
+ static_cast<std::int64_t>(chamber.floorGradientQ16[0])
+ *constraint.dx
+ +static_cast<std::int64_t>(chamber.floorGradientQ16[1])
+ *constraint.dy;
+ if(rise>constraint.maximumRiseQ16)
+ {error=passage.stableId
+ +" upper landing floor cannot clear its receiving FloatingIslands route";
+ return false;}
+ }
+ if(chamber.floorGradientQ16!=originalGradient)
+ std::printf("[PassageLandingChamberRouteFit] id=%s side=upper host=FloatingIslands route_points=%zu fitted_constraints=%zu source_gradient_q16=(%lld,%lld) fitted_gradient_q16=(%lld,%lld) foot_clearance_m=0.865 max_grade_deg=15.000 status=PASS\n",
+ passage.stableId.c_str(),route.size(),constraints.size(),
+ static_cast<long long>(originalGradient[0]),
+ static_cast<long long>(originalGradient[1]),
+ static_cast<long long>(chamber.floorGradientQ16[0]),
+ static_cast<long long>(chamber.floorGradientQ16[1]));
+ }
const std::uint64_t gradientSquared=static_cast<std::uint64_t>(
chamber.floorGradientQ16[0]*chamber.floorGradientQ16[0]
+chamber.floorGradientQ16[1]*chamber.floorGradientQ16[1]);
diff --git a/Standalone/Core/src/ShapeWorldInternal.h b/Standalone/Core/src/ShapeWorldInternal.h
index 6b1a6af..c20b0ce 100644
--- a/Standalone/Core/src/ShapeWorldInternal.h
+++ b/Standalone/Core/src/ShapeWorldInternal.h
@@ -1280,11 +1280,32 @@ public:
double unionDistance=std::numeric_limits<double>::infinity();
double unionShellDistance=std::numeric_limits<double>::infinity();
double unionFloorShellDistance=std::numeric_limits<double>::infinity();
+ double unionLandingChamberDistance=std::numeric_limits<double>::infinity();
double unionLandingChamberFloorShellDistance=
std::numeric_limits<double>::infinity();
double plannedTunnelPassageShellDistance=std::numeric_limits<double>::infinity();
const std::uint32_t reliefSeed=static_cast<std::uint32_t>(Owner?Owner->Seed:0);
const auto* queryStratum=FindBoundStratumForManagerZ(Z);
+ const auto effectiveLandingFloor=[&](
+ const VoxelForgeCore::ResolvedLayoutPassageLandingChamberV1& chamber,
+ double plannedFloorZ,double sampleXSubvoxels,double sampleYSubvoxels)
+ {
+ if(!std::isfinite(sampleXSubvoxels)||!std::isfinite(sampleYSubvoxels))
+ return plannedFloorZ;
+ double nativeGroundCoreVoxels=0.0;
+ if(!GetNativeSurfaceGroundHeightAt(
+ static_cast<float>(sampleXSubvoxels/Q),
+ static_cast<float>(sampleYSubvoxels/Q),
+ static_cast<float>(plannedFloorZ/Q),nativeGroundCoreVoxels))
+ return plannedFloorZ;
+ const double clearHeight=static_cast<double>(
+ chamber.clearHeightSubvoxels);
+ const double nativeFloor=nativeGroundCoreVoxels*Q;
+ // A native surface above the chamber's clear-height budget denotes a
+ // different layer surface, not a landing floor to clear from this room.
+ return nativeFloor>plannedFloorZ&&nativeFloor<=plannedFloorZ+clearHeight
+ ?nativeFloor:plannedFloorZ;
+ };
const bool plannedTunnelStratum=queryStratum&&queryStratum->Resolved
&&(queryStratum->Resolved->generatorKind=="TunnelNetwork"
||queryStratum->Resolved->generatorKind=="VerticalShafts")
@@ -1339,10 +1360,12 @@ public:
landingChamber->floorCenterSubvoxels[0]);
const double centerY=static_cast<double>(
landingChamber->floorCenterSubvoxels[1]);
- const double floorCenterZ=static_cast<double>(
+ const double plannedFloorCenterZ=static_cast<double>(
landingChamber->floorCenterSubvoxels[2])
+(landingChamber->floorGradientQ16[0]*(qx-centerX)
+landingChamber->floorGradientQ16[1]*(qy-centerY))/65536.0;
+ const double floorCenterZ=effectiveLandingFloor(*landingChamber,
+ plannedFloorCenterZ,qx,qy);
const double radialDistance=DeterministicSqrt(
(qx-centerX)*(qx-centerX)+(qy-centerY)*(qy-centerY))
-landingChamber->radiusSubvoxels;
@@ -1357,6 +1380,8 @@ public:
std::max(-floorDistance,floorDistance-shellThickness),
radialDistance);
unionDistance=std::min(unionDistance,chamberDistance);
+ unionLandingChamberDistance=std::min(unionLandingChamberDistance,
+ chamberDistance);
unionShellDistance=std::min(unionShellDistance,chamberShellDistance);
unionFloorShellDistance=std::min(unionFloorShellDistance,
chamberFloorShellDistance);
@@ -1746,15 +1771,18 @@ public:
departureTailDistance)
||nearRouteSegment(*lastTwo,*last,PortalWalkLeadMetres,true,0.0);
};
- const auto connectedSurfaceLandingShellContains=[&]()
+ const auto connectedNativeLandingShellContains=[&]()
{
if(!queryStratum||!queryStratum->Resolved
- ||queryStratum->Resolved->generatorKind!="SurfaceWorld")return false;
+ ||(queryStratum->Resolved->generatorKind!="SurfaceWorld"
+ &&queryStratum->Resolved->generatorKind!="FloatingIslands"))
+ return false;
const double queryX=qx/qPerMetre,queryY=qy/qPerMetre,queryZ=qz/qPerMetre;
constexpr double ChamberShellThicknessMetres=0.75;
constexpr double RouteClearanceMetres=1.25;
constexpr double RouteHeightClearanceMetres=1.5;
- constexpr double PortalWalkLeadMetres=9.0;
+ const double portalWalkLeadMetres=
+ queryStratum->Resolved->generatorKind=="FloatingIslands"?12.0:9.0;
for(const auto& passage:ResolvedLayout->passages)
{
if(passage.upperStrateIndex!=queryStratum->StrateIndex)continue;
@@ -1762,9 +1790,13 @@ public:
if(chamber.radiusSubvoxels<=0||chamber.clearHeightSubvoxels<=0)continue;
const double cx=static_cast<double>(chamber.floorCenterSubvoxels[0])/qPerMetre;
const double cy=static_cast<double>(chamber.floorCenterSubvoxels[1])/qPerMetre;
- const double floorZ=static_cast<double>(chamber.floorCenterSubvoxels[2])/qPerMetre
+ const double plannedFloorZ=static_cast<double>(
+ chamber.floorCenterSubvoxels[2])/qPerMetre
+chamber.floorGradientQ16[0]/65536.0*(queryX-cx)
+chamber.floorGradientQ16[1]/65536.0*(queryY-cy);
+ const double floorZ=effectiveLandingFloor(chamber,
+ plannedFloorZ*qPerMetre,queryX*qPerMetre,
+ queryY*qPerMetre)/qPerMetre;
const double radialDistance=std::hypot(queryX-cx,queryY-cy)
-static_cast<double>(chamber.radiusSubvoxels)/qPerMetre;
const double floorDistance=floorZ-queryZ;
@@ -1784,7 +1816,11 @@ public:
const double mouthZ=static_cast<double>(passage.upperMouthSubvoxels[2])
/qPerMetre;
std::size_t endpoint=route.size();
- double endpointDistanceSquared=1.0;
+ const double endpointRadius=
+ queryStratum->Resolved->generatorKind=="FloatingIslands"?3.0:1.0;
+ const double endpointHeight=
+ queryStratum->Resolved->generatorKind=="FloatingIslands"?2.0:1.5;
+ double endpointDistanceSquared=endpointRadius*endpointRadius;
for(std::size_t index=0;index<route.size();++index)
{
const double x=route[index]->values[0]/qPerMetre;
@@ -1793,7 +1829,7 @@ public:
const double dx=x-cx,dy=y-cy;
const double distanceSquared=dx*dx+dy*dy;
if(distanceSquared<endpointDistanceSquared
- &&std::abs(z-mouthZ)<=1.5)
+ &&std::abs(z-mouthZ)<=endpointHeight)
{endpoint=index;endpointDistanceSquared=distanceSquared;}
}
if(endpoint==route.size())continue;
@@ -1821,11 +1857,13 @@ public:
const double alongFromEndpoint=std::abs(
std::lerp(routeDistance[index-1],routeDistance[index],t)
-routeDistance[endpoint]);
- if(alongFromEndpoint>PortalWalkLeadMetres)continue;
+ if(alongFromEndpoint>portalWalkLeadMetres)continue;
const double routeX=ax+t*dx,routeY=ay+t*dy;
const double routeZ=az+t*(b.values[2]-a.values[2])/qPerMetre;
- if(std::hypot(queryX-routeX,queryY-routeY)<=RouteClearanceMetres
- &&std::abs(queryZ-routeZ)<=RouteHeightClearanceMetres)return true;
+ const double lateral=std::hypot(queryX-routeX,queryY-routeY);
+ const double vertical=std::abs(queryZ-routeZ);
+ if(lateral<=RouteClearanceMetres
+ &&vertical<=RouteHeightClearanceMetres)return true;
}
}
return false;
@@ -1887,13 +1925,19 @@ public:
}
if(nativeFloorSupport!=std::numeric_limits<float>::lowest()
&&nativeFloorSupport<0.0f)
+ {
+ // Host floor support keeps solid ground under a landing chamber, but it
+ // cannot refill the chamber air above the selected planned/native floor.
+ if(unionLandingChamberDistance<=0.0)
+ return passageAirDistance;
return std::min(nativeFloorSupport,unionDistance<=0.0
?passageAirDistance:density);
+ }
if(nativeTunnelFieldDensity!=std::numeric_limits<float>::lowest())
return std::max(density,passageAirDistance);
if(unionDistance>0.0&&unionShellDistance<0.0&&density>=0.0f)
{
- if(connectedSurfaceLandingShellContains())
+ if(connectedNativeLandingShellContains())
return std::max(density,passageAirDistance);
return static_cast<float>(unionShellDistance/Q);
}
@@ -2044,11 +2088,12 @@ public:
static_cast<double>(chamber.floorGradientQ16[0])/65536.0,
static_cast<double>(chamber.floorGradientQ16[1])/65536.0);
const double extent=reachCoreVoxels+0.01;
+ const double clearHeight=static_cast<double>(
+ chamber.clearHeightSubvoxels)/Q;
const double low[3]={cx-radius-extent,cy-radius-extent,
cz-floorExtent-extent};
const double high[3]={cx+radius+extent,cy+radius+extent,
- cz+floorExtent+static_cast<double>(
- chamber.clearHeightSubvoxels)/Q+extent};
+ cz+floorExtent+2.0*clearHeight+extent};
return overlaps(low,high);
};
if(chamberOverlaps(passage.upperLandingChamber)
@@ -5488,7 +5533,7 @@ private:
cx-radius-extent,cy-radius-extent,cz-floorExtent-extent};
const std::array<double,3> maximum{
cx+radius+extent,cy+radius+extent,
- cz+floorExtent+height+extent};
+ cz+floorExtent+2.0*height+extent};
FPassageProofBound proof;
for(std::size_t axis=0;axis<3;++axis)
{
@@ -5859,6 +5904,71 @@ public:
return std::isfinite(OutGroundZ)&&std::isfinite(OutCeilingZ);
}
+ bool GetNativeSurfaceGroundHeightAt(float X,float Y,float Z,
+ double& OutGroundZ) const
+ {
+ if(!ResolvedLayout||!std::isfinite(X)||!std::isfinite(Y)||!std::isfinite(Z))
+ return false;
+ const auto* bound=FindBoundStratumForManagerZ(Z);
+ if(!bound)return false;
+ constexpr double Scale=static_cast<double>(
+ VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel);
+ const double maxVoxel=static_cast<double>(std::numeric_limits<std::int64_t>::max())/Scale;
+ if(std::abs(static_cast<double>(X))>maxVoxel
+ ||std::abs(static_cast<double>(Y))>maxVoxel)return false;
+ const auto toFixed=[](float value)
+ {return static_cast<std::int64_t>(std::llround(static_cast<double>(value)
+ *VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel));};
+ const auto* field=std::get_if<FSurfaceWorldFieldAdapter>(&bound->Evaluator);
+ if(field&&field->Evaluator.isValid())
+ {
+ const auto column=field->Evaluator.point(toFixed(X),toFixed(Y),0);
+ OutGroundZ=static_cast<double>(column.groundHeightSubvoxels)/Scale;
+ return std::isfinite(OutGroundZ);
+ }
+ const auto* islands=std::get_if<FFloatingIslandFieldAdapter>(&bound->Evaluator);
+ if(!islands||!bound->IslandPlan)return false;
+ const auto& route=bound->IslandPlan->manifest.plan.route;
+ if(route.size()<2)return false;
+ const auto& recipe=bound->IslandPlan->manifest.recipe;
+ const std::int64_t routeLift=recipe.routeConstraints.capsuleHeightSubvoxels/2
+ +recipe.routeConstraints.minimumClearanceSubvoxels
+ +(recipe.geometryVersion>=2
+ ?VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel/8:0);
+ const std::int64_t supportRadius=recipe.routeConstraints
+ .supportProbeRadiusSubvoxels;
+ if(routeLift<0||supportRadius<0)return false;
+ const std::int64_t queryX=toFixed(X),queryY=toFixed(Y);
+ std::uint64_t nearestDistanceSquared=std::numeric_limits<std::uint64_t>::max();
+ std::int64_t nearestRouteZ=0;
+ bool found=false;
+ for(std::size_t index=1;index<route.size();++index)
+ {
+ const auto& a=route[index-1].positionSubvoxels;
+ const auto& b=route[index].positionSubvoxels;
+ const std::int64_t dx=b[0]-a[0],dy=b[1]-a[1];
+ const std::int64_t lengthSquared=dx*dx+dy*dy;
+ if(lengthSquared<=0)continue;
+ const std::int64_t projection=std::clamp(
+ (queryX-a[0])*dx+(queryY-a[1])*dy,
+ std::int64_t{0},lengthSquared);
+ const std::int64_t closestX=a[0]+dx*projection/lengthSquared;
+ const std::int64_t closestY=a[1]+dy*projection/lengthSquared;
+ const std::int64_t offsetX=queryX-closestX,offsetY=queryY-closestY;
+ const std::uint64_t distanceSquared=static_cast<std::uint64_t>(
+ offsetX*offsetX+offsetY*offsetY);
+ if(distanceSquared>static_cast<std::uint64_t>(supportRadius)*supportRadius
+ ||distanceSquared>=nearestDistanceSquared)continue;
+ const std::int64_t dz=b[2]-a[2];
+ nearestRouteZ=a[2]+dz*projection/lengthSquared;
+ nearestDistanceSquared=distanceSquared;
+ found=true;
+ }
+ if(!found)return false;
+ OutGroundZ=static_cast<double>(nearestRouteZ-routeLift)/Scale;
+ return std::isfinite(OutGroundZ);
+ }
+
EVoxelTileClass ClassifyBox(const FIntVector& Origin,int32 Step,int32 Cells) const
{ return ClassifyBoxDetailed(Origin,Step,Cells).Verdict; }
diff --git a/Standalone/Core/src/VoxelForgeCore.cpp b/Standalone/Core/src/VoxelForgeCore.cpp
index b139ec4..e40250c 100644
--- a/Standalone/Core/src/VoxelForgeCore.cpp
+++ b/Standalone/Core/src/VoxelForgeCore.cpp
@@ -1811,6 +1811,13 @@ namespace VoxelForgeCore
float World::densityAt(Vec3d position) const
{ return impl_&&impl_->shapeReady.load(std::memory_order_acquire)&&impl_->shape?impl_->shape->DensityAt(static_cast<float>(position.x),static_cast<float>(position.y),static_cast<float>(position.z)):0.0f; }
+ bool World::nativeSurfaceGroundHeightAt(Vec3d position,double& groundHeightVoxels) const
+ {
+ return impl_&&impl_->shapeReady.load(std::memory_order_acquire)&&impl_->shape
+ &&impl_->shape->GetNativeSurfaceGroundHeightAt(static_cast<float>(position.x),
+ static_cast<float>(position.y),static_cast<float>(position.z),
+ groundHeightVoxels);
+ }
MaterialSampleV1 World::materialAt(Vec3d position) const
{
if(!impl_||!impl_->shapeReady.load(std::memory_order_acquire)||!impl_->shape)
diff --git a/Standalone/Source/StreamBenchmarkPipeline.h b/Standalone/Source/StreamBenchmarkPipeline.h
index 2fcf4b5..3ed4dd1 100644
--- a/Standalone/Source/StreamBenchmarkPipeline.h
+++ b/Standalone/Source/StreamBenchmarkPipeline.h
@@ -3051,7 +3051,8 @@ namespace StandaloneStreamBenchmark
double supportMaximumMetres,std::uint32_t minimumSupportProbes,
double supportProbeRadiusMetres,
const std::function<bool(double,double,double)>& supportExemption={},
- const std::function<bool(double,double,double)>& passageInteriorPredicate={})
+ const std::function<bool(double,double,double)>& passageInteriorPredicate={},
+ const std::function<float(VoxelForgeCore::Vec3d)>& densityOverride={})
{
FWalkAudit audit;
if(path.size()<2)return audit;
@@ -3068,15 +3069,18 @@ namespace StandaloneStreamBenchmark
&&passageInteriorPredicate(xMetres,yMetres,zMetres);
if(inPassageInterior)++audit.passageInteriorCapsuleSamples;
const VoxelForgeCore::Vec3d position{xMetres/coreMetres,yMetres/coreMetres,zMetres/coreMetres};
- const float density=Field.densityAt(position);
+ const float density=densityOverride
+ ?densityOverride(position):Field.densityAt(position);
if(density<0.0f)
{
if(inPassageInterior)++audit.passageInteriorSolidSamples;
if(audit.firstBlockedCount<audit.firstBlocked.size())
{
audit.firstBlocked[audit.firstBlockedCount++]={xMetres,yMetres,zMetres,density};
+ const std::string dispatchPath=densityOverride
+ ?"synthetic-open-floor":Field.densityDispatchPathAt(position);
std::printf("[ResolvedWalkDispatch] kind=blocked xyz_m=(%.3f,%.3f,%.3f) path=%s\n",
- xMetres,yMetres,zMetres,Field.densityDispatchPathAt(position).c_str());
+ xMetres,yMetres,zMetres,dispatchPath.c_str());
}
++audit.blocked;return true;
}
@@ -3149,8 +3153,11 @@ namespace StandaloneStreamBenchmark
{
++audit.supportSamples;
offsetSampleZ=(footZ-depth)/coreMetres;
- lastUnsupportedDensity=Field.densityAt({supportX/coreMetres,
- supportY/coreMetres,offsetSampleZ});
+ const VoxelForgeCore::Vec3d supportPosition{
+ supportX/coreMetres,supportY/coreMetres,offsetSampleZ};
+ lastUnsupportedDensity=densityOverride
+ ?densityOverride(supportPosition)
+ :Field.densityAt(supportPosition);
if(lastUnsupportedDensity<0.0)
{
supported=true;break;
@@ -3172,11 +3179,16 @@ namespace StandaloneStreamBenchmark
audit.firstUnsupported[sample]={
firstUnsupportedX,firstUnsupportedY,firstUnsupportedZ,
lastUnsupportedDensity};
+ const VoxelForgeCore::Vec3d supportPosition{
+ firstUnsupportedX/coreMetres,firstUnsupportedY/coreMetres,
+ footZ/coreMetres};
+ const std::string dispatchPath=densityOverride
+ ?"synthetic-open-floor":Field.densityDispatchPathAt(
+ supportPosition);
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,firstUnsupportedZ,supportedProbes,
supportMask[0],supportMask[1],supportMask[2],supportMask[3],supportMask[4],
- Field.densityDispatchPathAt({firstUnsupportedX/coreMetres,
- firstUnsupportedY/coreMetres,footZ/coreMetres}).c_str());
+ dispatchPath.c_str());
}
}
}
@@ -3712,7 +3724,8 @@ namespace StandaloneStreamBenchmark
const auto passageInteriorWinsAt=[&](double xMetres,double yMetres,
double zMetres,std::size_t ignoredPassage=std::numeric_limits<std::size_t>::max(),
std::size_t ignoredSegment=std::numeric_limits<std::size_t>::max(),
- std::size_t selectedPassage=std::numeric_limits<std::size_t>::max())
+ std::size_t selectedPassage=std::numeric_limits<std::size_t>::max(),
+ bool includeLandingChambers=true)
{
constexpr double CornerBlendMetres=0.50;
constexpr double WallReliefMetres=0.21;
@@ -3748,8 +3761,9 @@ namespace StandaloneStreamBenchmark
+qToMetres(chamber.clearHeightSubvoxels));
return std::max({radialDistance,floorDistance,ceilingDistance})<=0.0;
};
- if(inLandingChamber(passage.upperLandingChamber)
- ||inLandingChamber(passage.lowerLandingChamber))return true;
+ if(includeLandingChambers
+ &&(inLandingChamber(passage.upperLandingChamber)
+ ||inLandingChamber(passage.lowerLandingChamber)))return true;
const auto& route=allPassageSmoothRoutes[passageIndex];
if(route.size()<2)continue;
double bestRoundDistance=std::numeric_limits<double>::infinity();
@@ -4722,7 +4736,13 @@ namespace StandaloneStreamBenchmark
const double mouthZ=qToMetres(upper?passage.upperMouthSubvoxels[2]
:passage.lowerMouthSubvoxels[2]);
std::size_t endpoint=route.size();
- double endpointDistanceSquared=1.0;
+ const double endpointRadius=stratum->generatorKind=="FloatingIslands"
+ ?3.0:1.0;
+ const double endpointHeight=stratum->generatorKind=="FloatingIslands"
+ ?2.0:1.5;
+ const double portalWalkLead=stratum->generatorKind=="FloatingIslands"
+ ?12.0:9.0;
+ double endpointDistanceSquared=endpointRadius*endpointRadius;
for(std::size_t index=0;index<route.size();++index)
{
const double dx=qToMetres(route[index]->values[0])-cx;
@@ -4730,7 +4750,7 @@ namespace StandaloneStreamBenchmark
const double z=qToMetres(route[index]->values[2]);
const double distanceSquared=dx*dx+dy*dy;
if(distanceSquared<endpointDistanceSquared
- &&std::abs(z-mouthZ)<=1.5)
+ &&std::abs(z-mouthZ)<=endpointHeight)
{endpoint=index;endpointDistanceSquared=distanceSquared;}
}
if(endpoint==route.size())return false;
@@ -4758,7 +4778,7 @@ namespace StandaloneStreamBenchmark
const double fromEndpoint=std::abs(std::lerp(
routeDistance[index-1],routeDistance[index],t)
-routeDistance[endpoint]);
- if(fromEndpoint>9.0)continue;
+ if(fromEndpoint>portalWalkLead)continue;
const double routeX=ax+t*dx,routeY=ay+t*dy;
const double routeZ=az+t*qToMetres(b.values[2]-a.values[2]);
const double lateralDistance=std::hypot(xMetres-routeX,
@@ -5167,6 +5187,21 @@ namespace StandaloneStreamBenchmark
const double radius=qToMetres(chamber.radiusSubvoxels);
const double gx=chamber.floorGradientQ16[0]/65536.0;
const double gy=chamber.floorGradientQ16[1]/65536.0;
+ const auto floorAt=[&](double x,double y)
+ {
+ const double planned=baseFloorZ+gx*(x-centerX)+gy*(y-centerY);
+ double nativeGroundVoxels=0.0;
+ if(Field.nativeSurfaceGroundHeightAt({x/coreMetres,y/coreMetres,
+ planned/coreMetres},nativeGroundVoxels))
+ {
+ const double nativeGround=nativeGroundVoxels*coreMetres;
+ const double clearHeight=qToMetres(
+ chamber.clearHeightSubvoxels);
+ if(nativeGround>planned&&nativeGround<=planned+clearHeight)
+ return nativeGround;
+ }
+ return planned;
+ };
for(const double radial:chamberFloorRadii)
{
if(radial>=radius-1.0)continue;
@@ -5177,16 +5212,18 @@ namespace StandaloneStreamBenchmark
*static_cast<double>(angleIndex)/ChamberAngularSamples;
const double sampleX=centerX+radial*std::cos(angle);
const double sampleY=centerY+radial*std::sin(angle);
- const double floorZ=baseFloorZ+gx*(sampleX-centerX)
- +gy*(sampleY-centerY);
+ const double floorZ=floorAt(sampleX,sampleY);
for(const double depth:PassageShellAuditDepthsMetres)
{
const double sampleZ=floorZ-depth;
const VoxelForgeCore::Vec3d position{sampleX/coreMetres,
sampleY/coreMetres,sampleZ/coreMetres};
if(Native.densityAt(position)<0.0f)continue;
- if(landingChamberConnectionContains(passage,upper,
- sampleX,sampleY,sampleZ))
+ if(passageInteriorWinsAt(sampleX,sampleY,sampleZ,
+ std::numeric_limits<std::size_t>::max(),
+ std::numeric_limits<std::size_t>::max(),passageIndex)
+ ||landingChamberConnectionContains(passage,upper,
+ sampleX,sampleY,sampleZ))
{++audit.chamberConnectionSkips;continue;}
++audit.chamberFloorSamples;
const float density=Field.densityAt(position);
@@ -5211,8 +5248,7 @@ namespace StandaloneStreamBenchmark
{
const double sampleX=centerX+(radius+depth)*nx;
const double sampleY=centerY+(radius+depth)*ny;
- const double floorZ=baseFloorZ+gx*(sampleX-centerX)
- +gy*(sampleY-centerY);
+ const double floorZ=floorAt(sampleX,sampleY);
const double sampleZ=floorZ+height;
const VoxelForgeCore::Vec3d position{sampleX/coreMetres,
sampleY/coreMetres,sampleZ/coreMetres};
@@ -5275,6 +5311,25 @@ namespace StandaloneStreamBenchmark
{return passageInteriorWinsAt(x,y,z,
std::numeric_limits<std::size_t>::max(),
std::numeric_limits<std::size_t>::max(),passageIndex);};
+ const auto floorAt=[&](double x,double y)
+ {
+ const double planned=centerZ+gx*(x-centerX)+gy*(y-centerY);
+ double nativeGroundVoxels=0.0;
+ if(field.nativeSurfaceGroundHeightAt({x/coreMetres,y/coreMetres,
+ planned/coreMetres},nativeGroundVoxels))
+ {
+ const double nativeGround=nativeGroundVoxels*coreMetres;
+ const double clearHeight=qToMetres(chamber.clearHeightSubvoxels);
+ if(nativeGround>planned&&nativeGround<=planned+clearHeight)
+ return nativeGround;
+ }
+ return planned;
+ };
+ const std::function<bool(double,double,double)> supportExemption=
+ [&](double x,double y,double z)
+ {return passageInteriorWinsAt(x,y,z,
+ std::numeric_limits<std::size_t>::max(),
+ std::numeric_limits<std::size_t>::max(),passageIndex,false);};
for(const auto& direction:directions)
{
std::vector<std::array<double,3>> chamberPath;
@@ -5286,12 +5341,12 @@ namespace StandaloneStreamBenchmark
const double distance=radius*step/intervals;
const double x=centerX+direction[0]*distance;
const double y=centerY+direction[1]*distance;
- const double floorZ=centerZ+gx*(x-centerX)+gy*(y-centerY);
+ const double floorZ=floorAt(x,y);
chamberPath.push_back({x/coreMetres,y/coreMetres,
(floorZ+1.13)/coreMetres});
}
const FWalkAudit part=auditPlayerPath(field,chamberPath,
- 0.125,0.125,1.125,3,0.45,{},interiorPredicate);
+ 0.125,0.125,1.125,3,0.45,supportExemption,interiorPredicate);
total.segments+=part.segments;total.centers+=part.centers;
total.capsuleSamples+=part.capsuleSamples;
total.blocked+=part.blocked;
@@ -5305,10 +5360,116 @@ namespace StandaloneStreamBenchmark
}
return total;
};
+ const auto auditOpenChamberFloorNegativeControl=[&](
+ const VoxelForgeCore::World& field,
+ const VoxelForgeCore::ResolvedLayoutPassageV1& passage,
+ std::size_t passageIndex,bool upper)
+ {
+ const auto& chamber=upper?passage.upperLandingChamber
+ :passage.lowerLandingChamber;
+ const double centerX=qToMetres(chamber.floorCenterSubvoxels[0]);
+ const double centerY=qToMetres(chamber.floorCenterSubvoxels[1]);
+ const double centerZ=qToMetres(chamber.floorCenterSubvoxels[2]);
+ const double gx=chamber.floorGradientQ16[0]/65536.0;
+ const double gy=chamber.floorGradientQ16[1]/65536.0;
+ const double chamberAuditRadius=std::min(5.75,
+ qToMetres(chamber.radiusSubvoxels)-1.5);
+ const double mouthRadius=qToMetres(passage.mouthRadiusSubvoxels);
+ const double radius=std::min(chamberAuditRadius-0.1,mouthRadius+1.25);
+ if(radius<=0.0)
+ {
+ std::printf("[PassageLandingChamberOpenFloorNegativeControl] id=%s side=%s radius_m=%.3f mouth_radius_m=%.3f unsupported=0 support_overlap_skips=0 expected=FAIL status=FAIL reason=no_outer_floor_sample\n",
+ passage.stableId.c_str(),upper?"upper":"lower",radius,mouthRadius);
+ return false;
+ }
+ const auto floorAt=[&](double x,double y)
+ {
+ const double planned=centerZ+gx*(x-centerX)+gy*(y-centerY);
+ double nativeGroundVoxels=0.0;
+ if(field.nativeSurfaceGroundHeightAt({x/coreMetres,y/coreMetres,
+ planned/coreMetres},nativeGroundVoxels))
+ {
+ const double nativeGround=nativeGroundVoxels*coreMetres;
+ const double clearHeight=qToMetres(chamber.clearHeightSubvoxels);
+ if(nativeGround>planned&&nativeGround<=planned+clearHeight)
+ return nativeGround;
+ }
+ return planned;
+ };
+ const std::function<bool(double,double,double)> interiorPredicate=
+ [&](double x,double y,double z)
+ {return passageInteriorWinsAt(x,y,z,
+ std::numeric_limits<std::size_t>::max(),
+ std::numeric_limits<std::size_t>::max(),passageIndex);};
+ const std::function<bool(double,double,double)> supportExemption=
+ [&](double x,double y,double z)
+ {return passageInteriorWinsAt(x,y,z,
+ std::numeric_limits<std::size_t>::max(),
+ std::numeric_limits<std::size_t>::max(),passageIndex,false);};
+ 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}}}};
+ std::vector<std::array<double,3>> path;
+ double selectedAngle=0.0;
+ bool foundOutsideBore=false;
+ for(std::size_t directionIndex=0;directionIndex<32&&!foundOutsideBore;
+ ++directionIndex)
+ {
+ selectedAngle=2.0*3.14159265358979323846
+ *static_cast<double>(directionIndex)/32.0;
+ const double nx=std::cos(selectedAngle),ny=std::sin(selectedAngle);
+ const double tangentX=-ny,tangentY=nx;
+ const double x0=centerX+radius*nx-0.25*tangentX;
+ const double y0=centerY+radius*ny-0.25*tangentY;
+ const double x1=centerX+radius*nx+0.25*tangentX;
+ const double y1=centerY+radius*ny+0.25*tangentY;
+ const double floor0=floorAt(x0,y0),floor1=floorAt(x1,y1);
+ const std::array<std::array<double,3>,2> candidate{{
+ {{x0,y0,floor0+1.13}},{{x1,y1,floor1+1.13}}}};
+ bool samplesOutsideBore=true;
+ for(const auto& point:candidate)
+ {
+ const double supportZ=point[2]-0.88-0.125;
+ for(const auto& offset:supportOffsets)
+ if(supportExemption(point[0]+offset[0],
+ point[1]+offset[1],supportZ))
+ {samplesOutsideBore=false;break;}
+ if(!samplesOutsideBore)break;
+ }
+ if(samplesOutsideBore)
+ {
+ path={{candidate[0][0]/coreMetres,candidate[0][1]/coreMetres,
+ candidate[0][2]/coreMetres},
+ {candidate[1][0]/coreMetres,candidate[1][1]/coreMetres,
+ candidate[1][2]/coreMetres}};
+ foundOutsideBore=true;
+ }
+ }
+ if(!foundOutsideBore)
+ {
+ std::printf("[PassageLandingChamberOpenFloorNegativeControl] id=%s side=%s radius_m=%.3f mouth_radius_m=%.3f unsupported=0 support_overlap_skips=0 expected=FAIL status=FAIL reason=no_bore_clear_spoke\n",
+ passage.stableId.c_str(),upper?"upper":"lower",radius,mouthRadius);
+ return false;
+ }
+ const std::function<float(VoxelForgeCore::Vec3d)> openDensity=
+ [](VoxelForgeCore::Vec3d){return 1.0f;};
+ const FWalkAudit control=auditPlayerPath(field,path,0.125,0.125,
+ 1.125,3,0.45,supportExemption,interiorPredicate,openDensity);
+ const bool passed=!control.passed&&control.unsupported>0
+ &&control.supportOverlapSkips==0;
+ std::printf("[PassageLandingChamberOpenFloorNegativeControl] id=%s side=%s radius_m=%.3f mouth_radius_m=%.3f angle_deg=%.1f unsupported=%llu support_overlap_skips=%llu result=%s expected=FAIL status=%s\n",
+ passage.stableId.c_str(),upper?"upper":"lower",radius,mouthRadius,
+ selectedAngle*180.0/3.14159265358979323846,
+ static_cast<unsigned long long>(control.unsupported),
+ static_cast<unsigned long long>(control.supportOverlapSkips),
+ control.passed?"PASS":"FAIL",passed?"PASS":"FAIL");
+ return passed;
+ };
std::uint64_t passageCount=0,passagePasses=0,blockedControls=0,naturalPasses=0;
std::uint64_t passageInteriorCapsuleSamples=0,passageInteriorSolidSamples=0;
std::uint64_t passageInteriorControls=0;
std::uint64_t landingChamberCount=0,landingChamberNegativeControls=0;
+ std::uint64_t openChamberFloorNegativeControls=0;
std::uint64_t mouthProfilePasses=0,ripplePasses=0,rippleControlsDetected=0;
std::uint64_t floorRippleControlsDetected=0,floorStepRippleControlsDetected=0;
std::uint64_t shellAudits=0,shellFloorSamples=0,shellFloorViolations=0;
@@ -5346,6 +5507,9 @@ namespace StandaloneStreamBenchmark
passage,passageIndex,true);
const FWalkAudit lowerChamberAudit=auditLandingChamber(Shape,
passage,passageIndex,false);
+ const bool openChamberFloorControl=auditOpenChamberFloorNegativeControl(
+ Shape,passage,passageIndex,true);
+ openChamberFloorNegativeControls+=openChamberFloorControl;
const bool landingChambersWalkable=upperChamberAudit.passed
&&lowerChamberAudit.passed;
const bool passageInteriorAirPassed=
@@ -5889,6 +6053,10 @@ namespace StandaloneStreamBenchmark
static_cast<unsigned long long>(landingChamberCount),
static_cast<unsigned long long>(landingChamberCount
-landingChamberNegativeControls));
+ std::printf("[PassageLandingChamberOpenFloorNegativeControlSummary] expected_fail_detected=%llu/%llu status=%s\n",
+ static_cast<unsigned long long>(openChamberFloorNegativeControls),
+ static_cast<unsigned long long>(passageCount),
+ openChamberFloorNegativeControls==passageCount?"PASS":"FAIL");
const bool shellAuditPassed=shellAudits==passageCount
&&shellFloorViolations==0&&shellWallViolations==0
&&shellChamberFloorViolations==0&&shellChamberWallViolations==0
@@ -5939,6 +6107,7 @@ namespace StandaloneStreamBenchmark
&&mouthProfilePasses==passageCount&&l23TerraceControlDetected
&&ripplePasses==passageCount
&&shellAuditPassed
+ &&openChamberFloorNegativeControls==passageCount
&&routePasses>0&&routePasses==routeWalkPasses&&routePasses==routeBindings
&&routeBindingFailures==0
&&tunnelNetworkRoutes==tunnelNetworkBlockedControls