passages: continuous floor h(s) along the dense route; shell-probe oracle fix (L115, v223)
Floor height from the planner profile h(s) by horizontal projection + arc-length interpolation; adjacent fine segments share endpoint values. Floor zero-crossing offsets max 7.8 mm (L114: up to 73 mm); rock-floor close-ups show no ribs. The 2 L114 shell misses were oracle false positives (points inside an overlapping bore); the oracle now checks every overlapping span; no gate relaxed. Fast tier PASS; Clang/GCC W1/W8/W12 deterministic. Speed regression grows: near-ready +17..+31% vs L109 (fine-segment/sample pairs 49.0M vs 19.8M). Not merged. 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
5e875ae504
commit
f403af1fc1
37 files changed
+2741
-183
No files matched your search
@@ -473,8 +473,9 @@ namespace VoxelForgeCore
|
||||
// Version 219 smooths passage XY while mapping each planned height chord over its sampled horizontal arc.
|
||||
// Version 220 adaptively samples passage curves and rounds open-air wall crests.
|
||||
// Version 221 ranks passage segments before floor shaping and preserves their signed exterior distance.
|
||||
// Version 222 selects the floor profile by centerline position, independent of tube radius.
|
||||
inline constexpr std::uint32_t WorldAssemblyEvaluatorVersion = 222;
|
||||
// Version 223 projects the floor onto one continuous arc-length profile and groups
|
||||
// dense passage samples into coarse tile candidates.
|
||||
inline constexpr std::uint32_t WorldAssemblyEvaluatorVersion = 223;
|
||||
|
||||
enum class FieldChannel : std::uint32_t
|
||||
{
|
||||
|
||||
@@ -256,6 +256,7 @@ public:
|
||||
struct FCandidateSegment
|
||||
{
|
||||
std::size_t segmentIndex=0;
|
||||
std::size_t segmentEndIndex=0;
|
||||
std::array<std::int64_t,3> minimumSubvoxels{},maximumSubvoxels{};
|
||||
std::array<std::int64_t,3> sweepMinimumSubvoxels{},sweepMaximumSubvoxels{};
|
||||
};
|
||||
@@ -330,6 +331,7 @@ public:
|
||||
const auto& bounds=shape.PassageFeatureBounds[featureIndex];
|
||||
FCandidateSegment candidate;
|
||||
candidate.segmentIndex=feature.segmentIndex;
|
||||
candidate.segmentEndIndex=feature.segmentEndIndex;
|
||||
candidate.minimumSubvoxels=bounds.minimumSubvoxels;
|
||||
candidate.maximumSubvoxels=bounds.maximumSubvoxels;
|
||||
candidate.sweepMinimumSubvoxels=bounds.minimumSubvoxels;
|
||||
@@ -1277,6 +1279,7 @@ public:
|
||||
|
||||
const std::ptrdiff_t lastIndex=static_cast<std::ptrdiff_t>(
|
||||
PassageSegmentData[passageIndex].size())-1;
|
||||
const auto& segments=PassageSegmentData[passageIndex];
|
||||
double bestDistance=std::numeric_limits<double>::infinity();
|
||||
double bestFloorCenterDistanceSq=std::numeric_limits<double>::infinity();
|
||||
const auto visitSegment=[&](std::size_t segmentIndex,int)
|
||||
@@ -1295,21 +1298,23 @@ public:
|
||||
const double ex=qx-cx,ey=qy-cy,ez=qz-cz;
|
||||
const double roundDistance=DeterministicSqrt(
|
||||
ex*ex+ey*ey+ez*ez)-radius;
|
||||
const double floorCenterDistanceSq=ex*ex+ey*ey+ez*ez;
|
||||
const double floorT=segment.horizontalLengthSq>1.0e-12
|
||||
?std::clamp(((qx-segment.a[0])*segment.delta[0]
|
||||
?(((qx-segment.a[0])*segment.delta[0]
|
||||
+(qy-segment.a[1])*segment.delta[1])
|
||||
/segment.horizontalLengthSq,0.0,1.0):t;
|
||||
const double floorRadius=segment.radiusA+floorT*segment.radiusDelta;
|
||||
/segment.horizontalLengthSq):t;
|
||||
const double floorTClamped=std::clamp(floorT,0.0,1.0);
|
||||
const double floorCenterDistanceSq=ex*ex+ey*ey+ez*ez;
|
||||
const double floorRadius=segment.radiusA
|
||||
+floorTClamped*segment.radiusDelta;
|
||||
const double floorDepth=PassageFlatFloorDepthSubvoxels(
|
||||
constants,segmentIndex,floorT,floorRadius,qPerMetre);
|
||||
constants,segmentIndex,floorTClamped,floorRadius,qPerMetre);
|
||||
const double floorCenterZ=PassageFlatFloorCenterZSubvoxels(
|
||||
constants,segmentIndex,floorT,segment,qx,qy,floorDepth,qPerMetre);
|
||||
constants,segments,segmentIndex,floorT,segment,
|
||||
qx,qy,floorDepth,qPerMetre);
|
||||
const double flatDistance=PassageFlatBottomDistance(
|
||||
static_cast<float>(roundDistance),floorCenterZ,qz,floorDepth,qPerMetre);
|
||||
// Radius-based tube selection can favor a wider downhill segment
|
||||
// and carry its lower floor plane backward. Select the floor profile
|
||||
// by the centerline position, independently of tube radius.
|
||||
// The profile uses the closest route projection's arc length. Tube
|
||||
// radius selects the bore shape only; it never selects floor height.
|
||||
if(floorCenterDistanceSq<bestFloorCenterDistanceSq
|
||||
||(floorCenterDistanceSq==bestFloorCenterDistanceSq
|
||||
&&segmentIndex<nearest.floorSegmentIndex))
|
||||
@@ -1365,14 +1370,18 @@ public:
|
||||
const double ex=qx-cx,ey=qy-cy,ez=qz-cz;
|
||||
const double roundDistance=DeterministicSqrt(ex*ex+ey*ey+ez*ez)-radius;
|
||||
const double floorT=segment.horizontalLengthSq>1.0e-12
|
||||
?std::clamp(((qx-segment.a[0])*segment.delta[0]
|
||||
?(((qx-segment.a[0])*segment.delta[0]
|
||||
+(qy-segment.a[1])*segment.delta[1])
|
||||
/segment.horizontalLengthSq,0.0,1.0):t;
|
||||
const double floorRadius=segment.radiusA+floorT*segment.radiusDelta;
|
||||
/segment.horizontalLengthSq):t;
|
||||
const double floorTClamped=std::clamp(floorT,0.0,1.0);
|
||||
const auto& segments=PassageSegmentData[passageIndex];
|
||||
const double floorRadius=segment.radiusA
|
||||
+floorTClamped*segment.radiusDelta;
|
||||
const double floorDepth=PassageFlatFloorDepthSubvoxels(
|
||||
constants,segmentIndex,floorT,floorRadius,qPerMetre);
|
||||
constants,segmentIndex,floorTClamped,floorRadius,qPerMetre);
|
||||
const double floorCenterZ=PassageFlatFloorCenterZSubvoxels(
|
||||
constants,segmentIndex,floorT,segment,qx,qy,floorDepth,qPerMetre);
|
||||
constants,segments,segmentIndex,floorT,segment,
|
||||
qx,qy,floorDepth,qPerMetre);
|
||||
const double flatDistance=PassageFlatBottomDistance(
|
||||
static_cast<float>(roundDistance),floorCenterZ,qz,floorDepth,qPerMetre);
|
||||
const double alongMetres=segment.authoredAlongMetres
|
||||
@@ -3401,12 +3410,13 @@ public:
|
||||
private:
|
||||
struct FPassageTileFeature
|
||||
{
|
||||
std::size_t passageIndex=0,segmentIndex=0;
|
||||
std::size_t passageIndex=0,segmentIndex=0,segmentEndIndex=0;
|
||||
};
|
||||
struct FPassageComposerConstants
|
||||
{
|
||||
double floorDepthMetres=0.0,totalPathLengthMetres=0.0;
|
||||
double authoredTotalPathLengthMetres=0.0;
|
||||
std::size_t routeProfileSegmentCount=0;
|
||||
double upperMouthX=0.0,upperMouthY=0.0;
|
||||
double upperMouthPlannedFloor=0.0;
|
||||
double upperMouthTangentX=0.0,upperMouthTangentY=0.0;
|
||||
@@ -3436,14 +3446,40 @@ private:
|
||||
}
|
||||
|
||||
static double PassageFlatFloorCenterZSubvoxels(
|
||||
const FPassageComposerConstants& constants,std::size_t segmentIndex,double floorT,
|
||||
const FPassageComposerConstants& constants,
|
||||
const std::vector<FPassageSegmentData>& segments,
|
||||
std::size_t segmentIndex,double floorT,
|
||||
const FPassageSegmentData& segment,double queryXSubvoxels,double queryYSubvoxels,
|
||||
double floorDepthSubvoxels,double qPerMetre)
|
||||
{
|
||||
if(!segment.routeSegment||qPerMetre<=0.0)
|
||||
return segment.a[2]+floorT*segment.delta[2];
|
||||
const double plannedFloor=segment.authoredFloorZA
|
||||
return segment.a[2]+std::clamp(floorT,0.0,1.0)*segment.delta[2];
|
||||
const std::size_t profileCount=std::min(
|
||||
constants.routeProfileSegmentCount,segments.size());
|
||||
double plannedFloor=segment.authoredFloorZA
|
||||
+floorT*segment.authoredFloorZDelta;
|
||||
if(profileCount>0)
|
||||
{
|
||||
if(floorT>=0.0&&floorT<=1.0)
|
||||
plannedFloor=segment.authoredFloorZA
|
||||
+floorT*segment.authoredFloorZDelta;
|
||||
else
|
||||
{
|
||||
const double distance=segment.authoredAlongMetres
|
||||
+floorT*segment.authoredLengthMetres;
|
||||
const auto profileEnd=segments.begin()+profileCount;
|
||||
const auto upper=std::lower_bound(segments.begin(),profileEnd,distance,
|
||||
[](const FPassageSegmentData& candidate,double value)
|
||||
{return candidate.authoredAlongMetres
|
||||
+candidate.authoredLengthMetres<value;});
|
||||
const auto& profileSegment=upper==profileEnd?*(profileEnd-1):*upper;
|
||||
const double profileT=profileSegment.authoredLengthMetres>1.0e-12
|
||||
?std::clamp((distance-profileSegment.authoredAlongMetres)
|
||||
/profileSegment.authoredLengthMetres,0.0,1.0):0.0;
|
||||
plannedFloor=profileSegment.authoredFloorZA
|
||||
+profileT*profileSegment.authoredFloorZDelta;
|
||||
}
|
||||
}
|
||||
const double mouthBlendFloor=VoxelForgeCore::PassageSpline::BlendUpperMouthFloorAtXY(
|
||||
constants.upperMouthReceivingRoute,queryXSubvoxels,queryYSubvoxels,
|
||||
plannedFloor,constants.upperMouthX,constants.upperMouthY,
|
||||
@@ -4325,7 +4361,7 @@ private:
|
||||
template<class FVisitor>
|
||||
void VisitNearestPassageSegmentRange(std::size_t passageIndex,
|
||||
std::ptrdiff_t first,std::ptrdiff_t last,double qx,double qy,double qz,
|
||||
int priority,double& bestDistance,double& bestCenterDistanceSq,
|
||||
int priority,double& bestDistance,double& bestFloorCenterDistanceSq,
|
||||
FVisitor&& visitor) const
|
||||
{
|
||||
(void)priority;
|
||||
@@ -4359,8 +4395,9 @@ private:
|
||||
if(static_cast<std::ptrdiff_t>(node.maximumSegment)<first
|
||||
||static_cast<std::ptrdiff_t>(node.minimumSegment)>last
|
||||
||(lowerBound(node)>bestDistance
|
||||
&&(bestCenterDistanceSq<0.0
|
||||
||centerDistanceLowerBoundSq(node)>bestCenterDistanceSq)))return;
|
||||
&&(bestFloorCenterDistanceSq<0.0
|
||||
||centerDistanceLowerBoundSq(node)
|
||||
>bestFloorCenterDistanceSq)))return;
|
||||
if(node.left<0)
|
||||
{
|
||||
for(const std::size_t segment:node.segments)
|
||||
@@ -4740,6 +4777,9 @@ private:
|
||||
segmentData.push_back(data);
|
||||
++preparedSegments;
|
||||
}
|
||||
constants.routeProfileSegmentCount=static_cast<std::size_t>(std::count_if(
|
||||
segmentData.begin(),segmentData.end(),
|
||||
[](const FPassageSegmentData& segment){return segment.routeSegment;}));
|
||||
PassageSegmentOffsets[passageIndex+1]=preparedSegments;
|
||||
}
|
||||
if(tracePreparation)
|
||||
@@ -4770,6 +4810,9 @@ private:
|
||||
constexpr double ReliefMetres=0.21;
|
||||
constexpr double SweepReachMetres=4.0;
|
||||
constexpr double CornerBlendMetres=0.50;
|
||||
constexpr std::size_t CandidateFineSamplesPerSpan=5;
|
||||
const double requiredReach=std::max(SweepReachMetres+ReliefMetres
|
||||
+CornerBlendMetres*0.25,PassageShellMetres+ReliefMetres);
|
||||
for(std::size_t passageIndex=0;passageIndex<ResolvedLayout->passages.size();
|
||||
++passageIndex)
|
||||
{
|
||||
@@ -4778,47 +4821,67 @@ private:
|
||||
std::vector<std::size_t> segmentIds(segmentCount);
|
||||
for(std::size_t i=0;i<segmentCount;++i)segmentIds[i]=i;
|
||||
BuildPassageNearestNode(passageIndex,std::move(segmentIds));
|
||||
for(std::size_t segmentIndex=0;segmentIndex<segmentCount;++segmentIndex)
|
||||
for(std::size_t segmentIndex=0;segmentIndex<segmentCount;
|
||||
segmentIndex+=CandidateFineSamplesPerSpan)
|
||||
{
|
||||
auto& prepared=PassageSegmentData[passageIndex][segmentIndex];
|
||||
const double maximumRadius=std::max(prepared.radiusA,
|
||||
prepared.radiusB)/Q;
|
||||
std::array<double,3> routeMinimum{},routeMaximum{};
|
||||
for(std::size_t axis=0;axis<3;++axis)
|
||||
const std::size_t segmentEndIndex=std::min(
|
||||
segmentIndex+CandidateFineSamplesPerSpan,segmentCount);
|
||||
std::array<double,3> routeMinimum{
|
||||
std::numeric_limits<double>::infinity(),
|
||||
std::numeric_limits<double>::infinity(),
|
||||
std::numeric_limits<double>::infinity()};
|
||||
std::array<double,3> routeMaximum{
|
||||
-std::numeric_limits<double>::infinity(),
|
||||
-std::numeric_limits<double>::infinity(),
|
||||
-std::numeric_limits<double>::infinity()};
|
||||
double maximumRadiusSubvoxels=0.0;
|
||||
for(std::size_t localIndex=segmentIndex;
|
||||
localIndex<segmentEndIndex;++localIndex)
|
||||
{
|
||||
routeMinimum[axis]=std::min(prepared.a[axis],prepared.b[axis])/Q;
|
||||
routeMaximum[axis]=std::max(prepared.a[axis],prepared.b[axis])/Q;
|
||||
}
|
||||
const double requiredReach=std::max(SweepReachMetres+ReliefMetres
|
||||
+CornerBlendMetres*0.25,PassageShellMetres+ReliefMetres);
|
||||
const double routeExtent=maximumRadius+requiredReach+0.01;
|
||||
const double tileExtent=routeExtent;
|
||||
FPassageProofBound proof;
|
||||
for(std::size_t axis=0;axis<3;++axis)
|
||||
{
|
||||
const double extent=routeExtent;
|
||||
proof.minimum[axis]=routeMinimum[axis]-extent;
|
||||
proof.maximum[axis]=routeMaximum[axis]+extent;
|
||||
}
|
||||
PassageProofBounds.push_back(proof);
|
||||
auto& prepared=PassageSegmentData[passageIndex][localIndex];
|
||||
maximumRadiusSubvoxels=std::max({maximumRadiusSubvoxels,
|
||||
prepared.radiusA,prepared.radiusB});
|
||||
std::array<double,3> localMinimum{},localMaximum{};
|
||||
for(std::size_t axis=0;axis<3;++axis)
|
||||
{
|
||||
localMinimum[axis]=std::min(prepared.a[axis],prepared.b[axis])/Q;
|
||||
localMaximum[axis]=std::max(prepared.a[axis],prepared.b[axis])/Q;
|
||||
routeMinimum[axis]=std::min(routeMinimum[axis],localMinimum[axis]);
|
||||
routeMaximum[axis]=std::max(routeMaximum[axis],localMaximum[axis]);
|
||||
}
|
||||
const double localExtent=requiredReach
|
||||
+std::max(prepared.radiusA,prepared.radiusB)/Q+0.01;
|
||||
FPassageProofBound proof;
|
||||
for(std::size_t axis=0;axis<3;++axis)
|
||||
{
|
||||
proof.minimum[axis]=localMinimum[axis]-localExtent;
|
||||
proof.maximum[axis]=localMaximum[axis]+localExtent;
|
||||
}
|
||||
PassageProofBounds.push_back(proof);
|
||||
|
||||
for(std::size_t axis=0;axis<3;++axis)
|
||||
{
|
||||
prepared.sweepMinimumSubvoxels[axis]=static_cast<std::int64_t>(
|
||||
std::floor((localMinimum[axis]-localExtent)*Q));
|
||||
prepared.sweepMaximumSubvoxels[axis]=static_cast<std::int64_t>(
|
||||
std::ceil((localMaximum[axis]+localExtent)*Q));
|
||||
}
|
||||
}
|
||||
const double routeExtent=maximumRadiusSubvoxels/Q+requiredReach+0.01;
|
||||
const double tileExtent=routeExtent;
|
||||
std::array<std::int64_t,3> featureMinimum{},featureMaximum{};
|
||||
std::array<std::int64_t,3> sweepMinimum{},sweepMaximum{};
|
||||
for(std::size_t axis=0;axis<3;++axis)
|
||||
{
|
||||
featureMinimum[axis]=static_cast<std::int64_t>(std::floor(
|
||||
(routeMinimum[axis]-tileExtent)*Q));
|
||||
featureMaximum[axis]=static_cast<std::int64_t>(std::ceil(
|
||||
(routeMaximum[axis]+tileExtent)*Q));
|
||||
sweepMinimum[axis]=featureMinimum[axis];
|
||||
sweepMaximum[axis]=featureMaximum[axis];
|
||||
prepared.sweepMinimumSubvoxels[axis]=sweepMinimum[axis];
|
||||
prepared.sweepMaximumSubvoxels[axis]=sweepMaximum[axis];
|
||||
}
|
||||
PassageFeatureBounds.push_back({
|
||||
static_cast<std::uint64_t>(PassageTileFeatures.size()),
|
||||
featureMinimum,featureMaximum});
|
||||
PassageTileFeatures.push_back({passageIndex,segmentIndex});
|
||||
PassageTileFeatures.push_back(
|
||||
{passageIndex,segmentIndex,segmentEndIndex});
|
||||
}
|
||||
}
|
||||
for(std::size_t i=0;i<PassageFeatureBounds.size();++i)
|
||||
@@ -11429,17 +11492,19 @@ inline void FStandaloneShapeWorld::FScopedPassageTileQueries::prepareSweptTubeBa
|
||||
passageSamples.passageIndex=passageIndex;
|
||||
passageSamples.samples.resize(gridSampleCount);
|
||||
const auto& constants=shape_->PassageComposerConstants[passageIndex];
|
||||
const auto& segments=shape_->PassageSegmentData[passageIndex];
|
||||
for(const auto& candidate:candidates)
|
||||
{
|
||||
if(candidate.segmentIndex>=shape_->PassageSegmentData[passageIndex].size())continue;
|
||||
if(candidate.segmentIndex>=segments.size())continue;
|
||||
const std::size_t segmentEndIndex=std::min(candidate.segmentEndIndex,
|
||||
segments.size());
|
||||
if(candidate.segmentIndex>=segmentEndIndex)continue;
|
||||
std::array<std::int32_t,3> first{},last{};
|
||||
for(std::size_t axis=0;axis<3;++axis)
|
||||
gridRange(axis,candidate.sweepMinimumSubvoxels[axis],
|
||||
candidate.sweepMaximumSubvoxels[axis],first[axis],last[axis]);
|
||||
if(first[0]>last[0]||first[1]>last[1]||first[2]>last[2])continue;
|
||||
|
||||
const auto& segment=shape_->PassageSegmentData[passageIndex][candidate.segmentIndex];
|
||||
if(segment.lengthSq<=0.0)continue;
|
||||
for(std::int32_t gz=first[2];gz<=last[2];++gz)
|
||||
{
|
||||
for(std::int32_t gy=first[1];gy<=last[1];++gy)
|
||||
@@ -11451,6 +11516,17 @@ inline void FStandaloneShapeWorld::FScopedPassageTileQueries::prepareSweptTubeBa
|
||||
+static_cast<std::int64_t>(gy)*sweep->stepSubvoxels);
|
||||
const double qz=static_cast<double>(sweep->gridMinimumSubvoxels[2]
|
||||
+static_cast<std::int64_t>(gz)*sweep->stepSubvoxels);
|
||||
for(std::size_t segmentIndex=candidate.segmentIndex;
|
||||
segmentIndex<segmentEndIndex;++segmentIndex)
|
||||
{
|
||||
const auto& segment=segments[segmentIndex];
|
||||
if(segment.lengthSq<=0.0
|
||||
||qx<segment.sweepMinimumSubvoxels[0]
|
||||
||qx>segment.sweepMaximumSubvoxels[0]
|
||||
||qy<segment.sweepMinimumSubvoxels[1]
|
||||
||qy>segment.sweepMaximumSubvoxels[1]
|
||||
||qz<segment.sweepMinimumSubvoxels[2]
|
||||
||qz>segment.sweepMaximumSubvoxels[2])continue;
|
||||
const double projectionXY=(qx-segment.a[0])*segment.delta[0]
|
||||
+(qy-segment.a[1])*segment.delta[1];
|
||||
const double t=std::clamp((projectionXY
|
||||
@@ -11462,16 +11538,18 @@ inline void FStandaloneShapeWorld::FScopedPassageTileQueries::prepareSweptTubeBa
|
||||
const double ex=qx-cx,ey=qy-cy,ez=qz-cz;
|
||||
const double signedDistance=FStandaloneShapeWorld::DeterministicSqrt(
|
||||
ex*ex+ey*ey+ez*ez)-radius;
|
||||
const double floorCenterDistanceSq=ex*ex+ey*ey+ez*ez;
|
||||
const double floorT=segment.horizontalLengthSq>1.0e-12
|
||||
?std::clamp(projectionXY/segment.horizontalLengthSq,0.0,1.0):t;
|
||||
const double floorRadius=segment.radiusA+floorT*segment.radiusDelta;
|
||||
?projectionXY/segment.horizontalLengthSq:t;
|
||||
const double floorTClamped=std::clamp(floorT,0.0,1.0);
|
||||
const double floorCenterDistanceSq=ex*ex+ey*ey+ez*ez;
|
||||
const double floorRadius=segment.radiusA
|
||||
+floorTClamped*segment.radiusDelta;
|
||||
const double floorDepth=FStandaloneShapeWorld::PassageFlatFloorDepthSubvoxels(
|
||||
constants,candidate.segmentIndex,floorT,floorRadius,qPerMetre);
|
||||
constants,segmentIndex,floorTClamped,floorRadius,qPerMetre);
|
||||
const double floorCenterZ=
|
||||
FStandaloneShapeWorld::PassageFlatFloorCenterZSubvoxels(
|
||||
constants,candidate.segmentIndex,floorT,segment,qx,qy,floorDepth,
|
||||
qPerMetre);
|
||||
constants,segments,segmentIndex,floorT,segment,
|
||||
qx,qy,floorDepth,qPerMetre);
|
||||
const double flatDistance=FStandaloneShapeWorld::PassageFlatBottomDistance(
|
||||
static_cast<float>(signedDistance),floorCenterZ,qz,floorDepth,qPerMetre);
|
||||
if(profile)++profileStats_->passageSweepSegmentSamplePairs;
|
||||
@@ -11485,14 +11563,14 @@ inline void FStandaloneShapeWorld::FScopedPassageTileQueries::prepareSweptTubeBa
|
||||
auto& sample=passageSamples.samples[sampleIndex];
|
||||
if(floorCenterDistanceSq<sample.floorCenterDistanceSq
|
||||
||(floorCenterDistanceSq==sample.floorCenterDistanceSq
|
||||
&&candidate.segmentIndex<sample.floorSegmentIndex))
|
||||
&&segmentIndex<sample.floorSegmentIndex))
|
||||
{
|
||||
sample.floorCenterDistanceSq=floorCenterDistanceSq;
|
||||
sample.floorCenterZSubvoxels=floorCenterZ;
|
||||
sample.floorDepthSubvoxels=floorDepth;
|
||||
sample.floorT=floorT;
|
||||
sample.floorSegmentIndex=static_cast<std::uint32_t>(
|
||||
candidate.segmentIndex);
|
||||
segmentIndex);
|
||||
}
|
||||
const double alongMetres=segment.authoredAlongMetres
|
||||
+t*segment.authoredLengthMetres;
|
||||
@@ -11536,19 +11614,20 @@ inline void FStandaloneShapeWorld::FScopedPassageTileQueries::prepareSweptTubeBa
|
||||
// independently above from the nearest centerline position.
|
||||
if(!sample.valid||signedDistance<sample.roundSignedDistance
|
||||
||(signedDistance==sample.roundSignedDistance
|
||||
&&candidate.segmentIndex<sample.segmentIndex))
|
||||
&&segmentIndex<sample.segmentIndex))
|
||||
{
|
||||
sample.signedDistance=flatDistance;
|
||||
sample.roundSignedDistance=signedDistance;
|
||||
sample.centerZSubvoxels=cz;
|
||||
sample.radiusSubvoxels=radius;
|
||||
sample.t=t;
|
||||
sample.segmentIndex=static_cast<std::uint32_t>(candidate.segmentIndex);
|
||||
sample.segmentIndex=static_cast<std::uint32_t>(segmentIndex);
|
||||
sample.valid=true;
|
||||
sample.hasWallRelief=false;
|
||||
if(profile)++profileStats_->passageSweepMinimumUpdates;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user