@pascal-app/core 0.6.0 → 0.7.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 +38 -2
- package/dist/events/bus.d.ts.map +1 -1
- package/dist/hooks/scene-registry/scene-registry.d.ts +2 -0
- package/dist/hooks/scene-registry/scene-registry.d.ts.map +1 -1
- package/dist/hooks/scene-registry/scene-registry.js +2 -0
- package/dist/hooks/spatial-grid/spatial-grid-manager.d.ts.map +1 -1
- package/dist/hooks/spatial-grid/spatial-grid-manager.js +164 -6
- package/dist/index.d.ts +8 -15
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -14
- package/dist/lib/door-operation.d.ts +7 -0
- package/dist/lib/door-operation.d.ts.map +1 -0
- package/dist/lib/door-operation.js +25 -0
- package/dist/lib/slab-polygon.d.ts +3 -0
- package/dist/lib/slab-polygon.d.ts.map +1 -0
- package/dist/lib/slab-polygon.js +58 -0
- package/dist/material-library.d.ts +5 -3
- package/dist/material-library.d.ts.map +1 -1
- package/dist/material-library.js +26 -49
- package/dist/schema/asset-url.d.ts +34 -0
- package/dist/schema/asset-url.d.ts.map +1 -0
- package/dist/schema/asset-url.js +79 -0
- package/dist/schema/asset-url.test.d.ts +2 -0
- package/dist/schema/asset-url.test.d.ts.map +1 -0
- package/dist/schema/asset-url.test.js +138 -0
- package/dist/schema/index.d.ts +7 -5
- package/dist/schema/index.d.ts.map +1 -1
- package/dist/schema/index.js +5 -3
- package/dist/schema/material.d.ts +3 -2
- package/dist/schema/material.d.ts.map +1 -1
- package/dist/schema/material.js +13 -11
- package/dist/schema/nodes/ceiling.d.ts +1 -1
- package/dist/schema/nodes/column.d.ts +520 -0
- package/dist/schema/nodes/column.d.ts.map +1 -0
- package/dist/schema/nodes/column.js +385 -0
- package/dist/schema/nodes/door.d.ts +73 -1
- package/dist/schema/nodes/door.d.ts.map +1 -1
- package/dist/schema/nodes/door.js +39 -2
- package/dist/schema/nodes/fence.d.ts +1 -1
- package/dist/schema/nodes/guide.d.ts +17 -0
- package/dist/schema/nodes/guide.d.ts.map +1 -1
- package/dist/schema/nodes/guide.js +11 -1
- package/dist/schema/nodes/item.d.ts +8 -0
- package/dist/schema/nodes/item.d.ts.map +1 -1
- package/dist/schema/nodes/item.js +18 -1
- package/dist/schema/nodes/level.d.ts +1 -1
- package/dist/schema/nodes/level.d.ts.map +1 -1
- package/dist/schema/nodes/level.js +6 -0
- package/dist/schema/nodes/roof-segment.d.ts +1 -1
- package/dist/schema/nodes/roof.d.ts +4 -4
- package/dist/schema/nodes/scan.d.ts.map +1 -1
- package/dist/schema/nodes/scan.js +2 -1
- package/dist/schema/nodes/site.d.ts +1 -0
- package/dist/schema/nodes/site.d.ts.map +1 -1
- package/dist/schema/nodes/slab.d.ts +1 -1
- package/dist/schema/nodes/spawn.d.ts +24 -0
- package/dist/schema/nodes/spawn.d.ts.map +1 -0
- package/dist/schema/nodes/spawn.js +8 -0
- package/dist/schema/nodes/stair-segment.d.ts +1 -1
- package/dist/schema/nodes/stair.d.ts +8 -8
- package/dist/schema/nodes/wall.d.ts +3 -3
- package/dist/schema/nodes/window.d.ts +56 -1
- package/dist/schema/nodes/window.d.ts.map +1 -1
- package/dist/schema/nodes/window.js +29 -0
- package/dist/schema/types.d.ts +324 -21
- package/dist/schema/types.d.ts.map +1 -1
- package/dist/schema/types.js +4 -0
- package/dist/store/actions/node-actions.d.ts.map +1 -1
- package/dist/store/actions/node-actions.js +6 -5
- package/dist/store/use-interactive.d.ts +43 -0
- package/dist/store/use-interactive.d.ts.map +1 -1
- package/dist/store/use-interactive.js +66 -0
- package/dist/store/use-scene.d.ts.map +1 -1
- package/dist/store/use-scene.js +60 -2
- package/dist/systems/stair/stair-opening-sync.d.ts.map +1 -1
- package/dist/systems/stair/stair-opening-sync.js +81 -20
- package/dist/systems/stair/stair-opening-sync.test.d.ts +2 -0
- package/dist/systems/stair/stair-opening-sync.test.d.ts.map +1 -0
- package/dist/systems/stair/stair-opening-sync.test.js +65 -0
- package/dist/systems/stair/stair-system.js +1 -1
- package/package.json +31 -3
package/dist/events/bus.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { ThreeEvent } from '@react-three/fiber';
|
|
2
2
|
import type { Object3D } from 'three';
|
|
3
|
-
import type { BuildingNode, CeilingNode, DoorNode, FenceNode, ItemNode, LevelNode, RoofNode, RoofSegmentNode, SiteNode, SlabNode, StairNode, StairSegmentNode, WallNode, WindowNode, ZoneNode } from '../schema';
|
|
3
|
+
import type { BuildingNode, CeilingNode, ColumnNode, DoorNode, FenceNode, GuideNode, ItemNode, LevelNode, RoofNode, RoofSegmentNode, SiteNode, SlabNode, SpawnNode, StairNode, StairSegmentNode, WallNode, WindowNode, ZoneNode } from '../schema';
|
|
4
4
|
import type { AnyNode } from '../schema/types';
|
|
5
5
|
export interface GridEvent {
|
|
6
6
|
/** World-space intersection point on the grid plane. */
|
|
@@ -32,7 +32,9 @@ export type BuildingEvent = NodeEvent<BuildingNode>;
|
|
|
32
32
|
export type LevelEvent = NodeEvent<LevelNode>;
|
|
33
33
|
export type ZoneEvent = NodeEvent<ZoneNode>;
|
|
34
34
|
export type SlabEvent = NodeEvent<SlabNode>;
|
|
35
|
+
export type SpawnEvent = NodeEvent<SpawnNode>;
|
|
35
36
|
export type CeilingEvent = NodeEvent<CeilingNode>;
|
|
37
|
+
export type ColumnEvent = NodeEvent<ColumnNode>;
|
|
36
38
|
export type RoofEvent = NodeEvent<RoofNode>;
|
|
37
39
|
export type RoofSegmentEvent = NodeEvent<RoofSegmentNode>;
|
|
38
40
|
export type StairEvent = NodeEvent<StairNode>;
|
|
@@ -67,6 +69,18 @@ export interface ThumbnailGenerateEvent {
|
|
|
67
69
|
*/
|
|
68
70
|
snapLevels?: boolean;
|
|
69
71
|
}
|
|
72
|
+
export interface CameraControlFitSceneEvent {
|
|
73
|
+
/**
|
|
74
|
+
* XZ-plane axis-aligned bounds for camera framing. Omitted values let the
|
|
75
|
+
* listener choose its default framing pose.
|
|
76
|
+
*/
|
|
77
|
+
bounds?: {
|
|
78
|
+
min: [number, number];
|
|
79
|
+
max: [number, number];
|
|
80
|
+
center: [number, number];
|
|
81
|
+
size: [number, number];
|
|
82
|
+
};
|
|
83
|
+
}
|
|
70
84
|
type CameraControlEvents = {
|
|
71
85
|
'camera-controls:view': CameraControlEvent;
|
|
72
86
|
'camera-controls:focus': CameraControlEvent;
|
|
@@ -74,11 +88,33 @@ type CameraControlEvents = {
|
|
|
74
88
|
'camera-controls:top-view': undefined;
|
|
75
89
|
'camera-controls:orbit-cw': undefined;
|
|
76
90
|
'camera-controls:orbit-ccw': undefined;
|
|
91
|
+
'camera-controls:fit-scene': CameraControlFitSceneEvent;
|
|
77
92
|
'camera-controls:generate-thumbnail': ThumbnailGenerateEvent;
|
|
78
93
|
};
|
|
79
94
|
type ToolEvents = {
|
|
80
95
|
'tool:cancel': undefined;
|
|
81
96
|
};
|
|
97
|
+
type GuideEvents = {
|
|
98
|
+
'guide:set-reference-scale': {
|
|
99
|
+
guideId: GuideNode['id'];
|
|
100
|
+
};
|
|
101
|
+
'guide:cancel-reference-scale': undefined;
|
|
102
|
+
'guide:deleted': {
|
|
103
|
+
guideId: GuideNode['id'];
|
|
104
|
+
};
|
|
105
|
+
};
|
|
106
|
+
type DoorAnimationEvents = {
|
|
107
|
+
'door:animation-completed': {
|
|
108
|
+
doorId: DoorNode['id'];
|
|
109
|
+
field: 'operationState' | 'swingAngle';
|
|
110
|
+
};
|
|
111
|
+
};
|
|
112
|
+
type WindowAnimationEvents = {
|
|
113
|
+
'window:animation-completed': {
|
|
114
|
+
windowId: WindowNode['id'];
|
|
115
|
+
field: 'operationState';
|
|
116
|
+
};
|
|
117
|
+
};
|
|
82
118
|
type PresetEvents = {
|
|
83
119
|
'preset:generate-thumbnail': {
|
|
84
120
|
presetId: string;
|
|
@@ -109,7 +145,7 @@ type AIChatEvents = {
|
|
|
109
145
|
}[];
|
|
110
146
|
};
|
|
111
147
|
};
|
|
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;
|
|
148
|
+
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<'spawn', SpawnEvent> & NodeEvents<'ceiling', CeilingEvent> & NodeEvents<'column', ColumnEvent> & NodeEvents<'roof', RoofEvent> & NodeEvents<'roof-segment', RoofSegmentEvent> & NodeEvents<'stair', StairEvent> & NodeEvents<'stair-segment', StairSegmentEvent> & NodeEvents<'window', WindowEvent> & NodeEvents<'door', DoorEvent> & CameraControlEvents & ToolEvents & GuideEvents & DoorAnimationEvents & WindowAnimationEvents & PresetEvents & ThumbnailEvents & SnapshotEvents & AIChatEvents;
|
|
113
149
|
export declare const emitter: import("mitt").Emitter<EditorEvents>;
|
|
114
150
|
export {};
|
|
115
151
|
//# 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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"}
|
|
@@ -5,11 +5,13 @@ export declare const sceneRegistry: {
|
|
|
5
5
|
site: Set<string>;
|
|
6
6
|
building: Set<string>;
|
|
7
7
|
ceiling: Set<string>;
|
|
8
|
+
column: Set<string>;
|
|
8
9
|
level: Set<string>;
|
|
9
10
|
wall: Set<string>;
|
|
10
11
|
fence: Set<string>;
|
|
11
12
|
item: Set<string>;
|
|
12
13
|
slab: Set<string>;
|
|
14
|
+
spawn: Set<string>;
|
|
13
15
|
zone: Set<string>;
|
|
14
16
|
roof: Set<string>;
|
|
15
17
|
'roof-segment': Set<string>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scene-registry.d.ts","sourceRoot":"","sources":["../../../src/hooks/scene-registry/scene-registry.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,KAAK,KAAK,MAAM,OAAO,CAAA;AAEnC,eAAO,MAAM,aAAa
|
|
1
|
+
{"version":3,"file":"scene-registry.d.ts","sourceRoot":"","sources":["../../../src/hooks/scene-registry/scene-registry.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,KAAK,KAAK,MAAM,OAAO,CAAA;AAEnC,eAAO,MAAM,aAAa;;;;;;;;;;;;;;;;;;;;;;;IA4BxB,gFAAgF;;CAOjF,CAAA;AAED,wBAAgB,WAAW,CACzB,EAAE,EAAE,MAAM,EACV,IAAI,EAAE,MAAM,OAAO,aAAa,CAAC,MAAM,EACvC,GAAG,EAAE,KAAK,CAAC,SAAS,CAAC,KAAK,CAAC,QAAQ,CAAC,QAkBrC"}
|
|
@@ -9,11 +9,13 @@ export const sceneRegistry = {
|
|
|
9
9
|
site: new Set(),
|
|
10
10
|
building: new Set(),
|
|
11
11
|
ceiling: new Set(),
|
|
12
|
+
column: new Set(),
|
|
12
13
|
level: new Set(),
|
|
13
14
|
wall: new Set(),
|
|
14
15
|
fence: new Set(),
|
|
15
16
|
item: new Set(),
|
|
16
17
|
slab: new Set(),
|
|
18
|
+
spawn: new Set(),
|
|
17
19
|
zone: new Set(),
|
|
18
20
|
roof: new Set(),
|
|
19
21
|
'roof-segment': new Set(),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"spatial-grid-manager.d.ts","sourceRoot":"","sources":["../../../src/hooks/spatial-grid/spatial-grid-manager.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAA6C,MAAM,cAAc,CAAA;
|
|
1
|
+
{"version":3,"file":"spatial-grid-manager.d.ts","sourceRoot":"","sources":["../../../src/hooks/spatial-grid/spatial-grid-manager.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { getScaledDimensions } from '../../schema';
|
|
1
|
+
import { getScaledDimensions, isLowProfileItemSurface } from '../../schema';
|
|
2
|
+
import useScene from '../../store/use-scene';
|
|
2
3
|
import { SpatialGrid } from './spatial-grid';
|
|
3
4
|
import { WallSpatialGrid } from './wall-spatial-grid';
|
|
4
5
|
// ============================================================================
|
|
@@ -37,6 +38,65 @@ function getItemFootprint(position, dimensions, rotation, inset = 0) {
|
|
|
37
38
|
[x + (-halfW * cos - halfD * sin), z + (-halfW * sin + halfD * cos)],
|
|
38
39
|
];
|
|
39
40
|
}
|
|
41
|
+
function getItemLocalBounds(item) {
|
|
42
|
+
const [width, height, depth] = getScaledDimensions(item);
|
|
43
|
+
const minZ = item.asset.attachTo === 'wall-side' ? -depth : -depth / 2;
|
|
44
|
+
const maxZ = item.asset.attachTo === 'wall-side' ? 0 : depth / 2;
|
|
45
|
+
return {
|
|
46
|
+
min: [-width / 2, 0, minZ],
|
|
47
|
+
max: [width / 2, height, maxZ],
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
function getItemParentAabb(item) {
|
|
51
|
+
const bounds = getItemLocalBounds(item);
|
|
52
|
+
const corners = [
|
|
53
|
+
[bounds.min[0], bounds.min[1], bounds.min[2]],
|
|
54
|
+
[bounds.min[0], bounds.min[1], bounds.max[2]],
|
|
55
|
+
[bounds.min[0], bounds.max[1], bounds.min[2]],
|
|
56
|
+
[bounds.min[0], bounds.max[1], bounds.max[2]],
|
|
57
|
+
[bounds.max[0], bounds.min[1], bounds.min[2]],
|
|
58
|
+
[bounds.max[0], bounds.min[1], bounds.max[2]],
|
|
59
|
+
[bounds.max[0], bounds.max[1], bounds.min[2]],
|
|
60
|
+
[bounds.max[0], bounds.max[1], bounds.max[2]],
|
|
61
|
+
];
|
|
62
|
+
const yRot = item.rotation[1] ?? 0;
|
|
63
|
+
const cos = Math.cos(yRot);
|
|
64
|
+
const sin = Math.sin(yRot);
|
|
65
|
+
let minX = Number.POSITIVE_INFINITY;
|
|
66
|
+
let minY = Number.POSITIVE_INFINITY;
|
|
67
|
+
let minZ = Number.POSITIVE_INFINITY;
|
|
68
|
+
let maxX = Number.NEGATIVE_INFINITY;
|
|
69
|
+
let maxY = Number.NEGATIVE_INFINITY;
|
|
70
|
+
let maxZ = Number.NEGATIVE_INFINITY;
|
|
71
|
+
for (const [cx, cy, cz] of corners) {
|
|
72
|
+
const rotatedX = cx * cos + cz * sin;
|
|
73
|
+
const rotatedZ = -cx * sin + cz * cos;
|
|
74
|
+
const worldX = rotatedX + item.position[0];
|
|
75
|
+
const worldY = cy + item.position[1];
|
|
76
|
+
const worldZ = rotatedZ + item.position[2];
|
|
77
|
+
minX = Math.min(minX, worldX);
|
|
78
|
+
minY = Math.min(minY, worldY);
|
|
79
|
+
minZ = Math.min(minZ, worldZ);
|
|
80
|
+
maxX = Math.max(maxX, worldX);
|
|
81
|
+
maxY = Math.max(maxY, worldY);
|
|
82
|
+
maxZ = Math.max(maxZ, worldZ);
|
|
83
|
+
}
|
|
84
|
+
return { minX, maxX, minY, maxY, minZ, maxZ };
|
|
85
|
+
}
|
|
86
|
+
function intervalsOverlap(minA, maxA, minB, maxB, epsilon = 1e-4) {
|
|
87
|
+
return minA < maxB - epsilon && maxA > minB + epsilon;
|
|
88
|
+
}
|
|
89
|
+
function resolveNodeLevelId(node, nodes) {
|
|
90
|
+
if (node.type === 'level')
|
|
91
|
+
return node.id;
|
|
92
|
+
let current = node;
|
|
93
|
+
while (current) {
|
|
94
|
+
if (current.type === 'level')
|
|
95
|
+
return current.id;
|
|
96
|
+
current = current.parentId ? nodes[current.parentId] : undefined;
|
|
97
|
+
}
|
|
98
|
+
return 'default';
|
|
99
|
+
}
|
|
40
100
|
/**
|
|
41
101
|
* Test if two line segments (a1->a2) and (b1->b2) intersect.
|
|
42
102
|
*/
|
|
@@ -373,8 +433,40 @@ export class SpatialGridManager {
|
|
|
373
433
|
}
|
|
374
434
|
// Query methods
|
|
375
435
|
canPlaceOnFloor(levelId, position, dimensions, rotation, ignoreIds) {
|
|
376
|
-
const
|
|
377
|
-
|
|
436
|
+
const nodes = useScene.getState().nodes;
|
|
437
|
+
const ignoreSet = new Set(ignoreIds ?? []);
|
|
438
|
+
const [width, , depth] = dimensions;
|
|
439
|
+
const yRot = rotation[1];
|
|
440
|
+
const cos = Math.abs(Math.cos(yRot));
|
|
441
|
+
const sin = Math.abs(Math.sin(yRot));
|
|
442
|
+
const rotatedW = width * cos + depth * sin;
|
|
443
|
+
const rotatedD = width * sin + depth * cos;
|
|
444
|
+
const draftBounds = {
|
|
445
|
+
minX: position[0] - rotatedW / 2,
|
|
446
|
+
maxX: position[0] + rotatedW / 2,
|
|
447
|
+
minZ: position[2] - rotatedD / 2,
|
|
448
|
+
maxZ: position[2] + rotatedD / 2,
|
|
449
|
+
};
|
|
450
|
+
const conflicts = [];
|
|
451
|
+
for (const node of Object.values(nodes)) {
|
|
452
|
+
if (node.type !== 'item')
|
|
453
|
+
continue;
|
|
454
|
+
const item = node;
|
|
455
|
+
if (item.asset.attachTo)
|
|
456
|
+
continue;
|
|
457
|
+
if (isLowProfileItemSurface(item))
|
|
458
|
+
continue;
|
|
459
|
+
if (ignoreSet.has(item.id))
|
|
460
|
+
continue;
|
|
461
|
+
if (resolveNodeLevelId(item, nodes) !== levelId)
|
|
462
|
+
continue;
|
|
463
|
+
const bounds = getItemParentAabb(item);
|
|
464
|
+
if (intervalsOverlap(draftBounds.minX, draftBounds.maxX, bounds.minX, bounds.maxX) &&
|
|
465
|
+
intervalsOverlap(draftBounds.minZ, draftBounds.maxZ, bounds.minZ, bounds.maxZ)) {
|
|
466
|
+
conflicts.push(item.id);
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
return { valid: conflicts.length === 0, conflictIds: conflicts };
|
|
378
470
|
}
|
|
379
471
|
/**
|
|
380
472
|
* Check if an item can be placed on a wall
|
|
@@ -396,7 +488,43 @@ export class SpatialGridManager {
|
|
|
396
488
|
// Convert local X position to parametric t (0-1)
|
|
397
489
|
const tCenter = localX / wallLength;
|
|
398
490
|
const [itemWidth, itemHeight] = dimensions;
|
|
399
|
-
|
|
491
|
+
const baseResult = this.getWallGrid(levelId).canPlaceOnWall(wallId, wallLength, wallHeight, tCenter, itemWidth, localY, itemHeight, attachType, side, ignoreIds);
|
|
492
|
+
if (!baseResult.valid)
|
|
493
|
+
return baseResult;
|
|
494
|
+
const nodes = useScene.getState().nodes;
|
|
495
|
+
const ignoreSet = new Set(ignoreIds ?? []);
|
|
496
|
+
const draftBounds = {
|
|
497
|
+
minX: localX - itemWidth / 2,
|
|
498
|
+
maxX: localX + itemWidth / 2,
|
|
499
|
+
minY: baseResult.adjustedY,
|
|
500
|
+
maxY: baseResult.adjustedY + itemHeight,
|
|
501
|
+
};
|
|
502
|
+
const conflicts = [];
|
|
503
|
+
for (const node of Object.values(nodes)) {
|
|
504
|
+
if (node.type !== 'item')
|
|
505
|
+
continue;
|
|
506
|
+
const item = node;
|
|
507
|
+
if (!(item.asset.attachTo === 'wall' || item.asset.attachTo === 'wall-side'))
|
|
508
|
+
continue;
|
|
509
|
+
if (ignoreSet.has(item.id))
|
|
510
|
+
continue;
|
|
511
|
+
if (item.parentId !== wallId)
|
|
512
|
+
continue;
|
|
513
|
+
if (attachType === 'wall-side' && item.asset.attachTo === 'wall-side' && side && item.side) {
|
|
514
|
+
if (side !== item.side)
|
|
515
|
+
continue;
|
|
516
|
+
}
|
|
517
|
+
const bounds = getItemParentAabb(item);
|
|
518
|
+
if (intervalsOverlap(draftBounds.minX, draftBounds.maxX, bounds.minX, bounds.maxX) &&
|
|
519
|
+
intervalsOverlap(draftBounds.minY, draftBounds.maxY, bounds.minY, bounds.maxY)) {
|
|
520
|
+
conflicts.push(item.id);
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
return {
|
|
524
|
+
...baseResult,
|
|
525
|
+
valid: conflicts.length === 0,
|
|
526
|
+
conflictIds: conflicts,
|
|
527
|
+
};
|
|
400
528
|
}
|
|
401
529
|
getWallForItem(levelId, itemId) {
|
|
402
530
|
return this.getWallGrid(levelId).getWallForItem(itemId);
|
|
@@ -541,8 +669,38 @@ export class SpatialGridManager {
|
|
|
541
669
|
return { valid: false, conflictIds: [] };
|
|
542
670
|
}
|
|
543
671
|
}
|
|
544
|
-
|
|
545
|
-
|
|
672
|
+
const nodes = useScene.getState().nodes;
|
|
673
|
+
const ignoreSet = new Set(ignoreIds ?? []);
|
|
674
|
+
const [width, , depth] = dimensions;
|
|
675
|
+
const yRot = rotation[1];
|
|
676
|
+
const cos = Math.abs(Math.cos(yRot));
|
|
677
|
+
const sin = Math.abs(Math.sin(yRot));
|
|
678
|
+
const rotatedW = width * cos + depth * sin;
|
|
679
|
+
const rotatedD = width * sin + depth * cos;
|
|
680
|
+
const draftBounds = {
|
|
681
|
+
minX: position[0] - rotatedW / 2,
|
|
682
|
+
maxX: position[0] + rotatedW / 2,
|
|
683
|
+
minZ: position[2] - rotatedD / 2,
|
|
684
|
+
maxZ: position[2] + rotatedD / 2,
|
|
685
|
+
};
|
|
686
|
+
const conflicts = [];
|
|
687
|
+
for (const node of Object.values(nodes)) {
|
|
688
|
+
if (node.type !== 'item')
|
|
689
|
+
continue;
|
|
690
|
+
const item = node;
|
|
691
|
+
if (item.asset.attachTo !== 'ceiling')
|
|
692
|
+
continue;
|
|
693
|
+
if (ignoreSet.has(item.id))
|
|
694
|
+
continue;
|
|
695
|
+
if (item.parentId !== ceilingId)
|
|
696
|
+
continue;
|
|
697
|
+
const bounds = getItemParentAabb(item);
|
|
698
|
+
if (intervalsOverlap(draftBounds.minX, draftBounds.maxX, bounds.minX, bounds.maxX) &&
|
|
699
|
+
intervalsOverlap(draftBounds.minZ, draftBounds.maxZ, bounds.minZ, bounds.maxZ)) {
|
|
700
|
+
conflicts.push(item.id);
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
return { valid: conflicts.length === 0, conflictIds: conflicts };
|
|
546
704
|
}
|
|
547
705
|
clearLevel(levelId) {
|
|
548
706
|
this.floorGrids.delete(levelId);
|
package/dist/index.d.ts
CHANGED
|
@@ -1,30 +1,23 @@
|
|
|
1
|
-
export type { BuildingEvent, CameraControlEvent, CeilingEvent, DoorEvent, EventSuffix, FenceEvent, GridEvent, ItemEvent, LevelEvent, NodeEvent, RoofEvent, RoofSegmentEvent, SiteEvent, SlabEvent, StairEvent, StairSegmentEvent, WallEvent, WindowEvent, ZoneEvent, } from './events/bus';
|
|
1
|
+
export type { BuildingEvent, CameraControlEvent, CameraControlFitSceneEvent, CeilingEvent, ColumnEvent, DoorEvent, EventSuffix, FenceEvent, GridEvent, ItemEvent, LevelEvent, NodeEvent, RoofEvent, RoofSegmentEvent, SiteEvent, SlabEvent, SpawnEvent, StairEvent, StairSegmentEvent, WallEvent, WindowEvent, ZoneEvent, } from './events/bus';
|
|
2
2
|
export { emitter, eventSuffixes } from './events/bus';
|
|
3
3
|
export { sceneRegistry, useRegistry, } from './hooks/scene-registry/scene-registry';
|
|
4
4
|
export { pointInPolygon, spatialGridManager } from './hooks/spatial-grid/spatial-grid-manager';
|
|
5
5
|
export { initSpatialGridSync, resolveLevelId, } from './hooks/spatial-grid/spatial-grid-sync';
|
|
6
6
|
export { useSpatialQuery } from './hooks/spatial-grid/use-spatial-query';
|
|
7
7
|
export { loadAssetUrl, saveAsset } from './lib/asset-storage';
|
|
8
|
+
export { clampDoorOperationState, getDoorRenderOpenAmount, getGarageVisibleOpeningRatio, isOperationDoorType, SECTIONAL_GARAGE_RENDER_OPEN_SCALE, } from './lib/door-operation';
|
|
9
|
+
export { getRenderableSlabPolygon } from './lib/slab-polygon';
|
|
8
10
|
export { detectSpacesForLevel, initSpaceDetectionSync, type Space, wallTouchesOthers, } from './lib/space-detection';
|
|
9
|
-
export {
|
|
10
|
-
export { getCatalogMaterialById, getLibraryMaterialIdFromRef, getMaterialPresetByRef, getMaterialsForTarget, LIBRARY_MATERIAL_REF_PREFIX, MATERIAL_CATALOG, type MaterialCatalogItem, toLibraryMaterialRef, } from './material-library';
|
|
11
|
+
export { getCatalogMaterialById, getLibraryMaterialIdFromRef, getMaterialPresetByRef, getMaterialsForCategory, LIBRARY_MATERIAL_REF_PREFIX, MATERIAL_CATALOG, MATERIAL_CATEGORIES, type MaterialCatalogItem, type MaterialCategory, toLibraryMaterialRef, } from './material-library';
|
|
11
12
|
export * from './schema';
|
|
12
|
-
export { type ControlValue, type ItemInteractiveState, useInteractive, } from './store/use-interactive';
|
|
13
13
|
export { getSceneHistoryPauseDepth, pauseSceneHistory, resetSceneHistoryPauseDepth, resumeSceneHistory, } from './store/history-control';
|
|
14
|
+
export { type ControlValue, type DoorAnimationState, type DoorInteractiveState, type ItemInteractiveState, useInteractive, type WindowAnimationState, type WindowInteractiveState, } from './store/use-interactive';
|
|
14
15
|
export { default as useLiveTransforms, type LiveTransform } from './store/use-live-transforms';
|
|
15
|
-
export { FenceSystem } from './systems/fence/fence-system';
|
|
16
16
|
export { clearSceneHistory, default as useScene } from './store/use-scene';
|
|
17
|
-
export {
|
|
18
|
-
export { DoorSystem } from './systems/door/door-system';
|
|
19
|
-
export { ItemSystem } from './systems/item/item-system';
|
|
20
|
-
export { RoofSystem } from './systems/roof/roof-system';
|
|
21
|
-
export { SlabSystem } from './systems/slab/slab-system';
|
|
22
|
-
export { StairSystem } from './systems/stair/stair-system';
|
|
23
|
-
export { DEFAULT_WALL_HEIGHT, DEFAULT_WALL_THICKNESS, getWallPlanFootprint, getWallThickness, } from './systems/wall/wall-footprint';
|
|
17
|
+
export { syncAutoStairOpenings } from './systems/stair/stair-opening-sync';
|
|
24
18
|
export { getClampedWallCurveOffset, getMaxWallCurveOffset, getWallChordFrame, getWallCurveFrameAt, getWallCurveLength, getWallMidpointHandlePoint, getWallStraightSnapOffset, getWallSurfacePolygon, isCurvedWall, normalizeWallCurveOffset, sampleWallCenterline, } from './systems/wall/wall-curve';
|
|
25
|
-
export {
|
|
26
|
-
export {
|
|
27
|
-
export { WindowSystem } from './systems/window/window-system';
|
|
19
|
+
export { DEFAULT_WALL_HEIGHT, DEFAULT_WALL_THICKNESS, getWallPlanFootprint, getWallThickness, } from './systems/wall/wall-footprint';
|
|
20
|
+
export { calculateLevelMiters, getAdjacentWallIds, getWallMiterBoundaryPoints, type Point2D, pointToKey, type WallMiterBoundaryPoints, type WallMiterData, } from './systems/wall/wall-mitering';
|
|
28
21
|
export type { SceneGraph } from './utils/clone-scene-graph';
|
|
29
22
|
export { cloneLevelSubtree, cloneSceneGraph, forkSceneGraph } from './utils/clone-scene-graph';
|
|
30
23
|
export { isObject } from './utils/types';
|
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,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,aAAa,EACb,kBAAkB,EAClB,0BAA0B,EAC1B,YAAY,EACZ,WAAW,EACX,SAAS,EACT,WAAW,EACX,UAAU,EACV,SAAS,EACT,SAAS,EACT,UAAU,EACV,SAAS,EACT,SAAS,EACT,gBAAgB,EAChB,SAAS,EACT,SAAS,EACT,UAAU,EACV,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,uBAAuB,EACvB,uBAAuB,EACvB,4BAA4B,EAC5B,mBAAmB,EACnB,kCAAkC,GACnC,MAAM,sBAAsB,CAAA;AAC7B,OAAO,EAAE,wBAAwB,EAAE,MAAM,oBAAoB,CAAA;AAC7D,OAAO,EACL,oBAAoB,EACpB,sBAAsB,EACtB,KAAK,KAAK,EACV,iBAAiB,GAClB,MAAM,uBAAuB,CAAA;AAC9B,OAAO,EACL,sBAAsB,EACtB,2BAA2B,EAC3B,sBAAsB,EACtB,uBAAuB,EACvB,2BAA2B,EAC3B,gBAAgB,EAChB,mBAAmB,EACnB,KAAK,mBAAmB,EACxB,KAAK,gBAAgB,EACrB,oBAAoB,GACrB,MAAM,oBAAoB,CAAA;AAC3B,cAAc,UAAU,CAAA;AACxB,OAAO,EACL,yBAAyB,EACzB,iBAAiB,EACjB,2BAA2B,EAC3B,kBAAkB,GACnB,MAAM,yBAAyB,CAAA;AAChC,OAAO,EACL,KAAK,YAAY,EACjB,KAAK,kBAAkB,EACvB,KAAK,oBAAoB,EACzB,KAAK,oBAAoB,EACzB,cAAc,EACd,KAAK,oBAAoB,EACzB,KAAK,sBAAsB,GAC5B,MAAM,yBAAyB,CAAA;AAChC,OAAO,EAAE,OAAO,IAAI,iBAAiB,EAAE,KAAK,aAAa,EAAE,MAAM,6BAA6B,CAAA;AAC9F,OAAO,EAAE,iBAAiB,EAAE,OAAO,IAAI,QAAQ,EAAE,MAAM,mBAAmB,CAAA;AAC1E,OAAO,EAAE,qBAAqB,EAAE,MAAM,oCAAoC,CAAA;AAC1E,OAAO,EACL,yBAAyB,EACzB,qBAAqB,EACrB,iBAAiB,EACjB,mBAAmB,EACnB,kBAAkB,EAClB,0BAA0B,EAC1B,yBAAyB,EACzB,qBAAqB,EACrB,YAAY,EACZ,wBAAwB,EACxB,oBAAoB,GACrB,MAAM,2BAA2B,CAAA;AAClC,OAAO,EACL,mBAAmB,EACnB,sBAAsB,EACtB,oBAAoB,EACpB,gBAAgB,GACjB,MAAM,+BAA+B,CAAA;AACtC,OAAO,EACL,oBAAoB,EACpB,kBAAkB,EAClB,0BAA0B,EAC1B,KAAK,OAAO,EACZ,UAAU,EACV,KAAK,uBAAuB,EAC5B,KAAK,aAAa,GACnB,MAAM,8BAA8B,CAAA;AACrC,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"}
|
package/dist/index.js
CHANGED
|
@@ -4,25 +4,18 @@ export { pointInPolygon, spatialGridManager } from './hooks/spatial-grid/spatial
|
|
|
4
4
|
export { initSpatialGridSync, resolveLevelId, } from './hooks/spatial-grid/spatial-grid-sync';
|
|
5
5
|
export { useSpatialQuery } from './hooks/spatial-grid/use-spatial-query';
|
|
6
6
|
export { loadAssetUrl, saveAsset } from './lib/asset-storage';
|
|
7
|
+
export { clampDoorOperationState, getDoorRenderOpenAmount, getGarageVisibleOpeningRatio, isOperationDoorType, SECTIONAL_GARAGE_RENDER_OPEN_SCALE, } from './lib/door-operation';
|
|
8
|
+
export { getRenderableSlabPolygon } from './lib/slab-polygon';
|
|
7
9
|
export { detectSpacesForLevel, initSpaceDetectionSync, wallTouchesOthers, } from './lib/space-detection';
|
|
8
|
-
export {
|
|
9
|
-
export { getCatalogMaterialById, getLibraryMaterialIdFromRef, getMaterialPresetByRef, getMaterialsForTarget, LIBRARY_MATERIAL_REF_PREFIX, MATERIAL_CATALOG, toLibraryMaterialRef, } from './material-library';
|
|
10
|
+
export { getCatalogMaterialById, getLibraryMaterialIdFromRef, getMaterialPresetByRef, getMaterialsForCategory, LIBRARY_MATERIAL_REF_PREFIX, MATERIAL_CATALOG, MATERIAL_CATEGORIES, toLibraryMaterialRef, } from './material-library';
|
|
10
11
|
export * from './schema';
|
|
11
|
-
export { useInteractive, } from './store/use-interactive';
|
|
12
12
|
export { getSceneHistoryPauseDepth, pauseSceneHistory, resetSceneHistoryPauseDepth, resumeSceneHistory, } from './store/history-control';
|
|
13
|
+
export { useInteractive, } from './store/use-interactive';
|
|
13
14
|
export { default as useLiveTransforms } from './store/use-live-transforms';
|
|
14
|
-
export { FenceSystem } from './systems/fence/fence-system';
|
|
15
15
|
export { clearSceneHistory, default as useScene } from './store/use-scene';
|
|
16
|
-
export {
|
|
17
|
-
export { DoorSystem } from './systems/door/door-system';
|
|
18
|
-
export { ItemSystem } from './systems/item/item-system';
|
|
19
|
-
export { RoofSystem } from './systems/roof/roof-system';
|
|
20
|
-
export { SlabSystem } from './systems/slab/slab-system';
|
|
21
|
-
export { StairSystem } from './systems/stair/stair-system';
|
|
22
|
-
export { DEFAULT_WALL_HEIGHT, DEFAULT_WALL_THICKNESS, getWallPlanFootprint, getWallThickness, } from './systems/wall/wall-footprint';
|
|
16
|
+
export { syncAutoStairOpenings } from './systems/stair/stair-opening-sync';
|
|
23
17
|
export { getClampedWallCurveOffset, getMaxWallCurveOffset, getWallChordFrame, getWallCurveFrameAt, getWallCurveLength, getWallMidpointHandlePoint, getWallStraightSnapOffset, getWallSurfacePolygon, isCurvedWall, normalizeWallCurveOffset, sampleWallCenterline, } from './systems/wall/wall-curve';
|
|
24
|
-
export {
|
|
25
|
-
export {
|
|
26
|
-
export { WindowSystem } from './systems/window/window-system';
|
|
18
|
+
export { DEFAULT_WALL_HEIGHT, DEFAULT_WALL_THICKNESS, getWallPlanFootprint, getWallThickness, } from './systems/wall/wall-footprint';
|
|
19
|
+
export { calculateLevelMiters, getAdjacentWallIds, getWallMiterBoundaryPoints, pointToKey, } from './systems/wall/wall-mitering';
|
|
27
20
|
export { cloneLevelSubtree, cloneSceneGraph, forkSceneGraph } from './utils/clone-scene-graph';
|
|
28
21
|
export { isObject } from './utils/types';
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { DoorNode, DoorType } from '../schema/nodes/door';
|
|
2
|
+
export declare const SECTIONAL_GARAGE_RENDER_OPEN_SCALE = 0.88;
|
|
3
|
+
export declare function clampDoorOperationState(value: number | undefined): number;
|
|
4
|
+
export declare function isOperationDoorType(doorType: DoorType | DoorNode['doorType'] | string | undefined): doorType is "folding" | "pocket" | "barn" | "sliding" | "garage-sectional" | "garage-rollup" | "garage-tiltup";
|
|
5
|
+
export declare function getDoorRenderOpenAmount(doorType: DoorType | DoorNode['doorType'], operationState: number | undefined): number;
|
|
6
|
+
export declare function getGarageVisibleOpeningRatio(doorType: DoorType | DoorNode['doorType'], operationState: number | undefined): number;
|
|
7
|
+
//# sourceMappingURL=door-operation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"door-operation.d.ts","sourceRoot":"","sources":["../../src/lib/door-operation.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAA;AAE9D,eAAO,MAAM,kCAAkC,OAAO,CAAA;AAEtD,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,UAEhE;AAED,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,QAAQ,GAAG,QAAQ,CAAC,UAAU,CAAC,GAAG,MAAM,GAAG,SAAS,kHAW/D;AAED,wBAAgB,uBAAuB,CACrC,QAAQ,EAAE,QAAQ,GAAG,QAAQ,CAAC,UAAU,CAAC,EACzC,cAAc,EAAE,MAAM,GAAG,SAAS,UAMnC;AAED,wBAAgB,4BAA4B,CAC1C,QAAQ,EAAE,QAAQ,GAAG,QAAQ,CAAC,UAAU,CAAC,EACzC,cAAc,EAAE,MAAM,GAAG,SAAS,UAOnC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export const SECTIONAL_GARAGE_RENDER_OPEN_SCALE = 0.88;
|
|
2
|
+
export function clampDoorOperationState(value) {
|
|
3
|
+
return Math.max(0, Math.min(1, value ?? 0));
|
|
4
|
+
}
|
|
5
|
+
export function isOperationDoorType(doorType) {
|
|
6
|
+
return (doorType === 'folding' ||
|
|
7
|
+
doorType === 'pocket' ||
|
|
8
|
+
doorType === 'barn' ||
|
|
9
|
+
doorType === 'sliding' ||
|
|
10
|
+
doorType === 'garage-sectional' ||
|
|
11
|
+
doorType === 'garage-rollup' ||
|
|
12
|
+
doorType === 'garage-tiltup');
|
|
13
|
+
}
|
|
14
|
+
export function getDoorRenderOpenAmount(doorType, operationState) {
|
|
15
|
+
const openAmount = clampDoorOperationState(operationState);
|
|
16
|
+
return doorType === 'garage-sectional'
|
|
17
|
+
? openAmount * SECTIONAL_GARAGE_RENDER_OPEN_SCALE
|
|
18
|
+
: openAmount;
|
|
19
|
+
}
|
|
20
|
+
export function getGarageVisibleOpeningRatio(doorType, operationState) {
|
|
21
|
+
if (doorType === 'garage-sectional') {
|
|
22
|
+
return Math.min(1, clampDoorOperationState(operationState) / SECTIONAL_GARAGE_RENDER_OPEN_SCALE);
|
|
23
|
+
}
|
|
24
|
+
return clampDoorOperationState(operationState);
|
|
25
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"slab-polygon.d.ts","sourceRoot":"","sources":["../../src/lib/slab-polygon.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAA;AAQzC,wBAAgB,wBAAwB,CAAC,QAAQ,EAAE,QAAQ,GAAG,KAAK,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAOpF"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { insetPolygonFromCentroid, simplifyClosedPolygon } from './polygon-geometry';
|
|
2
|
+
/** Half of default wall thickness — used to extend slab geometry under walls */
|
|
3
|
+
const SLAB_OUTSET = 0.05;
|
|
4
|
+
const AUTO_SLAB_INSET = 0.02;
|
|
5
|
+
const AUTO_SLAB_SIMPLIFY_TOLERANCE = 0.08;
|
|
6
|
+
export function getRenderableSlabPolygon(slabNode) {
|
|
7
|
+
return slabNode.autoFromWalls
|
|
8
|
+
? simplifyClosedPolygon(insetPolygonFromCentroid(slabNode.polygon, AUTO_SLAB_INSET), AUTO_SLAB_SIMPLIFY_TOLERANCE)
|
|
9
|
+
: outsetPolygon(slabNode.polygon, SLAB_OUTSET);
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Expand a polygon outward by a uniform distance.
|
|
13
|
+
* Offsets each edge outward then intersects consecutive offset edges.
|
|
14
|
+
*/
|
|
15
|
+
function outsetPolygon(polygon, amount) {
|
|
16
|
+
const n = polygon.length;
|
|
17
|
+
if (n < 3)
|
|
18
|
+
return polygon;
|
|
19
|
+
// Determine winding via signed area
|
|
20
|
+
let area2 = 0;
|
|
21
|
+
for (let i = 0; i < n; i++) {
|
|
22
|
+
const j = (i + 1) % n;
|
|
23
|
+
area2 += polygon[i][0] * polygon[j][1] - polygon[j][0] * polygon[i][1];
|
|
24
|
+
}
|
|
25
|
+
const s = area2 >= 0 ? 1 : -1;
|
|
26
|
+
// Offset each edge outward by amount
|
|
27
|
+
const offEdges = [];
|
|
28
|
+
for (let i = 0; i < n; i++) {
|
|
29
|
+
const j = (i + 1) % n;
|
|
30
|
+
const dx = polygon[j][0] - polygon[i][0];
|
|
31
|
+
const dz = polygon[j][1] - polygon[i][1];
|
|
32
|
+
const len = Math.sqrt(dx * dx + dz * dz);
|
|
33
|
+
if (len < 1e-9) {
|
|
34
|
+
offEdges.push([polygon[i][0], polygon[i][1], dx, dz]);
|
|
35
|
+
continue;
|
|
36
|
+
}
|
|
37
|
+
const nx = ((s * dz) / len) * amount;
|
|
38
|
+
const nz = ((s * -dx) / len) * amount;
|
|
39
|
+
offEdges.push([polygon[i][0] + nx, polygon[i][1] + nz, dx, dz]);
|
|
40
|
+
}
|
|
41
|
+
// Intersect consecutive offset edges to get new vertices
|
|
42
|
+
const result = [];
|
|
43
|
+
for (let i = 0; i < n; i++) {
|
|
44
|
+
const j = (i + 1) % n;
|
|
45
|
+
const [ax, az, adx, adz] = offEdges[i];
|
|
46
|
+
const [bx, bz, bdx, bdz] = offEdges[j];
|
|
47
|
+
const denom = adx * bdz - adz * bdx;
|
|
48
|
+
if (Math.abs(denom) < 1e-9) {
|
|
49
|
+
// Parallel edges — use offset endpoint
|
|
50
|
+
result.push([ax + adx, az + adz]);
|
|
51
|
+
}
|
|
52
|
+
else {
|
|
53
|
+
const t = ((bx - ax) * bdz - (bz - az) * bdx) / denom;
|
|
54
|
+
result.push([ax + t * adx, az + t * adz]);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
return result;
|
|
58
|
+
}
|
|
@@ -1,15 +1,17 @@
|
|
|
1
|
-
import { type MaterialPresetPayload
|
|
1
|
+
import { type MaterialPresetPayload } from './schema/material';
|
|
2
2
|
export type MaterialCatalogItem = {
|
|
3
3
|
id: string;
|
|
4
4
|
label: string;
|
|
5
|
+
category: MaterialCategory;
|
|
5
6
|
description?: string;
|
|
6
|
-
targets: MaterialTarget[];
|
|
7
7
|
previewThumbnailUrl?: string;
|
|
8
8
|
previewColor?: string;
|
|
9
9
|
preset: MaterialPresetPayload;
|
|
10
10
|
};
|
|
11
|
+
export declare const MATERIAL_CATEGORIES: readonly ["wood", "wallpaper", "parquet", "granite", "marble", "other"];
|
|
12
|
+
export type MaterialCategory = (typeof MATERIAL_CATEGORIES)[number];
|
|
11
13
|
export declare const MATERIAL_CATALOG: MaterialCatalogItem[];
|
|
12
|
-
export declare function
|
|
14
|
+
export declare function getMaterialsForCategory(category: MaterialCategory): MaterialCatalogItem[];
|
|
13
15
|
export declare function getCatalogMaterialById(id?: string): MaterialCatalogItem | undefined;
|
|
14
16
|
export declare const LIBRARY_MATERIAL_REF_PREFIX = "library:";
|
|
15
17
|
export declare function toLibraryMaterialRef(id: string): string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"material-library.d.ts","sourceRoot":"","sources":["../src/material-library.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,qBAAqB,
|
|
1
|
+
{"version":3,"file":"material-library.d.ts","sourceRoot":"","sources":["../src/material-library.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,qBAAqB,EAC3B,MAAM,mBAAmB,CAAA;AAE1B,MAAM,MAAM,mBAAmB,GAAG;IAChC,EAAE,EAAE,MAAM,CAAA;IACV,KAAK,EAAE,MAAM,CAAA;IACb,QAAQ,EAAE,gBAAgB,CAAA;IAC1B,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,mBAAmB,CAAC,EAAE,MAAM,CAAA;IAC5B,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,MAAM,EAAE,qBAAqB,CAAA;CAC9B,CAAA;AAED,eAAO,MAAM,mBAAmB,yEAOtB,CAAA;AACV,MAAM,MAAM,gBAAgB,GAAG,CAAC,OAAO,mBAAmB,CAAC,CAAC,MAAM,CAAC,CAAA;AAEnE,eAAO,MAAM,gBAAgB,EAAE,mBAAmB,EAiiBjD,CAAA;AAED,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,gBAAgB,GAAG,mBAAmB,EAAE,CAEzF;AAED,wBAAgB,sBAAsB,CAAC,EAAE,CAAC,EAAE,MAAM,GAAG,mBAAmB,GAAG,SAAS,CAGnF;AAED,eAAO,MAAM,2BAA2B,aAAa,CAAA;AAErD,wBAAgB,oBAAoB,CAAC,EAAE,EAAE,MAAM,UAE9C;AAED,wBAAgB,2BAA2B,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,iBAItE;AAED,wBAAgB,sBAAsB,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,qBAAqB,GAAG,IAAI,CAIhG"}
|