wip(assembler): round L36 -- tunnel floor without washboard; FI mouth without shards (evaluator v23)
The walk tread was built per segment as a one-sided density clamp, so its crossing with the native field moved at segment joins (L35: 2.25-2.48 cm washboard). Treads now overlap up to 2 m as bounded signed-distance slabs (0.06 cm residual). The FI mouth's crater detail and tread met without a smooth join; v23 filters the local field, drops thin isolated solids and smooth-unions the tread with the terrain. New floor ripple and mouth fragment/crease audits with L35 as failing controls. 24/24 passage rows, 30/30 determinism, 16/16 invariants, LOD0-8 rings; cost within noise. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CSFYgsdW8ejZSyiMf4qRSX
This commit is contained in:
1 parent
ba017077d1
commit
8be1c4d9ef
27 files changed
+1787
-55
No files matched your search
@@ -817,8 +817,15 @@ namespace StandaloneStreamBenchmark
|
||||
double periodMetres=0.0,amplitudeMetres=0.0,localPeakAmplitudeMetres=0.0;
|
||||
double coherentPeriodMetres=0.0,coherentAmplitudeMetres=0.0;
|
||||
double controlAmplitudeMetres=0.0;
|
||||
double floorPeriodMetres=0.0,floorAmplitudeMetres=0.0;
|
||||
double floorControlAmplitudeMetres=0.0;
|
||||
double floorCoherentPeriodMetres=0.0,floorCoherentAmplitudeMetres=0.0;
|
||||
std::vector<std::array<double,6>> floorPeakProfile;
|
||||
double floorPeakWindowStartMetres=0.0;
|
||||
std::uint64_t samples=0,expectedSamples=0;
|
||||
std::uint64_t floorSamples=0,floorExpectedSamples=0;
|
||||
bool controlDetected=false,passed=false;
|
||||
bool floorControlDetected=false;
|
||||
};
|
||||
constexpr double MaximumFlatRunMetres=8.0;
|
||||
constexpr double MinimumWallReliefMetres=0.20;
|
||||
@@ -1131,6 +1138,7 @@ namespace StandaloneStreamBenchmark
|
||||
constexpr double MaximumPeriodMetres=8.0;
|
||||
constexpr double PeriodStepMetres=0.0625;
|
||||
constexpr double RippleAmplitudeLimitMetres=0.035;
|
||||
constexpr double FloorRippleAmplitudeLimitMetres=0.015;
|
||||
struct FPathPoint
|
||||
{
|
||||
double x=0.0,y=0.0,z=0.0,radius=0.0,distance=0.0;
|
||||
@@ -1218,6 +1226,26 @@ namespace StandaloneStreamBenchmark
|
||||
values[i]-mean-slope*x});
|
||||
}
|
||||
};
|
||||
const auto appendDetrendedPairs=[](
|
||||
const std::vector<std::array<double,2>>& values,
|
||||
std::vector<std::array<double,2>>& output)
|
||||
{
|
||||
if(values.size()<64)return;
|
||||
double meanX=0.0,meanY=0.0;
|
||||
for(const auto& value:values){meanX+=value[0];meanY+=value[1];}
|
||||
meanX/=static_cast<double>(values.size());
|
||||
meanY/=static_cast<double>(values.size());
|
||||
double xy=0.0,xx=0.0;
|
||||
for(const auto& value:values)
|
||||
{
|
||||
const double x=value[0]-meanX;
|
||||
xy+=x*(value[1]-meanY);xx+=x*x;
|
||||
}
|
||||
const double slope=xx>0.0?xy/xx:0.0;
|
||||
for(const auto& value:values)
|
||||
output.push_back({value[0],value[1]-meanY
|
||||
-slope*(value[0]-meanX)});
|
||||
};
|
||||
std::vector<double> beadControl;
|
||||
beadControl.reserve(static_cast<std::size_t>(WindowLengthMetres/SampleSpacingMetres)+1);
|
||||
constexpr double BeadSpacingMetres=1.5;
|
||||
@@ -1234,20 +1262,64 @@ namespace StandaloneStreamBenchmark
|
||||
double ignoredPeriod=0.0;
|
||||
audit.controlAmplitudeMetres=sinusoidAmplitude(beadSamples,ignoredPeriod);
|
||||
audit.controlDetected=audit.controlAmplitudeMetres>=RippleAmplitudeLimitMetres;
|
||||
const std::array<double,4> windowStarts{{0.03,0.31,0.61,0.91}};
|
||||
audit.floorControlAmplitudeMetres=audit.controlAmplitudeMetres;
|
||||
audit.floorControlDetected=audit.floorControlAmplitudeMetres
|
||||
>=FloorRippleAmplitudeLimitMetres;
|
||||
const std::array<double,5> windowStarts{{0.03,0.31,0.457,0.61,0.91}};
|
||||
std::vector<std::array<double,2>> coherentSamples;
|
||||
std::vector<std::array<double,2>> coherentFloorSamples;
|
||||
for(const double fraction:windowStarts)
|
||||
{
|
||||
const double start=(total-WindowLengthMetres)*fraction;
|
||||
std::vector<double> radii;
|
||||
radii.reserve(static_cast<std::size_t>(WindowLengthMetres/SampleSpacingMetres)+1);
|
||||
std::vector<std::array<double,2>> floorResiduals;
|
||||
floorResiduals.reserve(static_cast<std::size_t>(WindowLengthMetres/
|
||||
SampleSpacingMetres)+1);
|
||||
std::vector<std::array<double,6>> floorDebugSamples;
|
||||
floorDebugSamples.reserve(static_cast<std::size_t>(WindowLengthMetres/
|
||||
SampleSpacingMetres)+1);
|
||||
for(std::size_t sample=0;
|
||||
sample<=static_cast<std::size_t>(WindowLengthMetres/SampleSpacingMetres);
|
||||
++sample)
|
||||
{
|
||||
++audit.expectedSamples;
|
||||
++audit.floorExpectedSamples;
|
||||
const double distance=start+static_cast<double>(sample)*SampleSpacingMetres;
|
||||
const auto pose=interpolate(distance);
|
||||
// Recover the composed walk surface from its zero crossing.
|
||||
// The support strip is segment-built and is not itself a true
|
||||
// signed-distance field, so a fixed centerline radius misses
|
||||
// the stepped top that the player actually walks on.
|
||||
const double expectedFloor=pose.z-pose.radius+0.20;
|
||||
constexpr double FloorProbeStepMetres=0.25;
|
||||
constexpr int FloorProbeCount=7;
|
||||
double previousDensity=0.0,previousZ=0.0;
|
||||
bool havePrevious=false,haveFloor=false;
|
||||
double bestFloor=0.0,bestDistance=std::numeric_limits<double>::infinity();
|
||||
for(int vertical=0;vertical<FloorProbeCount;++vertical)
|
||||
{
|
||||
const double z=expectedFloor-1.0+vertical*FloorProbeStepMetres;
|
||||
const double density=static_cast<double>(Field.densityAt({
|
||||
pose.x/coreMetres,pose.y/coreMetres,z/coreMetres}))*coreMetres;
|
||||
if(havePrevious&&previousDensity<0.0&&density>=0.0)
|
||||
{
|
||||
const double denominator=density-previousDensity;
|
||||
const double crossing=denominator>1.0e-12
|
||||
?previousZ+(z-previousZ)*(-previousDensity)/denominator:z;
|
||||
const double candidateDistance=std::abs(crossing-expectedFloor);
|
||||
if(candidateDistance<bestDistance)
|
||||
{bestDistance=candidateDistance;bestFloor=crossing;haveFloor=true;}
|
||||
}
|
||||
previousDensity=density;previousZ=z;havePrevious=true;
|
||||
}
|
||||
if(haveFloor)
|
||||
{
|
||||
floorResiduals.push_back({distance,bestFloor-expectedFloor});
|
||||
floorDebugSamples.push_back({distance,expectedFloor,bestFloor,
|
||||
pose.x,pose.y,pose.z});
|
||||
++audit.floorSamples;
|
||||
}
|
||||
const auto before=interpolate(std::max(0.0,distance-0.25));
|
||||
const auto after=interpolate(std::min(total,distance+0.25));
|
||||
const double tangentX=after.x-before.x,tangentY=after.y-before.y;
|
||||
@@ -1279,14 +1351,54 @@ namespace StandaloneStreamBenchmark
|
||||
}
|
||||
coherentSamples.insert(coherentSamples.end(),windowSamples.begin(),
|
||||
windowSamples.end());
|
||||
double floorWindowPeriod=0.0,floorWindowAmplitude=0.0;
|
||||
if(floorResiduals.size()>=static_cast<std::size_t>(WindowLengthMetres/
|
||||
SampleSpacingMetres)*3/4)
|
||||
{
|
||||
std::vector<std::array<double,2>> floorWindowSamples;
|
||||
appendDetrendedPairs(floorResiduals,floorWindowSamples);
|
||||
floorWindowAmplitude=sinusoidAmplitude(floorWindowSamples,
|
||||
floorWindowPeriod);
|
||||
if(floorWindowAmplitude>audit.floorAmplitudeMetres)
|
||||
{
|
||||
audit.floorAmplitudeMetres=floorWindowAmplitude;
|
||||
audit.floorPeriodMetres=floorWindowPeriod;
|
||||
audit.floorPeakWindowStartMetres=start;
|
||||
audit.floorPeakProfile=std::move(floorDebugSamples);
|
||||
}
|
||||
coherentFloorSamples.insert(coherentFloorSamples.end(),
|
||||
floorWindowSamples.begin(),floorWindowSamples.end());
|
||||
}
|
||||
const double floorWindowCoverage=static_cast<double>(floorResiduals.size())
|
||||
/(WindowLengthMetres/SampleSpacingMetres+1.0);
|
||||
double floorResidualMinimum=0.0,floorResidualMaximum=0.0;
|
||||
if(!floorResiduals.empty())
|
||||
{
|
||||
const auto extrema=std::minmax_element(floorResiduals.begin(),
|
||||
floorResiduals.end(),[](const auto& a,const auto& b)
|
||||
{return a[1]<b[1];});
|
||||
floorResidualMinimum=(*extrema.first)[1];
|
||||
floorResidualMaximum=(*extrema.second)[1];
|
||||
}
|
||||
std::printf("[PassageFloorRippleWindow] id=%s start_m=%.3f "
|
||||
"period_m=%.3f amplitude_m=%.4f coverage=%.3f "
|
||||
"residual_range_m=%.4f..%.4f threshold_m=0.015\n",
|
||||
passage.stableId.c_str(),start,floorWindowPeriod,floorWindowAmplitude,
|
||||
floorWindowCoverage,floorResidualMinimum,floorResidualMaximum);
|
||||
}
|
||||
audit.coherentAmplitudeMetres=sinusoidAmplitude(coherentSamples,
|
||||
audit.coherentPeriodMetres);
|
||||
audit.floorCoherentAmplitudeMetres=sinusoidAmplitude(coherentFloorSamples,
|
||||
audit.floorCoherentPeriodMetres);
|
||||
audit.amplitudeMetres=audit.localPeakAmplitudeMetres;
|
||||
const double coverage=audit.expectedSamples>0
|
||||
?static_cast<double>(audit.samples)/audit.expectedSamples:0.0;
|
||||
const double floorCoverage=audit.floorExpectedSamples>0
|
||||
?static_cast<double>(audit.floorSamples)/audit.floorExpectedSamples:0.0;
|
||||
audit.passed=audit.controlDetected&&coverage>=0.75
|
||||
&&audit.localPeakAmplitudeMetres<RippleAmplitudeLimitMetres;
|
||||
&&audit.localPeakAmplitudeMetres<RippleAmplitudeLimitMetres
|
||||
&&audit.floorControlDetected&&floorCoverage>=0.75
|
||||
&&audit.floorAmplitudeMetres<FloorRippleAmplitudeLimitMetres;
|
||||
return audit;
|
||||
};
|
||||
const auto looksNatural=[&](double flatRun,double reliefPeakToPeak)
|
||||
@@ -1908,6 +2020,7 @@ namespace StandaloneStreamBenchmark
|
||||
};
|
||||
std::uint64_t passageCount=0,passagePasses=0,blockedControls=0,naturalPasses=0;
|
||||
std::uint64_t mouthProfilePasses=0,ripplePasses=0,rippleControlsDetected=0;
|
||||
std::uint64_t floorRippleControlsDetected=0;
|
||||
std::uint64_t openAirViolations=0,openAirLegacyViolations=0,openAirSamples=0;
|
||||
std::uint64_t openAirAudits=0,openAirColumnSamples=0,openAirShortSpanSamples=0;
|
||||
std::uint64_t columnCrossings=0,shortGroundedSpans=0,columnConnectedEnds=0;
|
||||
@@ -1990,6 +2103,7 @@ namespace StandaloneStreamBenchmark
|
||||
mouthProfilePasses+=mouthProfileAudit.passed;
|
||||
ripplePasses+=rippleAudit.passed;
|
||||
rippleControlsDetected+=rippleAudit.controlDetected;
|
||||
floorRippleControlsDetected+=rippleAudit.floorControlDetected;
|
||||
passagePasses+=passageAudit.passed&&mouthsInRadius&&mouthsInContent
|
||||
&&naturalAudit.passed&&mouthProfileAudit.passed&&rippleAudit.passed;
|
||||
std::printf("[ResolvedPassageAudit] id=%s interface=%d-%d control_points=%zu center_samples=%llu capsule_samples=%llu blocked=%llu support_samples=%llu unsupported=%llu grade_failures=%llu mouth_content=%d/2 mouth_radius=%d/2 walkability=%s\n",
|
||||
@@ -2016,7 +2130,7 @@ namespace StandaloneStreamBenchmark
|
||||
mouthProfileAudit.wallFlatStepRunMetres,mouthProfileAudit.wallStepMetres,
|
||||
PassageProfileSpacingMetres,PassageProfilePlateauMinimumMetres,
|
||||
PassageProfileStepThresholdMetres,mouthProfileAudit.passed?"PASS":"FAIL");
|
||||
std::printf("[PassageRippleAudit] id=%s window_m=32.000 spacing_m=0.125 period_m=%.3f amplitude_m=%.4f amplitude_cm=%.2f coherent_period_m=%.3f coherent_amplitude_m=%.4f coherent_amplitude_cm=%.2f local_peak_amplitude_m=%.4f coverage=%llu/%llu threshold_m=0.035 synthetic_spheres_period_m=1.500 synthetic_spheres_amplitude_m=%.4f synthetic_spheres_detected=%s status=%s\n",
|
||||
std::printf("[PassageRippleAudit] id=%s window_m=32.000 spacing_m=0.125 period_m=%.3f amplitude_m=%.4f amplitude_cm=%.2f coherent_period_m=%.3f coherent_amplitude_m=%.4f coherent_amplitude_cm=%.2f local_peak_amplitude_m=%.4f coverage=%llu/%llu threshold_m=0.035 synthetic_spheres_period_m=1.500 synthetic_spheres_amplitude_m=%.4f synthetic_spheres_detected=%s floor_period_m=%.3f floor_amplitude_m=%.4f floor_amplitude_cm=%.2f floor_coherent_period_m=%.3f floor_coherent_amplitude_m=%.4f floor_coverage=%llu/%llu floor_threshold_m=0.015 floor_beaded_control_amplitude_m=%.4f floor_beaded_control_detected=%s status=%s\n",
|
||||
passage.stableId.c_str(),rippleAudit.periodMetres,
|
||||
rippleAudit.amplitudeMetres,rippleAudit.amplitudeMetres*100.0,
|
||||
rippleAudit.coherentPeriodMetres,rippleAudit.coherentAmplitudeMetres,
|
||||
@@ -2025,7 +2139,23 @@ namespace StandaloneStreamBenchmark
|
||||
static_cast<unsigned long long>(rippleAudit.samples),
|
||||
static_cast<unsigned long long>(rippleAudit.expectedSamples),
|
||||
rippleAudit.controlAmplitudeMetres,rippleAudit.controlDetected?"true":"false",
|
||||
rippleAudit.floorPeriodMetres,rippleAudit.floorAmplitudeMetres,
|
||||
rippleAudit.floorAmplitudeMetres*100.0,
|
||||
rippleAudit.floorCoherentPeriodMetres,rippleAudit.floorCoherentAmplitudeMetres,
|
||||
static_cast<unsigned long long>(rippleAudit.floorSamples),
|
||||
static_cast<unsigned long long>(rippleAudit.floorExpectedSamples),
|
||||
rippleAudit.floorControlAmplitudeMetres,
|
||||
rippleAudit.floorControlDetected?"true":"false",
|
||||
rippleAudit.passed?"PASS":"FAIL");
|
||||
for(std::size_t sample=0;sample<rippleAudit.floorPeakProfile.size();sample+=4)
|
||||
{
|
||||
const auto& value=rippleAudit.floorPeakProfile[sample];
|
||||
std::printf("[PassageFloorRippleSample] id=%s distance_m=%.3f "
|
||||
"expected_floor_m=%.4f sampled_floor_m=%.4f residual_m=%.4f "
|
||||
"route_xyz_m=(%.3f,%.3f,%.3f)\n",
|
||||
passage.stableId.c_str(),value[0],value[1],value[2],value[2]-value[1],
|
||||
value[3],value[4],value[5]);
|
||||
}
|
||||
std::printf("[PassageOpenAirAudit] id=%s support_samples=%llu violations=%llu column_samples=%llu short_span_samples=%llu l24_ungated_violations=%llu route_support_samples=%llu route_support_violations=%llu spacing_m=%.3f status=%s\n",
|
||||
passage.stableId.c_str(),static_cast<unsigned long long>(openAirAudit.supportSamples),
|
||||
static_cast<unsigned long long>(openAirAudit.violations),
|
||||
@@ -2340,10 +2470,11 @@ namespace StandaloneStreamBenchmark
|
||||
PassageProfilePlateauMinimumMetres,PassageProfileStepThresholdMetres,
|
||||
l23TerraceControlDetected?"DETECTED":"MISSED",
|
||||
mouthProfilePasses==passageCount&&l23TerraceControlDetected?"PASS":"FAIL");
|
||||
std::printf("[PassageRippleAuditSummary] passed=%llu/%llu synthetic_spheres_negative_control=%s max_amplitude_m=0.035 status=%s\n",
|
||||
std::printf("[PassageRippleAuditSummary] passed=%llu/%llu synthetic_spheres_negative_control=%s max_amplitude_m=0.035 floor_beaded_negative_control=%s max_floor_amplitude_m=0.015 status=%s\n",
|
||||
static_cast<unsigned long long>(ripplePasses),
|
||||
static_cast<unsigned long long>(passageCount),
|
||||
rippleControlsDetected==passageCount?"DETECTED":"MISSED",
|
||||
floorRippleControlsDetected==passageCount?"DETECTED":"MISSED",
|
||||
ripplePasses==passageCount?"PASS":"FAIL");
|
||||
const bool auditPassed=passageCount>0&&passagePasses==passageCount
|
||||
&&naturalPasses==passageCount&&l23SmoothWallDetected
|
||||
|
||||
Reference in new issue
Block a user