From 20f5f7ab4ac0e2ee2b3b15805f0b92b01948392c Mon Sep 17 00:00:00 2001 From: wass08 Date: Tue, 24 Feb 2026 10:27:51 +0900 Subject: [PATCH] fix wall elevation with slab holes --- .../spatial-grid/spatial-grid-manager.ts | 53 +++++++++++++++---- .../hooks/spatial-grid/spatial-grid-sync.ts | 2 +- packages/core/src/store/use-scene.ts | 1 - 3 files changed, 43 insertions(+), 13 deletions(-) diff --git a/packages/core/src/hooks/spatial-grid/spatial-grid-manager.ts b/packages/core/src/hooks/spatial-grid/spatial-grid-manager.ts index ebd5e6a9..945ced5c 100644 --- a/packages/core/src/hooks/spatial-grid/spatial-grid-manager.ts +++ b/packages/core/src/hooks/spatial-grid/spatial-grid-manager.ts @@ -201,6 +201,21 @@ export function wallOverlapsPolygon( const nz = (dz / len) * step if (pointInPolygon(start[0] + nx, start[1] + nz, polygon)) return true if (pointInPolygon(end[0] - nx, end[1] - nz, polygon)) return true + + // Also nudge perpendicular to the wall (into the slab interior) for walls that + // lie exactly on the slab boundary. The along-wall nudge keeps points on the + // boundary where pointInPolygon is unreliable; a perpendicular inward nudge + // moves the point clearly inside (or outside) the polygon. + // Sample the wall at 1/4, 1/2, 3/4 positions with a perpendicular nudge. + const PERP_STEP = 1e-4 + const pnx = (-nz / step) * PERP_STEP // perpendicular left + const pnz = (nx / step) * PERP_STEP + for (const t of [0.25, 0.5, 0.75]) { + const bx = start[0] + dx * t + const bz = start[1] + dz * t + if (pointInPolygon(bx + pnx, bz + pnz, polygon)) return true + if (pointInPolygon(bx - pnx, bz - pnz, polygon)) return true + } } // Check if midpoint is inside (catches walls crossing through) @@ -557,26 +572,42 @@ export class SpatialGridManager { let maxElevation = -Infinity for (const slab of slabMap.values()) { if (slab.polygon.length < 3) continue - if (wallOverlapsPolygon(start, end, slab.polygon)) { - // Check if wall midpoint is in a hole (if so, ignore this slab) + if (!wallOverlapsPolygon(start, end, slab.polygon)) continue + + const holes = slab.holes || [] + if (holes.length === 0) { + // No holes: wall is on this slab + const elevation = slab.elevation ?? 0.05 + if (elevation > maxElevation) maxElevation = elevation + continue + } + + // Sample multiple points along the wall to check whether any portion lies on + // solid slab (not inside any hole). Checking only the midpoint fails when the + // midpoint falls in a staircase hole but the wall's endpoints are on solid slab. + const dx = end[0] - start[0] + const dz = end[1] - start[1] + let hasValidPoint = false + for (const t of [0, 0.25, 0.5, 0.75, 1]) { + const px = start[0] + dx * t + const pz = start[1] + dz * t let inHole = false - const midX = (start[0] + end[0]) / 2 - const midZ = (start[1] + end[1]) / 2 - const holes = slab.holes || [] for (const hole of holes) { - if (hole.length >= 3 && pointInPolygon(midX, midZ, hole)) { + if (hole.length >= 3 && pointInPolygon(px, pz, hole)) { inHole = true break } } - if (!inHole) { - const elevation = slab.elevation ?? 0.05 - if (elevation > maxElevation) { - maxElevation = elevation - } + hasValidPoint = true + break } } + + if (hasValidPoint) { + const elevation = slab.elevation ?? 0.05 + if (elevation > maxElevation) maxElevation = elevation + } } return maxElevation === -Infinity ? 0 : maxElevation } diff --git a/packages/core/src/hooks/spatial-grid/spatial-grid-sync.ts b/packages/core/src/hooks/spatial-grid/spatial-grid-sync.ts index 9566159e..c6505eb3 100644 --- a/packages/core/src/hooks/spatial-grid/spatial-grid-sync.ts +++ b/packages/core/src/hooks/spatial-grid/spatial-grid-sync.ts @@ -85,7 +85,7 @@ export function initSpatialGridSync() { } } } else if (node.type === 'slab' && prev.type === 'slab') { - if (node.polygon !== prev.polygon || node.elevation !== prev.elevation) { + if (node.polygon !== prev.polygon || node.elevation !== prev.elevation || node.holes !== prev.holes) { const levelId = resolveLevelId(node, state.nodes) spatialGridManager.handleNodeUpdated(node, levelId) diff --git a/packages/core/src/store/use-scene.ts b/packages/core/src/store/use-scene.ts index 3a970b79..3f19f328 100644 --- a/packages/core/src/store/use-scene.ts +++ b/packages/core/src/store/use-scene.ts @@ -167,7 +167,6 @@ const useScene: UseSceneStore = create()( rootNodeIds: state.rootNodeIds, }), merge: (persistedState, currentState) => { - console.log('merge calling...', persistedState, currentState) const persisted = persistedState as Partial // Backward compat: add default scale to item nodes saved before scale was added if (persisted.nodes) {