@pascal-app/core 0.5.1 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/events/bus.d.ts +37 -3
- package/dist/events/bus.d.ts.map +1 -1
- package/dist/events/bus.js +1 -1
- package/dist/hooks/spatial-grid/spatial-grid.d.ts +2 -0
- package/dist/hooks/spatial-grid/spatial-grid.d.ts.map +1 -1
- package/dist/hooks/spatial-grid/spatial-grid.js +43 -20
- package/dist/index.d.ts +4 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -1
- package/dist/lib/polygon-geometry.d.ts +3 -0
- package/dist/lib/polygon-geometry.d.ts.map +1 -0
- package/dist/lib/polygon-geometry.js +90 -0
- package/dist/lib/space-detection.d.ts +10 -17
- package/dist/lib/space-detection.d.ts.map +1 -1
- package/dist/lib/space-detection.js +666 -453
- package/dist/material-library.d.ts +18 -0
- package/dist/material-library.d.ts.map +1 -0
- package/dist/material-library.js +603 -0
- package/dist/schema/index.d.ts +9 -4
- package/dist/schema/index.d.ts.map +1 -1
- package/dist/schema/index.js +5 -4
- package/dist/schema/material.d.ts +109 -0
- package/dist/schema/material.d.ts.map +1 -1
- package/dist/schema/material.js +52 -0
- package/dist/schema/nodes/ceiling.d.ts +10 -0
- package/dist/schema/nodes/ceiling.d.ts.map +1 -1
- package/dist/schema/nodes/ceiling.js +6 -0
- package/dist/schema/nodes/door.d.ts +1 -0
- package/dist/schema/nodes/door.d.ts.map +1 -1
- package/dist/schema/nodes/fence.d.ts +34 -0
- package/dist/schema/nodes/fence.d.ts.map +1 -1
- package/dist/schema/nodes/fence.js +5 -0
- package/dist/schema/nodes/item.d.ts +2 -2
- package/dist/schema/nodes/roof-segment.d.ts +2 -0
- package/dist/schema/nodes/roof-segment.d.ts.map +1 -1
- package/dist/schema/nodes/roof-segment.js +1 -0
- package/dist/schema/nodes/roof.d.ts +108 -0
- package/dist/schema/nodes/roof.d.ts.map +1 -1
- package/dist/schema/nodes/roof.js +58 -2
- package/dist/schema/nodes/site.d.ts +1 -1
- package/dist/schema/nodes/slab.d.ts +10 -0
- package/dist/schema/nodes/slab.d.ts.map +1 -1
- package/dist/schema/nodes/slab.js +7 -0
- package/dist/schema/nodes/stair-segment.d.ts +2 -0
- package/dist/schema/nodes/stair-segment.d.ts.map +1 -1
- package/dist/schema/nodes/stair-segment.js +1 -0
- package/dist/schema/nodes/stair.d.ts +122 -2
- package/dist/schema/nodes/stair.d.ts.map +1 -1
- package/dist/schema/nodes/stair.js +72 -2
- package/dist/schema/nodes/surface-hole-metadata.d.ts +10 -0
- package/dist/schema/nodes/surface-hole-metadata.d.ts.map +1 -0
- package/dist/schema/nodes/surface-hole-metadata.js +5 -0
- package/dist/schema/nodes/wall.d.ts +87 -1
- package/dist/schema/nodes/wall.d.ts.map +1 -1
- package/dist/schema/nodes/wall.js +45 -4
- package/dist/schema/nodes/window.d.ts +1 -0
- package/dist/schema/nodes/window.d.ts.map +1 -1
- package/dist/schema/types.d.ts +343 -5
- package/dist/schema/types.d.ts.map +1 -1
- package/dist/store/actions/node-actions.d.ts +1 -1
- package/dist/store/actions/node-actions.d.ts.map +1 -1
- package/dist/store/actions/node-actions.js +175 -0
- package/dist/store/history-control.d.ts +14 -0
- package/dist/store/history-control.d.ts.map +1 -0
- package/dist/store/history-control.js +22 -0
- package/dist/store/use-scene.d.ts.map +1 -1
- package/dist/store/use-scene.js +248 -2
- package/dist/systems/ceiling/ceiling-system.d.ts.map +1 -1
- package/dist/systems/ceiling/ceiling-system.js +7 -0
- package/dist/systems/fence/fence-system.d.ts.map +1 -1
- package/dist/systems/fence/fence-system.js +106 -39
- package/dist/systems/roof/roof-system.d.ts.map +1 -1
- package/dist/systems/roof/roof-system.js +31 -1
- package/dist/systems/slab/slab-system.d.ts.map +1 -1
- package/dist/systems/slab/slab-system.js +45 -8
- package/dist/systems/stair/stair-opening-sync.d.ts +6 -0
- package/dist/systems/stair/stair-opening-sync.d.ts.map +1 -0
- package/dist/systems/stair/stair-opening-sync.js +515 -0
- package/dist/systems/stair/stair-system.d.ts.map +1 -1
- package/dist/systems/stair/stair-system.js +119 -2
- package/dist/systems/wall/wall-curve.d.ts +43 -0
- package/dist/systems/wall/wall-curve.d.ts.map +1 -0
- package/dist/systems/wall/wall-curve.js +176 -0
- package/dist/systems/wall/wall-footprint.d.ts.map +1 -1
- package/dist/systems/wall/wall-footprint.js +16 -2
- package/dist/systems/wall/wall-mitering.d.ts +7 -0
- package/dist/systems/wall/wall-mitering.d.ts.map +1 -1
- package/dist/systems/wall/wall-mitering.js +76 -3
- package/dist/systems/wall/wall-system.d.ts.map +1 -1
- package/dist/systems/wall/wall-system.js +202 -2
- package/package.json +3 -3
|
@@ -1,13 +1,19 @@
|
|
|
1
1
|
import { useFrame } from '@react-three/fiber';
|
|
2
|
+
import { useEffect, useRef } from 'react';
|
|
2
3
|
import * as THREE from 'three';
|
|
3
4
|
import { mergeGeometries } from 'three/examples/jsm/utils/BufferGeometryUtils.js';
|
|
4
5
|
import { sceneRegistry } from '../../hooks/scene-registry/scene-registry';
|
|
5
6
|
import { spatialGridManager } from '../../hooks/spatial-grid/spatial-grid-manager';
|
|
6
7
|
import { resolveLevelId } from '../../hooks/spatial-grid/spatial-grid-sync';
|
|
7
8
|
import useScene from '../../store/use-scene';
|
|
9
|
+
import { syncAutoStairOpenings } from './stair-opening-sync';
|
|
8
10
|
const pendingStairUpdates = new Set();
|
|
9
11
|
const MAX_STAIRS_PER_FRAME = 2;
|
|
10
12
|
const MAX_SEGMENTS_PER_FRAME = 4;
|
|
13
|
+
const STAIR_TREAD_MATERIAL_INDEX = 0;
|
|
14
|
+
const STAIR_SIDE_MATERIAL_INDEX = 1;
|
|
15
|
+
const _uvPosition = new THREE.Vector3();
|
|
16
|
+
const _uvNormal = new THREE.Vector3();
|
|
11
17
|
// ============================================================================
|
|
12
18
|
// STAIR SYSTEM
|
|
13
19
|
// ============================================================================
|
|
@@ -15,6 +21,26 @@ export const StairSystem = () => {
|
|
|
15
21
|
const dirtyNodes = useScene((state) => state.dirtyNodes);
|
|
16
22
|
const clearDirty = useScene((state) => state.clearDirty);
|
|
17
23
|
const rootNodeIds = useScene((state) => state.rootNodeIds);
|
|
24
|
+
const syncingAutoOpeningsRef = useRef(false);
|
|
25
|
+
useEffect(() => {
|
|
26
|
+
const applyUpdates = (updates) => {
|
|
27
|
+
if (updates.length === 0)
|
|
28
|
+
return;
|
|
29
|
+
syncingAutoOpeningsRef.current = true;
|
|
30
|
+
useScene.getState().updateNodes(updates);
|
|
31
|
+
queueMicrotask(() => {
|
|
32
|
+
syncingAutoOpeningsRef.current = false;
|
|
33
|
+
});
|
|
34
|
+
};
|
|
35
|
+
applyUpdates(syncAutoStairOpenings(useScene.getState().nodes));
|
|
36
|
+
return useScene.subscribe((state, prevState) => {
|
|
37
|
+
if (syncingAutoOpeningsRef.current)
|
|
38
|
+
return;
|
|
39
|
+
if (state.nodes === prevState.nodes)
|
|
40
|
+
return;
|
|
41
|
+
applyUpdates(syncAutoStairOpenings(state.nodes));
|
|
42
|
+
});
|
|
43
|
+
}, []);
|
|
18
44
|
useFrame(() => {
|
|
19
45
|
if (rootNodeIds.length === 0) {
|
|
20
46
|
pendingStairUpdates.clear();
|
|
@@ -159,7 +185,7 @@ function generateStairSegmentGeometry(segment, absoluteHeight) {
|
|
|
159
185
|
}
|
|
160
186
|
}
|
|
161
187
|
shape.lineTo(0, 0);
|
|
162
|
-
const
|
|
188
|
+
const extrudedGeometry = new THREE.ExtrudeGeometry(shape, {
|
|
163
189
|
steps: 1,
|
|
164
190
|
depth: width,
|
|
165
191
|
bevelEnabled: false,
|
|
@@ -169,13 +195,21 @@ function generateStairSegmentGeometry(segment, absoluteHeight) {
|
|
|
169
195
|
const matrix = new THREE.Matrix4();
|
|
170
196
|
matrix.makeRotationY(-Math.PI / 2);
|
|
171
197
|
matrix.setPosition(width / 2, 0, 0);
|
|
172
|
-
|
|
198
|
+
extrudedGeometry.applyMatrix4(matrix);
|
|
199
|
+
extrudedGeometry.computeVertexNormals();
|
|
200
|
+
const geometry = extrudedGeometry.toNonIndexed() ?? extrudedGeometry;
|
|
201
|
+
if (geometry !== extrudedGeometry) {
|
|
202
|
+
extrudedGeometry.dispose();
|
|
203
|
+
}
|
|
204
|
+
applyStairSegmentUvs(geometry);
|
|
205
|
+
ensureUv2Attribute(geometry);
|
|
173
206
|
return geometry;
|
|
174
207
|
}
|
|
175
208
|
function updateStairSegmentGeometry(node, mesh) {
|
|
176
209
|
// Compute absolute height from parent chain
|
|
177
210
|
const absoluteHeight = computeAbsoluteHeight(node);
|
|
178
211
|
const newGeometry = generateStairSegmentGeometry(node, absoluteHeight);
|
|
212
|
+
applyStraightStairMaterialGroups(newGeometry);
|
|
179
213
|
mesh.geometry.dispose();
|
|
180
214
|
mesh.geometry = newGeometry;
|
|
181
215
|
// NOTE: position/rotation are NOT set here — they're set by syncSegmentMeshTransforms
|
|
@@ -274,12 +308,93 @@ function updateMergedStairGeometry(stairNode, group, nodes) {
|
|
|
274
308
|
geometries.push(geo);
|
|
275
309
|
}
|
|
276
310
|
const merged = mergeGeometries(geometries, false) ?? createEmptyGeometry();
|
|
311
|
+
applyStraightStairMaterialGroups(merged);
|
|
277
312
|
replaceMeshGeometry(mergedMesh, merged);
|
|
278
313
|
// Dispose individual geometries
|
|
279
314
|
for (const geo of geometries) {
|
|
280
315
|
geo.dispose();
|
|
281
316
|
}
|
|
282
317
|
}
|
|
318
|
+
function applyStraightStairMaterialGroups(geometry) {
|
|
319
|
+
const position = geometry.getAttribute('position');
|
|
320
|
+
if (!position || position.count < 3) {
|
|
321
|
+
geometry.clearGroups();
|
|
322
|
+
return;
|
|
323
|
+
}
|
|
324
|
+
const index = geometry.getIndex();
|
|
325
|
+
const triangleCount = index ? index.count / 3 : position.count / 3;
|
|
326
|
+
if (!Number.isFinite(triangleCount) || triangleCount <= 0) {
|
|
327
|
+
geometry.clearGroups();
|
|
328
|
+
return;
|
|
329
|
+
}
|
|
330
|
+
const triangleMaterials = new Array(triangleCount);
|
|
331
|
+
const v0 = new THREE.Vector3();
|
|
332
|
+
const v1 = new THREE.Vector3();
|
|
333
|
+
const v2 = new THREE.Vector3();
|
|
334
|
+
const edge1 = new THREE.Vector3();
|
|
335
|
+
const edge2 = new THREE.Vector3();
|
|
336
|
+
const normal = new THREE.Vector3();
|
|
337
|
+
for (let triangleIndex = 0; triangleIndex < triangleCount; triangleIndex++) {
|
|
338
|
+
const vertexOffset = triangleIndex * 3;
|
|
339
|
+
const a = index ? index.getX(vertexOffset) : vertexOffset;
|
|
340
|
+
const b = index ? index.getX(vertexOffset + 1) : vertexOffset + 1;
|
|
341
|
+
const c = index ? index.getX(vertexOffset + 2) : vertexOffset + 2;
|
|
342
|
+
v0.fromBufferAttribute(position, a);
|
|
343
|
+
v1.fromBufferAttribute(position, b);
|
|
344
|
+
v2.fromBufferAttribute(position, c);
|
|
345
|
+
edge1.subVectors(v1, v0);
|
|
346
|
+
edge2.subVectors(v2, v0);
|
|
347
|
+
normal.crossVectors(edge1, edge2);
|
|
348
|
+
triangleMaterials[triangleIndex] =
|
|
349
|
+
normal.lengthSq() > 0 && normal.normalize().y > 0.75
|
|
350
|
+
? STAIR_TREAD_MATERIAL_INDEX
|
|
351
|
+
: STAIR_SIDE_MATERIAL_INDEX;
|
|
352
|
+
}
|
|
353
|
+
geometry.clearGroups();
|
|
354
|
+
let currentMaterial = triangleMaterials[0];
|
|
355
|
+
let groupStart = 0;
|
|
356
|
+
for (let triangleIndex = 1; triangleIndex < triangleMaterials.length; triangleIndex++) {
|
|
357
|
+
const materialIndex = triangleMaterials[triangleIndex];
|
|
358
|
+
if (materialIndex === currentMaterial)
|
|
359
|
+
continue;
|
|
360
|
+
geometry.addGroup(groupStart * 3, (triangleIndex - groupStart) * 3, currentMaterial);
|
|
361
|
+
groupStart = triangleIndex;
|
|
362
|
+
currentMaterial = materialIndex;
|
|
363
|
+
}
|
|
364
|
+
geometry.addGroup(groupStart * 3, (triangleMaterials.length - groupStart) * 3, currentMaterial ?? STAIR_SIDE_MATERIAL_INDEX);
|
|
365
|
+
}
|
|
366
|
+
function applyStairSegmentUvs(geometry) {
|
|
367
|
+
const position = geometry.getAttribute('position');
|
|
368
|
+
const normal = geometry.getAttribute('normal');
|
|
369
|
+
if (!position || !normal || position.count === 0) {
|
|
370
|
+
geometry.deleteAttribute('uv');
|
|
371
|
+
return;
|
|
372
|
+
}
|
|
373
|
+
const uv = [];
|
|
374
|
+
for (let index = 0; index < position.count; index++) {
|
|
375
|
+
_uvPosition.fromBufferAttribute(position, index);
|
|
376
|
+
_uvNormal.fromBufferAttribute(normal, index).normalize();
|
|
377
|
+
const absX = Math.abs(_uvNormal.x);
|
|
378
|
+
const absY = Math.abs(_uvNormal.y);
|
|
379
|
+
const absZ = Math.abs(_uvNormal.z);
|
|
380
|
+
if (absY >= absX && absY >= absZ) {
|
|
381
|
+
uv.push(_uvPosition.x, _uvPosition.z);
|
|
382
|
+
}
|
|
383
|
+
else if (absX >= absZ) {
|
|
384
|
+
uv.push(_uvPosition.z, _uvPosition.y);
|
|
385
|
+
}
|
|
386
|
+
else {
|
|
387
|
+
uv.push(_uvPosition.x, _uvPosition.y);
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
geometry.setAttribute('uv', new THREE.Float32BufferAttribute(uv, 2));
|
|
391
|
+
}
|
|
392
|
+
function ensureUv2Attribute(geometry) {
|
|
393
|
+
const uv = geometry.getAttribute('uv');
|
|
394
|
+
if (!uv)
|
|
395
|
+
return;
|
|
396
|
+
geometry.setAttribute('uv2', new THREE.Float32BufferAttribute(Array.from(uv.array), 2));
|
|
397
|
+
}
|
|
283
398
|
/**
|
|
284
399
|
* Computes world-relative transforms for each segment by chaining
|
|
285
400
|
* based on attachmentSide. This mirrors the prototype's StairSystem logic.
|
|
@@ -334,6 +449,8 @@ function rotateXZ(x, z, angle) {
|
|
|
334
449
|
function createEmptyGeometry() {
|
|
335
450
|
const geometry = new THREE.BufferGeometry();
|
|
336
451
|
geometry.setAttribute('position', new THREE.Float32BufferAttribute([], 3));
|
|
452
|
+
geometry.addGroup(0, 0, STAIR_TREAD_MATERIAL_INDEX);
|
|
453
|
+
geometry.addGroup(0, 0, STAIR_SIDE_MATERIAL_INDEX);
|
|
337
454
|
return geometry;
|
|
338
455
|
}
|
|
339
456
|
function replaceMeshGeometry(mesh, geometry) {
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { Point2D } from './wall-mitering';
|
|
2
|
+
import type { FenceNode, WallNode } from '../../schema';
|
|
3
|
+
type WallCurveLike = Pick<WallNode | FenceNode, 'start' | 'end' | 'curveOffset'>;
|
|
4
|
+
type CurveFrame = {
|
|
5
|
+
point: Point2D;
|
|
6
|
+
tangent: Point2D;
|
|
7
|
+
normal: Point2D;
|
|
8
|
+
};
|
|
9
|
+
type WallSurfaceMiterOverrides = {
|
|
10
|
+
startLeft?: Point2D;
|
|
11
|
+
startRight?: Point2D;
|
|
12
|
+
endLeft?: Point2D;
|
|
13
|
+
endRight?: Point2D;
|
|
14
|
+
};
|
|
15
|
+
export declare function getWallStartPoint(wall: WallCurveLike): Point2D;
|
|
16
|
+
export declare function getWallEndPoint(wall: WallCurveLike): Point2D;
|
|
17
|
+
export declare function getWallChordLength(wall: WallCurveLike): number;
|
|
18
|
+
export declare function getMaxWallCurveOffset(wall: WallCurveLike): number;
|
|
19
|
+
export declare function getWallStraightSnapOffset(wall: WallCurveLike): number;
|
|
20
|
+
export declare function normalizeWallCurveOffset(wall: WallCurveLike, offset: number): number;
|
|
21
|
+
export declare function getClampedWallCurveOffset(wall: WallCurveLike): number;
|
|
22
|
+
export declare function isCurvedWall(wall: WallCurveLike): boolean;
|
|
23
|
+
export declare function getWallChordFrame(wall: WallCurveLike): {
|
|
24
|
+
start: Point2D;
|
|
25
|
+
end: Point2D;
|
|
26
|
+
midpoint: Point2D;
|
|
27
|
+
tangent: {
|
|
28
|
+
x: number;
|
|
29
|
+
y: number;
|
|
30
|
+
};
|
|
31
|
+
normal: {
|
|
32
|
+
x: number;
|
|
33
|
+
y: number;
|
|
34
|
+
};
|
|
35
|
+
length: number;
|
|
36
|
+
};
|
|
37
|
+
export declare function getWallCurveFrameAt(wall: WallCurveLike, t: number): CurveFrame;
|
|
38
|
+
export declare function getWallMidpointHandlePoint(wall: WallCurveLike): Point2D;
|
|
39
|
+
export declare function sampleWallCenterline(wall: WallCurveLike, segments?: number): Point2D[];
|
|
40
|
+
export declare function getWallCurveLength(wall: WallCurveLike, segments?: number): number;
|
|
41
|
+
export declare function getWallSurfacePolygon(wall: Pick<WallNode | FenceNode, 'start' | 'end' | 'curveOffset' | 'thickness'>, segments?: number, miterOverrides?: WallSurfaceMiterOverrides): Point2D[];
|
|
42
|
+
export {};
|
|
43
|
+
//# sourceMappingURL=wall-curve.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wall-curve.d.ts","sourceRoot":"","sources":["../../../src/systems/wall/wall-curve.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAA;AAC9C,OAAO,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAA;AAKvD,KAAK,aAAa,GAAG,IAAI,CAAC,QAAQ,GAAG,SAAS,EAAE,OAAO,GAAG,KAAK,GAAG,aAAa,CAAC,CAAA;AAEhF,KAAK,UAAU,GAAG;IAChB,KAAK,EAAE,OAAO,CAAA;IACd,OAAO,EAAE,OAAO,CAAA;IAChB,MAAM,EAAE,OAAO,CAAA;CAChB,CAAA;AAED,KAAK,yBAAyB,GAAG;IAC/B,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,QAAQ,CAAC,EAAE,OAAO,CAAA;CACnB,CAAA;AAcD,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,aAAa,GAAG,OAAO,CAE9D;AAED,wBAAgB,eAAe,CAAC,IAAI,EAAE,aAAa,GAAG,OAAO,CAE5D;AAED,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,aAAa,UAErD;AAED,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,aAAa,UAExD;AAED,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,aAAa,UAE5D;AAWD,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,aAAa,EAAE,MAAM,EAAE,MAAM,UAG3E;AAED,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,aAAa,UAI5D;AAED,wBAAgB,YAAY,CAAC,IAAI,EAAE,aAAa,WAE/C;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,aAAa;;;;;;;;;;;;;EA6BpD;AA+BD,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,aAAa,EAAE,CAAC,EAAE,MAAM,GAAG,UAAU,CAwC9E;AAED,wBAAgB,0BAA0B,CAAC,IAAI,EAAE,aAAa,WAE7D;AAED,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,aAAa,EAAE,QAAQ,SAA0B,aAG3F;AAED,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,aAAa,EAAE,QAAQ,SAA0B,UASzF;AAED,wBAAgB,qBAAqB,CACnC,IAAI,EAAE,IAAI,CAAC,QAAQ,GAAG,SAAS,EAAE,OAAO,GAAG,KAAK,GAAG,aAAa,GAAG,WAAW,CAAC,EAC/E,QAAQ,SAA0B,EAClC,cAAc,CAAC,EAAE,yBAAyB,aA2B3C"}
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
const CURVE_EPSILON = 1e-6;
|
|
2
|
+
const DEFAULT_SAMPLE_SEGMENTS = 24;
|
|
3
|
+
function clamp01(value) {
|
|
4
|
+
return Math.max(0, Math.min(1, value));
|
|
5
|
+
}
|
|
6
|
+
function lerp(a, b, t) {
|
|
7
|
+
return a + (b - a) * t;
|
|
8
|
+
}
|
|
9
|
+
function distance(a, b) {
|
|
10
|
+
return Math.hypot(b.x - a.x, b.y - a.y);
|
|
11
|
+
}
|
|
12
|
+
export function getWallStartPoint(wall) {
|
|
13
|
+
return { x: wall.start[0], y: wall.start[1] };
|
|
14
|
+
}
|
|
15
|
+
export function getWallEndPoint(wall) {
|
|
16
|
+
return { x: wall.end[0], y: wall.end[1] };
|
|
17
|
+
}
|
|
18
|
+
export function getWallChordLength(wall) {
|
|
19
|
+
return distance(getWallStartPoint(wall), getWallEndPoint(wall));
|
|
20
|
+
}
|
|
21
|
+
export function getMaxWallCurveOffset(wall) {
|
|
22
|
+
return getWallChordLength(wall) / 2;
|
|
23
|
+
}
|
|
24
|
+
export function getWallStraightSnapOffset(wall) {
|
|
25
|
+
return Math.min(0.03, Math.max(0.005, getWallChordLength(wall) * 0.005));
|
|
26
|
+
}
|
|
27
|
+
function clampCurveOffset(wall, offset) {
|
|
28
|
+
const maxOffset = getMaxWallCurveOffset(wall);
|
|
29
|
+
if (!Number.isFinite(maxOffset) || maxOffset < CURVE_EPSILON) {
|
|
30
|
+
return 0;
|
|
31
|
+
}
|
|
32
|
+
return Math.max(-maxOffset, Math.min(maxOffset, offset));
|
|
33
|
+
}
|
|
34
|
+
export function normalizeWallCurveOffset(wall, offset) {
|
|
35
|
+
const clamped = clampCurveOffset(wall, offset);
|
|
36
|
+
return Math.abs(clamped) <= getWallStraightSnapOffset(wall) ? 0 : clamped;
|
|
37
|
+
}
|
|
38
|
+
export function getClampedWallCurveOffset(wall) {
|
|
39
|
+
const value = wall.curveOffset ?? 0;
|
|
40
|
+
const normalized = normalizeWallCurveOffset(wall, value);
|
|
41
|
+
return Math.abs(normalized) > CURVE_EPSILON ? normalized : 0;
|
|
42
|
+
}
|
|
43
|
+
export function isCurvedWall(wall) {
|
|
44
|
+
return Math.abs(getClampedWallCurveOffset(wall)) > CURVE_EPSILON;
|
|
45
|
+
}
|
|
46
|
+
export function getWallChordFrame(wall) {
|
|
47
|
+
const start = getWallStartPoint(wall);
|
|
48
|
+
const end = getWallEndPoint(wall);
|
|
49
|
+
const dx = end.x - start.x;
|
|
50
|
+
const dy = end.y - start.y;
|
|
51
|
+
const length = Math.hypot(dx, dy);
|
|
52
|
+
if (length < CURVE_EPSILON) {
|
|
53
|
+
return {
|
|
54
|
+
start,
|
|
55
|
+
end,
|
|
56
|
+
midpoint: start,
|
|
57
|
+
tangent: { x: 1, y: 0 },
|
|
58
|
+
normal: { x: 0, y: 1 },
|
|
59
|
+
length: 0,
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
return {
|
|
63
|
+
start,
|
|
64
|
+
end,
|
|
65
|
+
midpoint: {
|
|
66
|
+
x: (start.x + end.x) / 2,
|
|
67
|
+
y: (start.y + end.y) / 2,
|
|
68
|
+
},
|
|
69
|
+
tangent: { x: dx / length, y: dy / length },
|
|
70
|
+
normal: { x: -dy / length, y: dx / length },
|
|
71
|
+
length,
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
function getWallArcData(wall) {
|
|
75
|
+
const chord = getWallChordFrame(wall);
|
|
76
|
+
const sagitta = getClampedWallCurveOffset(wall);
|
|
77
|
+
if (Math.abs(sagitta) <= CURVE_EPSILON || chord.length < CURVE_EPSILON) {
|
|
78
|
+
return null;
|
|
79
|
+
}
|
|
80
|
+
const absSagitta = Math.abs(sagitta);
|
|
81
|
+
const radius = chord.length * chord.length / (8 * absSagitta) + absSagitta / 2;
|
|
82
|
+
const centerOffset = radius - absSagitta;
|
|
83
|
+
const direction = Math.sign(sagitta) || 1;
|
|
84
|
+
const center = {
|
|
85
|
+
x: chord.midpoint.x + chord.normal.x * centerOffset * direction,
|
|
86
|
+
y: chord.midpoint.y + chord.normal.y * centerOffset * direction,
|
|
87
|
+
};
|
|
88
|
+
const startAngle = Math.atan2(chord.start.y - center.y, chord.start.x - center.x);
|
|
89
|
+
const endAngle = Math.atan2(chord.end.y - center.y, chord.end.x - center.x);
|
|
90
|
+
let delta = endAngle - startAngle;
|
|
91
|
+
if (direction > 0) {
|
|
92
|
+
while (delta <= 0)
|
|
93
|
+
delta += Math.PI * 2;
|
|
94
|
+
}
|
|
95
|
+
else {
|
|
96
|
+
while (delta >= 0)
|
|
97
|
+
delta -= Math.PI * 2;
|
|
98
|
+
}
|
|
99
|
+
return { center, radius, startAngle, delta, direction };
|
|
100
|
+
}
|
|
101
|
+
export function getWallCurveFrameAt(wall, t) {
|
|
102
|
+
const chord = getWallChordFrame(wall);
|
|
103
|
+
if (!isCurvedWall(wall) || chord.length < CURVE_EPSILON) {
|
|
104
|
+
return {
|
|
105
|
+
point: {
|
|
106
|
+
x: lerp(chord.start.x, chord.end.x, clamp01(t)),
|
|
107
|
+
y: lerp(chord.start.y, chord.end.y, clamp01(t)),
|
|
108
|
+
},
|
|
109
|
+
tangent: chord.tangent,
|
|
110
|
+
normal: chord.normal,
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
const arc = getWallArcData(wall);
|
|
114
|
+
if (!arc) {
|
|
115
|
+
return {
|
|
116
|
+
point: chord.midpoint,
|
|
117
|
+
tangent: chord.tangent,
|
|
118
|
+
normal: chord.normal,
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
const angle = arc.startAngle + arc.delta * clamp01(t);
|
|
122
|
+
const point = {
|
|
123
|
+
x: arc.center.x + Math.cos(angle) * arc.radius,
|
|
124
|
+
y: arc.center.y + Math.sin(angle) * arc.radius,
|
|
125
|
+
};
|
|
126
|
+
const tangent = arc.direction > 0
|
|
127
|
+
? { x: -Math.sin(angle), y: Math.cos(angle) }
|
|
128
|
+
: { x: Math.sin(angle), y: -Math.cos(angle) };
|
|
129
|
+
return {
|
|
130
|
+
point,
|
|
131
|
+
tangent,
|
|
132
|
+
normal: {
|
|
133
|
+
x: -tangent.y,
|
|
134
|
+
y: tangent.x,
|
|
135
|
+
},
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
export function getWallMidpointHandlePoint(wall) {
|
|
139
|
+
return getWallCurveFrameAt(wall, 0.5).point;
|
|
140
|
+
}
|
|
141
|
+
export function sampleWallCenterline(wall, segments = DEFAULT_SAMPLE_SEGMENTS) {
|
|
142
|
+
const count = Math.max(1, segments);
|
|
143
|
+
return Array.from({ length: count + 1 }, (_, index) => getWallCurveFrameAt(wall, index / count).point);
|
|
144
|
+
}
|
|
145
|
+
export function getWallCurveLength(wall, segments = DEFAULT_SAMPLE_SEGMENTS) {
|
|
146
|
+
const points = sampleWallCenterline(wall, segments);
|
|
147
|
+
let totalLength = 0;
|
|
148
|
+
for (let index = 1; index < points.length; index += 1) {
|
|
149
|
+
totalLength += distance(points[index - 1], points[index]);
|
|
150
|
+
}
|
|
151
|
+
return totalLength;
|
|
152
|
+
}
|
|
153
|
+
export function getWallSurfacePolygon(wall, segments = DEFAULT_SAMPLE_SEGMENTS, miterOverrides) {
|
|
154
|
+
const halfThickness = (wall.thickness ?? 0.1) / 2;
|
|
155
|
+
const count = Math.max(1, segments);
|
|
156
|
+
const left = [];
|
|
157
|
+
const right = [];
|
|
158
|
+
for (let index = 0; index <= count; index += 1) {
|
|
159
|
+
const frame = getWallCurveFrameAt(wall, index / count);
|
|
160
|
+
left.push({
|
|
161
|
+
x: frame.point.x + frame.normal.x * halfThickness,
|
|
162
|
+
y: frame.point.y + frame.normal.y * halfThickness,
|
|
163
|
+
});
|
|
164
|
+
right.push({
|
|
165
|
+
x: frame.point.x - frame.normal.x * halfThickness,
|
|
166
|
+
y: frame.point.y - frame.normal.y * halfThickness,
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
if (left.length > 0 && right.length > 0) {
|
|
170
|
+
left[0] = miterOverrides?.startLeft ?? left[0];
|
|
171
|
+
right[0] = miterOverrides?.startRight ?? right[0];
|
|
172
|
+
left[left.length - 1] = miterOverrides?.endLeft ?? left[left.length - 1];
|
|
173
|
+
right[right.length - 1] = miterOverrides?.endRight ?? right[right.length - 1];
|
|
174
|
+
}
|
|
175
|
+
return [...right, ...left.reverse()];
|
|
176
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"wall-footprint.d.ts","sourceRoot":"","sources":["../../../src/systems/wall/wall-footprint.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAA;
|
|
1
|
+
{"version":3,"file":"wall-footprint.d.ts","sourceRoot":"","sources":["../../../src/systems/wall/wall-footprint.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAA;AAE5C,OAAO,EAEL,KAAK,OAAO,EAEZ,KAAK,aAAa,EACnB,MAAM,iBAAiB,CAAA;AAExB,eAAO,MAAM,sBAAsB,MAAM,CAAA;AACzC,eAAO,MAAM,mBAAmB,MAAM,CAAA;AAGtC,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,QAAQ,GAAG,MAAM,CAE3D;AAED,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,QAAQ,EAAE,SAAS,EAAE,aAAa,GAAG,OAAO,EAAE,CA6D5F"}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { getWallSurfacePolygon, isCurvedWall } from './wall-curve';
|
|
2
|
+
import { getWallMiterBoundaryPoints, pointToKey, } from './wall-mitering';
|
|
2
3
|
export const DEFAULT_WALL_THICKNESS = 0.1;
|
|
3
4
|
export const DEFAULT_WALL_HEIGHT = 2.5;
|
|
5
|
+
const CURVED_WALL_SURFACE_SEGMENTS = 24;
|
|
4
6
|
export function getWallThickness(wallNode) {
|
|
5
7
|
return wallNode.thickness ?? DEFAULT_WALL_THICKNESS;
|
|
6
8
|
}
|
|
@@ -20,6 +22,19 @@ export function getWallPlanFootprint(wallNode, miterData) {
|
|
|
20
22
|
const keyEnd = pointToKey(wallEnd);
|
|
21
23
|
const startJunction = junctionData.get(keyStart)?.get(wallNode.id);
|
|
22
24
|
const endJunction = junctionData.get(keyEnd)?.get(wallNode.id);
|
|
25
|
+
if (isCurvedWall(wallNode)) {
|
|
26
|
+
const boundaryPoints = getWallMiterBoundaryPoints(wallNode, miterData);
|
|
27
|
+
if (!boundaryPoints) {
|
|
28
|
+
return [];
|
|
29
|
+
}
|
|
30
|
+
const { startLeft, startRight, endLeft, endRight } = boundaryPoints;
|
|
31
|
+
return getWallSurfacePolygon(wallNode, CURVED_WALL_SURFACE_SEGMENTS, {
|
|
32
|
+
endLeft,
|
|
33
|
+
endRight,
|
|
34
|
+
startLeft,
|
|
35
|
+
startRight,
|
|
36
|
+
});
|
|
37
|
+
}
|
|
23
38
|
const pStartLeft = startJunction?.left || {
|
|
24
39
|
x: wallStart.x + nUnit.x * halfT,
|
|
25
40
|
y: wallStart.y + nUnit.y * halfT,
|
|
@@ -28,7 +43,6 @@ export function getWallPlanFootprint(wallNode, miterData) {
|
|
|
28
43
|
x: wallStart.x - nUnit.x * halfT,
|
|
29
44
|
y: wallStart.y - nUnit.y * halfT,
|
|
30
45
|
};
|
|
31
|
-
// Junction offsets are stored relative to the outgoing direction.
|
|
32
46
|
const pEndLeft = endJunction?.right || {
|
|
33
47
|
x: wallEnd.x + nUnit.x * halfT,
|
|
34
48
|
y: wallEnd.y + nUnit.y * halfT,
|
|
@@ -3,6 +3,12 @@ export interface Point2D {
|
|
|
3
3
|
x: number;
|
|
4
4
|
y: number;
|
|
5
5
|
}
|
|
6
|
+
export interface WallMiterBoundaryPoints {
|
|
7
|
+
startLeft: Point2D;
|
|
8
|
+
startRight: Point2D;
|
|
9
|
+
endLeft: Point2D;
|
|
10
|
+
endRight: Point2D;
|
|
11
|
+
}
|
|
6
12
|
type WallIntersections = Map<string, {
|
|
7
13
|
left?: Point2D;
|
|
8
14
|
right?: Point2D;
|
|
@@ -24,6 +30,7 @@ export interface WallMiterData {
|
|
|
24
30
|
* Calculates miter data for all walls on a level
|
|
25
31
|
*/
|
|
26
32
|
export declare function calculateLevelMiters(walls: WallNode[]): WallMiterData;
|
|
33
|
+
export declare function getWallMiterBoundaryPoints(wall: WallNode, miterData: WallMiterData): WallMiterBoundaryPoints | null;
|
|
27
34
|
/**
|
|
28
35
|
* Gets wall IDs that share junctions with the given walls
|
|
29
36
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"wall-mitering.d.ts","sourceRoot":"","sources":["../../../src/systems/wall/wall-mitering.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAA;
|
|
1
|
+
{"version":3,"file":"wall-mitering.d.ts","sourceRoot":"","sources":["../../../src/systems/wall/wall-mitering.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAA;AAO5C,MAAM,WAAW,OAAO;IACtB,CAAC,EAAE,MAAM,CAAA;IACT,CAAC,EAAE,MAAM,CAAA;CACV;AAED,MAAM,WAAW,uBAAuB;IACtC,SAAS,EAAE,OAAO,CAAA;IAClB,UAAU,EAAE,OAAO,CAAA;IACnB,OAAO,EAAE,OAAO,CAAA;IAChB,QAAQ,EAAE,OAAO,CAAA;CAClB;AASD,KAAK,iBAAiB,GAAG,GAAG,CAAC,MAAM,EAAE;IAAE,IAAI,CAAC,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC,CAAA;AAGzE,KAAK,YAAY,GAAG,GAAG,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAAA;AAQlD,iBAAS,UAAU,CAAC,CAAC,EAAE,OAAO,EAAE,SAAS,SAAY,GAAG,MAAM,CAG7D;AA8CD,UAAU,QAAQ;IAChB,YAAY,EAAE,OAAO,CAAA;IACrB,cAAc,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,QAAQ,CAAC;QAAC,OAAO,EAAE,OAAO,GAAG,KAAK,GAAG,aAAa,CAAA;KAAE,CAAC,CAAA;CACpF;AA+ND,MAAM,WAAW,aAAa;IAE5B,YAAY,EAAE,YAAY,CAAA;IAE1B,SAAS,EAAE,GAAG,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAA;CACjC;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,QAAQ,EAAE,GAAG,aAAa,CAWrE;AAED,wBAAgB,0BAA0B,CACxC,IAAI,EAAE,QAAQ,EACd,SAAS,EAAE,aAAa,GACvB,uBAAuB,GAAG,IAAI,CA0BhC;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,QAAQ,EAAE,EAAE,YAAY,EAAE,GAAG,CAAC,MAAM,CAAC,GAAG,GAAG,CAAC,MAAM,CAAC,CA8C/F;AAGD,OAAO,EAAE,UAAU,EAAE,CAAA"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { getWallCurveFrameAt, isCurvedWall } from './wall-curve';
|
|
1
2
|
// ============================================================================
|
|
2
3
|
// UTILITY FUNCTIONS
|
|
3
4
|
// ============================================================================
|
|
@@ -79,6 +80,54 @@ function findJunctions(walls) {
|
|
|
79
80
|
}
|
|
80
81
|
return actualJunctions;
|
|
81
82
|
}
|
|
83
|
+
function getWallDirectionFromJunction(wall, endType) {
|
|
84
|
+
if (endType === 'passthrough') {
|
|
85
|
+
return {
|
|
86
|
+
x: wall.end[0] - wall.start[0],
|
|
87
|
+
y: wall.end[1] - wall.start[1],
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
if (isCurvedWall(wall)) {
|
|
91
|
+
const frame = getWallCurveFrameAt(wall, endType === 'start' ? 0 : 1);
|
|
92
|
+
return endType === 'start'
|
|
93
|
+
? frame.tangent
|
|
94
|
+
: { x: -frame.tangent.x, y: -frame.tangent.y };
|
|
95
|
+
}
|
|
96
|
+
return endType === 'start'
|
|
97
|
+
? { x: wall.end[0] - wall.start[0], y: wall.end[1] - wall.start[1] }
|
|
98
|
+
: { x: wall.start[0] - wall.end[0], y: wall.start[1] - wall.end[1] };
|
|
99
|
+
}
|
|
100
|
+
function getWallBoundaryFrame(wall, endType) {
|
|
101
|
+
if (isCurvedWall(wall)) {
|
|
102
|
+
const frame = getWallCurveFrameAt(wall, endType === 'start' ? 0 : 1);
|
|
103
|
+
return {
|
|
104
|
+
point: frame.point,
|
|
105
|
+
tangent: endType === 'start'
|
|
106
|
+
? frame.tangent
|
|
107
|
+
: { x: -frame.tangent.x, y: -frame.tangent.y },
|
|
108
|
+
normal: frame.normal,
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
const point = endType === 'start'
|
|
112
|
+
? { x: wall.start[0], y: wall.start[1] }
|
|
113
|
+
: { x: wall.end[0], y: wall.end[1] };
|
|
114
|
+
const vector = endType === 'start'
|
|
115
|
+
? { x: wall.end[0] - wall.start[0], y: wall.end[1] - wall.start[1] }
|
|
116
|
+
: { x: wall.start[0] - wall.end[0], y: wall.start[1] - wall.end[1] };
|
|
117
|
+
const length = Math.hypot(vector.x, vector.y);
|
|
118
|
+
if (length < 1e-9) {
|
|
119
|
+
return {
|
|
120
|
+
point,
|
|
121
|
+
tangent: { x: 1, y: 0 },
|
|
122
|
+
normal: { x: 0, y: 1 },
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
return {
|
|
126
|
+
point,
|
|
127
|
+
tangent: { x: vector.x / length, y: vector.y / length },
|
|
128
|
+
normal: { x: -vector.y / length, y: vector.x / length },
|
|
129
|
+
};
|
|
130
|
+
}
|
|
82
131
|
function calculateJunctionIntersections(junction, getThickness) {
|
|
83
132
|
const { meetingPoint, connectedWalls } = junction;
|
|
84
133
|
const processedWalls = [];
|
|
@@ -104,9 +153,7 @@ function calculateJunctionIntersections(junction, getThickness) {
|
|
|
104
153
|
}
|
|
105
154
|
else {
|
|
106
155
|
// Normal wall endpoint (start or end)
|
|
107
|
-
const v = endType
|
|
108
|
-
? { x: wall.end[0] - wall.start[0], y: wall.end[1] - wall.start[1] }
|
|
109
|
-
: { x: wall.start[0] - wall.end[0], y: wall.start[1] - wall.end[1] };
|
|
156
|
+
const v = getWallDirectionFromJunction(wall, endType);
|
|
110
157
|
const L = Math.sqrt(v.x * v.x + v.y * v.y);
|
|
111
158
|
if (L < 1e-9)
|
|
112
159
|
continue;
|
|
@@ -169,6 +216,32 @@ export function calculateLevelMiters(walls) {
|
|
|
169
216
|
}
|
|
170
217
|
return { junctionData, junctions };
|
|
171
218
|
}
|
|
219
|
+
export function getWallMiterBoundaryPoints(wall, miterData) {
|
|
220
|
+
const thickness = wall.thickness ?? 0.1;
|
|
221
|
+
const halfThickness = thickness / 2;
|
|
222
|
+
const startFrame = getWallBoundaryFrame(wall, 'start');
|
|
223
|
+
const endFrame = getWallBoundaryFrame(wall, 'end');
|
|
224
|
+
const startJunction = miterData.junctionData.get(pointToKey(startFrame.point))?.get(wall.id);
|
|
225
|
+
const endJunction = miterData.junctionData.get(pointToKey(endFrame.point))?.get(wall.id);
|
|
226
|
+
return {
|
|
227
|
+
startLeft: startJunction?.left ?? {
|
|
228
|
+
x: startFrame.point.x + startFrame.normal.x * halfThickness,
|
|
229
|
+
y: startFrame.point.y + startFrame.normal.y * halfThickness,
|
|
230
|
+
},
|
|
231
|
+
startRight: startJunction?.right ?? {
|
|
232
|
+
x: startFrame.point.x - startFrame.normal.x * halfThickness,
|
|
233
|
+
y: startFrame.point.y - startFrame.normal.y * halfThickness,
|
|
234
|
+
},
|
|
235
|
+
endLeft: endJunction?.right ?? {
|
|
236
|
+
x: endFrame.point.x + endFrame.normal.x * halfThickness,
|
|
237
|
+
y: endFrame.point.y + endFrame.normal.y * halfThickness,
|
|
238
|
+
},
|
|
239
|
+
endRight: endJunction?.left ?? {
|
|
240
|
+
x: endFrame.point.x - endFrame.normal.x * halfThickness,
|
|
241
|
+
y: endFrame.point.y - endFrame.normal.y * halfThickness,
|
|
242
|
+
},
|
|
243
|
+
};
|
|
244
|
+
}
|
|
172
245
|
/**
|
|
173
246
|
* Gets wall IDs that share junctions with the given walls
|
|
174
247
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"wall-system.d.ts","sourceRoot":"","sources":["../../../src/systems/wall/wall-system.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAM9B,OAAO,KAAK,EAAE,OAAO,EAAa,QAAQ,EAAE,MAAM,cAAc,CAAA;
|
|
1
|
+
{"version":3,"file":"wall-system.d.ts","sourceRoot":"","sources":["../../../src/systems/wall/wall-system.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAM9B,OAAO,KAAK,EAAE,OAAO,EAAa,QAAQ,EAAE,MAAM,cAAc,CAAA;AAIhE,OAAO,EAML,KAAK,aAAa,EACnB,MAAM,iBAAiB,CAAA;AAsRxB,eAAO,MAAM,UAAU,YAuDtB,CAAA;AA0DD;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAClC,QAAQ,EAAE,QAAQ,EAClB,aAAa,EAAE,OAAO,EAAE,EACxB,SAAS,EAAE,aAAa,EACxB,aAAa,SAAI,oFA2GlB"}
|