Refactor guide UI state and slab rendering

This commit is contained in:
sudhir
2026-05-01 00:33:57 +05:30
parent 1dc9ea0ba8
commit 3df3d12f46
9 changed files with 172 additions and 108 deletions
+2 -1
View File
@@ -33,6 +33,7 @@ export {
} from './hooks/spatial-grid/spatial-grid-sync'
export { useSpatialQuery } from './hooks/spatial-grid/use-spatial-query'
export { loadAssetUrl, saveAsset } from './lib/asset-storage'
export { getRenderableSlabPolygon } from './lib/slab-polygon'
export {
detectSpacesForLevel,
initSpaceDetectionSync,
@@ -71,7 +72,7 @@ export { DoorSystem } from './systems/door/door-system'
export { FenceSystem } from './systems/fence/fence-system'
export { ItemSystem } from './systems/item/item-system'
export { RoofSystem } from './systems/roof/roof-system'
export { getRenderableSlabPolygon, SlabSystem } from './systems/slab/slab-system'
export { SlabSystem } from './systems/slab/slab-system'
export { StairSystem } from './systems/stair/stair-system'
export {
getClampedWallCurveOffset,
+67
View File
@@ -0,0 +1,67 @@
import type { SlabNode } from '../schema'
import { insetPolygonFromCentroid, simplifyClosedPolygon } from './polygon-geometry'
/** Half of default wall thickness — used to extend slab geometry under walls */
const SLAB_OUTSET = 0.05
const AUTO_SLAB_INSET = 0.02
const AUTO_SLAB_SIMPLIFY_TOLERANCE = 0.08
export function getRenderableSlabPolygon(slabNode: SlabNode): Array<[number, number]> {
return slabNode.autoFromWalls
? simplifyClosedPolygon(
insetPolygonFromCentroid(slabNode.polygon, AUTO_SLAB_INSET),
AUTO_SLAB_SIMPLIFY_TOLERANCE,
)
: outsetPolygon(slabNode.polygon, SLAB_OUTSET)
}
/**
* Expand a polygon outward by a uniform distance.
* Offsets each edge outward then intersects consecutive offset edges.
*/
function outsetPolygon(polygon: Array<[number, number]>, amount: number): Array<[number, number]> {
const n = polygon.length
if (n < 3) return polygon
// Determine winding via signed area
let area2 = 0
for (let i = 0; i < n; i++) {
const j = (i + 1) % n
area2 += polygon[i]![0] * polygon[j]![1] - polygon[j]![0] * polygon[i]![1]
}
const s = area2 >= 0 ? 1 : -1
// Offset each edge outward by amount
const offEdges: Array<[number, number, number, number]> = []
for (let i = 0; i < n; i++) {
const j = (i + 1) % n
const dx = polygon[j]![0] - polygon[i]![0]
const dz = polygon[j]![1] - polygon[i]![1]
const len = Math.sqrt(dx * dx + dz * dz)
if (len < 1e-9) {
offEdges.push([polygon[i]![0], polygon[i]![1], dx, dz])
continue
}
const nx = ((s * dz) / len) * amount
const nz = ((s * -dx) / len) * amount
offEdges.push([polygon[i]![0] + nx, polygon[i]![1] + nz, dx, dz])
}
// Intersect consecutive offset edges to get new vertices
const result: Array<[number, number]> = []
for (let i = 0; i < n; i++) {
const j = (i + 1) % n
const [ax, az, adx, adz] = offEdges[i]!
const [bx, bz, bdx, bdz] = offEdges[j]!
const denom = adx * bdz - adz * bdx
if (Math.abs(denom) < 1e-9) {
// Parallel edges — use offset endpoint
result.push([ax + adx, az + adz])
} else {
const t = ((bx - ax) * bdz - (bz - az) * bdx) / denom
result.push([ax + t * adx, az + t * adz])
}
}
return result
}
-3
View File
@@ -9,7 +9,6 @@ export const GuideScaleReference = z.object({
measuredLengthUnits: z.number().positive(),
metersPerUnit: z.number().positive(),
label: z.string(),
visible: z.boolean().default(true),
})
export const GuideNode = BaseNode.extend({
@@ -20,8 +19,6 @@ export const GuideNode = BaseNode.extend({
rotation: z.tuple([z.number(), z.number(), z.number()]).default([0, 0, 0]),
scale: z.number().default(1),
opacity: z.number().min(0).max(100).default(50),
locked: z.boolean().default(false),
showIn3d: z.boolean().default(false),
scaleReference: GuideScaleReference.nullable().default(null),
})
+1 -66
View File
@@ -1,7 +1,7 @@
import { useFrame } from '@react-three/fiber'
import * as THREE from 'three'
import { sceneRegistry } from '../../hooks/scene-registry/scene-registry'
import { insetPolygonFromCentroid, simplifyClosedPolygon } from '../../lib/polygon-geometry'
import { getRenderableSlabPolygon } from '../../lib/slab-polygon'
import type { AnyNodeId, SlabNode } from '../../schema'
import useScene from '../../store/use-scene'
@@ -58,71 +58,6 @@ function updateSlabGeometry(node: SlabNode, mesh: THREE.Mesh) {
mesh.position.y = elevation < 0 ? elevation : 0
}
/** Half of default wall thickness — used to extend slab geometry under walls */
const SLAB_OUTSET = 0.05
const AUTO_SLAB_INSET = 0.02
const AUTO_SLAB_SIMPLIFY_TOLERANCE = 0.08
export function getRenderableSlabPolygon(slabNode: SlabNode): Array<[number, number]> {
return slabNode.autoFromWalls
? simplifyClosedPolygon(
insetPolygonFromCentroid(slabNode.polygon, AUTO_SLAB_INSET),
AUTO_SLAB_SIMPLIFY_TOLERANCE,
)
: outsetPolygon(slabNode.polygon, SLAB_OUTSET)
}
/**
* Expand a polygon outward by a uniform distance.
* Offsets each edge outward then intersects consecutive offset edges.
*/
function outsetPolygon(polygon: Array<[number, number]>, amount: number): Array<[number, number]> {
const n = polygon.length
if (n < 3) return polygon
// Determine winding via signed area
let area2 = 0
for (let i = 0; i < n; i++) {
const j = (i + 1) % n
area2 += polygon[i]![0] * polygon[j]![1] - polygon[j]![0] * polygon[i]![1]
}
const s = area2 >= 0 ? 1 : -1
// Offset each edge outward by amount
const offEdges: Array<[number, number, number, number]> = []
for (let i = 0; i < n; i++) {
const j = (i + 1) % n
const dx = polygon[j]![0] - polygon[i]![0]
const dz = polygon[j]![1] - polygon[i]![1]
const len = Math.sqrt(dx * dx + dz * dz)
if (len < 1e-9) {
offEdges.push([polygon[i]![0], polygon[i]![1], dx, dz])
continue
}
const nx = ((s * dz) / len) * amount
const nz = ((s * -dx) / len) * amount
offEdges.push([polygon[i]![0] + nx, polygon[i]![1] + nz, dx, dz])
}
// Intersect consecutive offset edges to get new vertices
const result: Array<[number, number]> = []
for (let i = 0; i < n; i++) {
const j = (i + 1) % n
const [ax, az, adx, adz] = offEdges[i]!
const [bx, bz, bdx, bdz] = offEdges[j]!
const denom = adx * bdz - adz * bdx
if (Math.abs(denom) < 1e-9) {
// Parallel edges — use offset endpoint
result.push([ax + adx, az + adz])
} else {
const t = ((bx - ax) * bdz - (bz - az) * bdx) / denom
result.push([ax + t * adx, az + t * adz])
}
}
return result
}
/**
* Generates extruded slab geometry from polygon
*/