feat(core): cavern graph v1, one continuous floor-capped tunnel into the landmark chamber (L46); R13
The flagged SW demo's ramp (57 carves + 107 support pillars, visibly ribbed) becomes one cubic-Bezier sweep: closest point by 17-point seed plus 5 Newton steps, a cubic floor profile, a rounded 2.6 m bore, and a hard floor cap applied after unions and relief that only adds support where the field is air. Optional resolved cavern-graph records (one room, one edge) enter canonical identity only when present; their bounds extend World::isTileShapeFree. Reachability passes (L43 control fails), headroom 2.8 m, floor ripple 1.8 mm (L45 ramp control fails at 17.9 mm), shape limits met; demo off: owner hashes identical to L45. fast/medium/full PASS. Research R13 (read-only): continuous SDF sweeps along curves. 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
f13b145f23
commit
e016f6a20f
14 files changed
+1753
-48
No files matched your search
@@ -56,6 +56,7 @@ namespace
|
||||
int RenderDistanceOverride=0;
|
||||
bool FloatingIslandsRecipe=false;
|
||||
bool LandmarkChamberDemo=false;
|
||||
bool LandmarkL45RampControl=false;
|
||||
bool AuditLandmarkReachability=false;
|
||||
bool TlsProbeRequested=false;
|
||||
int TlsProbeWorkers=0;
|
||||
@@ -115,10 +116,14 @@ namespace
|
||||
const VoxelForgeCore::WorldAssemblyManifest& worldAssembly,
|
||||
std::int32_t seed,
|
||||
std::vector<VoxelForgeCore::ResolvedLayoutStampRequestV1>& requests,
|
||||
std::vector<VoxelForgeCore::ResolvedCavernRoomV1>& cavernRooms,
|
||||
std::vector<VoxelForgeCore::ResolvedCavernEdgeV1>& cavernEdges,
|
||||
bool legacyRampControl,
|
||||
std::string& error)
|
||||
{
|
||||
using namespace VoxelForgeCore;
|
||||
requests.clear();
|
||||
cavernRooms.clear();cavernEdges.clear();
|
||||
const auto surface=std::find_if(layout.strates.begin(),layout.strates.end(),
|
||||
[](const auto& value){return value.generatorKind=="SurfaceWorld";});
|
||||
if(surface==layout.strates.end())
|
||||
@@ -444,6 +449,100 @@ namespace
|
||||
return startZ+descent*std::clamp((beforeFirstTurn+afterFirstTurn)
|
||||
/slopedLength,0.0,1.0);
|
||||
};
|
||||
// The resolved edge is one cubic sweep. Its floor controls are independent
|
||||
// of the curved XY centerline, so the floor remains an explicit profile.
|
||||
const double startFloor=surfaceHeight;
|
||||
const double endFloor=chamberCenterZ-0.5;
|
||||
const double firstLength=std::hypot(firstTurn.x-start.x,firstTurn.y-start.y);
|
||||
const double lastLength=std::hypot(end.x-firstTurn.x,end.y-firstTurn.y);
|
||||
const double estimatedLength=firstLength+lastLength;
|
||||
const double handleLength=estimatedLength/3.0;
|
||||
const double firstDirX=(firstTurn.x-start.x)/firstLength;
|
||||
const double firstDirY=(firstTurn.y-start.y)/firstLength;
|
||||
const double lastDirX=(end.x-firstTurn.x)/lastLength;
|
||||
const double lastDirY=(end.y-firstTurn.y)/lastLength;
|
||||
std::array<std::array<double,3>,4> curve={{
|
||||
{start.x,start.y,startFloor},
|
||||
{start.x+firstDirX*handleLength,start.y+firstDirY*handleLength,
|
||||
startFloor+(endFloor-startFloor)/3.0},
|
||||
{end.x-lastDirX*handleLength,end.y-lastDirY*handleLength,
|
||||
startFloor+2.0*(endFloor-startFloor)/3.0},
|
||||
{end.x,end.y,endFloor}}};
|
||||
ResolvedCavernRoomV1 room;
|
||||
room.stableId=chamber.stableId;room.strateIndex=surface->strateIndex;
|
||||
room.centerMicrometres=chamber.anchorPositionMicrometres;
|
||||
room.halfExtentsMicrometres=chamber.halfExtentsMicrometres;
|
||||
room.floorMicrometres=static_cast<std::int64_t>(std::llround(endFloor*1000000.0));
|
||||
room.smoothWidthMicrometres=chamber.smoothWidthMicrometres;
|
||||
room.irregularityAmplitudeMicrometres=chamber.irregularityAmplitudeMicrometres;
|
||||
room.irregularityWavelengthMicrometres=chamber.irregularityWavelengthMicrometres;
|
||||
if(!legacyRampControl)cavernRooms.push_back(room);
|
||||
ResolvedCavernEdgeV1 edge;
|
||||
edge.stableId="landmark/sw-arrival-chamber-tunnel-v1";
|
||||
edge.startAnchorStableId=passage->stableId+"/surface-ground-approach";
|
||||
edge.endRoomStableId=room.stableId;edge.strateIndex=surface->strateIndex;
|
||||
edge.boreRadiusMicrometres=2600000;
|
||||
edge.boreHeightMicrometres=4800000;
|
||||
edge.floorSupportDepthMicrometres=450000;
|
||||
edge.smoothWidthMicrometres=300000;
|
||||
edge.irregularityAmplitudeMicrometres=20000;
|
||||
edge.irregularityWavelengthMicrometres=3200000;
|
||||
double measuredCurveLength=0.0,arcAtThird=0.0,arcAtTwoThirds=0.0;
|
||||
std::array<double,2> previousCurvePoint={curve[0][0],curve[0][1]};
|
||||
for(int sample=1;sample<=256;++sample)
|
||||
{
|
||||
const double t=static_cast<double>(sample)/256.0,one=1.0-t;
|
||||
std::array<double,3> point{};
|
||||
for(std::size_t axis=0;axis<3;++axis)
|
||||
point[axis]=one*one*one*curve[0][axis]
|
||||
+3.0*one*one*t*curve[1][axis]+3.0*one*t*t*curve[2][axis]
|
||||
+t*t*t*curve[3][axis];
|
||||
const double dx=point[0]-previousCurvePoint[0];
|
||||
const double dy=point[1]-previousCurvePoint[1];
|
||||
const double horizontal=std::hypot(dx,dy);
|
||||
measuredCurveLength+=horizontal;
|
||||
if(sample==85)arcAtThird=measuredCurveLength;
|
||||
if(sample==171)arcAtTwoThirds=measuredCurveLength;
|
||||
previousCurvePoint={point[0],point[1]};
|
||||
}
|
||||
const double targetFloorThird=startFloor+(endFloor-startFloor)
|
||||
*(arcAtThird/measuredCurveLength);
|
||||
const double targetFloorTwoThirds=startFloor+(endFloor-startFloor)
|
||||
*(arcAtTwoThirds/measuredCurveLength);
|
||||
const double firstEquation=targetFloorThird
|
||||
-(8.0*startFloor+endFloor)/27.0;
|
||||
const double secondEquation=targetFloorTwoThirds
|
||||
-(startFloor+8.0*endFloor)/27.0;
|
||||
curve[1][2]=1.5*(2.0*firstEquation-secondEquation);
|
||||
curve[2][2]=1.5*(2.0*secondEquation-firstEquation);
|
||||
double maximumCurveGrade=0.0;
|
||||
std::array<double,3> previousCurvePosition=curve[0];
|
||||
for(int sample=1;sample<=256;++sample)
|
||||
{
|
||||
const double t=static_cast<double>(sample)/256.0,one=1.0-t;
|
||||
std::array<double,3> point{};
|
||||
for(std::size_t axis=0;axis<3;++axis)
|
||||
point[axis]=one*one*one*curve[0][axis]
|
||||
+3.0*one*one*t*curve[1][axis]+3.0*one*t*t*curve[2][axis]
|
||||
+t*t*t*curve[3][axis];
|
||||
const double horizontal=std::hypot(point[0]-previousCurvePosition[0],
|
||||
point[1]-previousCurvePosition[1]);
|
||||
maximumCurveGrade=std::max(maximumCurveGrade,std::atan2(
|
||||
std::abs(point[2]-previousCurvePosition[2]),
|
||||
std::max(1.0e-6,horizontal))*180.0/3.14159265358979323846);
|
||||
previousCurvePosition=point;
|
||||
}
|
||||
for(std::size_t i=0;i<curve.size();++i)
|
||||
for(std::size_t axis=0;axis<3;++axis)
|
||||
edge.controlPointsMicrometres[i][axis]=static_cast<std::int64_t>(
|
||||
std::llround(curve[i][axis]*1000000.0));
|
||||
if(!legacyRampControl)cavernEdges.push_back(edge);
|
||||
std::printf("[CavernGraphPlan] rooms=1 edges=1 room=%s edge=%s curve=cubic-bezier floor=cubic-profile length_m=%.3f max_grade_deg=%.3f bore_radius_m=2.600 bore_height_m=4.800 floor_um=%lld..%lld\n",
|
||||
room.stableId.c_str(),edge.stableId.c_str(),measuredCurveLength,maximumCurveGrade,
|
||||
static_cast<long long>(room.floorMicrometres),
|
||||
static_cast<long long>(edge.controlPointsMicrometres[0][2]));
|
||||
if(maximumCurveGrade>15.0)
|
||||
{error="landmark cavern edge exceeds the 15 degree walk grade";return false;}
|
||||
const double pointSpacing=0.6;
|
||||
const std::size_t rampCount=static_cast<std::size_t>(std::ceil(totalLength/pointSpacing));
|
||||
std::vector<ResolvedLayoutStampRequestV1> rampCarves;
|
||||
@@ -506,12 +605,15 @@ namespace
|
||||
}
|
||||
requests.push_back(std::move(mouthStamp));
|
||||
requests.push_back(std::move(mouthPortal));
|
||||
requests.insert(requests.end(),std::make_move_iterator(rampCarves.begin()),
|
||||
std::make_move_iterator(rampCarves.end()));
|
||||
requests.push_back(std::move(chamber));
|
||||
requests.insert(requests.end(),std::make_move_iterator(rampSupports.begin()),
|
||||
std::make_move_iterator(rampSupports.end()));
|
||||
requests.push_back(std::move(mouthLanding));
|
||||
if(legacyRampControl)
|
||||
{
|
||||
requests.insert(requests.end(),std::make_move_iterator(rampCarves.begin()),
|
||||
std::make_move_iterator(rampCarves.end()));
|
||||
requests.push_back(std::move(chamber));
|
||||
requests.insert(requests.end(),std::make_move_iterator(rampSupports.begin()),
|
||||
std::make_move_iterator(rampSupports.end()));
|
||||
}
|
||||
if(legacyRampControl)requests.push_back(std::move(mouthLanding));
|
||||
requests.push_back(std::move(chamberFloor));
|
||||
requests.push_back(std::move(dais));
|
||||
(void)seed;
|
||||
@@ -571,7 +673,8 @@ namespace
|
||||
" --mesh-export=FILE (write the exact generated tile meshes for offline rendering)\n"
|
||||
" --profile-column-overlap --far-horizon-lod8-step=N --force-generate\n"
|
||||
" --seed=N --recipe=surface-world|floating-islands\n"
|
||||
" --landmark-chamber-demo (opt-in natural SW landmark chamber and ramp)\n"
|
||||
" --landmark-chamber-demo (opt-in SW cavern room and swept tunnel)\n"
|
||||
" --landmark-l45-ramp-control (use the buried L45 stamp geometry as an audit control)\n"
|
||||
" --resolved-layout-output=FILE (canonical plan-time layout snapshot)\n"
|
||||
" --resolved-layout-only (exit after plan and snapshot validation)\n"
|
||||
" --audit-resolved-layout-boundaries (query Core at each recorded endpoint)\n"
|
||||
@@ -640,6 +743,7 @@ namespace
|
||||
else {std::fprintf(stderr,"Invalid --recipe value: %.*s\n",static_cast<int>(recipe.size()),recipe.data());return false;}
|
||||
}
|
||||
else if(arg=="--landmark-chamber-demo")options.LandmarkChamberDemo=true;
|
||||
else if(arg=="--landmark-l45-ramp-control")options.LandmarkL45RampControl=true;
|
||||
else if(arg.starts_with("--resolved-layout-output="))
|
||||
options.ResolvedLayoutOutputPath=std::string(arg.substr(std::string_view("--resolved-layout-output=").size()));
|
||||
else if(arg.starts_with("--seed="))
|
||||
@@ -722,6 +826,8 @@ namespace
|
||||
{std::fprintf(stderr,"--tls-probe-touch requires --tls-probe=N\n");return false;}
|
||||
if(options.RegionCrossing&&!options.HasCameraStep)
|
||||
{std::fprintf(stderr,"--region-crossing requires --camera-step=X,Y,Z\n");return false;}
|
||||
if(options.LandmarkL45RampControl&&!options.LandmarkChamberDemo)
|
||||
{std::fprintf(stderr,"--landmark-l45-ramp-control requires --landmark-chamber-demo\n");return false;}
|
||||
if(options.TlsProbeRequested)return true;
|
||||
if(!options.WorldAssemblerPrototype||!options.StreamBenchmark||!options.StreamPipeline)
|
||||
{
|
||||
@@ -820,10 +926,15 @@ int main(int argc,char** argv)
|
||||
if(options.LandmarkChamberDemo)
|
||||
{
|
||||
std::vector<VoxelForgeCore::ResolvedLayoutStampRequestV1> requests;
|
||||
if(!MakeLandmarkChamberDemoRequests(resolvedLayout,worldAssembly,seed,requests,error)
|
||||
std::vector<VoxelForgeCore::ResolvedCavernRoomV1> rooms;
|
||||
std::vector<VoxelForgeCore::ResolvedCavernEdgeV1> edges;
|
||||
if(!MakeLandmarkChamberDemoRequests(resolvedLayout,worldAssembly,seed,
|
||||
requests,rooms,edges,options.LandmarkL45RampControl,error)
|
||||
||!VoxelForgeCore::ResolveResolvedLayoutStampsV2(
|
||||
resolvedLayout,seed,requests,error))
|
||||
{std::fprintf(stderr,"Landmark chamber stamp resolution failed: %s\n",error.c_str());return 2;}
|
||||
resolvedLayout,seed,requests,error)
|
||||
||!VoxelForgeCore::ResolveResolvedCavernGraphV1(
|
||||
resolvedLayout,seed,rooms,edges,error))
|
||||
{std::fprintf(stderr,"Landmark cavern graph resolution failed: %s\n",error.c_str());return 2;}
|
||||
const auto audit=VoxelForgeCore::AuditResolvedLayoutStampPlacementV1(resolvedLayout);
|
||||
std::printf("[ResolvedStampPlacementAudit] vocabulary=%u records=%zu route_control=rejected band_control=rejected controls=%u/%u status=%s\n",
|
||||
resolvedLayout.stampVocabularyVersion,resolvedLayout.stamps.size(),
|
||||
@@ -849,9 +960,14 @@ int main(int argc,char** argv)
|
||||
stamp.irregularityAmplitudeMicrometres/1000000.0,
|
||||
stamp.irregularityWavelengthMicrometres/1000000.0,
|
||||
static_cast<unsigned long long>(stamp.irregularitySeed));
|
||||
std::printf("[LandmarkStampDemo] enabled=true seed=%d layout_id=%s passage_safe=true walk_route_clear=true version=%u deterministic_hash=seed,strate,stable_id status=PASS\n",
|
||||
seed,resolvedLayout.stableIdentity.c_str(),
|
||||
resolvedLayout.stampVocabularyVersion);
|
||||
if(options.LandmarkL45RampControl)
|
||||
std::printf("[LandmarkL45RampControl] enabled=true stamps=%zu graph_records=0 expected=segmented status=PASS\n",
|
||||
resolvedLayout.stamps.size());
|
||||
else
|
||||
std::printf("[LandmarkCavernGraphDemo] enabled=true seed=%d layout_id=%s rooms=%zu edges=%zu support_stamps=%zu passage_safe=true deterministic_hash=seed,strate,stable_id version=%u status=PASS\n",
|
||||
seed,resolvedLayout.stableIdentity.c_str(),
|
||||
resolvedLayout.cavernRooms.size(),resolvedLayout.cavernEdges.size(),
|
||||
resolvedLayout.stamps.size(),resolvedLayout.cavernGraphVocabularyVersion);
|
||||
}
|
||||
const std::string layoutJson=resolvedLayout.ToJson();
|
||||
const auto roundTrip=VoxelForgeCore::ResolvedLayoutSnapshotV3::FromJson(layoutJson,error);
|
||||
|
||||
Reference in new issue
Block a user