@pascal-app/viewer 1.1.0 → 1.1.1
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/README.md +157 -0
- package/dist/components/viewer/drone-controller.d.ts.map +1 -1
- package/dist/components/viewer/drone-controller.js +1 -5
- package/dist/components/viewer/first-person/build-collider-world.d.ts +14 -0
- package/dist/components/viewer/first-person/build-collider-world.d.ts.map +1 -0
- package/dist/components/viewer/first-person/build-collider-world.js +426 -0
- package/dist/components/viewer/first-person/ground-holes.d.ts +22 -0
- package/dist/components/viewer/first-person/ground-holes.d.ts.map +1 -0
- package/dist/components/viewer/first-person/ground-holes.js +116 -0
- package/dist/components/viewer/first-person/mechanism-targets.d.ts +27 -0
- package/dist/components/viewer/first-person/mechanism-targets.d.ts.map +1 -0
- package/dist/components/viewer/first-person/mechanism-targets.js +79 -0
- package/dist/components/viewer/first-person/terrain-collider.d.ts +32 -0
- package/dist/components/viewer/first-person/terrain-collider.d.ts.map +1 -0
- package/dist/components/viewer/first-person/terrain-collider.js +175 -0
- package/dist/components/viewer/glb-walkthrough-controller.d.ts +1 -1
- package/dist/components/viewer/glb-walkthrough-controller.d.ts.map +1 -1
- package/dist/components/viewer/glb-walkthrough-controller.js +3 -4
- package/dist/components/viewer/live-walkthrough-controller.d.ts +17 -0
- package/dist/components/viewer/live-walkthrough-controller.d.ts.map +1 -0
- package/dist/components/viewer/live-walkthrough-controller.js +1449 -0
- package/dist/components/viewer/post-processing.d.ts.map +1 -1
- package/dist/components/viewer/post-processing.js +22 -1
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/lib/daylight/room-map.d.ts +29 -4
- package/dist/lib/daylight/room-map.d.ts.map +1 -1
- package/dist/lib/daylight/room-map.js +219 -36
- package/dist/lib/daylight/room-scene.d.ts.map +1 -1
- package/dist/lib/daylight/room-scene.js +9 -3
- package/dist/lib/daylight/rooms.d.ts +15 -6
- package/dist/lib/daylight/rooms.d.ts.map +1 -1
- package/dist/lib/daylight/rooms.js +49 -9
- package/dist/lib/measurement-presentation.d.ts +2 -0
- package/dist/lib/measurement-presentation.d.ts.map +1 -1
- package/dist/lib/measurement-presentation.js +6 -0
- package/dist/lib/typing-target.d.ts +2 -0
- package/dist/lib/typing-target.d.ts.map +1 -0
- package/dist/lib/typing-target.js +7 -0
- package/dist/lib/viewer-config.d.ts +6 -0
- package/dist/lib/viewer-config.d.ts.map +1 -1
- package/dist/lib/viewer-config.js +2 -0
- package/dist/sfx/audio-settings.d.ts +81 -0
- package/dist/sfx/audio-settings.d.ts.map +1 -0
- package/dist/sfx/audio-settings.js +166 -0
- package/dist/sfx/index.d.ts +6 -0
- package/dist/sfx/index.d.ts.map +1 -0
- package/dist/sfx/index.js +5 -0
- package/dist/sfx/interaction-sounds.d.ts +7 -0
- package/dist/sfx/interaction-sounds.d.ts.map +1 -0
- package/dist/sfx/interaction-sounds.js +39 -0
- package/dist/sfx/player.d.ts +31 -0
- package/dist/sfx/player.d.ts.map +1 -0
- package/dist/sfx/player.js +255 -0
- package/dist/sfx/sounds.d.ts +60 -0
- package/dist/sfx/sounds.d.ts.map +1 -0
- package/dist/sfx/sounds.js +25 -0
- package/dist/sfx/use-viewer-ui-sounds.d.ts +8 -0
- package/dist/sfx/use-viewer-ui-sounds.d.ts.map +1 -0
- package/dist/sfx/use-viewer-ui-sounds.js +42 -0
- package/dist/store/use-first-person-hud.d.ts +13 -0
- package/dist/store/use-first-person-hud.d.ts.map +1 -0
- package/dist/store/use-first-person-hud.js +21 -0
- package/dist/systems/roof/roof-system.d.ts.map +1 -1
- package/dist/systems/roof/roof-system.js +27 -13
- package/dist/ui/components/action-button.d.ts +14 -0
- package/dist/ui/components/action-button.d.ts.map +1 -0
- package/dist/ui/components/action-button.js +21 -0
- package/dist/ui/components/action-menu-placement.d.ts +7 -0
- package/dist/ui/components/action-menu-placement.d.ts.map +1 -0
- package/dist/ui/components/action-menu-placement.js +10 -0
- package/dist/ui/components/floorplan-compass-button.d.ts +10 -0
- package/dist/ui/components/floorplan-compass-button.d.ts.map +1 -0
- package/dist/ui/components/floorplan-compass-button.js +22 -0
- package/dist/ui/components/follow-pascal-toggle.d.ts +6 -0
- package/dist/ui/components/follow-pascal-toggle.d.ts.map +1 -0
- package/dist/ui/components/follow-pascal-toggle.js +21 -0
- package/dist/ui/components/localized-html.d.ts +9 -0
- package/dist/ui/components/localized-html.d.ts.map +1 -0
- package/dist/ui/components/localized-html.js +16 -0
- package/dist/ui/components/render-settings-menu.d.ts +9 -0
- package/dist/ui/components/render-settings-menu.d.ts.map +1 -0
- package/dist/ui/components/render-settings-menu.js +145 -0
- package/dist/ui/components/rooms/room-highlight.d.ts +10 -0
- package/dist/ui/components/rooms/room-highlight.d.ts.map +1 -0
- package/dist/ui/components/rooms/room-highlight.js +56 -0
- package/dist/ui/components/rooms/room-labels.d.ts +278 -0
- package/dist/ui/components/rooms/room-labels.d.ts.map +1 -0
- package/dist/ui/components/rooms/room-labels.js +1295 -0
- package/dist/ui/components/rooms/viewer-rooms.d.ts +14 -0
- package/dist/ui/components/rooms/viewer-rooms.d.ts.map +1 -0
- package/dist/ui/components/rooms/viewer-rooms.js +123 -0
- package/dist/ui/components/scene-loader.d.ts +18 -0
- package/dist/ui/components/scene-loader.d.ts.map +1 -0
- package/dist/ui/components/scene-loader.js +29 -0
- package/dist/ui/components/sky-control.d.ts +37 -0
- package/dist/ui/components/sky-control.d.ts.map +1 -0
- package/dist/ui/components/sky-control.js +382 -0
- package/dist/ui/components/use-viewer-camera-navigation-sync.d.ts +4 -0
- package/dist/ui/components/use-viewer-camera-navigation-sync.d.ts.map +1 -0
- package/dist/ui/components/use-viewer-camera-navigation-sync.js +117 -0
- package/dist/ui/components/viewer-controls-bar.d.ts +20 -0
- package/dist/ui/components/viewer-controls-bar.d.ts.map +1 -0
- package/dist/ui/components/viewer-controls-bar.js +130 -0
- package/dist/ui/components/viewer-hover-label.d.ts +14 -0
- package/dist/ui/components/viewer-hover-label.d.ts.map +1 -0
- package/dist/ui/components/viewer-hover-label.js +28 -0
- package/dist/ui/components/viewer-scene-header.d.ts +34 -0
- package/dist/ui/components/viewer-scene-header.d.ts.map +1 -0
- package/dist/ui/components/viewer-scene-header.js +92 -0
- package/dist/ui/components/viewer-selection-manager.d.ts +7 -0
- package/dist/ui/components/viewer-selection-manager.d.ts.map +1 -0
- package/dist/ui/components/viewer-selection-manager.js +116 -0
- package/dist/ui/components/viewer-stage-modes.d.ts +7 -0
- package/dist/ui/components/viewer-stage-modes.d.ts.map +1 -0
- package/dist/ui/components/viewer-stage-modes.js +42 -0
- package/dist/ui/components/viewer-stage-switcher.d.ts +10 -0
- package/dist/ui/components/viewer-stage-switcher.d.ts.map +1 -0
- package/dist/ui/components/viewer-stage-switcher.js +16 -0
- package/dist/ui/components/viewer-stage.d.ts +25 -0
- package/dist/ui/components/viewer-stage.d.ts.map +1 -0
- package/dist/ui/components/viewer-stage.js +107 -0
- package/dist/ui/components/walkthrough-hud.d.ts +29 -0
- package/dist/ui/components/walkthrough-hud.d.ts.map +1 -0
- package/dist/ui/components/walkthrough-hud.js +55 -0
- package/dist/ui/floorplan/floorplan-camera-sync.d.ts +22 -0
- package/dist/ui/floorplan/floorplan-camera-sync.d.ts.map +1 -0
- package/dist/ui/floorplan/floorplan-camera-sync.js +157 -0
- package/dist/ui/floorplan/floorplan-dimension-renderer.d.ts +61 -0
- package/dist/ui/floorplan/floorplan-dimension-renderer.d.ts.map +1 -0
- package/dist/ui/floorplan/floorplan-dimension-renderer.js +280 -0
- package/dist/ui/floorplan/floorplan-geometry-renderer.d.ts +54 -0
- package/dist/ui/floorplan/floorplan-geometry-renderer.d.ts.map +1 -0
- package/dist/ui/floorplan/floorplan-geometry-renderer.js +317 -0
- package/dist/ui/floorplan/floorplan-label-angle.d.ts +24 -0
- package/dist/ui/floorplan/floorplan-label-angle.d.ts.map +1 -0
- package/dist/ui/floorplan/floorplan-label-angle.js +60 -0
- package/dist/ui/floorplan/floorplan-navigation-sync.d.ts +18 -0
- package/dist/ui/floorplan/floorplan-navigation-sync.d.ts.map +1 -0
- package/dist/ui/floorplan/floorplan-navigation-sync.js +41 -0
- package/dist/ui/floorplan/floorplan-preview-geometry.d.ts +26 -0
- package/dist/ui/floorplan/floorplan-preview-geometry.d.ts.map +1 -0
- package/dist/ui/floorplan/floorplan-preview-geometry.js +173 -0
- package/dist/ui/floorplan/floorplan-preview-navigation.d.ts +22 -0
- package/dist/ui/floorplan/floorplan-preview-navigation.d.ts.map +1 -0
- package/dist/ui/floorplan/floorplan-preview-navigation.js +41 -0
- package/dist/ui/floorplan/floorplan-preview-visibility.d.ts +8 -0
- package/dist/ui/floorplan/floorplan-preview-visibility.d.ts.map +1 -0
- package/dist/ui/floorplan/floorplan-preview-visibility.js +21 -0
- package/dist/ui/floorplan/floorplan-preview.d.ts +19 -0
- package/dist/ui/floorplan/floorplan-preview.d.ts.map +1 -0
- package/dist/ui/floorplan/floorplan-preview.js +700 -0
- package/dist/ui/hooks/use-mobile.d.ts +2 -0
- package/dist/ui/hooks/use-mobile.d.ts.map +1 -0
- package/dist/ui/hooks/use-mobile.js +14 -0
- package/dist/ui/index.d.ts +49 -0
- package/dist/ui/index.d.ts.map +1 -0
- package/dist/ui/index.js +48 -0
- package/dist/ui/lib/below-grade.d.ts +38 -0
- package/dist/ui/lib/below-grade.d.ts.map +1 -0
- package/dist/ui/lib/below-grade.js +102 -0
- package/dist/ui/lib/camera-pose.d.ts +19 -0
- package/dist/ui/lib/camera-pose.d.ts.map +1 -0
- package/dist/ui/lib/camera-pose.js +113 -0
- package/dist/ui/lib/cn.d.ts +3 -0
- package/dist/ui/lib/cn.d.ts.map +1 -0
- package/dist/ui/lib/cn.js +5 -0
- package/dist/ui/lib/level-name.d.ts +10 -0
- package/dist/ui/lib/level-name.d.ts.map +1 -0
- package/dist/ui/lib/level-name.js +33 -0
- package/dist/ui/lib/node-display-label.d.ts +8 -0
- package/dist/ui/lib/node-display-label.d.ts.map +1 -0
- package/dist/ui/lib/node-display-label.js +36 -0
- package/dist/ui/lib/room-area.d.ts +3 -0
- package/dist/ui/lib/room-area.d.ts.map +1 -0
- package/dist/ui/lib/room-area.js +8 -0
- package/dist/ui/lib/room-assembly-overlay.d.ts +46 -0
- package/dist/ui/lib/room-assembly-overlay.d.ts.map +1 -0
- package/dist/ui/lib/room-assembly-overlay.js +222 -0
- package/dist/ui/lib/room-name-messages.d.ts +28 -0
- package/dist/ui/lib/room-name-messages.d.ts.map +1 -0
- package/dist/ui/lib/room-name-messages.js +112 -0
- package/dist/ui/lib/room-selection.d.ts +58 -0
- package/dist/ui/lib/room-selection.d.ts.map +1 -0
- package/dist/ui/lib/room-selection.js +297 -0
- package/dist/ui/lib/scene-theme-name.d.ts +4 -0
- package/dist/ui/lib/scene-theme-name.d.ts.map +1 -0
- package/dist/ui/lib/scene-theme-name.js +22 -0
- package/dist/ui/lib/selection-modifiers.d.ts +20 -0
- package/dist/ui/lib/selection-modifiers.d.ts.map +1 -0
- package/dist/ui/lib/selection-modifiers.js +15 -0
- package/dist/ui/lib/viewer-selection.d.ts +132 -0
- package/dist/ui/lib/viewer-selection.d.ts.map +1 -0
- package/dist/ui/lib/viewer-selection.js +462 -0
- package/dist/ui/lib/zone-content.d.ts +6 -0
- package/dist/ui/lib/zone-content.d.ts.map +1 -0
- package/dist/ui/lib/zone-content.js +96 -0
- package/dist/ui/primitives/button.d.ts +11 -0
- package/dist/ui/primitives/button.d.ts.map +1 -0
- package/dist/ui/primitives/button.js +35 -0
- package/dist/ui/primitives/dropdown-menu.d.ts +26 -0
- package/dist/ui/primitives/dropdown-menu.d.ts.map +1 -0
- package/dist/ui/primitives/dropdown-menu.js +53 -0
- package/dist/ui/primitives/popover.d.ts +8 -0
- package/dist/ui/primitives/popover.d.ts.map +1 -0
- package/dist/ui/primitives/popover.js +17 -0
- package/dist/ui/primitives/switch.d.ts +5 -0
- package/dist/ui/primitives/switch.d.ts.map +1 -0
- package/dist/ui/primitives/switch.js +8 -0
- package/dist/ui/primitives/tooltip.d.ts +8 -0
- package/dist/ui/primitives/tooltip.d.ts.map +1 -0
- package/dist/ui/primitives/tooltip.js +17 -0
- package/dist/ui/store/camera-pose-store.d.ts +17 -0
- package/dist/ui/store/camera-pose-store.d.ts.map +1 -0
- package/dist/ui/store/camera-pose-store.js +15 -0
- package/dist/ui/store/navigation-sync-pose-store.d.ts +26 -0
- package/dist/ui/store/navigation-sync-pose-store.d.ts.map +1 -0
- package/dist/ui/store/navigation-sync-pose-store.js +16 -0
- package/dist/ui/store/use-follow-pascal.d.ts +30 -0
- package/dist/ui/store/use-follow-pascal.d.ts.map +1 -0
- package/dist/ui/store/use-follow-pascal.js +28 -0
- package/dist/ui/theme.css +339 -0
- package/package.json +34 -7
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
import { area, getWallArcData, getWallBaseElevationForNodes, getWallCurveFrameAt, getWallFaceOffsets, getWallTop, resolveCeilingHeight, roomDrawnFloor, } from '@pascal-app/core';
|
|
2
|
+
import { ShapeUtils, Vector2 } from 'three';
|
|
3
|
+
const ON_FACE = 1e-3;
|
|
4
|
+
const FLOOR_LIFT = 0.005;
|
|
5
|
+
const CEILING_DROP = 0.02;
|
|
6
|
+
const CURVE_SAMPLES = 24;
|
|
7
|
+
const MIN_PIECE_AREA = 0.01;
|
|
8
|
+
/**
|
|
9
|
+
* Curved boundaries leave hairline slivers between the sampled room face and
|
|
10
|
+
* the sampled wall footprint; they would add stray face runs.
|
|
11
|
+
*/
|
|
12
|
+
function clearPieces(geometry) {
|
|
13
|
+
return geometry.clearPolygon.filter((piece) => area([piece]) >= MIN_PIECE_AREA);
|
|
14
|
+
}
|
|
15
|
+
export function resolveRoomAssemblyHeights(room, nodes) {
|
|
16
|
+
const sceneNodes = nodes;
|
|
17
|
+
const { levelId } = room.key;
|
|
18
|
+
const zone = nodes[room.zoneId];
|
|
19
|
+
let floorY = 0;
|
|
20
|
+
// A drawn slab floors the room even with its floor switched off.
|
|
21
|
+
if (zone?.type === 'zone' && (zone.hasFloor !== false || roomDrawnFloor(nodes, zone.id))) {
|
|
22
|
+
const level = nodes[levelId];
|
|
23
|
+
const plate = level?.type === 'level'
|
|
24
|
+
? level.children
|
|
25
|
+
.map((id) => nodes[id])
|
|
26
|
+
.find((node) => node?.type === 'slab' && node.zoneIds?.includes(room.zoneId))
|
|
27
|
+
: undefined;
|
|
28
|
+
const drawn = plate ? null : roomDrawnFloor(nodes, room.zoneId);
|
|
29
|
+
const linked = plate ?? (drawn ? nodes[drawn.slabId] : room.slabId ? nodes[room.slabId] : undefined);
|
|
30
|
+
floorY = (linked?.type === 'slab' ? linked.elevation : zone.floor?.elevation) ?? 0;
|
|
31
|
+
}
|
|
32
|
+
const wallTops = new Map();
|
|
33
|
+
for (const id of room.boundaryWallIds) {
|
|
34
|
+
const wall = nodes[id];
|
|
35
|
+
if (wall?.type !== 'wall')
|
|
36
|
+
continue;
|
|
37
|
+
const base = getWallBaseElevationForNodes(wall, sceneNodes);
|
|
38
|
+
wallTops.set(id, getWallTop(wall, levelId, sceneNodes, base, 0.5));
|
|
39
|
+
}
|
|
40
|
+
const ceilingNode = room.ceilingId ? nodes[room.ceilingId] : undefined;
|
|
41
|
+
const ceiling = ceilingNode?.type === 'ceiling'
|
|
42
|
+
? {
|
|
43
|
+
polygon: ceilingNode.polygon,
|
|
44
|
+
holes: ceilingNode.holes,
|
|
45
|
+
y: resolveCeilingHeight(ceilingNode, sceneNodes),
|
|
46
|
+
}
|
|
47
|
+
: null;
|
|
48
|
+
return { floorY, wallTops, ceiling };
|
|
49
|
+
}
|
|
50
|
+
function heightsKey({ floorY, wallTops, ceiling }) {
|
|
51
|
+
const rings = ceiling ? [ceiling.polygon, ...ceiling.holes].map((ring) => ring.join(' ')) : [];
|
|
52
|
+
return [floorY, ...wallTops, ceiling?.y, ...rings].join('|');
|
|
53
|
+
}
|
|
54
|
+
const cache = new WeakMap();
|
|
55
|
+
/**
|
|
56
|
+
* The room geometry object is reused for as long as the level topology
|
|
57
|
+
* revision stands, so it keys the cache; heights and the ceiling outline are
|
|
58
|
+
* compared by value. Hover changes and pointer moves only ever hit.
|
|
59
|
+
*/
|
|
60
|
+
export function getRoomAssembly(geometry, heights) {
|
|
61
|
+
const key = heightsKey(heights);
|
|
62
|
+
const cached = cache.get(geometry);
|
|
63
|
+
if (cached?.key === key)
|
|
64
|
+
return cached.assembly;
|
|
65
|
+
const assembly = buildRoomAssembly(geometry, heights);
|
|
66
|
+
cache.set(geometry, { key, assembly });
|
|
67
|
+
return assembly;
|
|
68
|
+
}
|
|
69
|
+
function faceTest(wall, face) {
|
|
70
|
+
const offset = getWallFaceOffsets(wall)[face];
|
|
71
|
+
const arc = getWallArcData(wall);
|
|
72
|
+
if (arc) {
|
|
73
|
+
const radius = arc.radius - arc.direction * offset;
|
|
74
|
+
return ([x, z]) => Math.abs(Math.hypot(x - arc.center.x, z - arc.center.y) - radius) < ON_FACE;
|
|
75
|
+
}
|
|
76
|
+
const dx = wall.end[0] - wall.start[0];
|
|
77
|
+
const dz = wall.end[1] - wall.start[1];
|
|
78
|
+
const length = Math.hypot(dx, dz);
|
|
79
|
+
if (length < 1e-9)
|
|
80
|
+
return () => false;
|
|
81
|
+
return ([x, z]) => Math.abs(((x - wall.start[0]) * -dz + (z - wall.start[1]) * dx) / length - offset) < ON_FACE;
|
|
82
|
+
}
|
|
83
|
+
function* ringEdges(ring) {
|
|
84
|
+
for (let i = 0; i < ring.length; i++)
|
|
85
|
+
yield [ring[i], ring[(i + 1) % ring.length]];
|
|
86
|
+
}
|
|
87
|
+
function overlap(p, q, a, b) {
|
|
88
|
+
const ex = b[0] - a[0];
|
|
89
|
+
const ez = b[1] - a[1];
|
|
90
|
+
const lengthSq = ex * ex + ez * ez;
|
|
91
|
+
if (lengthSq < 1e-12)
|
|
92
|
+
return null;
|
|
93
|
+
const length = Math.sqrt(lengthSq);
|
|
94
|
+
const offLine = ([x, z]) => Math.abs((x - a[0]) * ez - (z - a[1]) * ex) / length;
|
|
95
|
+
if (offLine(p) > ON_FACE || offLine(q) > ON_FACE)
|
|
96
|
+
return null;
|
|
97
|
+
const up = ((p[0] - a[0]) * ex + (p[1] - a[1]) * ez) / lengthSq;
|
|
98
|
+
const uq = ((q[0] - a[0]) * ex + (q[1] - a[1]) * ez) / lengthSq;
|
|
99
|
+
const lo = Math.max(0, Math.min(up, uq));
|
|
100
|
+
const hi = Math.min(1, Math.max(up, uq));
|
|
101
|
+
if ((hi - lo) * length < 1e-4)
|
|
102
|
+
return null;
|
|
103
|
+
return [
|
|
104
|
+
[a[0] + ex * lo, a[1] + ez * lo],
|
|
105
|
+
[a[0] + ex * hi, a[1] + ez * hi],
|
|
106
|
+
];
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* The room-facing part of each boundary wall face. The clear polygon's
|
|
110
|
+
* boundary is exactly the mitered faces the room sees, clipped by T-stems
|
|
111
|
+
* and separators, so its edges are matched against each wall's footprint
|
|
112
|
+
* face edges; that also keeps collinear walls apart.
|
|
113
|
+
*/
|
|
114
|
+
export function roomWallFaces(geometry) {
|
|
115
|
+
const rings = clearPieces(geometry).flatMap(({ outer, holes }) => [outer, ...holes]);
|
|
116
|
+
const faces = [];
|
|
117
|
+
const seen = new Set();
|
|
118
|
+
for (const span of geometry.spans) {
|
|
119
|
+
if (span.kind !== 'wall')
|
|
120
|
+
continue;
|
|
121
|
+
const wallId = span.boundaryId;
|
|
122
|
+
const wall = geometry.context.walls.get(wallId);
|
|
123
|
+
if (!wall)
|
|
124
|
+
continue;
|
|
125
|
+
if (!rings.length) {
|
|
126
|
+
faces.push(...sampledFace(wall, span.face, span.t0, span.t1));
|
|
127
|
+
continue;
|
|
128
|
+
}
|
|
129
|
+
const key = `${wallId}:${span.face}`;
|
|
130
|
+
const footprint = geometry.context.wallFootprints.get(wallId);
|
|
131
|
+
if (seen.has(key) || !footprint)
|
|
132
|
+
continue;
|
|
133
|
+
seen.add(key);
|
|
134
|
+
const onFace = faceTest(wall, span.face);
|
|
135
|
+
const faceEdges = [...ringEdges(footprint)].filter(([a, b]) => onFace(a) && onFace(b));
|
|
136
|
+
for (const ring of rings) {
|
|
137
|
+
for (const [p, q] of ringEdges(ring)) {
|
|
138
|
+
if (!(onFace(p) && onFace(q)))
|
|
139
|
+
continue;
|
|
140
|
+
for (const [a, b] of faceEdges) {
|
|
141
|
+
const portion = overlap(p, q, a, b);
|
|
142
|
+
if (portion)
|
|
143
|
+
faces.push({ wallId, face: span.face, from: portion[0], to: portion[1] });
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
return faces;
|
|
149
|
+
}
|
|
150
|
+
// Only used when the clear polygon could not be computed for the room.
|
|
151
|
+
function sampledFace(wall, face, t0, t1) {
|
|
152
|
+
const offset = getWallFaceOffsets(wall)[face];
|
|
153
|
+
const steps = getWallArcData(wall) ? CURVE_SAMPLES : 1;
|
|
154
|
+
const points = Array.from({ length: steps + 1 }, (_, i) => {
|
|
155
|
+
const { point, normal } = getWallCurveFrameAt(wall, t0 + ((t1 - t0) * i) / steps);
|
|
156
|
+
return [point.x + normal.x * offset, point.y + normal.y * offset];
|
|
157
|
+
});
|
|
158
|
+
return points
|
|
159
|
+
.slice(1)
|
|
160
|
+
.map((to, i) => ({ wallId: wall.id, face, from: points[i], to }));
|
|
161
|
+
}
|
|
162
|
+
function pushTriangles(target, outer, holes, y) {
|
|
163
|
+
const contour = outer.map(([x, z]) => new Vector2(x, z));
|
|
164
|
+
const holePoints = holes.map((ring) => ring.map(([x, z]) => new Vector2(x, z)));
|
|
165
|
+
const points = [...contour, ...holePoints.flat()];
|
|
166
|
+
for (const triangle of ShapeUtils.triangulateShape(contour, holePoints)) {
|
|
167
|
+
for (const index of triangle)
|
|
168
|
+
target.push(points[index].x, y, points[index].y);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
function pushRing(target, ring, y) {
|
|
172
|
+
for (const [[ax, az], [bx, bz]] of ringEdges(ring))
|
|
173
|
+
target.push(ax, y, az, bx, y, bz);
|
|
174
|
+
}
|
|
175
|
+
export function buildRoomAssembly(geometry, heights) {
|
|
176
|
+
const floor = [];
|
|
177
|
+
const surfaces = [];
|
|
178
|
+
const outline = [];
|
|
179
|
+
const floorY = heights.floorY + FLOOR_LIFT;
|
|
180
|
+
for (const { outer, holes } of clearPieces(geometry)) {
|
|
181
|
+
pushTriangles(floor, outer, holes, floorY);
|
|
182
|
+
for (const ring of [outer, ...holes])
|
|
183
|
+
pushRing(outline, ring, floorY);
|
|
184
|
+
}
|
|
185
|
+
const faces = roomWallFaces(geometry);
|
|
186
|
+
const ends = new Map();
|
|
187
|
+
for (const { wallId, from, to } of faces) {
|
|
188
|
+
const top = heights.wallTops.get(wallId);
|
|
189
|
+
if (top === undefined || top <= floorY)
|
|
190
|
+
continue;
|
|
191
|
+
const [ax, az] = from;
|
|
192
|
+
const [bx, bz] = to;
|
|
193
|
+
surfaces.push(ax, floorY, az, bx, floorY, bz, bx, top, bz);
|
|
194
|
+
surfaces.push(ax, floorY, az, bx, top, bz, ax, top, az);
|
|
195
|
+
outline.push(ax, top, az, bx, top, bz);
|
|
196
|
+
for (const point of [from, to]) {
|
|
197
|
+
const key = `${wallId}:${point[0].toFixed(4)},${point[1].toFixed(4)}`;
|
|
198
|
+
const end = ends.get(key);
|
|
199
|
+
if (end)
|
|
200
|
+
end.count++;
|
|
201
|
+
else
|
|
202
|
+
ends.set(key, { point, top, count: 1 });
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
// Verticals only where a face run starts or stops, not between curve chords.
|
|
206
|
+
for (const { point, top, count } of ends.values()) {
|
|
207
|
+
if (count === 1)
|
|
208
|
+
outline.push(point[0], floorY, point[1], point[0], top, point[1]);
|
|
209
|
+
}
|
|
210
|
+
if (heights.ceiling) {
|
|
211
|
+
const { polygon, holes, y } = heights.ceiling;
|
|
212
|
+
pushTriangles(surfaces, polygon, holes, y - CEILING_DROP);
|
|
213
|
+
for (const ring of [polygon, ...holes])
|
|
214
|
+
pushRing(outline, ring, y - CEILING_DROP);
|
|
215
|
+
}
|
|
216
|
+
return {
|
|
217
|
+
floor: new Float32Array(floor),
|
|
218
|
+
surfaces: new Float32Array(surfaces),
|
|
219
|
+
outline: new Float32Array(outline),
|
|
220
|
+
faces,
|
|
221
|
+
};
|
|
222
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { MessageDescriptor } from '@pascal-app/core';
|
|
2
|
+
/** Anything that translates a descriptor: a `PascalI18n`, or a stand-in in tests. */
|
|
3
|
+
export type DescriptorTranslator = {
|
|
4
|
+
_(descriptor: MessageDescriptor): string;
|
|
5
|
+
};
|
|
6
|
+
/**
|
|
7
|
+
* The room-name catalog in the UI language. The catalog stays English (it is
|
|
8
|
+
* matched, numbered and stored as data); the combobox and room labels show these.
|
|
9
|
+
* The editor's `room-name-catalog.test.ts` fails when a catalog name has no entry here.
|
|
10
|
+
*/
|
|
11
|
+
export declare const ROOM_NAME_MESSAGES: Record<string, MessageDescriptor>;
|
|
12
|
+
/**
|
|
13
|
+
* A room name in the UI language. Catalog names stay English in the scene
|
|
14
|
+
* (numbering, MCP and exports read them); a catalog name with the number the
|
|
15
|
+
* picker adds shows translated with that number ("Bedroom 2" → "Chambre 2").
|
|
16
|
+
* Anything else the user typed shows as written.
|
|
17
|
+
*/
|
|
18
|
+
export declare function displayRoomName(name: string, i18n: DescriptorTranslator): string;
|
|
19
|
+
/**
|
|
20
|
+
* What an edit of a room's name field stores. The field shows the room's own
|
|
21
|
+
* catalog name translated ("Lounge 2" as "Salon 2"); when the edit only
|
|
22
|
+
* changes, adds or removes that name's number ("Salon 3"), it stores the
|
|
23
|
+
* English name with the new number ("Lounge 3"), as editing it in English
|
|
24
|
+
* would. Any other text, an exact translation of a different name included, is
|
|
25
|
+
* stored exactly as typed.
|
|
26
|
+
*/
|
|
27
|
+
export declare function editedRoomName(stored: string, text: string, i18n: DescriptorTranslator): string;
|
|
28
|
+
//# sourceMappingURL=room-name-messages.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"room-name-messages.d.ts","sourceRoot":"","sources":["../../../src/ui/lib/room-name-messages.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAA;AAEzD,qFAAqF;AACrF,MAAM,MAAM,oBAAoB,GAAG;IAAE,CAAC,CAAC,UAAU,EAAE,iBAAiB,GAAG,MAAM,CAAA;CAAE,CAAA;AAE/E;;;;GAIG;AACH,eAAO,MAAM,kBAAkB,EAAE,MAAM,CAAC,MAAM,EAAE,iBAAiB,CAgEhE,CAAA;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,oBAAoB,GAAG,MAAM,CAIhF;AAED;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,oBAAoB,GAAG,MAAM,CAM/F"}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The room-name catalog in the UI language. The catalog stays English (it is
|
|
3
|
+
* matched, numbered and stored as data); the combobox and room labels show these.
|
|
4
|
+
* The editor's `room-name-catalog.test.ts` fails when a catalog name has no entry here.
|
|
5
|
+
*/
|
|
6
|
+
export const ROOM_NAME_MESSAGES = {
|
|
7
|
+
'Living room': /* i18n */ { id: 'editor.roomName.livingRoom', message: 'Living room' },
|
|
8
|
+
'Family room': /* i18n */ { id: 'editor.roomName.familyRoom', message: 'Family room' },
|
|
9
|
+
'Dining room': /* i18n */ { id: 'editor.roomName.diningRoom', message: 'Dining room' },
|
|
10
|
+
Kitchen: /* i18n */ { id: 'editor.roomName.kitchen', message: 'Kitchen' },
|
|
11
|
+
Kitchenette: /* i18n */ { id: 'editor.roomName.kitchenette', message: 'Kitchenette' },
|
|
12
|
+
Pantry: /* i18n */ { id: 'editor.roomName.pantry', message: 'Pantry' },
|
|
13
|
+
Lounge: /* i18n */ { id: 'editor.roomName.lounge', message: 'Lounge' },
|
|
14
|
+
Den: /* i18n */ { id: 'editor.roomName.den', message: 'Den' },
|
|
15
|
+
Library: /* i18n */ { id: 'editor.roomName.library', message: 'Library' },
|
|
16
|
+
Playroom: /* i18n */ { id: 'editor.roomName.playroom', message: 'Playroom' },
|
|
17
|
+
'Home cinema': /* i18n */ { id: 'editor.roomName.homeCinema', message: 'Home cinema' },
|
|
18
|
+
'Games room': /* i18n */ { id: 'editor.roomName.gamesRoom', message: 'Games room' },
|
|
19
|
+
Sunroom: /* i18n */ { id: 'editor.roomName.sunroom', message: 'Sunroom' },
|
|
20
|
+
Bedroom: /* i18n */ { id: 'editor.roomName.bedroom', message: 'Bedroom' },
|
|
21
|
+
'Primary bedroom': /* i18n */ {
|
|
22
|
+
id: 'editor.roomName.primaryBedroom',
|
|
23
|
+
message: 'Primary bedroom',
|
|
24
|
+
},
|
|
25
|
+
'Guest room': /* i18n */ { id: 'editor.roomName.guestRoom', message: 'Guest room' },
|
|
26
|
+
"Kids' room": /* i18n */ { id: 'editor.roomName.kidsRoom', message: "Kids' room" },
|
|
27
|
+
Nursery: /* i18n */ { id: 'editor.roomName.nursery', message: 'Nursery' },
|
|
28
|
+
'Dressing room': /* i18n */ { id: 'editor.roomName.dressingRoom', message: 'Dressing room' },
|
|
29
|
+
'Walk-in closet': /* i18n */ { id: 'editor.roomName.walkInCloset', message: 'Walk-in closet' },
|
|
30
|
+
Bathroom: /* i18n */ { id: 'editor.roomName.bathroom', message: 'Bathroom' },
|
|
31
|
+
'En-suite': /* i18n */ { id: 'editor.roomName.enSuite', message: 'En-suite' },
|
|
32
|
+
'Shower room': /* i18n */ { id: 'editor.roomName.showerRoom', message: 'Shower room' },
|
|
33
|
+
Toilet: /* i18n */ { id: 'editor.roomName.toilet', message: 'Toilet' },
|
|
34
|
+
'Powder room': /* i18n */ { id: 'editor.roomName.powderRoom', message: 'Powder room' },
|
|
35
|
+
Office: /* i18n */ { id: 'editor.roomName.office', message: 'Office' },
|
|
36
|
+
Study: /* i18n */ { id: 'editor.roomName.study', message: 'Study' },
|
|
37
|
+
Studio: /* i18n */ { id: 'editor.roomName.studio', message: 'Studio' },
|
|
38
|
+
Workshop: /* i18n */ { id: 'editor.roomName.workshop', message: 'Workshop' },
|
|
39
|
+
Gym: /* i18n */ { id: 'editor.roomName.gym', message: 'Gym' },
|
|
40
|
+
Entrance: /* i18n */ { id: 'editor.roomName.entrance', message: 'Entrance' },
|
|
41
|
+
Hallway: /* i18n */ { id: 'editor.roomName.hallway', message: 'Hallway' },
|
|
42
|
+
Corridor: /* i18n */ { id: 'editor.roomName.corridor', message: 'Corridor' },
|
|
43
|
+
Landing: /* i18n */ { id: 'editor.roomName.landing', message: 'Landing' },
|
|
44
|
+
Stairwell: /* i18n */ { id: 'editor.roomName.stairwell', message: 'Stairwell' },
|
|
45
|
+
Mudroom: /* i18n */ { id: 'editor.roomName.mudroom', message: 'Mudroom' },
|
|
46
|
+
Laundry: /* i18n */ { id: 'editor.roomName.laundry', message: 'Laundry' },
|
|
47
|
+
'Utility room': /* i18n */ { id: 'editor.roomName.utilityRoom', message: 'Utility room' },
|
|
48
|
+
Storage: /* i18n */ { id: 'editor.roomName.storage', message: 'Storage' },
|
|
49
|
+
Closet: /* i18n */ { id: 'editor.roomName.closet', message: 'Closet' },
|
|
50
|
+
'Boiler room': /* i18n */ { id: 'editor.roomName.boilerRoom', message: 'Boiler room' },
|
|
51
|
+
Cellar: /* i18n */ { id: 'editor.roomName.cellar', message: 'Cellar' },
|
|
52
|
+
Basement: /* i18n */ { id: 'editor.roomName.basement', message: 'Basement' },
|
|
53
|
+
Attic: /* i18n */ { id: 'editor.roomName.attic', message: 'Attic' },
|
|
54
|
+
Garage: /* i18n */ { id: 'editor.roomName.garage', message: 'Garage' },
|
|
55
|
+
Garden: /* i18n */ { id: 'editor.roomName.garden', message: 'Garden' },
|
|
56
|
+
Patio: /* i18n */ { id: 'editor.roomName.patio', message: 'Patio' },
|
|
57
|
+
Terrace: /* i18n */ { id: 'editor.roomName.terrace', message: 'Terrace' },
|
|
58
|
+
Balcony: /* i18n */ { id: 'editor.roomName.balcony', message: 'Balcony' },
|
|
59
|
+
Porch: /* i18n */ { id: 'editor.roomName.porch', message: 'Porch' },
|
|
60
|
+
Veranda: /* i18n */ { id: 'editor.roomName.veranda', message: 'Veranda' },
|
|
61
|
+
Deck: /* i18n */ { id: 'editor.roomName.deck', message: 'Deck' },
|
|
62
|
+
Courtyard: /* i18n */ { id: 'editor.roomName.courtyard', message: 'Courtyard' },
|
|
63
|
+
'Pool area': /* i18n */ { id: 'editor.roomName.poolArea', message: 'Pool area' },
|
|
64
|
+
Carport: /* i18n */ { id: 'editor.roomName.carport', message: 'Carport' },
|
|
65
|
+
'Garden shed': /* i18n */ { id: 'editor.roomName.gardenShed', message: 'Garden shed' },
|
|
66
|
+
Mezzanine: /* i18n */ { id: 'editor.roomName.mezzanine', message: 'Mezzanine' },
|
|
67
|
+
Loft: /* i18n */ { id: 'editor.roomName.loft', message: 'Loft' },
|
|
68
|
+
'Reading nook': /* i18n */ { id: 'editor.roomName.readingNook', message: 'Reading nook' },
|
|
69
|
+
Gallery: /* i18n */ { id: 'editor.roomName.gallery', message: 'Gallery' },
|
|
70
|
+
};
|
|
71
|
+
/**
|
|
72
|
+
* A room name in the UI language. Catalog names stay English in the scene
|
|
73
|
+
* (numbering, MCP and exports read them); a catalog name with the number the
|
|
74
|
+
* picker adds shows translated with that number ("Bedroom 2" → "Chambre 2").
|
|
75
|
+
* Anything else the user typed shows as written.
|
|
76
|
+
*/
|
|
77
|
+
export function displayRoomName(name, i18n) {
|
|
78
|
+
const { lead, base, number, trail } = roomNameParts(name);
|
|
79
|
+
const label = catalogLabel(base, i18n);
|
|
80
|
+
return label === undefined ? name : `${lead}${label}${number}${trail}`;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* What an edit of a room's name field stores. The field shows the room's own
|
|
84
|
+
* catalog name translated ("Lounge 2" as "Salon 2"); when the edit only
|
|
85
|
+
* changes, adds or removes that name's number ("Salon 3"), it stores the
|
|
86
|
+
* English name with the new number ("Lounge 3"), as editing it in English
|
|
87
|
+
* would. Any other text, an exact translation of a different name included, is
|
|
88
|
+
* stored exactly as typed.
|
|
89
|
+
*/
|
|
90
|
+
export function editedRoomName(stored, text, i18n) {
|
|
91
|
+
const own = roomNameParts(stored).base;
|
|
92
|
+
const label = catalogLabel(own, i18n);
|
|
93
|
+
const edited = roomNameParts(text);
|
|
94
|
+
if (label === undefined || edited.base !== label)
|
|
95
|
+
return text;
|
|
96
|
+
return `${edited.lead}${own}${edited.number}${edited.trail}`;
|
|
97
|
+
}
|
|
98
|
+
function roomNameParts(name) {
|
|
99
|
+
const match = /^(\s*)(.*?)(\s+\d+)?(\s*)$/.exec(name);
|
|
100
|
+
return {
|
|
101
|
+
lead: match?.[1] ?? '',
|
|
102
|
+
base: match?.[2] ?? '',
|
|
103
|
+
number: match?.[3] ?? '',
|
|
104
|
+
trail: match?.[4] ?? '',
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
function catalogLabel(english, i18n) {
|
|
108
|
+
// Own keys only: a room named "constructor" or "__proto__" is free text.
|
|
109
|
+
if (!(english && Object.hasOwn(ROOM_NAME_MESSAGES, english)))
|
|
110
|
+
return undefined;
|
|
111
|
+
return i18n._(ROOM_NAME_MESSAGES[english]);
|
|
112
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { type AnyNode, type BoundarySpan, createRoomTopologyIndex, type MultiPolygon, roomClearPolygon, type TopologyRoom, type ZoneNode } from '@pascal-app/core';
|
|
2
|
+
import type { SelectionModifierKeys } from './selection-modifiers';
|
|
3
|
+
export type RoomKey = {
|
|
4
|
+
levelId: string;
|
|
5
|
+
zoneId: string;
|
|
6
|
+
};
|
|
7
|
+
export declare function sameRoom(a: RoomKey | null, b: RoomKey | null): boolean;
|
|
8
|
+
export declare function shouldSelectRoom(selected: RoomKey | null, hit: RoomKey | null, modifiers: SelectionModifierKeys): boolean;
|
|
9
|
+
export type RoomSelectionGeometry = TopologyRoom & {
|
|
10
|
+
key: RoomKey;
|
|
11
|
+
boundaryWallIds: string[];
|
|
12
|
+
clearPolygon: ReturnType<typeof roomClearPolygon>;
|
|
13
|
+
area: number;
|
|
14
|
+
hitPolygon: MultiPolygon;
|
|
15
|
+
/** A stacked open-below room (`floor.support: 'open'`) inside its host room. */
|
|
16
|
+
mezzanine: {
|
|
17
|
+
hostZoneId: string;
|
|
18
|
+
} | null;
|
|
19
|
+
};
|
|
20
|
+
export type RoomSelectionRecord = RoomSelectionGeometry & {
|
|
21
|
+
geometry: RoomSelectionGeometry;
|
|
22
|
+
name: string;
|
|
23
|
+
zoneId: string;
|
|
24
|
+
slabId: string | null;
|
|
25
|
+
slabName: string | null;
|
|
26
|
+
ceilingId: string | null;
|
|
27
|
+
ceilingName: string | null;
|
|
28
|
+
};
|
|
29
|
+
type Nodes = Record<string, AnyNode>;
|
|
30
|
+
export declare function isMezzanineZone(node: AnyNode | undefined): node is ZoneNode;
|
|
31
|
+
/**
|
|
32
|
+
* A zone that bounds no room (a drawn area), outlined the way a room is: its
|
|
33
|
+
* polygon as the floor, no walls of its own.
|
|
34
|
+
*/
|
|
35
|
+
export declare function describeZoneOutline(levelId: string, zone: ZoneNode): RoomSelectionRecord;
|
|
36
|
+
type RoomHitIndex = Pick<ReturnType<typeof createRoomTopologyIndex>, 'roomAtPoint' | 'roomForWallHit' | 'spansForWall'> & {
|
|
37
|
+
/** The selectable room a zone is (a mezzanine's own plate or ceiling points at it). */
|
|
38
|
+
roomForZone?: (levelId: string, zoneId: string) => TopologyRoom | null;
|
|
39
|
+
};
|
|
40
|
+
export declare function resolveRoomHit<T extends RoomHitIndex>(index: T, levelId: string, node: AnyNode | null, point: [number, number], view?: '2d' | '3d'): ReturnType<T['roomAtPoint']>;
|
|
41
|
+
export declare class RoomSelectionIndex {
|
|
42
|
+
readonly levelId: string;
|
|
43
|
+
readonly topology: import("@pascal-app/core").RoomTopologyIndex<import("@pascal-app/core").ExtractedRoom>;
|
|
44
|
+
private nodes;
|
|
45
|
+
private records;
|
|
46
|
+
private geometry;
|
|
47
|
+
private candidates;
|
|
48
|
+
private revision;
|
|
49
|
+
private readonly roomsById;
|
|
50
|
+
roomAtPoint(_levelId: string, point: [number, number]): RoomSelectionGeometry | null;
|
|
51
|
+
roomForZone(_levelId: string, zoneId: string): RoomSelectionGeometry | null;
|
|
52
|
+
roomForWallHit(levelId: string, wallId: string, face: 'a' | 'b', t: number): RoomSelectionGeometry | null;
|
|
53
|
+
spansForWall(levelId: string, wallId: string): readonly BoundarySpan[];
|
|
54
|
+
constructor(levelId: string);
|
|
55
|
+
update(nodes: Nodes): RoomSelectionRecord[];
|
|
56
|
+
}
|
|
57
|
+
export {};
|
|
58
|
+
//# sourceMappingURL=room-selection.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"room-selection.d.ts","sourceRoot":"","sources":["../../../src/ui/lib/room-selection.ts"],"names":[],"mappings":"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"}
|