core: chamber floors planned into the passage h(s) profile (L152, v239; surface landing support open)

Seed 2 planned grades 9.58/6.58/8.28 deg (were 19 deg); 0 solid in 320,355 passage interior samples; 0 shell,
chamber, wall violations; envelope audit clean. Open: the upper Surface World landing plane, fitted to the surface
route, leaves 5 route + 2 chamber support samples unsupported.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016dhxM43dnWvUu2B5Ph1iG1
This commit is contained in:
Fr0zkaandClaude Opus 5.5 committed 2026-11-01 19:17:14 +01:00
1 parent 5bd158d4eb
commit 11b59a9a9e
12 files changed
+1315 -81

No files matched your search

@@ -511,7 +511,8 @@ namespace VoxelForgeCore
// the planned graph route, preserves its walk corridor through shell overlaps, and keeps
// boundary-blended host rock from widening the authored passage wall.
// v238 plans one resolved passage spline with explicit landing chambers.
inline constexpr std::uint32_t WorldAssemblyEvaluatorVersion = 238;
// v239 plans their floor planes as the passage's continuous floor profile.
inline constexpr std::uint32_t WorldAssemblyEvaluatorVersion = 239;
enum class FieldChannel : std::uint32_t
{
@@ -1235,6 +1236,10 @@ namespace VoxelForgeCore
std::size_t lowerMouthControlIndex = 0;
ResolvedLayoutPassageLandingChamberV1 upperLandingChamber;
ResolvedLayoutPassageLandingChamberV1 lowerLandingChamber;
// When true, each control point's position.z - radius is the planned
// floor h(s), and both chamber planes continue that same endpoint profile.
// False preserves older resolved snapshots' runtime floor composition.
bool floorProfileIncludesLandingChambers = false;
std::vector<ResolvedLayoutPassagePointV1> controlPoints;
};
+92 -63
View File
@@ -565,7 +565,9 @@ namespace
<<"],\"lower_mouth_q\":["<<p.lowerMouthSubvoxels[0]<<','
<<p.lowerMouthSubvoxels[1]<<','<<p.lowerMouthSubvoxels[2]
<<"],\"mouth_radius_q\":"<<p.mouthRadiusSubvoxels
<<",\"mid_radius_q\":"<<p.midRadiusSubvoxels;
<<",\"mid_radius_q\":"<<p.midRadiusSubvoxels
<<",\"floor_profile_includes_landing_chambers\":"
<<(p.floorProfileIncludesLandingChambers?"true":"false");
const auto writeLandingChamber=[&](const char* name,
const ResolvedLayoutPassageLandingChamberV1& chamber)
{
@@ -1796,6 +1798,8 @@ std::optional<ResolvedLayoutSnapshotV3> ResolvedLayoutSnapshotV3::FromJson(
p.style=static_cast<std::uint32_t>(LayoutInt(v,"style"));
p.placementRadiusSubvoxels=LayoutInt(v,"placement_radius_q");
p.mouthRadiusSubvoxels=LayoutInt(v,"mouth_radius_q");p.midRadiusSubvoxels=LayoutInt(v,"mid_radius_q");
p.floorProfileIncludesLandingChambers=
LayoutBool(v,"floor_profile_includes_landing_chambers");
const auto& upper=v.Get("upper_mouth_q").AsArray();
const auto& lower=v.Get("lower_mouth_q").AsArray();
for(std::size_t axis=0;axis<3&&axis<upper.size();++axis)p.upperMouthSubvoxels[axis]=upper[axis].Integer();
@@ -3845,6 +3849,38 @@ bool PlanResolvedLayoutPassagesV1(ResolvedLayoutSnapshotV3& layout,std::int32_t
out={to->values[0]-from->values[0],to->values[1]-from->values[1]};
return out[0]!=0||out[1]!=0;
};
const auto plannedMouthFloor=[&](const ResolvedLayoutStratumV2& host,
const std::array<std::int64_t,3>& mouth,bool upperSide,
std::int64_t playerCenterAboveFloorQ,std::int64_t mouthRadiusQ)
{
std::int64_t result=mouth[2]-playerCenterAboveFloorQ;
const bool receivesRoute=upperSide
?host.generatorKind=="SurfaceWorld"||host.generatorKind=="TunnelNetwork"
:host.generatorKind=="TunnelNetwork"||host.generatorKind=="VerticalShafts";
if(!receivesRoute)return result;
std::vector<std::array<double,3>> route;
for(const auto& anchor:host.anchors)
if(anchor.kind=="route_point"&&anchor.values.size()>=3)
route.push_back({static_cast<double>(anchor.values[0]),
static_cast<double>(anchor.values[1]),
static_cast<double>(anchor.values[2])});
if(host.generatorKind=="TunnelNetwork"&&upperSide&&route.size()>2)
route.erase(route.begin(),route.end()-2);
else if(!upperSide&&(host.generatorKind=="TunnelNetwork"
||host.generatorKind=="VerticalShafts")&&route.size()>2)
{
route.resize(2);
}
double routeHeight=0.0,distanceSquared=0.0;
const double reach=static_cast<double>(mouthRadiusQ)/qPerMetre+0.5;
if(VoxelForgeCore::PassageSpline::ClosestRouteHeightAtXY(route,
static_cast<double>(mouth[0]),static_cast<double>(mouth[1]),
routeHeight,distanceSquared)
&&distanceSquared<=std::pow(reach*qPerMetre,2.0))
result=static_cast<std::int64_t>(std::llround(routeHeight
-playerCenterAboveFloorQ));
return result;
};
const auto radialWithin=[](const std::array<std::int64_t,3>& p,std::int64_t radius)
{return radius>0&&p[0]*p[0]+p[1]*p[1]<=radius*radius;};
const auto reachValue=[](std::uint64_t hash,std::int64_t lo,std::int64_t hi)
@@ -3977,6 +4013,10 @@ bool PlanResolvedLayoutPassagesV1(ResolvedLayoutSnapshotV3& layout,std::int32_t
&&std::any_of(lower.anchors.begin(),lower.anchors.end(),
[](const auto& anchor){return anchor.kind=="heightfield_profile"
&&anchor.values.size()>=2&&anchor.values[0]>0;});
const std::int64_t upperPlannedFloor=plannedMouthFloor(upper,upperMouth,
true,upperPlayerCenterAboveFloorQ,mouthRadius);
const std::int64_t lowerPlannedFloor=plannedMouthFloor(lower,lowerMouth,
false,playerCenterAboveFloorQ,mouthRadius);
const std::int64_t outerRingRadius=std::max<std::int64_t>(1,
placementRadius-mouthRadius-qPerMetre/2);
@@ -4170,7 +4210,7 @@ bool PlanResolvedLayoutPassagesV1(ResolvedLayoutSnapshotV3& layout,std::int32_t
const std::uint32_t hashedPhase=phase;
const int hashedDirection=direction;
const std::int64_t entryVerticalDistance=std::abs(
lowerMouth[2]-upperMouth[2]);
lowerPlannedFloor-upperPlannedFloor);
const std::int64_t entryRouteGradeQ16=profiledSurfaceJoin?8000
:style==0&&anchoredIslandPassage&&!anchoredSpiral?15500
:TargetGradeQ16;
@@ -4597,7 +4637,8 @@ bool PlanResolvedLayoutPassagesV1(ResolvedLayoutSnapshotV3& layout,std::int32_t
else pushXY(firstRing);
std::uint64_t totalHorizontal=0;std::uint32_t loops=0;
const std::int64_t verticalDistance=hasAnchorHelix
?std::abs(lowerMouth[2]-helixBedrockZ):std::abs(lowerMouth[2]-upperMouth[2]);
?std::abs(lowerPlannedFloor-(helixBedrockZ-playerCenterAboveFloorQ))
:std::abs(lowerPlannedFloor-upperPlannedFloor);
auto measurePath=[&]()
{
std::uint64_t total=0;
@@ -4923,6 +4964,13 @@ bool PlanResolvedLayoutPassagesV1(ResolvedLayoutSnapshotV3& layout,std::int32_t
chamberFloorControls,chamberFloorProfile,
lowerMouthIndex,route,qPerMetre);
}
// Commit the endpoint route fit into h(s) before chamber records are
// resolved. The passage field and both landing planes then consume the
// same deterministic profile instead of blending the chamber in later.
for(std::size_t i=0;i<passage.controlPoints.size();++i)
passage.controlPoints[i].positionSubvoxels[2]=static_cast<std::int64_t>(
std::llround(chamberFloorProfile[i]))
+passage.controlPoints[i].radiusSubvoxels;
const auto resolveLandingChamber=[&](
ResolvedLayoutPassageLandingChamberV1& chamber,
const std::array<std::int64_t,3>& mouth,std::size_t endpointIndex,
@@ -4953,71 +5001,51 @@ bool PlanResolvedLayoutPassagesV1(ResolvedLayoutSnapshotV3& layout,std::int32_t
horizontalSquared),
PassageRoundRatio(dy<0?-dz:dz,std::abs(dy)*65536,
horizontalSquared)};
if(host.generatorKind=="SurfaceWorld")
if(host.generatorKind=="SurfaceWorld"&&side[0]=='u')
{
// The surface route enters the outer half of this chamber. Fit
// its landing plane to that receiving route, while keeping its
// center height equal to the passage's planned h(s) endpoint.
const auto surfaceRoute=routePoints(host);
std::vector<std::array<double,3>> nearbyRoute;
// Fit the landing floor only to route anchors inside its
// chamber footprint; samples beyond the chamber can pull
// the floor away from the route at the joint.
const double supportRadius=static_cast<double>(
chamber.radiusSubvoxels);
for(const auto& point:surfaceRoute)
const double radiusSquared=static_cast<double>(
chamber.radiusSubvoxels)*chamber.radiusSubvoxels;
double farthestDistanceSquared=0.0;
std::array<double,3> farthestPoint{};
for(const auto& routePoint:surfaceRoute)
{
const double routeDx=point[0]-endpoint.positionSubvoxels[0];
const double routeDy=point[1]-endpoint.positionSubvoxels[1];
if(routeDx*routeDx+routeDy*routeDy<=supportRadius*supportRadius)
nearbyRoute.push_back(point);
const double routeDx=routePoint[0]-mouth[0];
const double routeDy=routePoint[1]-mouth[1];
const double distanceSquared=routeDx*routeDx+routeDy*routeDy;
if(distanceSquared<=radiusSquared
&&distanceSquared>farthestDistanceSquared)
{
farthestDistanceSquared=distanceSquared;
farthestPoint=routePoint;
}
}
if(nearbyRoute.size()>=2)
double mouthRouteHeight=0.0,mouthRouteDistanceSquared=0.0;
if(farthestDistanceSquared>0.0
&&VoxelForgeCore::PassageSpline::ClosestRouteHeightAtXY(
surfaceRoute,static_cast<double>(mouth[0]),
static_cast<double>(mouth[1]),mouthRouteHeight,
mouthRouteDistanceSquared))
{
std::array<double,3> mean{};
for(const auto& point:nearbyRoute)
for(std::size_t axis=0;axis<3;++axis)
mean[axis]+=point[axis]/nearbyRoute.size();
double xx=0.0,xy=0.0,yy=0.0,xz=0.0,yz=0.0;
for(const auto& point:nearbyRoute)
{
const double routeDx=point[0]-mean[0];
const double routeDy=point[1]-mean[1];
const double routeDz=point[2]-mean[2];
xx+=routeDx*routeDx;xy+=routeDx*routeDy;
yy+=routeDy*routeDy;xz+=routeDx*routeDz;
yz+=routeDy*routeDz;
}
const double determinant=xx*yy-xy*xy;
double gradientX=0.0,gradientY=0.0;
if(determinant>1.0e-9)
{
gradientX=(xz*yy-yz*xy)/determinant;
gradientY=(yz*xx-xz*xy)/determinant;
}
else
{
// Route anchors can be collinear inside the chamber.
// Fit their dominant horizontal direction by least
// squares instead of extrapolating from one far point.
const double trace=xx+yy;
const double discriminant=std::sqrt(std::max(0.0,
(xx-yy)*(xx-yy)+4.0*xy*xy));
const double variance=0.5*(trace+discriminant);
if(variance>1.0e-9)
{
double axisX=1.0,axisY=0.0;
if(std::abs(xy)>1.0e-12)
{axisX=xy;axisY=variance-xx;}
else if(yy>xx)
{axisX=0.0;axisY=1.0;}
const double axisLength=std::hypot(axisX,axisY);
axisX/=axisLength;axisY/=axisLength;
const double routeSlope=(axisX*xz+axisY*yz)/variance;
gradientX=routeSlope*axisX;
gradientY=routeSlope*axisY;
}
}
chamber.floorGradientQ16={
static_cast<std::int32_t>(std::llround(gradientX*65536.0)),
static_cast<std::int32_t>(std::llround(gradientY*65536.0))};
const std::int64_t surfaceDx=static_cast<std::int64_t>(
std::llround(farthestPoint[0]-mouth[0]));
const std::int64_t surfaceDy=static_cast<std::int64_t>(
std::llround(farthestPoint[1]-mouth[1]));
const std::int64_t surfaceDz=static_cast<std::int64_t>(
std::llround(farthestPoint[2]-mouthRouteHeight));
const std::int64_t surfaceHorizontalSquared=surfaceDx*surfaceDx
+surfaceDy*surfaceDy;
if(surfaceHorizontalSquared>0)
chamber.floorGradientQ16={
PassageRoundRatio(surfaceDx<0?-surfaceDz:surfaceDz,
std::abs(surfaceDx)*65536,
surfaceHorizontalSquared),
PassageRoundRatio(surfaceDy<0?-surfaceDz:surfaceDz,
std::abs(surfaceDy)*65536,
surfaceHorizontalSquared)};
}
}
const std::uint64_t gradientSquared=static_cast<std::uint64_t>(
@@ -5053,6 +5081,7 @@ bool PlanResolvedLayoutPassagesV1(ResolvedLayoutSnapshotV3& layout,std::int32_t
||!resolveLandingChamber(passage.lowerLandingChamber,lowerMouth,
lowerMouthIndex,lowerMouthIndex-1,lower,"lower"))
return false;
passage.floorProfileIncludesLandingChambers=true;
std::printf("[PassageLandingChamberPlan] id=%s upper_radius_m=%.3f lower_radius_m=%.3f clear_height_m=4.500 upper_floor_grade_q16=(%lld,%lld) lower_floor_grade_q16=(%lld,%lld) status=PASS\n",
passage.stableId.c_str(),
passage.upperLandingChamber.radiusSubvoxels/static_cast<double>(qPerMetre),
+12 -4
View File
@@ -3836,6 +3836,7 @@ private:
std::array<double,2> lowerLandingFloorGradient{};
double lowerLandingRadiusSubvoxels=0.0;
std::size_t routeEndControlIndex=0;
bool floorProfileIncludesLandingChambers=false;
};
struct FPassageSegmentData
{
@@ -3937,6 +3938,8 @@ private:
+profileT*profileSegment.authoredFloorZDelta;
}
}
if(constants.floorProfileIncludesLandingChambers)
return plannedFloor+floorDepthSubvoxels;
const double upperBlendFloor=VoxelForgeCore::PassageSpline::BlendUpperMouthFloorAtXY(
constants.upperMouthReceivingRoute,queryXSubvoxels,queryYSubvoxels,
plannedFloor,constants.upperMouthX,constants.upperMouthY,
@@ -5112,6 +5115,8 @@ private:
passage.lowerMouthControlIndex,1,passage.controlPoints.size()-1);
auto& constants=PassageComposerConstants[passageIndex];
constants.routeEndControlIndex=routeEnd;
constants.floorProfileIncludesLandingChambers=
passage.floorProfileIncludesLandingChambers;
for(std::size_t axis=0;axis<3;++axis)
{
constants.upperLandingFloorCenterSubvoxels[axis]=static_cast<double>(
@@ -5177,8 +5182,10 @@ private:
upperMouthFloorDepth=std::max(upperMouthFloorDepth,
std::max(0.0,(controls.front()[2]-routeHeight)/qPerMetre
+constants.upperMouthPlayerCenterHeightMetres));
if(upperStratum->generatorKind=="TunnelNetwork"
if(!passage.floorProfileIncludesLandingChambers
&&(upperStratum->generatorKind=="TunnelNetwork"
||upperStratum->generatorKind=="SurfaceWorld")
)
VoxelForgeCore::PassageSpline::BlendEndpointFloorToRoute(
controls,plannedFloorProfile,0,route,qPerMetre,
constants.upperMouthPlayerCenterHeightMetres);
@@ -5226,9 +5233,10 @@ private:
&&distanceSquared<=std::pow(controls[routeEnd][3]
+2.0*qPerMetre,2.0))
{
VoxelForgeCore::PassageSpline::BlendEndpointFloorToRoute(
controls,plannedFloorProfile,routeEnd,
constants.lowerMouthReceivingRoute,qPerMetre);
if(!passage.floorProfileIncludesLandingChambers)
VoxelForgeCore::PassageSpline::BlendEndpointFloorToRoute(
controls,plannedFloorProfile,routeEnd,
constants.lowerMouthReceivingRoute,qPerMetre);
constants.lowerMouthX=controls[routeEnd][0];
constants.lowerMouthY=controls[routeEnd][1];
constants.lowerMouthPlannedFloor=plannedFloorProfile[routeEnd];