handle holes in spatial grid manager

This commit is contained in:
wass08
2026-02-12 10:46:07 +09:00
parent 29e7fa09ef
commit cfa7b8bfc1
2 changed files with 62 additions and 12 deletions
@@ -42,6 +42,13 @@ export function SlabPanel() {
} }
}, [node, setEditingHoleIndex]) }, [node, setEditingHoleIndex])
// Clear hole editing state on unmount
useEffect(() => {
return () => {
setEditingHoleIndex(null)
}
}, [setEditingHoleIndex])
const handleAddHole = useCallback(() => { const handleAddHole = useCallback(() => {
if (!node) return if (!node) return
@@ -457,7 +457,7 @@ export class SpatialGridManager {
/** /**
* Get the total slab elevation at a given (x, z) position on a level. * Get the total slab elevation at a given (x, z) position on a level.
* Returns the highest slab elevation if the point is inside any slab polygon, otherwise 0. * Returns the highest slab elevation if the point is inside any slab polygon (but not in any holes), otherwise 0.
*/ */
getSlabElevationAt(levelId: string, x: number, z: number): number { getSlabElevationAt(levelId: string, x: number, z: number): number {
const slabMap = this.slabsByLevel.get(levelId) const slabMap = this.slabsByLevel.get(levelId)
@@ -466,9 +466,22 @@ export class SpatialGridManager {
let maxElevation = 0 let maxElevation = 0
for (const slab of slabMap.values()) { for (const slab of slabMap.values()) {
if (slab.polygon.length >= 3 && pointInPolygon(x, z, slab.polygon)) { if (slab.polygon.length >= 3 && pointInPolygon(x, z, slab.polygon)) {
const elevation = slab.elevation ?? 0.05 // Check if point is in any hole
if (elevation > maxElevation) { let inHole = false
maxElevation = elevation if (slab.holes && slab.holes.length > 0) {
for (const hole of slab.holes) {
if (hole.length >= 3 && pointInPolygon(x, z, hole)) {
inHole = true
break
}
}
}
if (!inHole) {
const elevation = slab.elevation ?? 0.05
if (elevation > maxElevation) {
maxElevation = elevation
}
} }
} }
} }
@@ -477,7 +490,7 @@ export class SpatialGridManager {
/** /**
* Get the slab elevation for an item using its full footprint (bounding box). * Get the slab elevation for an item using its full footprint (bounding box).
* Checks if any part of the item's rotated footprint overlaps with any slab polygon. * Checks if any part of the item's rotated footprint overlaps with any slab polygon (excluding holes).
* Returns the highest overlapping slab elevation, or 0 if none. * Returns the highest overlapping slab elevation, or 0 if none.
*/ */
getSlabElevationForItem( getSlabElevationForItem(
@@ -492,9 +505,24 @@ export class SpatialGridManager {
let maxElevation = -Infinity let maxElevation = -Infinity
for (const slab of slabMap.values()) { for (const slab of slabMap.values()) {
if (slab.polygon.length >= 3 && itemOverlapsPolygon(position, dimensions, rotation, slab.polygon, 0.01)) { if (slab.polygon.length >= 3 && itemOverlapsPolygon(position, dimensions, rotation, slab.polygon, 0.01)) {
const elevation = slab.elevation ?? 0.05 // Check if item is entirely within a hole (if so, ignore this slab)
if (elevation > maxElevation) { // We consider it entirely in a hole if the item center is in the hole
maxElevation = elevation let inHole = false
if (slab.holes && slab.holes.length > 0) {
const [cx, , cz] = position
for (const hole of slab.holes) {
if (hole.length >= 3 && pointInPolygon(cx, cz, hole)) {
inHole = true
break
}
}
}
if (!inHole) {
const elevation = slab.elevation ?? 0.05
if (elevation > maxElevation) {
maxElevation = elevation
}
} }
} }
} }
@@ -502,7 +530,7 @@ export class SpatialGridManager {
} }
/** /**
* Get the slab elevation for a wall by checking if it overlaps with any slab polygon. * Get the slab elevation for a wall by checking if it overlaps with any slab polygon (excluding holes).
* Uses wallOverlapsPolygon which handles edge cases (points on boundary, collinear segments). * Uses wallOverlapsPolygon which handles edge cases (points on boundary, collinear segments).
* Returns the highest slab elevation found, or 0 if none. * Returns the highest slab elevation found, or 0 if none.
*/ */
@@ -518,9 +546,24 @@ export class SpatialGridManager {
for (const slab of slabMap.values()) { for (const slab of slabMap.values()) {
if (slab.polygon.length < 3) continue if (slab.polygon.length < 3) continue
if (wallOverlapsPolygon(start, end, slab.polygon)) { if (wallOverlapsPolygon(start, end, slab.polygon)) {
const elevation = slab.elevation ?? 0.05 // Check if wall midpoint is in a hole (if so, ignore this slab)
if (elevation > maxElevation) { let inHole = false
maxElevation = elevation if (slab.holes && slab.holes.length > 0) {
const midX = (start[0] + end[0]) / 2
const midZ = (start[1] + end[1]) / 2
for (const hole of slab.holes) {
if (hole.length >= 3 && pointInPolygon(midX, midZ, hole)) {
inHole = true
break
}
}
}
if (!inHole) {
const elevation = slab.elevation ?? 0.05
if (elevation > maxElevation) {
maxElevation = elevation
}
} }
} }
} }