@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
package/dist/events/bus.d.ts
CHANGED
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
import type { ThreeEvent } from '@react-three/fiber';
|
|
2
|
+
import type { Object3D } from 'three';
|
|
2
3
|
import type { BuildingNode, CeilingNode, DoorNode, FenceNode, ItemNode, LevelNode, RoofNode, RoofSegmentNode, SiteNode, SlabNode, StairNode, StairSegmentNode, WallNode, WindowNode, ZoneNode } from '../schema';
|
|
3
4
|
import type { AnyNode } from '../schema/types';
|
|
4
5
|
export interface GridEvent {
|
|
5
6
|
/** World-space intersection point on the grid plane. */
|
|
6
7
|
position: [number, number, number];
|
|
7
8
|
/**
|
|
8
|
-
* Building-local intersection point
|
|
9
|
+
* Building-local intersection point, relative to the currently selected building.
|
|
9
10
|
* Equals `position` when no building is selected.
|
|
10
|
-
* Use this for placing
|
|
11
|
+
* Use this for placing or committing anything that lives inside a building
|
|
12
|
+
* (walls, slabs, items, etc.).
|
|
11
13
|
*/
|
|
12
14
|
localPosition: [number, number, number];
|
|
13
15
|
nativeEvent: ThreeEvent<PointerEvent>;
|
|
@@ -17,6 +19,8 @@ export interface NodeEvent<T extends AnyNode = AnyNode> {
|
|
|
17
19
|
position: [number, number, number];
|
|
18
20
|
localPosition: [number, number, number];
|
|
19
21
|
normal?: [number, number, number];
|
|
22
|
+
faceIndex?: number;
|
|
23
|
+
object: Object3D;
|
|
20
24
|
stopPropagation: () => void;
|
|
21
25
|
nativeEvent: ThreeEvent<PointerEvent>;
|
|
22
26
|
}
|
|
@@ -48,6 +52,20 @@ export interface CameraControlEvent {
|
|
|
48
52
|
}
|
|
49
53
|
export interface ThumbnailGenerateEvent {
|
|
50
54
|
projectId: string;
|
|
55
|
+
captureMode?: 'standard' | 'viewport' | 'area';
|
|
56
|
+
cropRegion?: {
|
|
57
|
+
x: number;
|
|
58
|
+
y: number;
|
|
59
|
+
width: number;
|
|
60
|
+
height: number;
|
|
61
|
+
};
|
|
62
|
+
/**
|
|
63
|
+
* When true, snap levels to their true positions before capturing (for a
|
|
64
|
+
* consistent auto-thumbnail angle) and defer the capture if the tab is
|
|
65
|
+
* hidden, the background auto-save path. Omit for user-driven captures
|
|
66
|
+
* that should fire immediately from the current camera pose.
|
|
67
|
+
*/
|
|
68
|
+
snapLevels?: boolean;
|
|
51
69
|
}
|
|
52
70
|
type CameraControlEvents = {
|
|
53
71
|
'camera-controls:view': CameraControlEvent;
|
|
@@ -75,7 +93,23 @@ type ThumbnailEvents = {
|
|
|
75
93
|
'thumbnail:before-capture': undefined;
|
|
76
94
|
'thumbnail:after-capture': undefined;
|
|
77
95
|
};
|
|
78
|
-
type
|
|
96
|
+
type SnapshotEvents = {
|
|
97
|
+
'snapshot:saved': undefined;
|
|
98
|
+
'camera:go-to-position': {
|
|
99
|
+
position: [number, number, number];
|
|
100
|
+
target: [number, number, number];
|
|
101
|
+
};
|
|
102
|
+
};
|
|
103
|
+
type AIChatEvents = {
|
|
104
|
+
'ai-chat:attach-images': {
|
|
105
|
+
images: {
|
|
106
|
+
url: string;
|
|
107
|
+
name: string;
|
|
108
|
+
kind: 'snapshot' | 'render';
|
|
109
|
+
}[];
|
|
110
|
+
};
|
|
111
|
+
};
|
|
112
|
+
type EditorEvents = GridEvents & NodeEvents<'wall', WallEvent> & NodeEvents<'fence', FenceEvent> & NodeEvents<'item', ItemEvent> & NodeEvents<'site', SiteEvent> & NodeEvents<'building', BuildingEvent> & NodeEvents<'level', LevelEvent> & NodeEvents<'zone', ZoneEvent> & NodeEvents<'slab', SlabEvent> & NodeEvents<'ceiling', CeilingEvent> & NodeEvents<'roof', RoofEvent> & NodeEvents<'roof-segment', RoofSegmentEvent> & NodeEvents<'stair', StairEvent> & NodeEvents<'stair-segment', StairSegmentEvent> & NodeEvents<'window', WindowEvent> & NodeEvents<'door', DoorEvent> & CameraControlEvents & ToolEvents & PresetEvents & ThumbnailEvents & SnapshotEvents & AIChatEvents;
|
|
79
113
|
export declare const emitter: import("mitt").Emitter<EditorEvents>;
|
|
80
114
|
export {};
|
|
81
115
|
//# sourceMappingURL=bus.d.ts.map
|
package/dist/events/bus.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bus.d.ts","sourceRoot":"","sources":["../../src/events/bus.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAA;
|
|
1
|
+
{"version":3,"file":"bus.d.ts","sourceRoot":"","sources":["../../src/events/bus.ts"],"names":[],"mappings":"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"}
|
package/dist/events/bus.js
CHANGED
|
@@ -4,10 +4,12 @@ interface SpatialGridConfig {
|
|
|
4
4
|
export declare class SpatialGrid {
|
|
5
5
|
private readonly cells;
|
|
6
6
|
private readonly itemCells;
|
|
7
|
+
private readonly itemBounds;
|
|
7
8
|
private readonly config;
|
|
8
9
|
constructor(config: SpatialGridConfig);
|
|
9
10
|
private posToCell;
|
|
10
11
|
private cellKey;
|
|
12
|
+
private getAABB;
|
|
11
13
|
private getItemCells;
|
|
12
14
|
insert(itemId: string, position: [number, number, number], dimensions: [number, number, number], rotation: [number, number, number]): void;
|
|
13
15
|
remove(itemId: string): void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"spatial-grid.d.ts","sourceRoot":"","sources":["../../../src/hooks/spatial-grid/spatial-grid.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"spatial-grid.d.ts","sourceRoot":"","sources":["../../../src/hooks/spatial-grid/spatial-grid.ts"],"names":[],"mappings":"AAaA,UAAU,iBAAiB;IACzB,QAAQ,EAAE,MAAM,CAAA;CACjB;AAED,qBAAa,WAAW;IACtB,OAAO,CAAC,QAAQ,CAAC,KAAK,CAA+B;IACrD,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAkC;IAC5D,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAgC;IAE3D,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAmB;gBAE9B,MAAM,EAAE,iBAAiB;IAIrC,OAAO,CAAC,SAAS;IAIjB,OAAO,CAAC,OAAO;IAKf,OAAO,CAAC,OAAO;IAuBf,OAAO,CAAC,YAAY;IAgBpB,MAAM,CACJ,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAClC,UAAU,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EACpC,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC;IAiBpC,MAAM,CAAC,MAAM,EAAE,MAAM;IAkBrB,MAAM,CACJ,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAClC,UAAU,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EACpC,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC;IASpC,QAAQ,CACN,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAClC,UAAU,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EACpC,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAClC,SAAS,GAAE,MAAM,EAAO,GACvB;QAAE,KAAK,EAAE,OAAO,CAAC;QAAC,WAAW,EAAE,MAAM,EAAE,CAAA;KAAE;IA0C5C,WAAW,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE;IAkB3D,YAAY,IAAI,MAAM;CAGvB"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export class SpatialGrid {
|
|
2
2
|
cells = new Map();
|
|
3
3
|
itemCells = new Map(); // reverse lookup
|
|
4
|
+
itemBounds = new Map(); // actual AABB for narrow-phase
|
|
4
5
|
config;
|
|
5
6
|
constructor(config) {
|
|
6
7
|
this.config = config;
|
|
@@ -11,27 +12,27 @@ export class SpatialGrid {
|
|
|
11
12
|
cellKey(cx, cz) {
|
|
12
13
|
return `${cx},${cz}`;
|
|
13
14
|
}
|
|
14
|
-
//
|
|
15
|
-
|
|
16
|
-
// Simplified: axis-aligned bounding box
|
|
17
|
-
// For full rotation support, compute rotated corners
|
|
15
|
+
// Compute the axis-aligned bounding box for a rotated item
|
|
16
|
+
getAABB(position, dimensions, rotation) {
|
|
18
17
|
const [x, , z] = position;
|
|
19
18
|
const [w, , d] = dimensions;
|
|
20
|
-
const yRot = rotation[1];
|
|
21
|
-
// Compute rotated footprint (simplified for 90° increments)
|
|
19
|
+
const yRot = rotation[1];
|
|
22
20
|
const cos = Math.abs(Math.cos(yRot));
|
|
23
21
|
const sin = Math.abs(Math.sin(yRot));
|
|
24
22
|
const rotatedW = w * cos + d * sin;
|
|
25
23
|
const rotatedD = w * sin + d * cos;
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
24
|
+
return {
|
|
25
|
+
minX: x - rotatedW / 2,
|
|
26
|
+
maxX: x + rotatedW / 2,
|
|
27
|
+
minZ: z - rotatedD / 2,
|
|
28
|
+
maxZ: z + rotatedD / 2,
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
// Get all cells an item occupies based on its AABB
|
|
32
|
+
getItemCells(bounds) {
|
|
33
|
+
const { minX, maxX, minZ, maxZ } = bounds;
|
|
30
34
|
const [minCx, minCz] = this.posToCell(minX, minZ);
|
|
31
|
-
|
|
32
|
-
// This allows adjacent items (touching but not overlapping) to not conflict
|
|
33
|
-
const epsilon = 1e-6;
|
|
34
|
-
const [maxCx, maxCz] = this.posToCell(maxX - epsilon, maxZ - epsilon);
|
|
35
|
+
const [maxCx, maxCz] = this.posToCell(maxX, maxZ);
|
|
35
36
|
const keys = [];
|
|
36
37
|
for (let cx = minCx; cx <= maxCx; cx++) {
|
|
37
38
|
for (let cz = minCz; cz <= maxCz; cz++) {
|
|
@@ -42,8 +43,10 @@ export class SpatialGrid {
|
|
|
42
43
|
}
|
|
43
44
|
// Register an item
|
|
44
45
|
insert(itemId, position, dimensions, rotation) {
|
|
45
|
-
const
|
|
46
|
+
const bounds = this.getAABB(position, dimensions, rotation);
|
|
47
|
+
const cellKeys = this.getItemCells(bounds);
|
|
46
48
|
this.itemCells.set(itemId, new Set(cellKeys));
|
|
49
|
+
this.itemBounds.set(itemId, bounds);
|
|
47
50
|
for (const key of cellKeys) {
|
|
48
51
|
if (!this.cells.has(key)) {
|
|
49
52
|
this.cells.set(key, { itemIds: new Set() });
|
|
@@ -66,6 +69,7 @@ export class SpatialGrid {
|
|
|
66
69
|
}
|
|
67
70
|
}
|
|
68
71
|
this.itemCells.delete(itemId);
|
|
72
|
+
this.itemBounds.delete(itemId);
|
|
69
73
|
}
|
|
70
74
|
// Update = remove + insert
|
|
71
75
|
update(itemId, position, dimensions, rotation) {
|
|
@@ -73,23 +77,42 @@ export class SpatialGrid {
|
|
|
73
77
|
this.insert(itemId, position, dimensions, rotation);
|
|
74
78
|
}
|
|
75
79
|
// Query: is this placement valid?
|
|
80
|
+
// Uses cells as broad-phase, then checks actual AABB overlap (narrow-phase)
|
|
81
|
+
// to avoid false positives when adjacent items share a cell but don't overlap.
|
|
76
82
|
canPlace(position, dimensions, rotation, ignoreIds = []) {
|
|
77
|
-
const
|
|
83
|
+
const bounds = this.getAABB(position, dimensions, rotation);
|
|
84
|
+
const cellKeys = this.getItemCells(bounds);
|
|
78
85
|
const ignoreSet = new Set(ignoreIds);
|
|
79
|
-
|
|
86
|
+
// Broad phase: collect candidate items from overlapping cells
|
|
87
|
+
const candidates = new Set();
|
|
80
88
|
for (const key of cellKeys) {
|
|
81
89
|
const cell = this.cells.get(key);
|
|
82
90
|
if (cell) {
|
|
83
91
|
for (const id of cell.itemIds) {
|
|
84
92
|
if (!ignoreSet.has(id)) {
|
|
85
|
-
|
|
93
|
+
candidates.add(id);
|
|
86
94
|
}
|
|
87
95
|
}
|
|
88
96
|
}
|
|
89
97
|
}
|
|
98
|
+
// Narrow phase: check actual AABB overlap
|
|
99
|
+
// Items that merely touch (share an edge) are allowed; only true overlap conflicts.
|
|
100
|
+
const EPSILON = 1e-4; // tolerance to allow touching
|
|
101
|
+
const conflicts = [];
|
|
102
|
+
for (const id of candidates) {
|
|
103
|
+
const other = this.itemBounds.get(id);
|
|
104
|
+
if (!other)
|
|
105
|
+
continue;
|
|
106
|
+
if (bounds.minX < other.maxX - EPSILON &&
|
|
107
|
+
bounds.maxX > other.minX + EPSILON &&
|
|
108
|
+
bounds.minZ < other.maxZ - EPSILON &&
|
|
109
|
+
bounds.maxZ > other.minZ + EPSILON) {
|
|
110
|
+
conflicts.push(id);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
90
113
|
return {
|
|
91
|
-
valid: conflicts.
|
|
92
|
-
conflictIds:
|
|
114
|
+
valid: conflicts.length === 0,
|
|
115
|
+
conflictIds: conflicts,
|
|
93
116
|
};
|
|
94
117
|
}
|
|
95
118
|
// Query: get all items near a point (for snapping, selection, etc.)
|
package/dist/index.d.ts
CHANGED
|
@@ -7,8 +7,10 @@ export { useSpatialQuery } from './hooks/spatial-grid/use-spatial-query';
|
|
|
7
7
|
export { loadAssetUrl, saveAsset } from './lib/asset-storage';
|
|
8
8
|
export { detectSpacesForLevel, initSpaceDetectionSync, type Space, wallTouchesOthers, } from './lib/space-detection';
|
|
9
9
|
export { baseMaterial, glassMaterial } from './materials';
|
|
10
|
+
export { getCatalogMaterialById, getLibraryMaterialIdFromRef, getMaterialPresetByRef, getMaterialsForTarget, LIBRARY_MATERIAL_REF_PREFIX, MATERIAL_CATALOG, type MaterialCatalogItem, toLibraryMaterialRef, } from './material-library';
|
|
10
11
|
export * from './schema';
|
|
11
12
|
export { type ControlValue, type ItemInteractiveState, useInteractive, } from './store/use-interactive';
|
|
13
|
+
export { getSceneHistoryPauseDepth, pauseSceneHistory, resetSceneHistoryPauseDepth, resumeSceneHistory, } from './store/history-control';
|
|
12
14
|
export { default as useLiveTransforms, type LiveTransform } from './store/use-live-transforms';
|
|
13
15
|
export { FenceSystem } from './systems/fence/fence-system';
|
|
14
16
|
export { clearSceneHistory, default as useScene } from './store/use-scene';
|
|
@@ -19,7 +21,8 @@ export { RoofSystem } from './systems/roof/roof-system';
|
|
|
19
21
|
export { SlabSystem } from './systems/slab/slab-system';
|
|
20
22
|
export { StairSystem } from './systems/stair/stair-system';
|
|
21
23
|
export { DEFAULT_WALL_HEIGHT, DEFAULT_WALL_THICKNESS, getWallPlanFootprint, getWallThickness, } from './systems/wall/wall-footprint';
|
|
22
|
-
export {
|
|
24
|
+
export { getClampedWallCurveOffset, getMaxWallCurveOffset, getWallChordFrame, getWallCurveFrameAt, getWallCurveLength, getWallMidpointHandlePoint, getWallStraightSnapOffset, getWallSurfacePolygon, isCurvedWall, normalizeWallCurveOffset, sampleWallCenterline, } from './systems/wall/wall-curve';
|
|
25
|
+
export { calculateLevelMiters, getWallMiterBoundaryPoints, type Point2D, type WallMiterBoundaryPoints, pointToKey, type WallMiterData, } from './systems/wall/wall-mitering';
|
|
23
26
|
export { WallSystem } from './systems/wall/wall-system';
|
|
24
27
|
export { WindowSystem } from './systems/window/window-system';
|
|
25
28
|
export type { SceneGraph } from './utils/clone-scene-graph';
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,aAAa,EACb,kBAAkB,EAClB,YAAY,EACZ,SAAS,EACT,WAAW,EACX,UAAU,EACV,SAAS,EACT,SAAS,EACT,UAAU,EACV,SAAS,EACT,SAAS,EACT,gBAAgB,EAChB,SAAS,EACT,SAAS,EACT,UAAU,EACV,iBAAiB,EACjB,SAAS,EACT,WAAW,EACX,SAAS,GACV,MAAM,cAAc,CAAA;AACrB,OAAO,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAA;AACrD,OAAO,EACL,aAAa,EACb,WAAW,GACZ,MAAM,uCAAuC,CAAA;AAC9C,OAAO,EAAE,cAAc,EAAE,kBAAkB,EAAE,MAAM,2CAA2C,CAAA;AAC9F,OAAO,EACL,mBAAmB,EACnB,cAAc,GACf,MAAM,wCAAwC,CAAA;AAC/C,OAAO,EAAE,eAAe,EAAE,MAAM,wCAAwC,CAAA;AACxE,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAA;AAC7D,OAAO,EACL,oBAAoB,EACpB,sBAAsB,EACtB,KAAK,KAAK,EACV,iBAAiB,GAClB,MAAM,uBAAuB,CAAA;AAC9B,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AACzD,cAAc,UAAU,CAAA;AACxB,OAAO,EACL,KAAK,YAAY,EACjB,KAAK,oBAAoB,EACzB,cAAc,GACf,MAAM,yBAAyB,CAAA;AAChC,OAAO,EAAE,OAAO,IAAI,iBAAiB,EAAE,KAAK,aAAa,EAAE,MAAM,6BAA6B,CAAA;AAC9F,OAAO,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAA;AAC1D,OAAO,EAAE,iBAAiB,EAAE,OAAO,IAAI,QAAQ,EAAE,MAAM,mBAAmB,CAAA;AAC1E,OAAO,EAAE,aAAa,EAAE,MAAM,kCAAkC,CAAA;AAChE,OAAO,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAA;AACvD,OAAO,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAA;AACvD,OAAO,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAA;AACvD,OAAO,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAA;AACvD,OAAO,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAA;AAC1D,OAAO,EACL,mBAAmB,EACnB,sBAAsB,EACtB,oBAAoB,EACpB,gBAAgB,GACjB,MAAM,+BAA+B,CAAA;AACtC,OAAO,EACL,oBAAoB,EACpB,KAAK,OAAO,EACZ,UAAU,EACV,KAAK,aAAa,GACnB,MAAM,8BAA8B,CAAA;AACrC,OAAO,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAA;AACvD,OAAO,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAA;AAC7D,YAAY,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAA;AAC3D,OAAO,EAAE,iBAAiB,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAA;AAC9F,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -6,8 +6,10 @@ export { useSpatialQuery } from './hooks/spatial-grid/use-spatial-query';
|
|
|
6
6
|
export { loadAssetUrl, saveAsset } from './lib/asset-storage';
|
|
7
7
|
export { detectSpacesForLevel, initSpaceDetectionSync, wallTouchesOthers, } from './lib/space-detection';
|
|
8
8
|
export { baseMaterial, glassMaterial } from './materials';
|
|
9
|
+
export { getCatalogMaterialById, getLibraryMaterialIdFromRef, getMaterialPresetByRef, getMaterialsForTarget, LIBRARY_MATERIAL_REF_PREFIX, MATERIAL_CATALOG, toLibraryMaterialRef, } from './material-library';
|
|
9
10
|
export * from './schema';
|
|
10
11
|
export { useInteractive, } from './store/use-interactive';
|
|
12
|
+
export { getSceneHistoryPauseDepth, pauseSceneHistory, resetSceneHistoryPauseDepth, resumeSceneHistory, } from './store/history-control';
|
|
11
13
|
export { default as useLiveTransforms } from './store/use-live-transforms';
|
|
12
14
|
export { FenceSystem } from './systems/fence/fence-system';
|
|
13
15
|
export { clearSceneHistory, default as useScene } from './store/use-scene';
|
|
@@ -18,7 +20,8 @@ export { RoofSystem } from './systems/roof/roof-system';
|
|
|
18
20
|
export { SlabSystem } from './systems/slab/slab-system';
|
|
19
21
|
export { StairSystem } from './systems/stair/stair-system';
|
|
20
22
|
export { DEFAULT_WALL_HEIGHT, DEFAULT_WALL_THICKNESS, getWallPlanFootprint, getWallThickness, } from './systems/wall/wall-footprint';
|
|
21
|
-
export {
|
|
23
|
+
export { getClampedWallCurveOffset, getMaxWallCurveOffset, getWallChordFrame, getWallCurveFrameAt, getWallCurveLength, getWallMidpointHandlePoint, getWallStraightSnapOffset, getWallSurfacePolygon, isCurvedWall, normalizeWallCurveOffset, sampleWallCenterline, } from './systems/wall/wall-curve';
|
|
24
|
+
export { calculateLevelMiters, getWallMiterBoundaryPoints, pointToKey, } from './systems/wall/wall-mitering';
|
|
22
25
|
export { WallSystem } from './systems/wall/wall-system';
|
|
23
26
|
export { WindowSystem } from './systems/window/window-system';
|
|
24
27
|
export { cloneLevelSubtree, cloneSceneGraph, forkSceneGraph } from './utils/clone-scene-graph';
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export declare function insetPolygonFromCentroid(polygon: Array<[number, number]>, inset: number): Array<[number, number]>;
|
|
2
|
+
export declare function simplifyClosedPolygon(polygon: Array<[number, number]>, tolerance: number): Array<[number, number]>;
|
|
3
|
+
//# sourceMappingURL=polygon-geometry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"polygon-geometry.d.ts","sourceRoot":"","sources":["../../src/lib/polygon-geometry.ts"],"names":[],"mappings":"AAAA,wBAAgB,wBAAwB,CACtC,OAAO,EAAE,KAAK,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,EAChC,KAAK,EAAE,MAAM,GACZ,KAAK,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAuBzB;AAuED,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,KAAK,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,EAChC,SAAS,EAAE,MAAM,GAChB,KAAK,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAiCzB"}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
export function insetPolygonFromCentroid(polygon, inset) {
|
|
2
|
+
if (inset <= 0) {
|
|
3
|
+
return polygon.map(([x, z]) => [x, z]);
|
|
4
|
+
}
|
|
5
|
+
const centroid = polygon.reduce((acc, [x, z]) => ({ x: acc.x + x, z: acc.z + z }), { x: 0, z: 0 });
|
|
6
|
+
centroid.x /= Math.max(polygon.length, 1);
|
|
7
|
+
centroid.z /= Math.max(polygon.length, 1);
|
|
8
|
+
return polygon.map(([x, z]) => {
|
|
9
|
+
const dx = x - centroid.x;
|
|
10
|
+
const dz = z - centroid.z;
|
|
11
|
+
const length = Math.hypot(dx, dz);
|
|
12
|
+
if (length <= inset + 1e-6) {
|
|
13
|
+
return [x, z];
|
|
14
|
+
}
|
|
15
|
+
const scale = (length - inset) / length;
|
|
16
|
+
return [centroid.x + dx * scale, centroid.z + dz * scale];
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
function pointLineDistance(point, start, end) {
|
|
20
|
+
const dx = end[0] - start[0];
|
|
21
|
+
const dz = end[1] - start[1];
|
|
22
|
+
const lengthSquared = dx * dx + dz * dz;
|
|
23
|
+
if (lengthSquared < 1e-9) {
|
|
24
|
+
return Math.hypot(point[0] - start[0], point[1] - start[1]);
|
|
25
|
+
}
|
|
26
|
+
const cross = (point[0] - start[0]) * dz - (point[1] - start[1]) * dx;
|
|
27
|
+
return Math.abs(cross) / Math.sqrt(lengthSquared);
|
|
28
|
+
}
|
|
29
|
+
function dedupePolygonPoints(polygon, tolerance = 1e-6) {
|
|
30
|
+
const deduped = [];
|
|
31
|
+
for (const point of polygon) {
|
|
32
|
+
const previous = deduped[deduped.length - 1];
|
|
33
|
+
if (previous && Math.hypot(point[0] - previous[0], point[1] - previous[1]) <= tolerance) {
|
|
34
|
+
continue;
|
|
35
|
+
}
|
|
36
|
+
deduped.push(point);
|
|
37
|
+
}
|
|
38
|
+
if (deduped.length > 2 &&
|
|
39
|
+
Math.hypot(deduped[0][0] - deduped[deduped.length - 1][0], deduped[0][1] - deduped[deduped.length - 1][1]) <= tolerance) {
|
|
40
|
+
deduped.pop();
|
|
41
|
+
}
|
|
42
|
+
return deduped;
|
|
43
|
+
}
|
|
44
|
+
function simplifyPolyline(points, tolerance) {
|
|
45
|
+
if (points.length <= 2) {
|
|
46
|
+
return points.map(([x, z]) => [x, z]);
|
|
47
|
+
}
|
|
48
|
+
let maxDistance = -1;
|
|
49
|
+
let splitIndex = -1;
|
|
50
|
+
for (let index = 1; index < points.length - 1; index += 1) {
|
|
51
|
+
const distance = pointLineDistance(points[index], points[0], points[points.length - 1]);
|
|
52
|
+
if (distance > maxDistance) {
|
|
53
|
+
maxDistance = distance;
|
|
54
|
+
splitIndex = index;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
if (maxDistance <= tolerance || splitIndex === -1) {
|
|
58
|
+
return [points[0], points[points.length - 1]];
|
|
59
|
+
}
|
|
60
|
+
const left = simplifyPolyline(points.slice(0, splitIndex + 1), tolerance);
|
|
61
|
+
const right = simplifyPolyline(points.slice(splitIndex), tolerance);
|
|
62
|
+
return [...left.slice(0, -1), ...right];
|
|
63
|
+
}
|
|
64
|
+
export function simplifyClosedPolygon(polygon, tolerance) {
|
|
65
|
+
const cleanPolygon = dedupePolygonPoints(polygon);
|
|
66
|
+
if (cleanPolygon.length <= 3 || tolerance <= 0) {
|
|
67
|
+
return cleanPolygon;
|
|
68
|
+
}
|
|
69
|
+
let anchorA = 0;
|
|
70
|
+
let anchorB = Math.floor(cleanPolygon.length / 2);
|
|
71
|
+
let maxDistanceSquared = -1;
|
|
72
|
+
for (let i = 0; i < cleanPolygon.length; i += 1) {
|
|
73
|
+
for (let j = i + 1; j < cleanPolygon.length; j += 1) {
|
|
74
|
+
const dx = cleanPolygon[j][0] - cleanPolygon[i][0];
|
|
75
|
+
const dz = cleanPolygon[j][1] - cleanPolygon[i][1];
|
|
76
|
+
const distanceSquared = dx * dx + dz * dz;
|
|
77
|
+
if (distanceSquared > maxDistanceSquared) {
|
|
78
|
+
maxDistanceSquared = distanceSquared;
|
|
79
|
+
anchorA = i;
|
|
80
|
+
anchorB = j;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
const forward = cleanPolygon.slice(anchorA, anchorB + 1);
|
|
85
|
+
const wrapped = [...cleanPolygon.slice(anchorB), ...cleanPolygon.slice(0, anchorA + 1)];
|
|
86
|
+
const simplifiedForward = simplifyPolyline(forward, tolerance);
|
|
87
|
+
const simplifiedWrapped = simplifyPolyline(wrapped, tolerance);
|
|
88
|
+
const simplified = dedupePolygonPoints([...simplifiedForward.slice(0, -1), ...simplifiedWrapped.slice(0, -1)], tolerance * 0.25);
|
|
89
|
+
return simplified.length >= 3 ? simplified : cleanPolygon;
|
|
90
|
+
}
|
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type WallNode } from '../schema';
|
|
2
|
+
type Point2D = {
|
|
3
|
+
x: number;
|
|
4
|
+
y: number;
|
|
5
|
+
};
|
|
2
6
|
export type Space = {
|
|
3
7
|
id: string;
|
|
4
8
|
levelId: string;
|
|
@@ -6,29 +10,18 @@ export type Space = {
|
|
|
6
10
|
wallIds: string[];
|
|
7
11
|
isExterior: boolean;
|
|
8
12
|
};
|
|
9
|
-
/**
|
|
10
|
-
* Initializes space detection sync with scene and editor stores
|
|
11
|
-
* Call this once during app initialization
|
|
12
|
-
*/
|
|
13
|
-
export declare function initSpaceDetectionSync(sceneStore: any, // useScene store
|
|
14
|
-
editorStore: any): () => void;
|
|
15
13
|
type WallSideUpdate = {
|
|
16
14
|
wallId: string;
|
|
17
15
|
frontSide: 'interior' | 'exterior' | 'unknown';
|
|
18
16
|
backSide: 'interior' | 'exterior' | 'unknown';
|
|
19
17
|
};
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
*/
|
|
24
|
-
export declare function detectSpacesForLevel(levelId: string, walls: WallNode[], gridResolution?: number): {
|
|
25
|
-
wallUpdates: WallSideUpdate[];
|
|
18
|
+
export declare function resolveWallSurfaceSides(wall: Pick<WallNode, 'start' | 'end' | 'thickness' | 'frontSide' | 'backSide'>, roomPolygons: Point2D[][]): Pick<WallSideUpdate, 'frontSide' | 'backSide'>;
|
|
19
|
+
export declare function detectSpacesForLevel(levelId: string, walls: WallNode[]): {
|
|
20
|
+
roomPolygons: Point2D[][];
|
|
26
21
|
spaces: Space[];
|
|
22
|
+
wallUpdates: WallSideUpdate[];
|
|
27
23
|
};
|
|
28
|
-
|
|
29
|
-
* Checks if a wall touches any other walls
|
|
30
|
-
* Used to determine if space detection should run
|
|
31
|
-
*/
|
|
24
|
+
export declare function initSpaceDetectionSync(sceneStore: any, editorStore: any): () => void;
|
|
32
25
|
export declare function wallTouchesOthers(wall: WallNode, otherWalls: WallNode[]): boolean;
|
|
33
26
|
export {};
|
|
34
27
|
//# sourceMappingURL=space-detection.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"space-detection.d.ts","sourceRoot":"","sources":["../../src/lib/space-detection.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"space-detection.d.ts","sourceRoot":"","sources":["../../src/lib/space-detection.ts"],"names":[],"mappings":"AAKA,OAAO,EAA6F,KAAK,QAAQ,EAAE,MAAM,WAAW,CAAA;AAQpI,KAAK,OAAO,GAAG;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,CAAA;AAEvC,MAAM,MAAM,KAAK,GAAG;IAClB,EAAE,EAAE,MAAM,CAAA;IACV,OAAO,EAAE,MAAM,CAAA;IACf,OAAO,EAAE,KAAK,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAA;IAChC,OAAO,EAAE,MAAM,EAAE,CAAA;IACjB,UAAU,EAAE,OAAO,CAAA;CACpB,CAAA;AAED,KAAK,cAAc,GAAG;IACpB,MAAM,EAAE,MAAM,CAAA;IACd,SAAS,EAAE,UAAU,GAAG,UAAU,GAAG,SAAS,CAAA;IAC9C,QAAQ,EAAE,UAAU,GAAG,UAAU,GAAG,SAAS,CAAA;CAC9C,CAAA;AA4VD,wBAAgB,uBAAuB,CACrC,IAAI,EAAE,IAAI,CAAC,QAAQ,EAAE,OAAO,GAAG,KAAK,GAAG,WAAW,GAAG,WAAW,GAAG,UAAU,CAAC,EAC9E,YAAY,EAAE,OAAO,EAAE,EAAE,GACxB,IAAI,CAAC,cAAc,EAAE,WAAW,GAAG,UAAU,CAAC,CA4ChD;AA0WD,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE;;;;EAEtE;AAsED,wBAAgB,sBAAsB,CAAC,UAAU,EAAE,GAAG,EAAE,WAAW,EAAE,GAAG,GAAG,MAAM,IAAI,CAuDpF;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,QAAQ,EAAE,UAAU,EAAE,QAAQ,EAAE,GAAG,OAAO,CAiBjF"}
|