research: chamber support bodies (L153, 3 designs fail; kept as patch)

Support under chambers and 9 m approaches either refilled the bore or left the same 5 Surface World route + 2 upper
chamber probes unsupported in all three variants (identical counts with or without support), so those probes are
likely not under the support footprint. Also exposed an FI chamber content-band validation failure.

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:51:35 +01:00
1 parent 11b59a9a9e
commit bea40502af
11 files changed
+703

No files matched your search

@@ -0,0 +1,302 @@
diff --git a/Standalone/Core/include/VoxelForgeCore/VoxelForgeCore.h b/Standalone/Core/include/VoxelForgeCore/VoxelForgeCore.h
index 4799b9e..e3ecf5e 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 gives landing chambers and their route approaches tapered floor support.
+ inline constexpr std::uint32_t WorldAssemblyEvaluatorVersion = 240;
enum class FieldChannel : std::uint32_t
{
diff --git a/Standalone/Core/src/ShapeWorldInternal.h b/Standalone/Core/src/ShapeWorldInternal.h
index 6b1a6af..f0e0da4 100644
--- a/Standalone/Core/src/ShapeWorldInternal.h
+++ b/Standalone/Core/src/ShapeWorldInternal.h
@@ -57,6 +57,7 @@ static constexpr double VF_PassageShellThicknessMetres=0.75;
static constexpr double VF_PassageWallReliefMetres=0.21;
static constexpr double VF_PassageCornerBlendMetres=0.50;
static constexpr double VF_PassageReachMarginMetres=0.01;
+static constexpr double VF_LandingSupportBoundsDepthMetres=2.20;
// Radial support in metres: shell + maximum relief + the smooth-max support
// (corner-blend width / 6) + a 1 cm guard for float and bound rounding.
static constexpr double VF_PassageInfluenceReachMetres=
@@ -1260,11 +1261,92 @@ public:
constexpr double WallReliefMetres=VF_PassageWallReliefMetres;
constexpr double OpenAirSideWallHeightMetres=1.0;
constexpr double MouthShellBlendMetres=5.0;
+ // Landing floors carry a tapered footing below their walk plane. Surface
+ // landings use local native ground within a 2 m budget; cave and shaft
+ // landings reuse the cave planner's 0.75 m floor-support depth.
+ constexpr double LandingSupportMaximumDepthMetres=2.0;
+ constexpr double LandingSupportFallbackDepthMetres=0.75;
+ constexpr double LandingSupportTaperMetres=1.0;
+ constexpr double LandingSupportGroundEmbedMetres=0.20;
+ constexpr double LandingSupportTopBiasSubvoxels=2.0;
const double qPerMetre=Q*1000000.0/
std::max<std::uint32_t>(1,ResolvedLayout->coreVoxelSizeMicrometres);
const double qx=static_cast<double>(X)*Q,qy=static_cast<double>(Y)*Q,
qz=static_cast<double>(Z)*Q;
const double shellThickness=FloorShellThicknessMetres*qPerMetre;
+ const auto* queryStratum=FindBoundStratumForManagerZ(Z);
+ double landingSupportDistanceVoxels=std::numeric_limits<double>::infinity();
+ double landingSupportAirClipVoxels=-std::numeric_limits<double>::infinity();
+ double routeUnionDistance=std::numeric_limits<double>::infinity();
+ bool surfaceGroundQueried=false,surfaceGroundValid=false;
+ double surfaceGroundVoxels=0.0;
+ const bool surfaceLandingStratum=queryStratum&&queryStratum->Resolved
+ &&queryStratum->Resolved->generatorKind=="SurfaceWorld";
+ const auto surfaceGroundAtQuery=[&]()
+ {
+ if(!surfaceGroundQueried)
+ {
+ surfaceGroundQueried=true;
+ const double layoutWidth=GetResolvedLayoutChunkWidthVoxels();
+ if(layoutWidth>0.0)
+ {
+ const int32 chunkZ=FMath::FloorToInt(
+ static_cast<float>(static_cast<double>(Z)/layoutWidth));
+ float ground=0.0f,ceiling=0.0f;
+ surfaceGroundValid=GetNativeSurfaceHeightsAt(
+ X,Y,chunkZ,ground,ceiling);
+ if(surfaceGroundValid)surfaceGroundVoxels=ground;
+ }
+ }
+ return surfaceGroundValid?surfaceGroundVoxels
+ :std::numeric_limits<double>::quiet_NaN();
+ };
+ const auto includeLandingSupport=[&](double floorSubvoxels,
+ double centerDistanceSubvoxels,double footprintRadiusSubvoxels)
+ {
+ if(!(footprintRadiusSubvoxels>0.0))return;
+ const double floorVoxels=floorSubvoxels/Q;
+ const double centerDistanceVoxels=centerDistanceSubvoxels/Q;
+ const double radiusVoxels=footprintRadiusSubvoxels/Q;
+ const double supportDepthVoxels=(surfaceLandingStratum
+ ?LandingSupportMaximumDepthMetres:LandingSupportFallbackDepthMetres)
+ *qPerMetre/Q;
+ const double taperVoxels=LandingSupportTaperMetres*qPerMetre/Q;
+ const double embedVoxels=LandingSupportGroundEmbedMetres*qPerMetre/Q;
+ const double topBiasVoxels=LandingSupportTopBiasSubvoxels/Q;
+ if(centerDistanceVoxels>=radiusVoxels+taperVoxels
+ ||static_cast<double>(Z)<floorVoxels-supportDepthVoxels-embedVoxels
+ ||static_cast<double>(Z)>floorVoxels+topBiasVoxels)return;
+
+ double groundAnchorVoxels=floorVoxels-supportDepthVoxels;
+ if(surfaceLandingStratum)
+ {
+ const double ground=surfaceGroundAtQuery();
+ if(std::isfinite(ground))
+ groundAnchorVoxels=std::max(groundAnchorVoxels,
+ std::min(ground,floorVoxels));
+ }
+ const double radialFade=std::clamp(
+ (radiusVoxels+taperVoxels-centerDistanceVoxels)/taperVoxels,
+ 0.0,1.0);
+ const double smoothFade=radialFade*radialFade*(3.0-2.0*radialFade);
+ const double supportTop=groundAnchorVoxels
+ +(floorVoxels+topBiasVoxels-groundAnchorVoxels)*smoothFade;
+ const double supportBottom=groundAnchorVoxels-embedVoxels*smoothFade;
+ const double supportDistance=std::max(
+ centerDistanceVoxels-(radiusVoxels+taperVoxels),
+ std::max(static_cast<double>(Z)-supportTop,
+ supportBottom-static_cast<double>(Z)));
+ landingSupportDistanceVoxels=std::min(landingSupportDistanceVoxels,
+ supportDistance);
+ };
+ const auto applyLandingSupport=[&](float composed)
+ {
+ if(!std::isfinite(landingSupportDistanceVoxels))return composed;
+ const double clippedSupportDistance=std::max(landingSupportDistanceVoxels,
+ landingSupportAirClipVoxels);
+ return std::min(composed,static_cast<float>(clippedSupportDistance));
+ };
struct FNearestTubeSample
{
double signedDistance=std::numeric_limits<double>::infinity();
@@ -1284,7 +1366,6 @@ public:
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 bool plannedTunnelStratum=queryStratum&&queryStratum->Resolved
&&(queryStratum->Resolved->generatorKind=="TunnelNetwork"
||queryStratum->Resolved->generatorKind=="VerticalShafts")
@@ -1346,6 +1427,9 @@ public:
const double radialDistance=DeterministicSqrt(
(qx-centerX)*(qx-centerX)+(qy-centerY)*(qy-centerY))
-landingChamber->radiusSubvoxels;
+ includeLandingSupport(floorCenterZ,
+ radialDistance+landingChamber->radiusSubvoxels,
+ landingChamber->radiusSubvoxels);
const double floorDistance=floorCenterZ-qz;
const double ceilingDistance=qz-(floorCenterZ
+landingChamber->clearHeightSubvoxels);
@@ -1578,6 +1662,42 @@ public:
visitShellSegment);
}
if(!nearest.valid)continue;
+ if(queryStratum&&queryStratum->Resolved
+ &&(queryStratum->StrateIndex==passage.upperStrateIndex
+ ||queryStratum->StrateIndex==passage.lowerStrateIndex)
+ &&nearest.floorSegmentIndex<PassageSegmentData[passageIndex].size())
+ {
+ constexpr double LandingApproachLengthMetres=9.0;
+ const auto& floorSegment=
+ PassageSegmentData[passageIndex][nearest.floorSegmentIndex];
+ const double floorAlongMetres=floorSegment.authoredAlongMetres
+ +nearest.floorT*floorSegment.authoredLengthMetres;
+ const bool upperApproach=queryStratum->StrateIndex
+ ==passage.upperStrateIndex
+ &&floorAlongMetres>=-LandingSupportTaperMetres
+ &&floorAlongMetres<=LandingApproachLengthMetres;
+ const bool lowerApproach=queryStratum->StrateIndex
+ ==passage.lowerStrateIndex
+ &&constants.totalPathLengthMetres-floorAlongMetres
+ <=LandingApproachLengthMetres
+ &&constants.totalPathLengthMetres-floorAlongMetres
+ >=-LandingSupportTaperMetres;
+ if(floorSegment.routeSegment&&(upperApproach||lowerApproach))
+ {
+ const double routeX=floorSegment.a[0]
+ +nearest.floorT*floorSegment.delta[0];
+ const double routeY=floorSegment.a[1]
+ +nearest.floorT*floorSegment.delta[1];
+ const double routeDistance=DeterministicSqrt(
+ (qx-routeX)*(qx-routeX)+(qy-routeY)*(qy-routeY));
+ const double floorRadius=floorSegment.radiusA
+ +std::clamp(nearest.floorT,0.0,1.0)*floorSegment.radiusDelta;
+ const double supportRadius=std::max(0.0,
+ floorRadius-0.23*qPerMetre);
+ includeLandingSupport(nearest.floorCenterZ-nearest.floorDepth,
+ routeDistance,supportRadius);
+ }
+ }
const double wallElevationMetres=(qz-(nearest.floorCenterZ
-nearest.floorDepth))/qPerMetre;
double distanceToCenter=std::max(1.0e-9,
@@ -1648,6 +1768,8 @@ public:
static_cast<double>(shapedDistance)-floorShellThickness);
nearest.floorShellSignedDistance=std::min(
nearest.floorShellSignedDistance,floorShellDistance);
+ routeUnionDistance=std::min(routeUnionDistance,
+ static_cast<double>(shapedDistance));
unionDistance=std::min(unionDistance,static_cast<double>(shapedDistance));
unionFloorShellDistance=std::min(unionFloorShellDistance,
nearest.floorShellSignedDistance);
@@ -1657,13 +1779,18 @@ public:
std::min(localShellDistance,nearest.shellSignedDistance));
}
- if(!std::isfinite(unionDistance))return density;
+ if(!std::isfinite(unionDistance))return applyLandingSupport(density);
const float passageAirDistance=static_cast<float>(-unionDistance/Q);
+ // Keep support out of the passage bore while allowing it under the
+ // chamber's own floor, where the chamber volume is naturally open.
+ if(std::isfinite(routeUnionDistance))
+ landingSupportAirClipVoxels=-routeUnionDistance/Q;
// Keep the landing floor shell where it is exposed to the chamber. At
// the tunnel joint, the passage void must be able to open through that
// floor shell so its own continuous floor and shell define the throat.
if(unionLandingChamberFloorShellDistance<0.0&&unionDistance>0.0)
- return static_cast<float>(unionLandingChamberFloorShellDistance/Q);
+ return applyLandingSupport(
+ static_cast<float>(unionLandingChamberFloorShellDistance/Q));
const auto plannedPortalWalkCorridorContains=[&]()
{
if(!queryStratum||!queryStratum->Resolved
@@ -1855,7 +1982,7 @@ public:
// otherwise the neighboring field can widen its wall by a whole
// shell thickness. Native graph air still wins above via the
// positive nativeTunnelFieldDensity path.
- return passageAirDistance;
+ return applyLandingSupport(passageAirDistance);
}
// Air is the union of the native graph and passage voids. Keeping the
// signed passage distance outside the void as well gives marching cubes
@@ -1865,9 +1992,10 @@ public:
&&plannedTunnelPassageShellDistance<0.0&&unionDistance>0.0)
{
if(nativeTunnelFieldDensity>=0.0f&&plannedPortalWalkCorridorContains())
- return std::max(nativeTunnelFieldDensity,passageAirDistance);
- return std::min(density,
- static_cast<float>(plannedTunnelPassageShellDistance/Q));
+ return applyLandingSupport(
+ std::max(nativeTunnelFieldDensity,passageAirDistance));
+ return applyLandingSupport(std::min(density,
+ static_cast<float>(plannedTunnelPassageShellDistance/Q)));
}
if(nativeTunnelFieldDensity>=0.0f)
{
@@ -1875,29 +2003,30 @@ public:
// cave voids after the explicit mouth fade has ended. Keep this scoped
// to the planner-crossing passage shell so nearby portal joints stay open.
if(plannedTunnelPassageShellDistance<0.0&&unionDistance>0.0)
- return std::min(nativeTunnelFieldDensity,
- static_cast<float>(plannedTunnelPassageShellDistance/Q));
+ return applyLandingSupport(std::min(nativeTunnelFieldDensity,
+ static_cast<float>(plannedTunnelPassageShellDistance/Q)));
constexpr float NativeCaveAirMarginVoxels=0.75f;
if(unionDistance>0.0
&&nativeTunnelFieldDensity<NativeCaveAirMarginVoxels
&&unionFloorShellDistance<0.0)
- return std::min(nativeTunnelFieldDensity,
- static_cast<float>(unionFloorShellDistance/Q));
- return std::max(nativeTunnelFieldDensity,passageAirDistance);
+ return applyLandingSupport(std::min(nativeTunnelFieldDensity,
+ static_cast<float>(unionFloorShellDistance/Q)));
+ return applyLandingSupport(
+ std::max(nativeTunnelFieldDensity,passageAirDistance));
}
if(nativeFloorSupport!=std::numeric_limits<float>::lowest()
&&nativeFloorSupport<0.0f)
- return std::min(nativeFloorSupport,unionDistance<=0.0
- ?passageAirDistance:density);
+ return applyLandingSupport(std::min(nativeFloorSupport,unionDistance<=0.0
+ ?passageAirDistance:density));
if(nativeTunnelFieldDensity!=std::numeric_limits<float>::lowest())
- return std::max(density,passageAirDistance);
+ return applyLandingSupport(std::max(density,passageAirDistance));
if(unionDistance>0.0&&unionShellDistance<0.0&&density>=0.0f)
{
if(connectedSurfaceLandingShellContains())
- return std::max(density,passageAirDistance);
- return static_cast<float>(unionShellDistance/Q);
+ return applyLandingSupport(std::max(density,passageAirDistance));
+ return applyLandingSupport(static_cast<float>(unionShellDistance/Q));
}
- return std::max(density,passageAirDistance);
+ return applyLandingSupport(std::max(density,passageAirDistance));
}
float ApplyResolvedStrateComposition(float density,float X,float Y,float Z) const
@@ -2044,8 +2173,11 @@ 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 supportDepth=(VF_LandingSupportBoundsDepthMetres*1000000.0/
+ std::max<std::uint32_t>(1,
+ ResolvedLayout->coreVoxelSizeMicrometres));
const double low[3]={cx-radius-extent,cy-radius-extent,
- cz-floorExtent-extent};
+ cz-floorExtent-supportDepth-extent};
const double high[3]={cx+radius+extent,cy+radius+extent,
cz+floorExtent+static_cast<double>(
chamber.clearHeightSubvoxels)/Q+extent};
@@ -5484,8 +5616,12 @@ private:
const double height=static_cast<double>(
chamber.clearHeightSubvoxels)/Q;
const double extent=requiredReachCoreVoxels+0.01;
+ const double supportDepth=(VF_LandingSupportBoundsDepthMetres*1000000.0/
+ std::max<std::uint32_t>(1,
+ ResolvedLayout->coreVoxelSizeMicrometres));
const std::array<double,3> minimum{
- cx-radius-extent,cy-radius-extent,cz-floorExtent-extent};
+ cx-radius-extent,cy-radius-extent,
+ cz-floorExtent-supportDepth-extent};
const std::array<double,3> maximum{
cx+radius+extent,cy+radius+extent,
cz+floorExtent+height+extent};