passages: contiguous BVH node ranges + child-bound reuse (L83); scaling and serial floor measured
Exact through LOD2 (all near tile hashes equal L82). W8 LOD0-2: SW 1.09->1.06, FI 2.47->2.34, TN 2.39->2.43 (noise), VS 1.20->1.18 s. Fast tier PASS. Scaling W4/W8/W12/W16 (LOD0-2, FI): 3.59 / 2.48 / 2.33 / 2.34 s - flattens past W8-W12. Estimated infinite-worker floor ~1.0 s FI/TN = shape compile (0.35-0.41 s, not overlapped: no shape-free tiles in these views) + slowest single LOD0 tile service (0.51-0.59 s). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016dhxM43dnWvUu2B5Ph1iG1
This commit is contained in:
1 parent
f572108dc4
commit
a81b5b7d06
8 files changed
+800
-22
No files matched your search
@@ -4055,6 +4055,7 @@ private:
|
||||
std::array<double,3> minimum{},maximum{};
|
||||
double maximumRadius=0.0;
|
||||
std::size_t minimumSegment=0,maximumSegment=0;
|
||||
bool segmentRangeContiguous=false;
|
||||
std::vector<std::size_t> segments;
|
||||
int left=-1,right=-1;
|
||||
};
|
||||
@@ -4873,6 +4874,8 @@ private:
|
||||
node.maximumSegment=*std::max_element(segments.begin(),segments.end());
|
||||
node.segments=segments;
|
||||
std::sort(node.segments.begin(),node.segments.end());
|
||||
node.segmentRangeContiguous=node.segments.size()
|
||||
==node.maximumSegment-node.minimumSegment+1;
|
||||
const int nodeIndex=static_cast<int>(PassageNearestNodes[passageIndex].size());
|
||||
PassageNearestNodes[passageIndex].push_back(std::move(node));
|
||||
if(segments.size()>4)
|
||||
@@ -4918,6 +4921,10 @@ private:
|
||||
bool hasCandidate=false;
|
||||
if(node.left<0)
|
||||
{
|
||||
if(node.segmentRangeContiguous)
|
||||
hasCandidate=static_cast<std::ptrdiff_t>(node.maximumSegment)>=first
|
||||
&&static_cast<std::ptrdiff_t>(node.minimumSegment)<end;
|
||||
else
|
||||
for(const std::size_t segment:node.segments)
|
||||
hasCandidate=hasCandidate
|
||||
||(static_cast<std::ptrdiff_t>(segment)>=first
|
||||
@@ -5510,8 +5517,8 @@ private:
|
||||
template<typename FVisit>
|
||||
void VisitNearestPassageSpatialNode(std::size_t passageIndex,int nodeIndex,
|
||||
std::size_t first,std::size_t end,double qx,double qy,double qz,int priority,
|
||||
const std::vector<std::uint8_t>* activeNodes,double& bestDistance,
|
||||
FVisit& visit) const
|
||||
const std::vector<std::uint8_t>* activeNodes,double knownLowerBound,
|
||||
double& bestDistance,FVisit& visit) const
|
||||
{
|
||||
if(passageIndex>=PassageNearestNodes.size()||nodeIndex<0)return;
|
||||
const auto& nodes=PassageNearestNodes[passageIndex];
|
||||
@@ -5528,8 +5535,7 @@ private:
|
||||
candidate=std::lower_bound(node.segments.begin(),node.segments.end(),first);
|
||||
if(candidate==node.segments.end()||*candidate>=end)return;
|
||||
}
|
||||
const double lowerBound=PassageNearestNodeLowerBound(node,qx,qy,qz);
|
||||
if(lowerBound>bestDistance)return;
|
||||
if(knownLowerBound>bestDistance)return;
|
||||
if(node.left<0)
|
||||
{
|
||||
for(auto it=candidate;it!=node.segments.end();++it)
|
||||
@@ -5554,9 +5560,11 @@ private:
|
||||
const int nearChild=leftBound<=rightBound?node.left:node.right;
|
||||
const int farChild=leftBound<=rightBound?node.right:node.left;
|
||||
VisitNearestPassageSpatialNode(passageIndex,nearChild,first,end,qx,qy,qz,
|
||||
priority,activeNodes,bestDistance,visit);
|
||||
priority,activeNodes,leftBound<=rightBound?leftBound:rightBound,
|
||||
bestDistance,visit);
|
||||
VisitNearestPassageSpatialNode(passageIndex,farChild,first,end,qx,qy,qz,
|
||||
priority,activeNodes,bestDistance,visit);
|
||||
priority,activeNodes,leftBound<=rightBound?rightBound:leftBound,
|
||||
bestDistance,visit);
|
||||
}
|
||||
|
||||
template<typename FVisit>
|
||||
@@ -5570,9 +5578,18 @@ private:
|
||||
const auto* tileQueries=ActivePassageTileQueries;
|
||||
const auto* activeNodes=tileQueries&&tileQueries->matches(*this)
|
||||
?tileQueries->segmentRangeNodeMask(passageIndex,first,last+1,priority):nullptr;
|
||||
if(activeNodes&&(activeNodes->empty()||!(*activeNodes)[0]))return;
|
||||
if(!activeNodes)
|
||||
{
|
||||
const auto& root=PassageNearestNodes[passageIndex][0];
|
||||
if(root.maximumSegment<static_cast<std::size_t>(first)
|
||||
||root.minimumSegment>=static_cast<std::size_t>(last+1))return;
|
||||
}
|
||||
const double rootLowerBound=PassageNearestNodeLowerBound(
|
||||
PassageNearestNodes[passageIndex][0],qx,qy,qz);
|
||||
VisitNearestPassageSpatialNode(passageIndex,0,static_cast<std::size_t>(first),
|
||||
static_cast<std::size_t>(last+1),qx,qy,qz,priority,activeNodes,
|
||||
bestDistance,callback);
|
||||
rootLowerBound,bestDistance,callback);
|
||||
}
|
||||
|
||||
bool PassagePotentialWithinNode(std::size_t passageIndex,int nodeIndex,
|
||||
@@ -5581,13 +5598,18 @@ private:
|
||||
{
|
||||
if(passageIndex>=PassageNearestNodes.size()||nodeIndex<0)return false;
|
||||
const auto& nodes=PassageNearestNodes[passageIndex];
|
||||
const auto& node=nodes[static_cast<std::size_t>(nodeIndex)];
|
||||
const std::size_t nodeOffset=static_cast<std::size_t>(nodeIndex);
|
||||
if(nodeOffset>=nodes.size())return false;
|
||||
const auto& node=nodes[nodeOffset];
|
||||
if(node.maximumSegment<first||node.minimumSegment>=end)return false;
|
||||
const bool allSegmentsInRange=first<=node.minimumSegment
|
||||
&&node.maximumSegment<end;
|
||||
const auto candidate=allSegmentsInRange?node.segments.begin()
|
||||
:std::lower_bound(node.segments.begin(),node.segments.end(),first);
|
||||
if(candidate==node.segments.end()||*candidate>=end)return false;
|
||||
if(!node.segmentRangeContiguous)
|
||||
{
|
||||
const bool allSegmentsInRange=first<=node.minimumSegment
|
||||
&&node.maximumSegment<end;
|
||||
const auto candidate=allSegmentsInRange?node.segments.begin()
|
||||
:std::lower_bound(node.segments.begin(),node.segments.end(),first);
|
||||
if(candidate==node.segments.end()||*candidate>=end)return false;
|
||||
}
|
||||
if(PassageNearestNodeLowerBound(node,qx,qy,qz)>signedDistanceLimit)return false;
|
||||
if(node.left<0)return true;
|
||||
const double leftBound=PassageNearestNodeLowerBound(
|
||||
@@ -5691,10 +5713,11 @@ private:
|
||||
{
|
||||
const auto possible=[&](std::ptrdiff_t first,std::ptrdiff_t last)
|
||||
{
|
||||
return first<=last&&passageIndex<PassageNearestNodes.size()
|
||||
&&!PassageNearestNodes[passageIndex].empty()
|
||||
&&PassagePotentialWithinNode(passageIndex,0,static_cast<std::size_t>(first),
|
||||
static_cast<std::size_t>(last+1),qx,qy,qz,signedDistanceLimit);
|
||||
if(first>last||passageIndex>=PassageNearestNodes.size()
|
||||
||PassageNearestNodes[passageIndex].empty())return false;
|
||||
return PassagePotentialWithinNode(passageIndex,0,
|
||||
static_cast<std::size_t>(first),static_cast<std::size_t>(last+1),
|
||||
qx,qy,qz,signedDistanceLimit);
|
||||
};
|
||||
return possible(carveBegin,carveEnd)
|
||||
||possible(0,std::min<std::ptrdiff_t>(8,lowerMouthIndex)-1)
|
||||
@@ -5710,11 +5733,15 @@ private:
|
||||
const auto& nodes=PassageNearestNodes[passageIndex];
|
||||
const auto& node=nodes[static_cast<std::size_t>(nodeIndex)];
|
||||
if(node.maximumSegment<first||node.minimumSegment>=end)return false;
|
||||
const bool allSegmentsInRange=first<=node.minimumSegment
|
||||
&&node.maximumSegment<end;
|
||||
auto candidate=allSegmentsInRange?node.segments.begin()
|
||||
:std::lower_bound(node.segments.begin(),node.segments.end(),first);
|
||||
if(candidate==node.segments.end()||*candidate>=end)return false;
|
||||
auto candidate=node.segments.begin();
|
||||
if(!node.segmentRangeContiguous)
|
||||
{
|
||||
const bool allSegmentsInRange=first<=node.minimumSegment
|
||||
&&node.maximumSegment<end;
|
||||
candidate=allSegmentsInRange?node.segments.begin()
|
||||
:std::lower_bound(node.segments.begin(),node.segments.end(),first);
|
||||
if(candidate==node.segments.end()||*candidate>=end)return false;
|
||||
}
|
||||
const double xyReach=0.39*qPerMetre;
|
||||
if(qx+xyReach<node.minimum[0]||qx-xyReach>node.maximum[0]
|
||||
||qy+xyReach<node.minimum[1]||qy-xyReach>node.maximum[1])return false;
|
||||
|
||||
Reference in new issue
Block a user