feat(core): native lattice generator, slice 1 -- helix-ramp spine + small maze (L58); research R27

Core.Lattice.PrimitiveField v1, opt-in per strate (legacy Maze/VerticalShaft stay legacy): resolves the real
arrival and departure mouths first, plans a mandatory spine, then maze cells and two dead ends (9 rooms,
9 edges, stable IDs). The spine descends 20 m through four helix turns (6 m radius, 3 m clear width, 5 m
pitch, 2.6 m clearance; max grade 10.0 deg); each feature is one filleted void (0.57 m measured). Final-field
reachability passes at 883 stations; an orphaned shaft control is rejected; exact intervals (0 misses) and
a whole-surface audit with 0 flags. Whole view 1.69 s (above the 1 s target). fast/medium/full PASS.
Research R27 (self-checked): static stream-to-pool water design.

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-10-25 15:45:32 +01:00
1 parent 1e3e04bbac
commit 6c6cc37e1d
25 files changed
+280497 -117

No files matched your search

+278 -65
View File
@@ -378,10 +378,10 @@ public:
}
}
}
else if(Stratum.generatorKind=="Caves"
&&Stratum.recipeId=="Core.Caves.PrimitiveField"
&&Stratum.recipeVersion==1
&&Stratum.passageCapabilities.hasNativeCaveField)
else if(VoxelForgeCore::HasNativeGraphField(Stratum)
&&(VoxelForgeCore::IsNativeCaveFieldStratum(Stratum)
?Stratum.passageCapabilities.hasNativeCaveField
:Stratum.passageCapabilities.hasNativeLatticeField))
{
Bound.Kind=FBoundStratumField::EKind::Caves;
Bound.Evaluator.emplace<FCavesFieldAdapter>(
@@ -1819,14 +1819,28 @@ public:
float ApplyResolvedStrateComposition(float density,float X,float Y,float Z) const
{
const float graphDensity=ApplyResolvedCavernGraph(density,X,Y,Z);
const float composed=ApplyResolvedStratePassageCarves(
ApplyResolvedStrateBoundaryBand(graphDensity,X,Y,Z),X,Y,Z);
const float stamped=StampRuntime.empty()?composed:ApplyResolvedSdfStamps(composed,X,Y,Z);
const auto* bound=FindBoundStratumForManagerZ(Z);
const bool nativeLattice=bound&&bound->Resolved
&&VoxelForgeCore::IsNativeLatticeFieldStratum(*bound->Resolved)
&&bound->Resolved->passageCapabilities.hasNativeLatticeField;
// The native lattice field is a complete host-rock SDF: it owns both the
// voids and the surrounding solid. Replacing its air-side distances with
// the generic stratum transition distance creates a discontinuity at a
// mouth that crosses a wide transition band. Keep that opt-in field whole;
// its host-rock value already supplies the ceiling and bedrock.
const float boundary=nativeLattice?graphDensity
:ApplyResolvedStrateBoundaryBand(graphDensity,X,Y,Z);
// The native lattice owns its resolved arrival/departure portals and their
// supported spine. Reapplying legacy passage carves here can erase the
// tread immediately above a broad legacy mouth or support column.
const float composed=nativeLattice?boundary
:ApplyResolvedStratePassageCarves(boundary,X,Y,Z);
const float stamped=StampRuntime.empty()?composed:ApplyResolvedSdfStamps(composed,X,Y,Z);
if(bound&&bound->Kind==FBoundStratumField::EKind::Caves
&&bound->Resolved&&bound->Resolved->recipeId=="Core.Caves.PrimitiveField"
&&bound->Resolved->recipeVersion==1
&&bound->Resolved->passageCapabilities.hasNativeCaveField)
&&bound->Resolved&&VoxelForgeCore::HasNativeGraphField(*bound->Resolved)
&&(VoxelForgeCore::IsNativeCaveFieldStratum(*bound->Resolved)
?bound->Resolved->passageCapabilities.hasNativeCaveField
:bound->Resolved->passageCapabilities.hasNativeLatticeField))
return stamped;
// The legacy landmark demo retains its compatibility floor cap. Native caves
// already combine each floor with its wall before the single void carve above.
@@ -3040,7 +3054,9 @@ public:
if(NativeFloatingIslandDensityAt(X,Y,Z,Density))return "FloatingIslands-native";
const auto* Bound=FindBoundStratumForZ(Z);
if(Bound&&Bound->Kind==FBoundStratumField::EKind::Caves
&&NativeSurfaceDensityAt(X,Y,Z,Density))return "Caves-native";
&&NativeSurfaceDensityAt(X,Y,Z,Density))
return Bound->Resolved&&VoxelForgeCore::IsNativeLatticeFieldStratum(*Bound->Resolved)
?"Lattice-native":"Caves-native";
if(NativeSurfaceDensityAt(X,Y,Z,Density))return "SurfaceWorld-native";
if(UsesLegacySurfaceField(X,Y,Z))return "SurfaceWorld-legacy";
if(Bound&&Bound->Resolved)
@@ -3162,7 +3178,7 @@ public:
}
bool bHasLegacySurfaceSample=false;
bool bHasNativeIslandSample=false;
bool bHasNativeCavesSample=false;
bool bHasNativeGraphSample=false;
std::array<float,8> NativeIslandDensity{};
std::array<bool,8> HasNativeIslandSample{};
for(int32 Lane=0;Lane<Count;++Lane)
@@ -3172,13 +3188,13 @@ public:
const float SampleZ=static_cast<float>(Z);
bHasLegacySurfaceSample|=UsesLegacySurfaceField(SampleX,SampleY,SampleZ);
const auto* bound=FindBoundStratumForZ(SampleZ);
bHasNativeCavesSample|=bound
bHasNativeGraphSample|=bound
&&bound->Kind==FBoundStratumField::EKind::Caves;
HasNativeIslandSample[static_cast<std::size_t>(Lane)]=NativeFloatingIslandDensityAt(
SampleX,SampleY,SampleZ,NativeIslandDensity[static_cast<std::size_t>(Lane)]);
bHasNativeIslandSample|=HasNativeIslandSample[static_cast<std::size_t>(Lane)];
}
if(bHasLegacySurfaceSample||bHasNativeIslandSample||bHasNativeCavesSample)
if(bHasLegacySurfaceSample||bHasNativeIslandSample||bHasNativeGraphSample)
{
for(int32 Lane=0;Lane<Count;++Lane)
{
@@ -3315,14 +3331,25 @@ private:
{
const VoxelForgeCore::ResolvedCavernRoomV1* room=nullptr;
const VoxelForgeCore::ResolvedCavernEdgeV1* edge=nullptr;
bool nativeCaves=false;
bool nativeGraph=false;
std::array<std::int64_t,3> boundsMinimumMicrometres{},boundsMaximumMicrometres{};
std::array<double,3> centerMetres{},halfExtentsMetres{};
struct FSegment
{
std::array<double,3> start{},end{},minimum{},maximum{};
};
struct FSegmentNode
{
std::array<double,3> minimum{},maximum{};
std::size_t first=0,end=0;
int left=-1,right=-1;
};
std::vector<FSegment> segments;
std::vector<std::uint32_t> segmentOrder;
std::vector<FSegmentNode> segmentNodes;
double minimumFloorMetres=std::numeric_limits<double>::infinity();
double maximumFloorMetres=-std::numeric_limits<double>::infinity();
double maximumSegmentGrade=0.0;
std::array<float,3> centerVoxels{},halfExtentsVoxels{};
std::array<std::array<float,3>,4> controlPointsVoxels{};
float floorVoxels=0.0f;
@@ -3753,22 +3780,22 @@ private:
if(!ResolvedLayout||!Owner||Owner->CoreVoxelSizeMicrons==0
||ResolvedLayout->cavernGraphVocabularyVersion
!=VoxelForgeCore::ResolvedLayoutCavernGraphVocabularyVersionV1)return;
const auto isNativeCavesStrate=[this](std::int32_t strateIndex)
const auto isNativeGraphStrate=[this](std::int32_t strateIndex)
{
const auto found=std::find_if(ResolvedLayout->strates.begin(),
ResolvedLayout->strates.end(),[strateIndex](const auto& stratum)
{return stratum.strateIndex==strateIndex;});
return found!=ResolvedLayout->strates.end()
&&found->generatorKind=="Caves"
&&found->recipeId=="Core.Caves.PrimitiveField"
&&found->recipeVersion==1
&&found->passageCapabilities.hasNativeCaveField;
&&VoxelForgeCore::HasNativeGraphField(*found)
&&(VoxelForgeCore::IsNativeCaveFieldStratum(*found)
?found->passageCapabilities.hasNativeCaveField
:found->passageCapabilities.hasNativeLatticeField);
};
const float micronsPerVoxel=static_cast<float>(Owner->CoreVoxelSizeMicrons);
for(const auto& room:ResolvedLayout->cavernRooms)
{
FCavernRuntimeFeature runtime;runtime.room=&room;
runtime.nativeCaves=isNativeCavesStrate(room.strateIndex);
runtime.nativeGraph=isNativeGraphStrate(room.strateIndex);
runtime.boundsMinimumMicrometres=room.boundsMinimumMicrometres;
runtime.boundsMaximumMicrometres=room.boundsMaximumMicrometres;
for(std::size_t axis=0;axis<3;++axis)
@@ -3794,7 +3821,7 @@ private:
for(const auto& edge:ResolvedLayout->cavernEdges)
{
FCavernRuntimeFeature runtime;runtime.edge=&edge;
runtime.nativeCaves=isNativeCavesStrate(edge.strateIndex);
runtime.nativeGraph=isNativeGraphStrate(edge.strateIndex);
runtime.boundsMinimumMicrometres=edge.boundsMinimumMicrometres;
runtime.boundsMaximumMicrometres=edge.boundsMaximumMicrometres;
for(std::size_t point=0;point<4;++point)
@@ -3827,8 +3854,69 @@ private:
segment.minimum[axis]=std::min(segment.start[axis],segment.end[axis]);
segment.maximum[axis]=std::max(segment.start[axis],segment.end[axis]);
}
runtime.minimumFloorMetres=std::min(runtime.minimumFloorMetres,
std::min(segment.start[2],segment.end[2]));
runtime.maximumFloorMetres=std::max(runtime.maximumFloorMetres,
std::max(segment.start[2],segment.end[2]));
const double horizontal=std::hypot(segment.end[0]-segment.start[0],
segment.end[1]-segment.start[1]);
if(horizontal>1.0e-9)
runtime.maximumSegmentGrade=std::max(runtime.maximumSegmentGrade,
std::abs((segment.end[2]-segment.start[2])/horizontal));
runtime.segments.push_back(segment);
}
runtime.segmentOrder.resize(runtime.segments.size());
for(std::size_t index=0;index<runtime.segmentOrder.size();++index)
runtime.segmentOrder[index]=static_cast<std::uint32_t>(index);
if(!runtime.segmentOrder.empty())
{
const auto buildSegmentNode=[&](const auto& self,std::size_t first,
std::size_t end)->int
{
FCavernRuntimeFeature::FSegmentNode node;
node.first=first;node.end=end;
node.minimum.fill(std::numeric_limits<double>::infinity());
node.maximum.fill(-std::numeric_limits<double>::infinity());
for(std::size_t offset=first;offset<end;++offset)
{
const auto& segment=runtime.segments[
runtime.segmentOrder[offset]];
for(std::size_t axis=0;axis<3;++axis)
{
node.minimum[axis]=std::min(node.minimum[axis],segment.minimum[axis]);
node.maximum[axis]=std::max(node.maximum[axis],segment.maximum[axis]);
}
}
const int nodeIndex=static_cast<int>(runtime.segmentNodes.size());
runtime.segmentNodes.push_back(node);
if(end-first>4)
{
std::size_t splitAxis=0;
for(std::size_t axis=1;axis<3;++axis)
if(node.maximum[axis]-node.minimum[axis]
>node.maximum[splitAxis]-node.minimum[splitAxis])
splitAxis=axis;
const std::size_t middle=first+(end-first)/2;
std::nth_element(runtime.segmentOrder.begin()+first,
runtime.segmentOrder.begin()+middle,
runtime.segmentOrder.begin()+end,
[&](std::uint32_t a,std::uint32_t b)
{
const auto& left=runtime.segments[a];
const auto& right=runtime.segments[b];
const double ca=left.minimum[splitAxis]+left.maximum[splitAxis];
const double cb=right.minimum[splitAxis]+right.maximum[splitAxis];
return ca==cb?a<b:ca<cb;
});
const int left=self(self,first,middle);
const int right=self(self,middle,end);
runtime.segmentNodes[nodeIndex].left=left;
runtime.segmentNodes[nodeIndex].right=right;
}
return nodeIndex;
};
buildSegmentNode(buildSegmentNode,0,runtime.segmentOrder.size());
}
CavernRuntime.push_back(runtime);
}
std::stable_sort(CavernRuntime.begin(),CavernRuntime.end(),[](const auto& a,const auto& b)
@@ -3838,8 +3926,8 @@ private:
const std::int32_t rightStrate=b.room?b.room->strateIndex
:b.edge?b.edge->strateIndex:-1;
if(leftStrate!=rightStrate)return leftStrate<rightStrate;
if(a.nativeCaves!=b.nativeCaves)return a.nativeCaves;
if(!a.nativeCaves)return false;
if(a.nativeGraph!=b.nativeGraph)return a.nativeGraph;
if(!a.nativeGraph)return false;
const std::string& left=a.room?a.room->stableId:a.edge->stableId;
const std::string& right=b.room?b.room->stableId:b.edge->stableId;
return left<right;
@@ -5106,9 +5194,10 @@ public:
}
else if(Candidate->Kind==FBoundStratumField::EKind::Caves)
{
if(!Candidate->Resolved||Candidate->Resolved->recipeId!="Core.Caves.PrimitiveField"
||Candidate->Resolved->recipeVersion!=1
||!Candidate->Resolved->passageCapabilities.hasNativeCaveField
if(!Candidate->Resolved||!VoxelForgeCore::HasNativeGraphField(*Candidate->Resolved)
||(VoxelForgeCore::IsNativeCaveFieldStratum(*Candidate->Resolved)
?!Candidate->Resolved->passageCapabilities.hasNativeCaveField
:!Candidate->Resolved->passageCapabilities.hasNativeLatticeField)
||!std::get_if<FCavesFieldAdapter>(&Candidate->Evaluator))return false;
}
else return false;
@@ -5144,6 +5233,11 @@ public:
FMetricInterval caveVoid{std::numeric_limits<double>::infinity(),
std::numeric_limits<double>::infinity(),true};
bool haveFeature=false;
double latticeFloorSupportLowerBound=std::numeric_limits<double>::infinity();
const auto* resolvedStratum=FindResolvedLayoutStratum(strateIndex);
const bool nativeLattice=resolvedStratum
&&VoxelForgeCore::IsNativeLatticeFieldStratum(*resolvedStratum)
&&resolvedStratum->passageCapabilities.hasNativeLatticeField;
for(const std::uint32_t index:candidates)
{
if(index>=CavernRuntime.size())continue;
@@ -5185,18 +5279,32 @@ public:
if(!(radius>0.0&&height>0.0))return {0.0,0.0,false};
double tubeMinimum=std::numeric_limits<double>::infinity();
double tubeMaximum=std::numeric_limits<double>::infinity();
double floorMinimum=std::numeric_limits<double>::infinity();
double floorMaximum=-std::numeric_limits<double>::infinity();
double maximumGrade=0.0;
for(const auto& segment:feature.segments)
const std::array<double,3> inverseScale={1.0/radius,1.0/radius,
1.0/height};
const std::array<double,3> boxMinimum={lo[0]*inverseScale[0],
lo[1]*inverseScale[1],lo[2]*inverseScale[2]};
const std::array<double,3> boxMaximum={hi[0]*inverseScale[0],
hi[1]*inverseScale[1],hi[2]*inverseScale[2]};
const double scale=std::min(radius,height);
const auto nodeLowerBound=[&](const FCavernRuntimeFeature::FSegmentNode& node)
{
const std::array<double,3> inverseScale={1.0/radius,1.0/radius,
1.0/height};
std::array<double,3> boxMinimum{},boxMaximum{},segmentStart{},segmentEnd{};
double gapSquared=0.0;
for(std::size_t axis=0;axis<3;++axis)
{
const double low=node.minimum[axis]*inverseScale[axis];
const double high=node.maximum[axis]*inverseScale[axis];
const double gap=high<boxMinimum[axis]?boxMinimum[axis]-high
:low>boxMaximum[axis]?low-boxMaximum[axis]:0.0;
gapSquared+=gap*gap;
}
return (std::sqrt(gapSquared)-1.0)*scale;
};
const auto evaluateSegment=[&](std::uint32_t segmentIndex)
{
const auto& segment=feature.segments[segmentIndex];
std::array<double,3> segmentStart{},segmentEnd{};
for(std::size_t axis=0;axis<3;++axis)
{
boxMinimum[axis]=lo[axis]*inverseScale[axis];
boxMaximum[axis]=hi[axis]*inverseScale[axis];
segmentStart[axis]=segment.start[axis]*inverseScale[axis];
segmentEnd[axis]=segment.end[axis]*inverseScale[axis];
}
@@ -5237,19 +5345,33 @@ public:
farthestSquared+=farthest*farthest;
}
const double distanceUpper=std::sqrt(farthestSquared);
const double scale=std::min(radius,height);
tubeMinimum=std::min(tubeMinimum,(distanceLower-1.0)*scale);
tubeMaximum=std::min(tubeMaximum,(distanceUpper-1.0)*scale);
floorMinimum=std::min(floorMinimum,
std::min(segment.start[2],segment.end[2]));
floorMaximum=std::max(floorMaximum,
std::max(segment.start[2],segment.end[2]));
const double horizontal=std::hypot(segment.end[0]-segment.start[0],
segment.end[1]-segment.start[1]);
if(horizontal>1.0e-9)
maximumGrade=std::max(maximumGrade,
std::abs((segment.end[2]-segment.start[2])/horizontal));
}
};
if(feature.segmentNodes.empty())return {0.0,0.0,false};
const auto visitNode=[&](const auto& self,int nodeIndex)->void
{
if(nodeIndex<0||static_cast<std::size_t>(nodeIndex)>=feature.segmentNodes.size())return;
const auto& node=feature.segmentNodes[static_cast<std::size_t>(nodeIndex)];
if(nodeLowerBound(node)>tubeMaximum)return;
if(node.left<0)
{
for(std::size_t offset=node.first;offset<node.end;++offset)
evaluateSegment(feature.segmentOrder[offset]);
return;
}
const double leftBound=nodeLowerBound(feature.segmentNodes[
static_cast<std::size_t>(node.left)]);
const double rightBound=nodeLowerBound(feature.segmentNodes[
static_cast<std::size_t>(node.right)]);
if(leftBound<=rightBound)
{self(self,node.left);self(self,node.right);}
else {self(self,node.right);self(self,node.left);}
};
visitNode(visitNode,0);
const double floorMinimum=feature.minimumFloorMetres;
const double floorMaximum=feature.maximumFloorMetres;
const double maximumGrade=feature.maximumSegmentGrade;
if(!std::isfinite(tubeMinimum)||!std::isfinite(tubeMaximum)
||!std::isfinite(floorMinimum)||!std::isfinite(floorMaximum))
return {0.0,0.0,false};
@@ -5267,6 +5389,23 @@ public:
SmoothMaxMetres(tube.maximum,floor.maximum,width),true};
}
else return {0.0,0.0,false};
if(nativeLattice)
{
const double supportDepth=feature.edge
?feature.edge->floorSupportDepthMicrometres/1000000.0:0.0;
const double floorMinimum=feature.edge
?feature.minimumFloorMetres:std::numeric_limits<double>::infinity();
const double floorMaximum=feature.edge
?feature.maximumFloorMetres:-std::numeric_limits<double>::infinity();
const bool overlapsXY=hi[0]>=feature.boundsMinimumMicrometres[0]/1.0e6
&&lo[0]<=feature.boundsMaximumMicrometres[0]/1.0e6
&&hi[1]>=feature.boundsMinimumMicrometres[1]/1.0e6
&&lo[1]<=feature.boundsMaximumMicrometres[1]/1.0e6;
if(supportDepth>0.0&&overlapsXY
&&hi[2]>=floorMinimum-supportDepth&&lo[2]<=floorMaximum)
latticeFloorSupportLowerBound=std::min(latticeFloorSupportLowerBound,
std::max(-supportDepth,lo[2]-floorMaximum));
}
if(!std::isfinite(featureVoid.minimum)||!std::isfinite(featureVoid.maximum))
return {0.0,0.0,false};
if(!haveFeature)
@@ -5276,8 +5415,12 @@ public:
else
{
const double width=feature.room
?feature.room->smoothWidthMicrometres/1000000.0
:feature.edge->smoothWidthMicrometres/1000000.0;
?(feature.room->unionWidthMicrometres>0
?feature.room->unionWidthMicrometres
:feature.room->smoothWidthMicrometres)/1000000.0
:(feature.edge->unionWidthMicrometres>0
?feature.edge->unionWidthMicrometres
:feature.edge->smoothWidthMicrometres)/1000000.0;
caveVoid.minimum=SmoothMinMetres(caveVoid.minimum,featureVoid.minimum,width);
caveVoid.maximum=SmoothMinMetres(caveVoid.maximum,featureVoid.maximum,width);
}
@@ -5289,6 +5432,11 @@ public:
result.minimum=std::max(HostRockMetres,-caveVoid.maximum);
result.maximum=std::max(HostRockMetres,-caveVoid.minimum);
}
// The final lattice field owns an extra support cap after feature union.
// Lower only the interval minimum when a box could touch that cap; the
// untouched maximum remains a sound bound when only part of the box does.
if(std::isfinite(latticeFloorSupportLowerBound))
result.minimum=std::min(result.minimum,latticeFloorSupportLowerBound);
// Cover floating-point rounding in interval endpoints and the field's fixed-point
// coordinate conversion while keeping the interval tight compared with one micron.
constexpr double OutwardPaddingMetres=1.0e-6;
@@ -5356,9 +5504,10 @@ public:
bIslandOtherStrateOverlap=true;
if(CaveBound&&CaveBound!=Bound)bBadPlan=true;
CaveBound=Bound;
if(!Bound->Resolved||Bound->Resolved->recipeId!="Core.Caves.PrimitiveField"
||Bound->Resolved->recipeVersion!=1
||!Bound->Resolved->passageCapabilities.hasNativeCaveField
if(!Bound->Resolved||!VoxelForgeCore::HasNativeGraphField(*Bound->Resolved)
||(VoxelForgeCore::IsNativeCaveFieldStratum(*Bound->Resolved)
?!Bound->Resolved->passageCapabilities.hasNativeCaveField
:!Bound->Resolved->passageCapabilities.hasNativeLatticeField)
||!std::get_if<FCavesFieldAdapter>(&Bound->Evaluator))bBadPlan=true;
}
else
@@ -6768,9 +6917,10 @@ private:
const auto* bound=FindBoundStratumForManagerZ(Z);
if(!bound)return density;
if(bound->Kind==FBoundStratumField::EKind::Caves
&&bound->Resolved&&bound->Resolved->recipeId=="Core.Caves.PrimitiveField"
&&bound->Resolved->recipeVersion==1
&&bound->Resolved->passageCapabilities.hasNativeCaveField)
&&bound->Resolved&&VoxelForgeCore::HasNativeGraphField(*bound->Resolved)
&&(VoxelForgeCore::IsNativeCaveFieldStratum(*bound->Resolved)
?bound->Resolved->passageCapabilities.hasNativeCaveField
:bound->Resolved->passageCapabilities.hasNativeLatticeField))
return ApplyResolvedNativeCavesField(density,X,Y,Z,*bound,tileQueries,scoped);
const double micronsPerVoxel=Owner->CoreVoxelSizeMicrons;
const std::array<double,3> worldMicrometres={X*micronsPerVoxel,
@@ -6937,6 +7087,10 @@ private:
candidates=&localCandidates;
}
double caveVoid=std::numeric_limits<double>::infinity();
double latticeFloorSupportMinimum=std::numeric_limits<double>::infinity();
const bool nativeLattice=bound.Resolved
&&VoxelForgeCore::IsNativeLatticeFieldStratum(*bound.Resolved)
&&bound.Resolved->passageCapabilities.hasNativeLatticeField;
for(const std::uint32_t index:*candidates)
{
if(index>=CavernRuntime.size())continue;
@@ -6963,9 +7117,16 @@ private:
else if(feature.edge&&!feature.segments.empty())
{
double tube=std::numeric_limits<double>::infinity();
double nearestFloor=0.0,nearestGrade=0.0;
for(const auto& segment:feature.segments)
double nearestFloor=0.0,nearestGrade=0.0,nearestRadial=0.0;
const double radius=feature.edge->boreRadiusMicrometres/1000000.0;
const double height=feature.edge->boreHeightMicrometres/1000000.0;
if(!(radius>0.0&&height>0.0))continue;
const double minScale=std::min(radius,height);
std::uint32_t nearestSegment=std::numeric_limits<std::uint32_t>::max();
const auto evaluateSegment=[&](std::uint32_t segmentIndex)
{
if(segmentIndex>=feature.segments.size())return;
const auto& segment=feature.segments[segmentIndex];
double lengthSquared=0.0,dot=0.0;
for(std::size_t axis=0;axis<3;++axis)
{
@@ -6983,22 +7144,64 @@ private:
if(axis<2)radialSquared+=delta*delta;
else vertical=delta;
}
const double radius=feature.edge->boreRadiusMicrometres/1000000.0;
const double height=feature.edge->boreHeightMicrometres/1000000.0;
if(!(radius>0.0&&height>0.0))continue;
const double normalized=std::sqrt(radialSquared/(radius*radius)
+vertical*vertical/(height*height));
const double distance=(normalized-1.0)*std::min(radius,height);
if(distance<tube)
if(distance<tube||(distance==tube&&segmentIndex<nearestSegment))
{
tube=distance;
tube=distance;nearestSegment=segmentIndex;
nearestFloor=segment.start[2]+t*(segment.end[2]-segment.start[2]);
nearestRadial=std::sqrt(radialSquared);
const double horizontal=std::hypot(
segment.end[0]-segment.start[0],segment.end[1]-segment.start[1]);
nearestGrade=horizontal>1.0e-9
?(segment.end[2]-segment.start[2])/horizontal:0.0;
}
};
const auto nodeLowerBound=[&](const FCavernRuntimeFeature::FSegmentNode& node)
{
double gapSquared=0.0;
for(std::size_t axis=0;axis<3;++axis)
{
const double scale=axis==2?height:radius;
const double q=point[axis]/scale;
const double low=node.minimum[axis]/scale;
const double high=node.maximum[axis]/scale;
const double gap=q<low?low-q:q>high?q-high:0.0;
gapSquared+=gap*gap;
}
return (std::sqrt(gapSquared)-1.0)*minScale;
};
if(!feature.segmentNodes.empty())
{
const auto visitNode=[&](const auto& self,int nodeIndex)->void
{
if(nodeIndex<0||static_cast<std::size_t>(nodeIndex)>=feature.segmentNodes.size())return;
const auto& node=feature.segmentNodes[static_cast<std::size_t>(nodeIndex)];
if(nodeLowerBound(node)>tube)return;
if(node.left<0)
{
for(std::size_t offset=node.first;offset<node.end;++offset)
evaluateSegment(feature.segmentOrder[offset]);
return;
}
const double leftBound=nodeLowerBound(feature.segmentNodes[
static_cast<std::size_t>(node.left)]);
const double rightBound=nodeLowerBound(feature.segmentNodes[
static_cast<std::size_t>(node.right)]);
if(leftBound<=rightBound)
{self(self,node.left);self(self,node.right);}
else {self(self,node.right);self(self,node.left);}
};
visitNode(visitNode,0);
}
else for(std::uint32_t segment=0;segment<feature.segments.size();++segment)
evaluateSegment(segment);
const double supportDepth=feature.edge->floorSupportDepthMicrometres/1000000.0;
if(nativeLattice&&supportDepth>0.0&&nearestRadial<radius-0.12
&&point[2]<nearestFloor&&nearestFloor-point[2]<=supportDepth)
latticeFloorSupportMinimum=std::min(latticeFloorSupportMinimum,
(point[2]-nearestFloor)/std::sqrt(1.0+nearestGrade*nearestGrade));
const double floor=(nearestFloor-point[2])
/std::sqrt(1.0+nearestGrade*nearestGrade);
const double width=feature.edge->smoothWidthMicrometres/1000000.0;
@@ -7007,8 +7210,13 @@ private:
if(!std::isfinite(featureVoid))continue;
if(!std::isfinite(caveVoid))caveVoid=featureVoid;
else caveVoid=SmoothMinMetres(caveVoid,featureVoid,
feature.room?feature.room->smoothWidthMicrometres/1000000.0
:feature.edge->smoothWidthMicrometres/1000000.0);
feature.room
?(feature.room->unionWidthMicrometres>0
?feature.room->unionWidthMicrometres
:feature.room->smoothWidthMicrometres)/1000000.0
:(feature.edge->unionWidthMicrometres>0
?feature.edge->unionWidthMicrometres
:feature.edge->smoothWidthMicrometres)/1000000.0);
}
// A versioned native caves recipe owns a solid host-rock field. The
// resolved interval oracle uses the same finite -32 m solid value; using
@@ -7016,8 +7224,13 @@ private:
// terrain detail into the cave floor and invalidate those proofs.
constexpr double HostRockMetres=-32.0;
const double hostDistance=HostRockMetres;
const double composed=std::isfinite(caveVoid)
double composed=std::isfinite(caveVoid)
?SmoothMaxMetres(hostDistance,-caveVoid,0.0):hostDistance;
// Keep the floor support owned by the lattice route after smooth-unioning
// neighboring room and corridor voids. This cap is limited to each record's
// explicit support depth so separated helix turns remain independent.
if(std::isfinite(latticeFloorSupportMinimum))
composed=std::min(composed,latticeFloorSupportMinimum);
return static_cast<float>(composed/metresPerVoxel);
}