wip(assembler): round L35 -- smooth passage walls without regular ribs (evaluator v21)

The shared passage carve took the minimum of piecewise-linear capsules (scallops at joins) and added
wall relief on regular 8 m / 4 m octaves, which read as evenly spaced ribs. Interior sweep joins are
now Catmull-Rom smoothed and the relief uses irregular rotated 43/29/19 m scales; the natural wobble
remains. New axial ripple audit (0.125 m radius samples, 0.5-8 m periods): beaded control and L34
geometry fail, all 24 passage rows pass. FI mouth tread apron tapered. 30/30 determinism, 16/16
invariants, ring audits LOD0-8 pass; 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:
Fr0zkaandClaude Opus 5.5 committed 2026-10-22 07:28:50 +02:00
1 parent 49e29fcd36
commit ba017077d1
28 files changed
+1727 -17

No files matched your search

+197 -2
View File
@@ -812,6 +812,14 @@ namespace StandaloneStreamBenchmark
std::uint64_t floorSamples=0,wallSamples=0,missingFloorSamples=0,missingWallSamples=0;
bool passed=false;
};
struct FPassageRippleAudit
{
double periodMetres=0.0,amplitudeMetres=0.0,localPeakAmplitudeMetres=0.0;
double coherentPeriodMetres=0.0,coherentAmplitudeMetres=0.0;
double controlAmplitudeMetres=0.0;
std::uint64_t samples=0,expectedSamples=0;
bool controlDetected=false,passed=false;
};
constexpr double MaximumFlatRunMetres=8.0;
constexpr double MinimumWallReliefMetres=0.20;
constexpr double PassageProfileSpacingMetres=0.125;
@@ -1113,6 +1121,174 @@ namespace StandaloneStreamBenchmark
&&audit.wallSamples>=8;
return audit;
};
const auto auditPassageRipples=[&](const VoxelForgeCore::World& Field,
const VoxelForgeCore::ResolvedLayoutPassageV1& passage)
{
FPassageRippleAudit audit;
constexpr double SampleSpacingMetres=0.125;
constexpr double WindowLengthMetres=32.0;
constexpr double MinimumPeriodMetres=0.5;
constexpr double MaximumPeriodMetres=8.0;
constexpr double PeriodStepMetres=0.0625;
constexpr double RippleAmplitudeLimitMetres=0.035;
struct FPathPoint
{
double x=0.0,y=0.0,z=0.0,radius=0.0,distance=0.0;
};
const std::size_t end=std::min<std::size_t>(passage.lowerMouthControlIndex,
passage.controlPoints.size()-1);
if(end<2)return audit;
std::vector<FPathPoint> path;
path.reserve(end+1);
for(std::size_t i=0;i<=end;++i)
{
const auto& point=passage.controlPoints[i];
FPathPoint value{qToMetres(point.positionSubvoxels[0]),
qToMetres(point.positionSubvoxels[1]),
qToMetres(point.positionSubvoxels[2]),
qToMetres(point.radiusSubvoxels),0.0};
if(!path.empty())
{
const auto& previous=path.back();
value.distance=previous.distance+std::sqrt(
(value.x-previous.x)*(value.x-previous.x)
+(value.y-previous.y)*(value.y-previous.y)
+(value.z-previous.z)*(value.z-previous.z));
}
path.push_back(value);
}
const double total=path.back().distance;
if(total<WindowLengthMetres)return audit;
const auto interpolate=[&](double distance)
{
distance=std::clamp(distance,0.0,total);
const auto upper=std::lower_bound(path.begin()+1,path.end(),distance,
[](const FPathPoint& point,double value){return point.distance<value;});
const auto& b=*upper;
const auto& a=*(upper-1);
const double length=b.distance-a.distance;
const double t=length>1.0e-9?(distance-a.distance)/length:0.0;
return FPathPoint{std::lerp(a.x,b.x,t),std::lerp(a.y,b.y,t),
std::lerp(a.z,b.z,t),std::lerp(a.radius,b.radius,t),distance};
};
const auto sinusoidAmplitude=[&](const std::vector<std::array<double,2>>& samples,
double& bestPeriod)
{
if(samples.size()<64)return 0.0;
double best=0.0;
for(double period=MinimumPeriodMetres;
period<=MaximumPeriodMetres+1.0e-9;period+=PeriodStepMetres)
{
const double angular=6.2831853071795864769/period;
double cc=0.0,ss=0.0,cs=0.0,yc=0.0,ys=0.0;
for(const auto& sample:samples)
{
const double phase=angular*sample[0];
const double c=std::cos(phase),s=std::sin(phase);
cc+=c*c;ss+=s*s;cs+=c*s;
yc+=sample[1]*c;ys+=sample[1]*s;
}
const double determinant=cc*ss-cs*cs;
if(determinant<=1.0e-9)continue;
const double cosine=(yc*ss-ys*cs)/determinant;
const double sine=(ys*cc-yc*cs)/determinant;
const double amplitude=std::hypot(cosine,sine);
if(amplitude>best){best=amplitude;bestPeriod=period;}
}
return best;
};
const auto appendDetrendedProfile=[&](const std::vector<double>& values,
double startDistance,std::vector<std::array<double,2>>& output)
{
if(values.size()<64)return;
const double meanIndex=0.5*static_cast<double>(values.size()-1);
double mean=0.0,xy=0.0,xx=0.0;
for(double value:values)mean+=value;
mean/=static_cast<double>(values.size());
for(std::size_t i=0;i<values.size();++i)
{
const double x=(static_cast<double>(i)-meanIndex)*SampleSpacingMetres;
xy+=x*(values[i]-mean);xx+=x*x;
}
const double slope=xx>0.0?xy/xx:0.0;
for(std::size_t i=0;i<values.size();++i)
{
const double x=(static_cast<double>(i)-meanIndex)*SampleSpacingMetres;
output.push_back({startDistance+static_cast<double>(i)*SampleSpacingMetres,
values[i]-mean-slope*x});
}
};
std::vector<double> beadControl;
beadControl.reserve(static_cast<std::size_t>(WindowLengthMetres/SampleSpacingMetres)+1);
constexpr double BeadSpacingMetres=1.5;
constexpr double BeadSphereRadiusMetres=2.0;
for(std::size_t i=0;i<=static_cast<std::size_t>(WindowLengthMetres/SampleSpacingMetres);++i)
{
const double x=static_cast<double>(i)*SampleSpacingMetres;
const double nearest=std::abs(std::remainder(x,BeadSpacingMetres));
beadControl.push_back(std::sqrt(std::max(0.0,
BeadSphereRadiusMetres*BeadSphereRadiusMetres-nearest*nearest)));
}
std::vector<std::array<double,2>> beadSamples;
appendDetrendedProfile(beadControl,0.0,beadSamples);
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}};
std::vector<std::array<double,2>> coherentSamples;
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);
for(std::size_t sample=0;
sample<=static_cast<std::size_t>(WindowLengthMetres/SampleSpacingMetres);
++sample)
{
++audit.expectedSamples;
const double distance=start+static_cast<double>(sample)*SampleSpacingMetres;
const auto pose=interpolate(distance);
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;
const double tangentLength=std::hypot(tangentX,tangentY);
if(tangentLength<=1.0e-6)continue;
const double nx=-tangentY/tangentLength,ny=tangentX/tangentLength;
const double sampleRadius=std::max(0.20,pose.radius-0.18);
const double x0=pose.x/coreMetres,y0=pose.y/coreMetres,z0=pose.z/coreMetres;
const double offset=sampleRadius/coreMetres;
const double left=static_cast<double>(Field.densityAt(
{x0+nx*offset,y0+ny*offset,z0}))*coreMetres;
const double right=static_cast<double>(Field.densityAt(
{x0-nx*offset,y0-ny*offset,z0}))*coreMetres;
if(!std::isfinite(left)||!std::isfinite(right)
||left< -0.75||left>0.75||right< -0.75||right>0.75)continue;
radii.push_back(sampleRadius+0.5*(left+right));
++audit.samples;
}
if(radii.size()<static_cast<std::size_t>(WindowLengthMetres/
SampleSpacingMetres)*3/4)continue;
std::vector<std::array<double,2>> windowSamples;
appendDetrendedProfile(radii,start,windowSamples);
double localPeriod=0.0;
const double localAmplitude=sinusoidAmplitude(windowSamples,localPeriod);
if(localAmplitude>audit.localPeakAmplitudeMetres)
{
audit.localPeakAmplitudeMetres=localAmplitude;
audit.periodMetres=localPeriod;
}
coherentSamples.insert(coherentSamples.end(),windowSamples.begin(),
windowSamples.end());
}
audit.coherentAmplitudeMetres=sinusoidAmplitude(coherentSamples,
audit.coherentPeriodMetres);
audit.amplitudeMetres=audit.localPeakAmplitudeMetres;
const double coverage=audit.expectedSamples>0
?static_cast<double>(audit.samples)/audit.expectedSamples:0.0;
audit.passed=audit.controlDetected&&coverage>=0.75
&&audit.localPeakAmplitudeMetres<RippleAmplitudeLimitMetres;
return audit;
};
const auto looksNatural=[&](double flatRun,double reliefPeakToPeak)
{return flatRun<=MaximumFlatRunMetres
&&reliefPeakToPeak>=MinimumWallReliefMetres;};
@@ -1731,7 +1907,7 @@ namespace StandaloneStreamBenchmark
return zUm>=stratum->content.bottomMicrometres&&zUm<stratum->content.topMicrometres;
};
std::uint64_t passageCount=0,passagePasses=0,blockedControls=0,naturalPasses=0;
std::uint64_t mouthProfilePasses=0;
std::uint64_t mouthProfilePasses=0,ripplePasses=0,rippleControlsDetected=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;
@@ -1781,6 +1957,7 @@ namespace StandaloneStreamBenchmark
const FPassageNaturalnessAudit naturalAudit=auditPassageNaturalness(Shape,passage);
const FPassageMouthProfileAudit mouthProfileAudit=
auditPassageMouthProfiles(Shape,passage);
const FPassageRippleAudit rippleAudit=auditPassageRipples(Shape,passage);
const FPassageOpenAirAudit openAirAudit=auditPassageOpenAir(Shape,blockedWorld,
passage,passageIndex);
const FPassageColumnAudit columnAudit=auditPassageColumns(Shape,blockedWorld,
@@ -1811,8 +1988,10 @@ namespace StandaloneStreamBenchmark
&&mouthInContent(passage.lowerStrateIndex,passage.lowerMouthSubvoxels);
++passageCount;naturalPasses+=naturalAudit.passed;
mouthProfilePasses+=mouthProfileAudit.passed;
ripplePasses+=rippleAudit.passed;
rippleControlsDetected+=rippleAudit.controlDetected;
passagePasses+=passageAudit.passed&&mouthsInRadius&&mouthsInContent
&&naturalAudit.passed&&mouthProfileAudit.passed;
&&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",
passage.stableId.c_str(),passage.upperStrateIndex,passage.lowerStrateIndex,
passage.controlPoints.size(),static_cast<unsigned long long>(passageAudit.centers),
@@ -1837,6 +2016,16 @@ 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",
passage.stableId.c_str(),rippleAudit.periodMetres,
rippleAudit.amplitudeMetres,rippleAudit.amplitudeMetres*100.0,
rippleAudit.coherentPeriodMetres,rippleAudit.coherentAmplitudeMetres,
rippleAudit.coherentAmplitudeMetres*100.0,
rippleAudit.localPeakAmplitudeMetres,
static_cast<unsigned long long>(rippleAudit.samples),
static_cast<unsigned long long>(rippleAudit.expectedSamples),
rippleAudit.controlAmplitudeMetres,rippleAudit.controlDetected?"true":"false",
rippleAudit.passed?"PASS":"FAIL");
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),
@@ -2151,9 +2340,15 @@ 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",
static_cast<unsigned long long>(ripplePasses),
static_cast<unsigned long long>(passageCount),
rippleControlsDetected==passageCount?"DETECTED":"MISSED",
ripplePasses==passageCount?"PASS":"FAIL");
const bool auditPassed=passageCount>0&&passagePasses==passageCount
&&naturalPasses==passageCount&&l23SmoothWallDetected
&&mouthProfilePasses==passageCount&&l23TerraceControlDetected
&&ripplePasses==passageCount
&&openAirAudits==passageCount&&openAirViolations==0&&l24OpenAirControlDetected
&&columnAuditsPassed&&noLongBridgeAuditPassed
&&routePasses>0&&routePasses==routeWalkPasses&&routePasses==routeBindings