core: one tunnel for two strates with landing chambers (L151, owner design; v238, grade open)
Each passage records upper and lower landing chambers (floor, gradient, radius, 4.5 m clear height) composed with the tunnel shell; cave route endpoints bind to the chambers; envelope audit permits only the named chamber joints. Seed 2: 0 solid in 319,579 passage+chamber capsule samples, 0 shell violations, 0 envelope conflicts, controls fire. Open: tunnel-to-chamber floor blend leaves 19.1/19.0 deg grades (limit 15); sweeps/timing not run. 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
9ac60d5d18
commit
5bd158d4eb
21 files changed
+1949
-105
No files matched your search
@@ -1280,6 +1280,8 @@ public:
|
||||
double unionDistance=std::numeric_limits<double>::infinity();
|
||||
double unionShellDistance=std::numeric_limits<double>::infinity();
|
||||
double unionFloorShellDistance=std::numeric_limits<double>::infinity();
|
||||
double unionLandingChamberFloorShellDistance=
|
||||
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);
|
||||
@@ -1317,14 +1319,56 @@ public:
|
||||
const bool passageTargetsPlannedTunnelNetwork=plannedTunnelStratum;
|
||||
const double mouthShellBlendMetres=passageTargetsPlannedTunnelNetwork
|
||||
?2.0:MouthShellBlendMetres;
|
||||
// Legacy native cave fields own the floor and mouth carve on their
|
||||
// lower-strate boundary. The planner's TunnelNetwork field instead
|
||||
// needs the shared passage composer to carry its incoming mouth open.
|
||||
if(passageTargetsNativeCaveField&&!passageTargetsPlannedTunnelNetwork)
|
||||
continue;
|
||||
// Legacy native cave fields own the tunnel bore on their lower-strate
|
||||
// boundary. The shared passage composer still owns its landing chamber.
|
||||
if(passageProfile)++passageProfile->passageIterations;
|
||||
const auto& constants=PassageComposerConstants[passageIndex];
|
||||
|
||||
const VoxelForgeCore::ResolvedLayoutPassageLandingChamberV1* landingChamber=nullptr;
|
||||
if(queryStratum&&queryStratum->Resolved)
|
||||
{
|
||||
if(queryStratum->StrateIndex==passage.upperStrateIndex)
|
||||
landingChamber=&passage.upperLandingChamber;
|
||||
else if(queryStratum->StrateIndex==passage.lowerStrateIndex)
|
||||
landingChamber=&passage.lowerLandingChamber;
|
||||
}
|
||||
if(landingChamber&&landingChamber->radiusSubvoxels>0
|
||||
&&landingChamber->clearHeightSubvoxels>0)
|
||||
{
|
||||
const double centerX=static_cast<double>(
|
||||
landingChamber->floorCenterSubvoxels[0]);
|
||||
const double centerY=static_cast<double>(
|
||||
landingChamber->floorCenterSubvoxels[1]);
|
||||
const double floorCenterZ=static_cast<double>(
|
||||
landingChamber->floorCenterSubvoxels[2])
|
||||
+(landingChamber->floorGradientQ16[0]*(qx-centerX)
|
||||
+landingChamber->floorGradientQ16[1]*(qy-centerY))/65536.0;
|
||||
const double radialDistance=DeterministicSqrt(
|
||||
(qx-centerX)*(qx-centerX)+(qy-centerY)*(qy-centerY))
|
||||
-landingChamber->radiusSubvoxels;
|
||||
const double floorDistance=floorCenterZ-qz;
|
||||
const double ceilingDistance=qz-(floorCenterZ
|
||||
+landingChamber->clearHeightSubvoxels);
|
||||
const double chamberDistance=std::max({radialDistance,
|
||||
floorDistance,ceilingDistance});
|
||||
const double chamberShellDistance=std::max(-chamberDistance,
|
||||
chamberDistance-shellThickness);
|
||||
const double chamberFloorShellDistance=std::max(
|
||||
std::max(-floorDistance,floorDistance-shellThickness),
|
||||
radialDistance);
|
||||
unionDistance=std::min(unionDistance,chamberDistance);
|
||||
unionShellDistance=std::min(unionShellDistance,chamberShellDistance);
|
||||
unionFloorShellDistance=std::min(unionFloorShellDistance,
|
||||
chamberFloorShellDistance);
|
||||
unionLandingChamberFloorShellDistance=std::min(
|
||||
unionLandingChamberFloorShellDistance,chamberFloorShellDistance);
|
||||
if(passageTargetsPlannedTunnelNetwork)
|
||||
plannedTunnelPassageShellDistance=std::min(
|
||||
plannedTunnelPassageShellDistance,chamberShellDistance);
|
||||
}
|
||||
if(passageTargetsNativeCaveField&&!passageTargetsPlannedTunnelNetwork)
|
||||
continue;
|
||||
|
||||
FNearestTubeSample nearest;
|
||||
const bool usePreparedSweep=passageTileScopeMatches
|
||||
&&passageTileQueries->hasSweptTubeBase();
|
||||
@@ -1615,6 +1659,11 @@ public:
|
||||
|
||||
if(!std::isfinite(unionDistance))return density;
|
||||
const float passageAirDistance=static_cast<float>(-unionDistance/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);
|
||||
const auto plannedPortalWalkCorridorContains=[&]()
|
||||
{
|
||||
if(!queryStratum||!queryStratum->Resolved
|
||||
@@ -1678,7 +1727,11 @@ public:
|
||||
const double routeFloor=std::lerp(a[2],b[2],t)-1.13;
|
||||
return queryZ>=routeFloor-0.30&&queryZ<=routeFloor+2.25;
|
||||
};
|
||||
constexpr double PortalWalkLeadMetres=8.0;
|
||||
// The connected layer route begins inside the landing chamber. Let
|
||||
// its air open the chamber's plain side shell through the chamber
|
||||
// radius plus the shell thickness; the condition below remains
|
||||
// limited to samples where the tunnel/chamber shell is present.
|
||||
constexpr double PortalWalkLeadMetres=9.0;
|
||||
const auto arrival=position(*first),arrivalInner=position(*second);
|
||||
const double arrivalInnerDistance=std::hypot(
|
||||
arrivalInner[0]-arrival[0],arrivalInner[1]-arrival[1]);
|
||||
@@ -1693,6 +1746,90 @@ public:
|
||||
departureTailDistance)
|
||||
||nearRouteSegment(*lastTwo,*last,PortalWalkLeadMetres,true,0.0);
|
||||
};
|
||||
const auto connectedSurfaceLandingShellContains=[&]()
|
||||
{
|
||||
if(!queryStratum||!queryStratum->Resolved
|
||||
||queryStratum->Resolved->generatorKind!="SurfaceWorld")return false;
|
||||
const double queryX=qx/qPerMetre,queryY=qy/qPerMetre,queryZ=qz/qPerMetre;
|
||||
constexpr double ChamberShellThicknessMetres=0.75;
|
||||
constexpr double RouteClearanceMetres=1.25;
|
||||
constexpr double RouteHeightClearanceMetres=1.5;
|
||||
constexpr double PortalWalkLeadMetres=9.0;
|
||||
for(const auto& passage:ResolvedLayout->passages)
|
||||
{
|
||||
if(passage.upperStrateIndex!=queryStratum->StrateIndex)continue;
|
||||
const auto& chamber=passage.upperLandingChamber;
|
||||
if(chamber.radiusSubvoxels<=0||chamber.clearHeightSubvoxels<=0)continue;
|
||||
const double cx=static_cast<double>(chamber.floorCenterSubvoxels[0])/qPerMetre;
|
||||
const double cy=static_cast<double>(chamber.floorCenterSubvoxels[1])/qPerMetre;
|
||||
const double floorZ=static_cast<double>(chamber.floorCenterSubvoxels[2])/qPerMetre
|
||||
+chamber.floorGradientQ16[0]/65536.0*(queryX-cx)
|
||||
+chamber.floorGradientQ16[1]/65536.0*(queryY-cy);
|
||||
const double radialDistance=std::hypot(queryX-cx,queryY-cy)
|
||||
-static_cast<double>(chamber.radiusSubvoxels)/qPerMetre;
|
||||
const double floorDistance=floorZ-queryZ;
|
||||
const double ceilingDistance=queryZ-(floorZ
|
||||
+static_cast<double>(chamber.clearHeightSubvoxels)/qPerMetre);
|
||||
const double chamberDistance=std::max({radialDistance,
|
||||
floorDistance,ceilingDistance});
|
||||
const double chamberShellDistance=std::max(-chamberDistance,
|
||||
chamberDistance-ChamberShellThicknessMetres);
|
||||
if(chamberDistance<=0.0||chamberShellDistance>=0.0)continue;
|
||||
|
||||
std::vector<const VoxelForgeCore::ResolvedLayoutAnchorV2*> route;
|
||||
for(const auto& anchor:queryStratum->Resolved->anchors)
|
||||
if(anchor.kind=="route_point"&&anchor.values.size()>=3)
|
||||
route.push_back(&anchor);
|
||||
if(route.size()<2)continue;
|
||||
const double mouthZ=static_cast<double>(passage.upperMouthSubvoxels[2])
|
||||
/qPerMetre;
|
||||
std::size_t endpoint=route.size();
|
||||
double endpointDistanceSquared=1.0;
|
||||
for(std::size_t index=0;index<route.size();++index)
|
||||
{
|
||||
const double x=route[index]->values[0]/qPerMetre;
|
||||
const double y=route[index]->values[1]/qPerMetre;
|
||||
const double z=route[index]->values[2]/qPerMetre;
|
||||
const double dx=x-cx,dy=y-cy;
|
||||
const double distanceSquared=dx*dx+dy*dy;
|
||||
if(distanceSquared<endpointDistanceSquared
|
||||
&&std::abs(z-mouthZ)<=1.5)
|
||||
{endpoint=index;endpointDistanceSquared=distanceSquared;}
|
||||
}
|
||||
if(endpoint==route.size())continue;
|
||||
std::vector<double> routeDistance(route.size(),0.0);
|
||||
for(std::size_t index=1;index<route.size();++index)
|
||||
{
|
||||
const double dx=(route[index]->values[0]-route[index-1]->values[0])
|
||||
/qPerMetre;
|
||||
const double dy=(route[index]->values[1]-route[index-1]->values[1])
|
||||
/qPerMetre;
|
||||
routeDistance[index]=routeDistance[index-1]+std::hypot(dx,dy);
|
||||
}
|
||||
for(std::size_t index=1;index<route.size();++index)
|
||||
{
|
||||
const auto& a=*route[index-1];
|
||||
const auto& b=*route[index];
|
||||
const double ax=a.values[0]/qPerMetre,ay=a.values[1]/qPerMetre;
|
||||
const double az=a.values[2]/qPerMetre;
|
||||
const double dx=(b.values[0]-a.values[0])/qPerMetre;
|
||||
const double dy=(b.values[1]-a.values[1])/qPerMetre;
|
||||
const double horizontalLengthSquared=dx*dx+dy*dy;
|
||||
if(horizontalLengthSquared<=1.0e-12)continue;
|
||||
const double t=std::clamp(((queryX-ax)*dx+(queryY-ay)*dy)
|
||||
/horizontalLengthSquared,0.0,1.0);
|
||||
const double alongFromEndpoint=std::abs(
|
||||
std::lerp(routeDistance[index-1],routeDistance[index],t)
|
||||
-routeDistance[endpoint]);
|
||||
if(alongFromEndpoint>PortalWalkLeadMetres)continue;
|
||||
const double routeX=ax+t*dx,routeY=ay+t*dy;
|
||||
const double routeZ=az+t*(b.values[2]-a.values[2])/qPerMetre;
|
||||
if(std::hypot(queryX-routeX,queryY-routeY)<=RouteClearanceMetres
|
||||
&&std::abs(queryZ-routeZ)<=RouteHeightClearanceMetres)return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
if(plannedTunnelStratum
|
||||
&&nativeTunnelFieldDensity!=std::numeric_limits<float>::lowest()
|
||||
&&nativeTunnelFieldDensity<0.0f)
|
||||
@@ -1755,7 +1892,11 @@ public:
|
||||
if(nativeTunnelFieldDensity!=std::numeric_limits<float>::lowest())
|
||||
return 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 std::max(density,passageAirDistance);
|
||||
}
|
||||
|
||||
@@ -1892,6 +2033,26 @@ public:
|
||||
}
|
||||
if(overlaps(low,high))return true;
|
||||
}
|
||||
const auto chamberOverlaps=[&](
|
||||
const VoxelForgeCore::ResolvedLayoutPassageLandingChamberV1& chamber)
|
||||
{
|
||||
const double cx=static_cast<double>(chamber.floorCenterSubvoxels[0])/Q;
|
||||
const double cy=static_cast<double>(chamber.floorCenterSubvoxels[1])/Q;
|
||||
const double cz=static_cast<double>(chamber.floorCenterSubvoxels[2])/Q;
|
||||
const double radius=static_cast<double>(chamber.radiusSubvoxels)/Q;
|
||||
const double floorExtent=radius*std::hypot(
|
||||
static_cast<double>(chamber.floorGradientQ16[0])/65536.0,
|
||||
static_cast<double>(chamber.floorGradientQ16[1])/65536.0);
|
||||
const double extent=reachCoreVoxels+0.01;
|
||||
const double low[3]={cx-radius-extent,cy-radius-extent,
|
||||
cz-floorExtent-extent};
|
||||
const double high[3]={cx+radius+extent,cy+radius+extent,
|
||||
cz+floorExtent+static_cast<double>(
|
||||
chamber.clearHeightSubvoxels)/Q+extent};
|
||||
return overlaps(low,high);
|
||||
};
|
||||
if(chamberOverlaps(passage.upperLandingChamber)
|
||||
||chamberOverlaps(passage.lowerLandingChamber))return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -3668,6 +3829,12 @@ private:
|
||||
double lowerMouthPlannedFloor=0.0;
|
||||
double lowerMouthTangentX=0.0,lowerMouthTangentY=0.0;
|
||||
std::vector<std::array<double,3>> lowerMouthReceivingRoute;
|
||||
std::array<double,3> upperLandingFloorCenterSubvoxels{};
|
||||
std::array<double,2> upperLandingFloorGradient{};
|
||||
double upperLandingRadiusSubvoxels=0.0;
|
||||
std::array<double,3> lowerLandingFloorCenterSubvoxels{};
|
||||
std::array<double,2> lowerLandingFloorGradient{};
|
||||
double lowerLandingRadiusSubvoxels=0.0;
|
||||
std::size_t routeEndControlIndex=0;
|
||||
};
|
||||
struct FPassageSegmentData
|
||||
@@ -3692,6 +3859,49 @@ private:
|
||||
std::max(0.0,radiusSubvoxels-0.23*qPerMetre));
|
||||
}
|
||||
|
||||
static double BlendPassageFloorToLandingChambers(
|
||||
const FPassageComposerConstants& constants,
|
||||
const FPassageSegmentData& segment,double floorT,
|
||||
double queryXSubvoxels,double queryYSubvoxels,double plannedFloor,
|
||||
double qPerMetre)
|
||||
{
|
||||
if(qPerMetre<=0.0||!(constants.totalPathLengthMetres>0.0))
|
||||
return plannedFloor;
|
||||
const double alongMetres=segment.authoredAlongMetres
|
||||
+floorT*segment.authoredLengthMetres;
|
||||
constexpr double LandingFloorBlendMetres=12.0;
|
||||
const auto floorWeight=[&](double distanceMetres,double radiusSubvoxels)
|
||||
{
|
||||
if(!(radiusSubvoxels>0.0))return 0.0;
|
||||
const double radiusMetres=radiusSubvoxels/qPerMetre;
|
||||
if(distanceMetres<=radiusMetres)return 1.0;
|
||||
if(distanceMetres>=radiusMetres+LandingFloorBlendMetres)return 0.0;
|
||||
const double t=(distanceMetres-radiusMetres)/LandingFloorBlendMetres;
|
||||
return 1.0-t*t*(3.0-2.0*t);
|
||||
};
|
||||
const double upperWeight=floorWeight(std::max(0.0,alongMetres),
|
||||
constants.upperLandingRadiusSubvoxels);
|
||||
const double lowerWeight=floorWeight(std::max(0.0,
|
||||
constants.totalPathLengthMetres-alongMetres),
|
||||
constants.lowerLandingRadiusSubvoxels);
|
||||
if(upperWeight<=0.0&&lowerWeight<=0.0)return plannedFloor;
|
||||
const auto floorAt=[&](const std::array<double,3>& center,
|
||||
const std::array<double,2>& gradient)
|
||||
{
|
||||
return center[2]+gradient[0]*(queryXSubvoxels-center[0])
|
||||
+gradient[1]*(queryYSubvoxels-center[1]);
|
||||
};
|
||||
const double upperFloor=floorAt(constants.upperLandingFloorCenterSubvoxels,
|
||||
constants.upperLandingFloorGradient);
|
||||
const double lowerFloor=floorAt(constants.lowerLandingFloorCenterSubvoxels,
|
||||
constants.lowerLandingFloorGradient);
|
||||
const double totalWeight=upperWeight+lowerWeight;
|
||||
if(totalWeight<=1.0)
|
||||
return plannedFloor*(1.0-totalWeight)
|
||||
+upperFloor*upperWeight+lowerFloor*lowerWeight;
|
||||
return (upperFloor*upperWeight+lowerFloor*lowerWeight)/totalWeight;
|
||||
}
|
||||
|
||||
static double PassageFlatFloorCenterZSubvoxels(
|
||||
const FPassageComposerConstants& constants,
|
||||
const std::vector<FPassageSegmentData>& segments,
|
||||
@@ -3742,7 +3952,9 @@ private:
|
||||
-constants.lowerMouthTangentX,-constants.lowerMouthTangentY,
|
||||
VoxelForgeCore::PassageSpline::UpperMouthFloorBlendRadiusMetres,1.13,
|
||||
qPerMetre);
|
||||
return lowerBlendFloor+floorDepthSubvoxels;
|
||||
const double landingFloor=BlendPassageFloorToLandingChambers(constants,
|
||||
segment,floorT,queryXSubvoxels,queryYSubvoxels,lowerBlendFloor,qPerMetre);
|
||||
return landingFloor+floorDepthSubvoxels;
|
||||
}
|
||||
|
||||
static float PassageFlatBottomDistance(float roundDistanceSubvoxels,
|
||||
@@ -4900,6 +5112,23 @@ private:
|
||||
passage.lowerMouthControlIndex,1,passage.controlPoints.size()-1);
|
||||
auto& constants=PassageComposerConstants[passageIndex];
|
||||
constants.routeEndControlIndex=routeEnd;
|
||||
for(std::size_t axis=0;axis<3;++axis)
|
||||
{
|
||||
constants.upperLandingFloorCenterSubvoxels[axis]=static_cast<double>(
|
||||
passage.upperLandingChamber.floorCenterSubvoxels[axis]);
|
||||
constants.lowerLandingFloorCenterSubvoxels[axis]=static_cast<double>(
|
||||
passage.lowerLandingChamber.floorCenterSubvoxels[axis]);
|
||||
}
|
||||
constants.upperLandingFloorGradient={
|
||||
passage.upperLandingChamber.floorGradientQ16[0]/65536.0,
|
||||
passage.upperLandingChamber.floorGradientQ16[1]/65536.0};
|
||||
constants.lowerLandingFloorGradient={
|
||||
passage.lowerLandingChamber.floorGradientQ16[0]/65536.0,
|
||||
passage.lowerLandingChamber.floorGradientQ16[1]/65536.0};
|
||||
constants.upperLandingRadiusSubvoxels=static_cast<double>(
|
||||
passage.upperLandingChamber.radiusSubvoxels);
|
||||
constants.lowerLandingRadiusSubvoxels=static_cast<double>(
|
||||
passage.lowerLandingChamber.radiusSubvoxels);
|
||||
const auto upperStratum=std::find_if(ResolvedLayout->strates.begin(),
|
||||
ResolvedLayout->strates.end(),[&](const auto& stratum)
|
||||
{return stratum.strateIndex==passage.upperStrateIndex;});
|
||||
@@ -4928,7 +5157,8 @@ private:
|
||||
double upperMouthFloorDepth=authoredUpperMouthFloorDepth;
|
||||
if(upperStratum!=ResolvedLayout->strates.end()
|
||||
&&(upperStratum->generatorKind=="FloatingIslands"
|
||||
||upperStratum->generatorKind=="TunnelNetwork"))
|
||||
||upperStratum->generatorKind=="TunnelNetwork"
|
||||
||upperStratum->generatorKind=="SurfaceWorld"))
|
||||
{
|
||||
std::vector<std::array<double,3>> route;
|
||||
for(const auto& anchor:upperStratum->anchors)
|
||||
@@ -4947,16 +5177,19 @@ private:
|
||||
upperMouthFloorDepth=std::max(upperMouthFloorDepth,
|
||||
std::max(0.0,(controls.front()[2]-routeHeight)/qPerMetre
|
||||
+constants.upperMouthPlayerCenterHeightMetres));
|
||||
if(upperStratum->generatorKind=="TunnelNetwork")
|
||||
if(upperStratum->generatorKind=="TunnelNetwork"
|
||||
||upperStratum->generatorKind=="SurfaceWorld")
|
||||
VoxelForgeCore::PassageSpline::BlendEndpointFloorToRoute(
|
||||
controls,plannedFloorProfile,0,route,qPerMetre);
|
||||
controls,plannedFloorProfile,0,route,qPerMetre,
|
||||
constants.upperMouthPlayerCenterHeightMetres);
|
||||
}
|
||||
}
|
||||
controls.front()[3]=std::max(controls.front()[3],
|
||||
upperMouthFloorDepth*qPerMetre);
|
||||
if(upperStratum!=ResolvedLayout->strates.end()
|
||||
&&(upperStratum->generatorKind=="FloatingIslands"
|
||||
||upperStratum->generatorKind=="TunnelNetwork"))
|
||||
||upperStratum->generatorKind=="TunnelNetwork"
|
||||
||upperStratum->generatorKind=="SurfaceWorld"))
|
||||
for(const auto& anchor:upperStratum->anchors)
|
||||
if(anchor.kind=="route_point"&&anchor.values.size()>=3)
|
||||
constants.upperMouthReceivingRoute.push_back({
|
||||
@@ -5044,8 +5277,8 @@ private:
|
||||
constants.upperMouthTangentY=sampledSegments.front().b[1]
|
||||
-sampledSegments.front().a[1];
|
||||
}
|
||||
const std::string lowerMouthAnchor=passage.stableId+"/lower-mouth";
|
||||
const std::string upperMouthAnchor=passage.stableId+"/upper-mouth";
|
||||
const std::string lowerMouthAnchor=passage.stableId+"/lower-landing-chamber";
|
||||
const std::string upperMouthAnchor=passage.stableId+"/upper-landing-chamber";
|
||||
for(const auto& edge:ResolvedLayout->cavernEdges)
|
||||
{
|
||||
if(edge.controlPointsMicrometres.size()<2)continue;
|
||||
@@ -5230,6 +5463,40 @@ private:
|
||||
std::ceil((localMaximum[axis]+localExtent)*Q));
|
||||
}
|
||||
}
|
||||
const auto includeLandingChamber=[&](
|
||||
const VoxelForgeCore::ResolvedLayoutPassageLandingChamberV1& chamber)
|
||||
{
|
||||
const double cx=static_cast<double>(chamber.floorCenterSubvoxels[0])/Q;
|
||||
const double cy=static_cast<double>(chamber.floorCenterSubvoxels[1])/Q;
|
||||
const double cz=static_cast<double>(chamber.floorCenterSubvoxels[2])/Q;
|
||||
const double radius=static_cast<double>(chamber.radiusSubvoxels)/Q;
|
||||
const double gx=static_cast<double>(chamber.floorGradientQ16[0])/65536.0;
|
||||
const double gy=static_cast<double>(chamber.floorGradientQ16[1])/65536.0;
|
||||
const double floorExtent=radius*std::hypot(gx,gy);
|
||||
const double height=static_cast<double>(
|
||||
chamber.clearHeightSubvoxels)/Q;
|
||||
const double extent=requiredReachCoreVoxels+0.01;
|
||||
const std::array<double,3> minimum{
|
||||
cx-radius-extent,cy-radius-extent,cz-floorExtent-extent};
|
||||
const std::array<double,3> maximum{
|
||||
cx+radius+extent,cy+radius+extent,
|
||||
cz+floorExtent+height+extent};
|
||||
FPassageProofBound proof;
|
||||
for(std::size_t axis=0;axis<3;++axis)
|
||||
{
|
||||
routeMinimum[axis]=std::min(routeMinimum[axis],minimum[axis]);
|
||||
routeMaximum[axis]=std::max(routeMaximum[axis],maximum[axis]);
|
||||
proof.minimum[axis]=minimum[axis];
|
||||
proof.maximum[axis]=maximum[axis];
|
||||
}
|
||||
PassageProofBounds.push_back(proof);
|
||||
};
|
||||
if(segmentIndex==0)
|
||||
includeLandingChamber(
|
||||
ResolvedLayout->passages[passageIndex].upperLandingChamber);
|
||||
if(segmentEndIndex==segmentCount)
|
||||
includeLandingChamber(
|
||||
ResolvedLayout->passages[passageIndex].lowerLandingChamber);
|
||||
const double routeExtent=maximumRadiusSubvoxels/Q
|
||||
+requiredReachCoreVoxels+0.01;
|
||||
const double tileExtent=routeExtent;
|
||||
|
||||
Reference in new issue
Block a user