fix(measure): measure the strate, not the band above its floor
The window excluded a whole chunk (32 voxels) at each end to avoid a 4-voxel seal band -- 8x too much. On 4-chunk strates that discarded half of every strate, floor included, so the pass was measuring the open air above the ground and calling it the strate. The margin now derives from the seal that actually exists: ceil(2 x BoundarySealThickness), clamped to [1, height/4], overridable via InteriorMarginVoxels. The fixture resolves to 8 voxels. FlatPlain/CrystalChamber walkable fraction: 0.00044 -> 0.0578, ~132x. The "99.95% empty void" reading was the window, not the world. Metrics now carry ResolvedMarginVoxels, SampledMinZ and SampledMaxZ, and the test prints them. A measurement that does not state the volume it measured is exactly how the previous defect survived review. VerticalShafts largest-component share rose only 0.074 -> 0.119 across 57 components: the window explained part of the swiss-cheese signal, not all of it. That one is at least partly real. Coarse-lie guard still load-bearing: 24 routes checked, 3 refuted at full resolution (was 21 / 2). Build clean, 18 succeeded / 0 warnings / 0 failed, confirmed in Saved/Logs/VoxelM.log rather than from the agent's summary. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Bp7FxoQcSoiuhxjuLr6aBM
This commit is contained in:
1 parent
6988e5ace1
commit
13399529b5
4 files changed
+245
-69
No files matched your search
@@ -26,6 +26,10 @@ namespace VoxelStrateMeasurePrivate
|
||||
float ExtentY = 0.0f;
|
||||
float ExtentZ = 0.0f;
|
||||
|
||||
int32 ResolvedMarginVoxels = 0;
|
||||
int32 SampledMinZ = 0;
|
||||
int32 SampledMaxZ = 0;
|
||||
|
||||
// 1 = air, 0 = solid. The polarity is deliberately explicit at the sampling site below.
|
||||
TArray<uint8> Air;
|
||||
|
||||
@@ -114,14 +118,74 @@ namespace VoxelStrateMeasurePrivate
|
||||
return Refuse(OutReason, TEXT("The requested strate has no positive vertical extent."));
|
||||
}
|
||||
|
||||
// Exclude the complete top and bottom chunks. Those outer chunks contain the seal bands;
|
||||
// the measurement is about the strate interior, not the boundary bedrock.
|
||||
const int64 InteriorMinZ = (static_cast<int64>(Slot.BottomChunkZ) + 1) * CHUNK_SIZE;
|
||||
const int64 InteriorMaxZ = static_cast<int64>(Slot.TopChunkZ) * CHUNK_SIZE;
|
||||
const int64 StrateBottomZ = static_cast<int64>(Slot.BottomChunkZ) * CHUNK_SIZE;
|
||||
const int64 StrateTopZ = (static_cast<int64>(Slot.TopChunkZ) + 1) * CHUNK_SIZE;
|
||||
const int64 StrateHeight = StrateTopZ - StrateBottomZ;
|
||||
if (StrateHeight <= 0)
|
||||
{
|
||||
return Refuse(OutReason, TEXT("The requested strate has no positive voxel height."));
|
||||
}
|
||||
|
||||
// Resolve the margin from the same blended parameter query used by generation. The
|
||||
// representative chunk is deliberately in the middle of this slot and uses the sample
|
||||
// centre's XY chunk, so a future non-Hard transition resolves through the manager exactly
|
||||
// as generation does at that representative location.
|
||||
const int32 MidChunkZ = Slot.BottomChunkZ
|
||||
+ (Slot.TopChunkZ - Slot.BottomChunkZ) / 2;
|
||||
const FIntVector RepresentativeChunk(
|
||||
FMath::FloorToInt(Settings.CenterXY.X / static_cast<float>(CHUNK_SIZE)),
|
||||
FMath::FloorToInt(Settings.CenterXY.Y / static_cast<float>(CHUNK_SIZE)),
|
||||
MidChunkZ);
|
||||
const FStrateGenerationParams RepresentativeParams =
|
||||
Manager.GetGenerationParams(RepresentativeChunk);
|
||||
|
||||
const int64 MaxMargin64 = FMath::Max<int64>(1, StrateHeight / 4);
|
||||
const int32 MaxMargin = static_cast<int32>(
|
||||
FMath::Min<int64>(MaxMargin64, static_cast<int64>(INT32_MAX)));
|
||||
int32 RequestedMargin = Settings.InteriorMarginVoxels;
|
||||
if (RequestedMargin < 0)
|
||||
{
|
||||
const float DoubleSealThickness = 2.0f * RepresentativeParams.BoundarySealThickness;
|
||||
if (FMath::IsNaN(RepresentativeParams.BoundarySealThickness))
|
||||
{
|
||||
return Refuse(OutReason, TEXT("BoundarySealThickness is NaN; the interior margin cannot be derived."));
|
||||
}
|
||||
|
||||
// Avoid converting an infinite value to int. A positive overflow is still an
|
||||
// intentionally absurd seal request and therefore resolves to the safe maximum;
|
||||
// negative infinity resolves to the minimum.
|
||||
if (!FMath::IsFinite(DoubleSealThickness))
|
||||
{
|
||||
RequestedMargin = DoubleSealThickness > 0.0f ? MaxMargin : 1;
|
||||
}
|
||||
else if (DoubleSealThickness >= static_cast<float>(INT32_MAX))
|
||||
{
|
||||
RequestedMargin = MaxMargin;
|
||||
}
|
||||
else if (DoubleSealThickness <= static_cast<float>(INT32_MIN))
|
||||
{
|
||||
RequestedMargin = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
RequestedMargin = FMath::CeilToInt(DoubleSealThickness);
|
||||
}
|
||||
}
|
||||
const int32 ResolvedMargin = FMath::Clamp(RequestedMargin, 1, MaxMargin);
|
||||
|
||||
const int64 InteriorMinZ = StrateBottomZ + static_cast<int64>(ResolvedMargin);
|
||||
const int64 InteriorMaxZ = StrateTopZ - static_cast<int64>(ResolvedMargin);
|
||||
const int64 InteriorHeight = InteriorMaxZ - InteriorMinZ;
|
||||
if (InteriorHeight <= 0)
|
||||
{
|
||||
return Refuse(OutReason, TEXT("The strate is too short after excluding its top and bottom chunks."));
|
||||
return Refuse(OutReason, TEXT("The strate has no measurable height after applying its interior margin."));
|
||||
}
|
||||
if (InteriorMinZ < static_cast<int64>(INT32_MIN)
|
||||
|| InteriorMinZ > static_cast<int64>(INT32_MAX)
|
||||
|| InteriorMaxZ < static_cast<int64>(INT32_MIN)
|
||||
|| InteriorMaxZ > static_cast<int64>(INT32_MAX))
|
||||
{
|
||||
return Refuse(OutReason, TEXT("The sampled Z window is outside the metrics struct's int32 range."));
|
||||
}
|
||||
|
||||
const int64 XYExtent = static_cast<int64>(Settings.RadiusInVoxels) * 2;
|
||||
@@ -188,6 +252,9 @@ namespace VoxelStrateMeasurePrivate
|
||||
OutGrid.ExtentX = MaxX - MinX;
|
||||
OutGrid.ExtentY = MaxY - MinY;
|
||||
OutGrid.ExtentZ = MaxZ - MinZ;
|
||||
OutGrid.ResolvedMarginVoxels = ResolvedMargin;
|
||||
OutGrid.SampledMinZ = static_cast<int32>(InteriorMinZ);
|
||||
OutGrid.SampledMaxZ = static_cast<int32>(InteriorMaxZ);
|
||||
OutGrid.Air.SetNumUninitialized(OutGrid.CellCount);
|
||||
|
||||
bool bSawNonFiniteDensity = false;
|
||||
@@ -627,6 +694,9 @@ FVoxelStrateMetrics VF_MeasureStrate(
|
||||
return Result;
|
||||
}
|
||||
|
||||
Result.ResolvedMarginVoxels = Grid.ResolvedMarginVoxels;
|
||||
Result.SampledMinZ = Grid.SampledMinZ;
|
||||
Result.SampledMaxZ = Grid.SampledMaxZ;
|
||||
VoxelStrateMeasurePrivate::BuildMetricsFromGrid(Grid, Settings, Result);
|
||||
Result.bValid = Result.NumSampled > 0;
|
||||
if (!Result.bValid)
|
||||
|
||||
Reference in new issue
Block a user