@kerros/viewer 0.0.0-stage → 0.1.0-rc.2
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/LICENSE +21 -0
- package/README.md +31 -2
- package/dist/adapters/basemap.js +11 -0
- package/dist/adapters/basemap.js.map +1 -0
- package/dist/adapters/persistence.js +121 -0
- package/dist/adapters/persistence.js.map +1 -0
- package/dist/adapters/status.js +18 -0
- package/dist/adapters/status.js.map +1 -0
- package/dist/components/ElevatorPanel.js +120 -0
- package/dist/components/ElevatorPanel.js.map +1 -0
- package/dist/components/Icons.js +57 -0
- package/dist/components/Icons.js.map +1 -0
- package/dist/components/Inspector.js +1184 -0
- package/dist/components/Inspector.js.map +1 -0
- package/dist/components/NavigatePanel.js +301 -0
- package/dist/components/NavigatePanel.js.map +1 -0
- package/dist/components/NavigationGraph.js +234 -0
- package/dist/components/NavigationGraph.js.map +1 -0
- package/dist/components/StructureExplorer.js +510 -0
- package/dist/components/StructureExplorer.js.map +1 -0
- package/dist/components/StructureView.js +286 -0
- package/dist/components/StructureView.js.map +1 -0
- package/dist/components/controls.js +170 -0
- package/dist/components/controls.js.map +1 -0
- package/dist/components/graphLayout.js +27 -0
- package/dist/components/graphLayout.js.map +1 -0
- package/dist/host.js +169 -0
- package/dist/host.js.map +1 -0
- package/dist/i18n.js +88 -0
- package/dist/i18n.js.map +1 -0
- package/dist/index.js +171 -0
- package/dist/index.js.map +1 -0
- package/dist/map/CabinMaterials.js +81 -0
- package/dist/map/CabinMaterials.js.map +1 -0
- package/dist/map/CabinMirror.js +43 -0
- package/dist/map/CabinMirror.js.map +1 -0
- package/dist/map/Doors.js +80 -0
- package/dist/map/Doors.js.map +1 -0
- package/dist/map/ElevatorCabin.js +93 -0
- package/dist/map/ElevatorCabin.js.map +1 -0
- package/dist/map/FixtureLights.js +117 -0
- package/dist/map/FixtureLights.js.map +1 -0
- package/dist/map/MapCanvas.js +2161 -0
- package/dist/map/MapCanvas.js.map +1 -0
- package/dist/map/Passenger.js +69 -0
- package/dist/map/Passenger.js.map +1 -0
- package/dist/map/SceneLayer.js +1534 -0
- package/dist/map/SceneLayer.js.map +1 -0
- package/dist/map/UndergroundContext.js +153 -0
- package/dist/map/UndergroundContext.js.map +1 -0
- package/dist/map/ambience.js +194 -0
- package/dist/map/ambience.js.map +1 -0
- package/dist/map/architecture.js +305 -0
- package/dist/map/architecture.js.map +1 -0
- package/dist/map/bathMusic.js +92 -0
- package/dist/map/bathMusic.js.map +1 -0
- package/dist/map/cameraAim.js +33 -0
- package/dist/map/cameraAim.js.map +1 -0
- package/dist/map/elevators.js +56 -0
- package/dist/map/elevators.js.map +1 -0
- package/dist/map/excavation.js +52 -0
- package/dist/map/excavation.js.map +1 -0
- package/dist/map/exteriors.js +25 -0
- package/dist/map/exteriors.js.map +1 -0
- package/dist/map/features.js +218 -0
- package/dist/map/features.js.map +1 -0
- package/dist/map/fences.js +29 -0
- package/dist/map/fences.js.map +1 -0
- package/dist/map/journey.js +112 -0
- package/dist/map/journey.js.map +1 -0
- package/dist/map/levels.js +6 -0
- package/dist/map/levels.js.map +1 -0
- package/dist/map/lighting.js +142 -0
- package/dist/map/lighting.js.map +1 -0
- package/dist/map/loadBasemap.js +26 -0
- package/dist/map/loadBasemap.js.map +1 -0
- package/dist/map/materials.js +183 -0
- package/dist/map/materials.js.map +1 -0
- package/dist/map/poolLighting.js +39 -0
- package/dist/map/poolLighting.js.map +1 -0
- package/dist/map/projection.js +24 -0
- package/dist/map/projection.js.map +1 -0
- package/dist/map/rampGeometry.js +38 -0
- package/dist/map/rampGeometry.js.map +1 -0
- package/dist/map/route.js +107 -0
- package/dist/map/route.js.map +1 -0
- package/dist/map/stairSurfaces.js +115 -0
- package/dist/map/stairSurfaces.js.map +1 -0
- package/dist/map/surfaces.js +136 -0
- package/dist/map/surfaces.js.map +1 -0
- package/dist/map/textures.js +95 -0
- package/dist/map/textures.js.map +1 -0
- package/dist/map/underground.js +34 -0
- package/dist/map/underground.js.map +1 -0
- package/dist/map/walk.js +433 -0
- package/dist/map/walk.js.map +1 -0
- package/dist/map/walkContext.js +46 -0
- package/dist/map/walkContext.js.map +1 -0
- package/dist/map/walkDimensions.js +7 -0
- package/dist/map/walkDimensions.js.map +1 -0
- package/dist/map/walkJourney.js +85 -0
- package/dist/map/walkJourney.js.map +1 -0
- package/dist/map/walkSurfaces.js +106 -0
- package/dist/map/walkSurfaces.js.map +1 -0
- package/dist/map/wallJoins.js +70 -0
- package/dist/map/wallJoins.js.map +1 -0
- package/dist/map/water.js +274 -0
- package/dist/map/water.js.map +1 -0
- package/dist/model/authoring.js +80 -0
- package/dist/model/authoring.js.map +1 -0
- package/dist/model/boundaries.js +548 -0
- package/dist/model/boundaries.js.map +1 -0
- package/dist/model/coverage.js +30 -0
- package/dist/model/coverage.js.map +1 -0
- package/dist/model/document.js +52 -0
- package/dist/model/document.js.map +1 -0
- package/dist/model/doors.js +47 -0
- package/dist/model/doors.js.map +1 -0
- package/dist/model/factory.js +56 -0
- package/dist/model/factory.js.map +1 -0
- package/dist/model/geometry.js +394 -0
- package/dist/model/geometry.js.map +1 -0
- package/dist/model/inference.js +182 -0
- package/dist/model/inference.js.map +1 -0
- package/dist/model/materials.js +11 -0
- package/dist/model/materials.js.map +1 -0
- package/dist/model/mutations.js +157 -0
- package/dist/model/mutations.js.map +1 -0
- package/dist/model/navigation.js +275 -0
- package/dist/model/navigation.js.map +1 -0
- package/dist/model/ontology.js +109 -0
- package/dist/model/ontology.js.map +1 -0
- package/dist/model/passages.js +5 -0
- package/dist/model/passages.js.map +1 -0
- package/dist/model/portals.js +42 -0
- package/dist/model/portals.js.map +1 -0
- package/dist/model/precision.js +11 -0
- package/dist/model/precision.js.map +1 -0
- package/dist/model/project.js +17 -0
- package/dist/model/project.js.map +1 -0
- package/dist/model/ramps.js +10 -0
- package/dist/model/ramps.js.map +1 -0
- package/dist/model/roomNavigation.js +87 -0
- package/dist/model/roomNavigation.js.map +1 -0
- package/dist/model/routeClearance.js +72 -0
- package/dist/model/routeClearance.js.map +1 -0
- package/dist/model/spaces.js +104 -0
- package/dist/model/spaces.js.map +1 -0
- package/dist/model/stairGeometry.js +40 -0
- package/dist/model/stairGeometry.js.map +1 -0
- package/dist/model/stairTraversal.js +48 -0
- package/dist/model/stairTraversal.js.map +1 -0
- package/dist/model/topology.js +63 -0
- package/dist/model/topology.js.map +1 -0
- package/dist/model/types.js +35 -0
- package/dist/model/types.js.map +1 -0
- package/dist/model/validate.js +240 -0
- package/dist/model/validate.js.map +1 -0
- package/dist/model/vertical.js +129 -0
- package/dist/model/vertical.js.map +1 -0
- package/dist/model/walls.js +71 -0
- package/dist/model/walls.js.map +1 -0
- package/dist/styles.css +4931 -0
- package/dist/theme/index.js +34 -0
- package/dist/theme/index.js.map +1 -0
- package/dist/types/adapters/basemap.d.ts +2 -0
- package/dist/types/adapters/persistence.d.ts +29 -0
- package/dist/types/adapters/status.d.ts +4 -0
- package/dist/types/components/ElevatorPanel.d.ts +18 -0
- package/dist/types/components/Icons.d.ts +8 -0
- package/dist/types/components/Inspector.d.ts +38 -0
- package/dist/types/components/NavigatePanel.d.ts +27 -0
- package/dist/types/components/NavigationGraph.d.ts +10 -0
- package/dist/types/components/StructureExplorer.d.ts +8 -0
- package/dist/types/components/StructureView.d.ts +22 -0
- package/dist/types/components/controls.d.ts +52 -0
- package/dist/types/components/graphLayout.d.ts +9 -0
- package/dist/types/i18n.d.ts +85 -0
- package/dist/types/import/analysisPreview.d.ts +27 -0
- package/dist/types/import/brief.d.ts +22 -0
- package/dist/types/import/checkpoint.d.ts +49 -0
- package/dist/types/import/instructions.d.ts +7 -0
- package/dist/types/import/usage.d.ts +10 -0
- package/dist/types/map/CabinMaterials.d.ts +18 -0
- package/dist/types/map/CabinMirror.d.ts +13 -0
- package/dist/types/map/Doors.d.ts +11 -0
- package/dist/types/map/ElevatorCabin.d.ts +20 -0
- package/dist/types/map/FixtureLights.d.ts +35 -0
- package/dist/types/map/MapCanvas.d.ts +87 -0
- package/dist/types/map/Passenger.d.ts +18 -0
- package/dist/types/map/SceneLayer.d.ts +306 -0
- package/dist/types/map/UndergroundContext.d.ts +18 -0
- package/dist/types/map/ambience.d.ts +29 -0
- package/dist/types/map/architecture.d.ts +8 -0
- package/dist/types/map/bathMusic.d.ts +14 -0
- package/dist/types/map/cameraAim.d.ts +20 -0
- package/dist/types/map/elevators.d.ts +16 -0
- package/dist/types/map/excavation.d.ts +9 -0
- package/dist/types/map/exteriors.d.ts +3 -0
- package/dist/types/map/features.d.ts +33 -0
- package/dist/types/map/fences.d.ts +4 -0
- package/dist/types/map/journey.d.ts +36 -0
- package/dist/types/map/levels.d.ts +4 -0
- package/dist/types/map/lighting.d.ts +103 -0
- package/dist/types/map/loadBasemap.d.ts +4 -0
- package/dist/types/map/materials.d.ts +38 -0
- package/dist/types/map/poolLighting.d.ts +11 -0
- package/dist/types/map/projection.d.ts +9 -0
- package/dist/types/map/rampGeometry.d.ts +8 -0
- package/dist/types/map/route.d.ts +59 -0
- package/dist/types/map/stairSurfaces.d.ts +29 -0
- package/dist/types/map/surfaces.d.ts +36 -0
- package/dist/types/map/textures.d.ts +8 -0
- package/dist/types/map/underground.d.ts +30 -0
- package/dist/types/map/walk.d.ts +232 -0
- package/dist/types/map/walkContext.d.ts +11 -0
- package/dist/types/map/walkDimensions.d.ts +5 -0
- package/dist/types/map/walkJourney.d.ts +33 -0
- package/dist/types/map/walkSurfaces.d.ts +27 -0
- package/dist/types/map/wallJoins.d.ts +6 -0
- package/dist/types/map/water.d.ts +12 -0
- package/dist/types/model/authoring.d.ts +38 -0
- package/dist/types/model/boundaries.d.ts +41 -0
- package/dist/types/model/coverage.d.ts +8 -0
- package/dist/types/model/document.d.ts +9 -0
- package/dist/types/model/doors.d.ts +19 -0
- package/dist/types/model/factory.d.ts +5 -0
- package/dist/types/model/geometry.d.ts +99 -0
- package/dist/types/model/host.d.ts +154 -0
- package/dist/types/model/inference.d.ts +46 -0
- package/dist/types/model/live.d.ts +60 -0
- package/dist/types/model/materials.d.ts +28 -0
- package/dist/types/model/mutations.d.ts +178 -0
- package/dist/types/model/navigation.d.ts +70 -0
- package/dist/types/model/ontology.d.ts +43 -0
- package/dist/types/model/passages.d.ts +2 -0
- package/dist/types/model/portals.d.ts +9 -0
- package/dist/types/model/precision.d.ts +11 -0
- package/dist/types/model/project.d.ts +8 -0
- package/dist/types/model/ramps.d.ts +7 -0
- package/dist/types/model/roomNavigation.d.ts +15 -0
- package/dist/types/model/routeClearance.d.ts +11 -0
- package/dist/types/model/spaces.d.ts +46 -0
- package/dist/types/model/stairGeometry.d.ts +27 -0
- package/dist/types/model/stairTraversal.d.ts +8 -0
- package/dist/types/model/topology.d.ts +14 -0
- package/dist/types/model/types.d.ts +369 -0
- package/dist/types/model/validate.d.ts +38 -0
- package/dist/types/model/vertical.d.ts +145 -0
- package/dist/types/model/walls.d.ts +71 -0
- package/dist/types/schema/index.d.ts +25 -0
- package/dist/types/theme/index.d.ts +55 -0
- package/dist/types/viewer/FloorViewer.d.ts +76 -0
- package/dist/types/viewer/ViewerWorkspace.d.ts +2 -0
- package/dist/types/viewer/host.d.ts +11 -0
- package/dist/types/viewer/index.d.ts +2 -0
- package/dist/types/viewer/panels.d.ts +12 -0
- package/dist/viewer/FloorViewer.js +104 -0
- package/dist/viewer/FloorViewer.js.map +1 -0
- package/dist/viewer/ViewerWorkspace.js +370 -0
- package/dist/viewer/ViewerWorkspace.js.map +1 -0
- package/dist/viewer/panels.js +35 -0
- package/dist/viewer/panels.js.map +1 -0
- package/package.json +58 -4
|
@@ -0,0 +1,394 @@
|
|
|
1
|
+
import ot from "polygon-clipping";
|
|
2
|
+
import { uid as G } from "./types.js";
|
|
3
|
+
import { replaceBoundaryUses as dt, splitBoundarySpace as ft, preserveBoundary as lt, boundaryEdges as rt } from "./boundaries.js";
|
|
4
|
+
import { MIN_WALL_LENGTH as ct, JOIN_EPS as _, MIN_SPACE_AREA as p, GEOMETRY_EPS as Y, MIN_RING_EDGE as ht } from "./precision.js";
|
|
5
|
+
const u = (t, n) => Math.hypot(t[0] - n[0], t[1] - n[1]), K = (t, n) => {
|
|
6
|
+
const s = n * Math.PI / 180;
|
|
7
|
+
return [t[0] * Math.cos(s) - t[1] * Math.sin(s), t[0] * Math.sin(s) + t[1] * Math.cos(s)];
|
|
8
|
+
}, J = Math.PI / 180, j = 6378137, Q = 0.00669437999014, V = (t) => {
|
|
9
|
+
const n = Math.sin(t * J) ** 2;
|
|
10
|
+
return {
|
|
11
|
+
lng: J * (j / Math.sqrt(1 - Q * n)) * Math.cos(t * J),
|
|
12
|
+
lat: J * (j * (1 - Q)) / (1 - Q * n) ** 1.5
|
|
13
|
+
};
|
|
14
|
+
}, Mt = (t, n = 0) => n ? [t[0], t[1], n] : [t[0], t[1]], Nt = (t, n, s) => {
|
|
15
|
+
const o = V(t[1]), a = [t[0] + n / o.lng, t[1] + s / o.lat];
|
|
16
|
+
return t[2] ? [a[0], a[1], t[2]] : a;
|
|
17
|
+
}, St = (t, n) => {
|
|
18
|
+
const s = V(n[1]), o = [(t[0] - n[0]) * s.lng, (t[1] - n[1]) * s.lat];
|
|
19
|
+
return n[2] ? K(o, n[2]) : o;
|
|
20
|
+
}, yt = (t, n) => {
|
|
21
|
+
const s = V(n[1]), o = n[2] ? K(t, -n[2]) : t;
|
|
22
|
+
return [n[0] + o[0] / s.lng, n[1] + o[1] / s.lat];
|
|
23
|
+
}, it = (t, n) => [t[0] + n[0], t[1] + n[1]], k = (t) => t.length ? u(t[0], t[t.length - 1]) < 1e-8 ? t : [...t, t[0]] : [], L = (t) => t.length > 1 && u(t[0], t[t.length - 1]) < 1e-8 ? t.slice(0, -1) : t, T = (t) => Math.abs(
|
|
24
|
+
t.reduce((n, s, o) => {
|
|
25
|
+
const a = t[(o + 1) % t.length];
|
|
26
|
+
return n + s[0] * a[1] - a[0] * s[1];
|
|
27
|
+
}, 0)
|
|
28
|
+
) / 2, Pt = (t) => t.rings ? T(t.rings[0]) - t.rings.slice(1).reduce((n, s) => n + T(s), 0) : t.width * t.depth, ut = (t) => {
|
|
29
|
+
const n = L(t);
|
|
30
|
+
return [n.reduce((s, o) => s + o[0], 0) / n.length, n.reduce((s, o) => s + o[1], 0) / n.length];
|
|
31
|
+
}, It = (t, n, s, o = 0) => k(
|
|
32
|
+
[
|
|
33
|
+
[-n / 2, -s / 2],
|
|
34
|
+
[n / 2, -s / 2],
|
|
35
|
+
[n / 2, s / 2],
|
|
36
|
+
[-n / 2, s / 2]
|
|
37
|
+
].map((a) => it(t, K(a, o)))
|
|
38
|
+
);
|
|
39
|
+
function xt(t, n, s, o) {
|
|
40
|
+
const a = (h, c, g) => (c[0] - h[0]) * (g[1] - h[1]) - (c[1] - h[1]) * (g[0] - h[0]), [i, f, d, r] = [a(t, n, s), a(t, n, o), a(s, o, t), a(s, o, n)], e = 1e-9;
|
|
41
|
+
return (i > e && f < -e || i < -e && f > e) && (d > e && r < -e || d < -e && r > e);
|
|
42
|
+
}
|
|
43
|
+
function D(t, n, s) {
|
|
44
|
+
const o = u(n, s), a = o ? Math.max(0, Math.min(1, ((t[0] - n[0]) * (s[0] - n[0]) + (t[1] - n[1]) * (s[1] - n[1])) / o ** 2)) : 0, i = [n[0] + (s[0] - n[0]) * a, n[1] + (s[1] - n[1]) * a];
|
|
45
|
+
return { point: i, t: a, distance: u(t, i), length: o };
|
|
46
|
+
}
|
|
47
|
+
function Ft(t, n) {
|
|
48
|
+
const { t: s } = D(n, t.axis[0], t.axis[1]);
|
|
49
|
+
return t.high + (t.low - t.high) * s;
|
|
50
|
+
}
|
|
51
|
+
const _t = (t) => t.rings ?? [It(t.position, t.width, t.depth, t.rotation)], tt = /* @__PURE__ */ new WeakMap();
|
|
52
|
+
function nt(t, n) {
|
|
53
|
+
var i;
|
|
54
|
+
let s = tt.get(t);
|
|
55
|
+
const o = s == null ? void 0 : s.ids.get(n);
|
|
56
|
+
if (!s || s.length !== t.length || o === void 0 || ((i = t[o]) == null ? void 0 : i.id) !== n) {
|
|
57
|
+
const f = /* @__PURE__ */ new Map();
|
|
58
|
+
t.forEach((d, r) => {
|
|
59
|
+
f.has(d.id) || f.set(d.id, r);
|
|
60
|
+
}), s = { length: t.length, ids: f }, tt.set(t, s);
|
|
61
|
+
}
|
|
62
|
+
const a = s.ids.get(n);
|
|
63
|
+
return a === void 0 ? void 0 : t[a];
|
|
64
|
+
}
|
|
65
|
+
function R(t, n) {
|
|
66
|
+
return [
|
|
67
|
+
nt(t.junctions, n.startId).position,
|
|
68
|
+
nt(t.junctions, n.endId).position
|
|
69
|
+
];
|
|
70
|
+
}
|
|
71
|
+
function At(t, n) {
|
|
72
|
+
const s = t.barriers.find((d) => d.id === n.barrierId);
|
|
73
|
+
if (!s) return n.position;
|
|
74
|
+
const [o, a] = R(t, s), i = u(o, a), f = i ? (n.offset ?? i / 2) / i : 0;
|
|
75
|
+
return [o[0] + (a[0] - o[0]) * f, o[1] + (a[1] - o[1]) * f];
|
|
76
|
+
}
|
|
77
|
+
function Bt(t, n) {
|
|
78
|
+
const s = t.barriers.find((i) => i.id === n.barrierId);
|
|
79
|
+
if (!s) return n.rotation;
|
|
80
|
+
const [o, a] = R(t, s);
|
|
81
|
+
return Math.atan2(a[1] - o[1], a[0] - o[0]) * 180 / Math.PI;
|
|
82
|
+
}
|
|
83
|
+
function Gt(t, n) {
|
|
84
|
+
let s = !1;
|
|
85
|
+
for (let o = 0, a = n.length - 1; o < n.length; a = o++) {
|
|
86
|
+
const i = n[o], f = n[a];
|
|
87
|
+
i[1] > t[1] != f[1] > t[1] && t[0] < (f[0] - i[0]) * (t[1] - i[1]) / (f[1] - i[1]) + i[0] && (s = !s);
|
|
88
|
+
}
|
|
89
|
+
return s;
|
|
90
|
+
}
|
|
91
|
+
const W = (t, n, s) => (n[0] - t[0]) * (s[1] - t[1]) - (n[1] - t[1]) * (s[0] - t[0]);
|
|
92
|
+
function mt(t, n, s, o) {
|
|
93
|
+
const a = (i, f, d) => Math.abs(W(f, d, i)) < 1e-8 * u(f, d) && i[0] >= Math.min(f[0], d[0]) - 1e-8 && i[0] <= Math.max(f[0], d[0]) + 1e-8 && i[1] >= Math.min(f[1], d[1]) - 1e-8 && i[1] <= Math.max(f[1], d[1]) + 1e-8;
|
|
94
|
+
return W(t, n, s) * W(t, n, o) < 0 && W(s, o, t) * W(s, o, n) < 0 || a(s, t, n) || a(o, t, n) || a(t, s, o) || a(n, s, o);
|
|
95
|
+
}
|
|
96
|
+
function Tt(t, n) {
|
|
97
|
+
try {
|
|
98
|
+
return ot.difference(t, n).every((s) => T(s[0]) < 1e-3);
|
|
99
|
+
} catch {
|
|
100
|
+
return !1;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
const F = ct, st = F;
|
|
104
|
+
function C(t, n, s) {
|
|
105
|
+
const o = t.junctions.find((a) => a.floorId === s && u(a.position, n) < _);
|
|
106
|
+
if (o) return o.position;
|
|
107
|
+
for (const a of t.barriers) {
|
|
108
|
+
if (a.floorId !== s) continue;
|
|
109
|
+
const [i, f] = R(t, a), d = D(n, i, f);
|
|
110
|
+
if (d.distance > _) continue;
|
|
111
|
+
const r = d.t <= 0.5 ? i : f;
|
|
112
|
+
if (u(d.point, r) < F - 1e-6) return r;
|
|
113
|
+
}
|
|
114
|
+
return n;
|
|
115
|
+
}
|
|
116
|
+
function H(t, n, s) {
|
|
117
|
+
if (n = C(t, n, s), t.junctions.some((o) => o.floorId === s && u(o.position, n) < _)) return null;
|
|
118
|
+
for (const o of t.barriers.filter((a) => a.floorId === s)) {
|
|
119
|
+
const [a, i] = R(t, o), f = D(n, a, i);
|
|
120
|
+
if (f.distance > _ || f.t <= 0 || f.t >= 1) continue;
|
|
121
|
+
const d = u(a, n);
|
|
122
|
+
for (const r of t.objects.filter((e) => e.barrierId === o.id)) {
|
|
123
|
+
if (Math.abs((r.offset ?? 0) - d) < r.width / 2) return "A junction cannot split an opening.";
|
|
124
|
+
if (((r.offset ?? 0) < d ? d : u(n, i)) < st - 1e-6)
|
|
125
|
+
return `Leave at least ${st} m of wall around an opening.`;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
return null;
|
|
129
|
+
}
|
|
130
|
+
function Ct(t, n, s, o) {
|
|
131
|
+
n = C(t, n, o), s = C(t, s, o);
|
|
132
|
+
const a = H(t, n, o) ?? H(t, s, o);
|
|
133
|
+
if (a) return a;
|
|
134
|
+
const i = s[0] - n[0], f = s[1] - n[1], d = u(n, s), r = [0, d], e = (h, c) => h > Y && h < c - Y;
|
|
135
|
+
for (const h of rt(t).filter((c) => c.floorId === o)) {
|
|
136
|
+
const [c, g] = R(t, h), N = g[0] - c[0], E = g[1] - c[1], x = i * E - f * N;
|
|
137
|
+
if (Math.abs(x) < 1e-12 * d * u(c, g)) {
|
|
138
|
+
for (const U of [c, g]) {
|
|
139
|
+
const $ = D(U, n, s);
|
|
140
|
+
$.distance <= Y && r.push($.t * d);
|
|
141
|
+
}
|
|
142
|
+
continue;
|
|
143
|
+
}
|
|
144
|
+
const S = ((c[0] - n[0]) * E - (c[1] - n[1]) * N) / x, A = ((c[0] - n[0]) * f - (c[1] - n[1]) * i) / x;
|
|
145
|
+
if (S < 0 || S > 1 || A < 0 || A > 1) continue;
|
|
146
|
+
if (r.push(S * d), e(Math.min(A, 1 - A) * u(c, g), "kind" in h ? F : ht))
|
|
147
|
+
return "That crossing would leave a boundary segment too short.";
|
|
148
|
+
const q = H(t, [n[0] + S * i, n[1] + S * f], o);
|
|
149
|
+
if (q) return q;
|
|
150
|
+
}
|
|
151
|
+
return r.sort((h, c) => h - c), r.some((h, c) => c > 0 && e(h - r[c - 1], F)) ? "That crossing would leave a boundary segment too short." : null;
|
|
152
|
+
}
|
|
153
|
+
function et(t, n, s) {
|
|
154
|
+
n = C(t, n, s);
|
|
155
|
+
const o = t.junctions.find((f) => f.floorId === s && u(f.position, n) < _);
|
|
156
|
+
if (o) return o.id;
|
|
157
|
+
const a = H(t, n, s);
|
|
158
|
+
if (a) throw new Error(a);
|
|
159
|
+
const i = G();
|
|
160
|
+
t.junctions.push({ id: i, floorId: s, position: n });
|
|
161
|
+
for (const f of [...t.barriers].filter((d) => d.floorId === s)) {
|
|
162
|
+
const [d, r] = R(t, f), e = D(n, d, r);
|
|
163
|
+
if (e.distance > _ || e.t <= 0 || e.t >= 1) continue;
|
|
164
|
+
const h = u(d, n), c = t.objects.filter((E) => E.barrierId === f.id), g = G(), N = f.endId;
|
|
165
|
+
f.endId = i, t.barriers.push({ ...f, id: g, startId: i, endId: N }), dt(t, f.id, [{ edgeId: f.id }, { edgeId: g }]), c.forEach((E) => {
|
|
166
|
+
(E.offset ?? 0) > h && (E.barrierId = g, E.offset = (E.offset ?? 0) - h);
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
return i;
|
|
170
|
+
}
|
|
171
|
+
function Rt(t, n) {
|
|
172
|
+
var a;
|
|
173
|
+
const s = t.barriers.find((i) => i.id === n);
|
|
174
|
+
s && lt(t, s);
|
|
175
|
+
const o = new Set(t.objects.filter((i) => i.barrierId === n).map((i) => i.id));
|
|
176
|
+
t.objects = t.objects.filter((i) => !o.has(i.id));
|
|
177
|
+
for (const i of t.objects) i.parentId && o.has(i.parentId) && (i.parentId = void 0);
|
|
178
|
+
if (t.barriers = t.barriers.filter((i) => i.id !== n), t.junctions = t.junctions.filter(
|
|
179
|
+
(i) => rt(t).some((f) => f.startId === i.id || f.endId === i.id)
|
|
180
|
+
), (a = t.navNodes) != null && a.length) {
|
|
181
|
+
const i = new Set(t.objects.map((d) => d.id));
|
|
182
|
+
t.navNodes = t.navNodes.filter((d) => d.objectId === void 0 || i.has(d.objectId));
|
|
183
|
+
const f = new Set(t.navNodes.map((d) => d.id));
|
|
184
|
+
t.navEdges = (t.navEdges ?? []).filter(
|
|
185
|
+
(d) => f.has(d.aId) && f.has(d.bId) && (d.objectId === void 0 || i.has(d.objectId))
|
|
186
|
+
);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
function gt(t, n, s, o, a) {
|
|
190
|
+
if (u(n, s) < F - 1e-6) throw new Error(`A segment must be at least ${F} m long.`);
|
|
191
|
+
if (n = C(t, n, o), s = C(t, s, o), u(n, s) < F - 1e-6) return;
|
|
192
|
+
const i = et(t, n, o), f = et(t, s, o);
|
|
193
|
+
if (i === f || t.barriers.some(
|
|
194
|
+
(r) => r.floorId === o && r.kind === a && (r.startId === i && r.endId === f || r.startId === f && r.endId === i)
|
|
195
|
+
))
|
|
196
|
+
return;
|
|
197
|
+
const d = {
|
|
198
|
+
id: G(),
|
|
199
|
+
floorId: o,
|
|
200
|
+
startId: i,
|
|
201
|
+
endId: f,
|
|
202
|
+
kind: a,
|
|
203
|
+
name: a === "wall" ? "Wall" : "Site fence",
|
|
204
|
+
thickness: a === "wall" ? 0.3 : 0.1,
|
|
205
|
+
height: a === "wall" ? 3.5 : 2
|
|
206
|
+
};
|
|
207
|
+
return t.barriers.push(d), d;
|
|
208
|
+
}
|
|
209
|
+
function $t(t, n, s, o, a = !0) {
|
|
210
|
+
var X, Z;
|
|
211
|
+
const i = t.objects.find((l) => l.id === n);
|
|
212
|
+
if (!((X = i == null ? void 0 : i.rings) != null && X.length)) throw new Error("Pick a room or zone to split.");
|
|
213
|
+
if (((Z = i.geometry) == null ? void 0 : Z.mode) === "boundaries") return ft(t, i, s, o, a);
|
|
214
|
+
const f = u(s, o);
|
|
215
|
+
if (f < 1e-6) throw new Error("Draw a line across the room to split it.");
|
|
216
|
+
const d = [(o[0] - s[0]) / f, (o[1] - s[1]) / f], r = [d[1], -d[0]], e = i.rings.map(k), h = Math.max(f, ...e.flat().map((l) => u(s, l))) * 4 + 10, c = [s[0] - d[0] * h, s[1] - d[1] * h], g = [s[0] + d[0] * h, s[1] + d[1] * h], N = (l) => k([
|
|
217
|
+
c,
|
|
218
|
+
g,
|
|
219
|
+
[g[0] + r[0] * h * l, g[1] + r[1] * h * l],
|
|
220
|
+
[c[0] + r[0] * h * l, c[1] + r[1] * h * l]
|
|
221
|
+
]), E = (l) => {
|
|
222
|
+
const I = ot.intersection(e, [N(l)]);
|
|
223
|
+
if (!I.length) throw new Error("The cut must cross the room from one wall to the opposite wall.");
|
|
224
|
+
const v = (w) => T(w[0]) - w.slice(1).reduce((b, M) => b + T(M), 0), m = I.filter((w) => v(w) >= p).sort((w, b) => v(b) - v(w));
|
|
225
|
+
if (!m.length) throw new Error(`Each split space needs at least ${p} m² of usable area.`);
|
|
226
|
+
if (m.length > 1)
|
|
227
|
+
throw new Error("That cut would leave disconnected pieces — draw a single straight line across the room.");
|
|
228
|
+
return m[0].map(k);
|
|
229
|
+
}, x = (l) => `${l[0].toFixed(4)},${l[1].toFixed(4)}`, S = new Set(e.flat().map(x)), A = (l) => l.map((I) => {
|
|
230
|
+
const v = L(I), m = v.filter((b, M) => {
|
|
231
|
+
if (S.has(x(b))) return !0;
|
|
232
|
+
const y = v[(M + v.length - 1) % v.length], P = v[(M + 1) % v.length];
|
|
233
|
+
return !(S.has(x(y)) && u(b, y) < _ || S.has(x(P)) && u(b, P) < _);
|
|
234
|
+
}), w = m.some(
|
|
235
|
+
(b, M) => m.some(
|
|
236
|
+
(y, P) => P > M + 1 && !(M === 0 && P === m.length - 1) && mt(b, m[(M + 1) % m.length], y, m[(P + 1) % m.length])
|
|
237
|
+
)
|
|
238
|
+
);
|
|
239
|
+
return m.length >= 3 && T(m) >= 0.01 && !w ? k(m) : I;
|
|
240
|
+
}), q = A(E(1)), U = A(E(-1)), $ = (l, I) => {
|
|
241
|
+
l.rings = I, l.position = ut(I[0]);
|
|
242
|
+
const v = L(I[0]), m = v.map((b) => b[0]), w = v.map((b) => b[1]);
|
|
243
|
+
l.width = Math.max(...m) - Math.min(...m), l.depth = Math.max(...w) - Math.min(...w);
|
|
244
|
+
}, B = structuredClone(i);
|
|
245
|
+
if (B.id = G(), B.name = `${i.name} 2`, B.feedId = void 0, $(i, q), $(B, U), t.objects.push(B), !a) return B.id;
|
|
246
|
+
const z = [];
|
|
247
|
+
for (const l of e) {
|
|
248
|
+
const I = L(l);
|
|
249
|
+
for (let v = 0; v < I.length; v++) {
|
|
250
|
+
const m = I[v], w = I[(v + 1) % I.length], b = [w[0] - m[0], w[1] - m[1]], M = d[0] * b[1] - d[1] * b[0];
|
|
251
|
+
if (Math.abs(M) < 1e-12) continue;
|
|
252
|
+
const y = [m[0] - s[0], m[1] - s[1]], P = (y[0] * d[1] - y[1] * d[0]) / M;
|
|
253
|
+
P < -1e-9 || P > 1 + 1e-9 || z.push((y[0] * b[1] - y[1] * b[0]) / M);
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
z.sort((l, I) => l - I);
|
|
257
|
+
const O = z.filter((l, I) => I === 0 || l - z[I - 1] > 1e-4), at = t.barriers.length;
|
|
258
|
+
for (let l = 0; l + 1 < O.length; l += 2) {
|
|
259
|
+
const I = [s[0] + d[0] * O[l], s[1] + d[1] * O[l]], v = [s[0] + d[0] * O[l + 1], s[1] + d[1] * O[l + 1]];
|
|
260
|
+
u(I, v) >= F - 1e-6 && gt(t, I, v, i.floorId, "wall");
|
|
261
|
+
}
|
|
262
|
+
return t.barriers.slice(at).forEach((l) => {
|
|
263
|
+
l.name = "Partition", l.thickness = 0.18;
|
|
264
|
+
}), B.id;
|
|
265
|
+
}
|
|
266
|
+
function Ot(t, n) {
|
|
267
|
+
var d;
|
|
268
|
+
if (!t.floors.find((r) => r.id === n)) throw new Error("That floor is not part of this project.");
|
|
269
|
+
if (t.floors.length <= 1) throw new Error("A project needs at least one floor.");
|
|
270
|
+
const o = new Set(t.objects.filter((r) => r.floorId === n).map((r) => r.id)), a = new Set(t.barriers.filter((r) => r.floorId === n).map((r) => r.id)), i = [n, ...o, ...a];
|
|
271
|
+
t.floors = t.floors.filter((r) => r.id !== n), t.junctions = t.junctions.filter((r) => r.floorId !== n), t.barriers = t.barriers.filter((r) => r.floorId !== n), t.virtualBoundaries && (t.virtualBoundaries = t.virtualBoundaries.filter((r) => r.floorId !== n)), t.objects = t.objects.filter((r) => r.floorId !== n), t.drawings = t.drawings.filter((r) => r.floorId !== n);
|
|
272
|
+
for (const r of t.objects)
|
|
273
|
+
r.barrierId && a.has(r.barrierId) && (r.barrierId = void 0, r.offset = void 0), r.parentId && o.has(r.parentId) && (r.parentId = void 0), r.watchedIds && (r.watchedIds = r.watchedIds.filter((e) => !o.has(e)), r.watchedIds.length || (r.watchedIds = void 0)), r.servedFloorIds && (r.servedFloorIds = r.servedFloorIds.filter((e) => e !== n), r.servedFloorIds.length || (r.servedFloorIds = void 0));
|
|
274
|
+
if (t.navNodes) {
|
|
275
|
+
const r = new Set(
|
|
276
|
+
t.navNodes.filter((e) => e.floorId === n || e.objectId && o.has(e.objectId)).map((e) => e.id)
|
|
277
|
+
);
|
|
278
|
+
t.navNodes = t.navNodes.filter((e) => !r.has(e.id)), t.navEdges = (t.navEdges ?? []).filter(
|
|
279
|
+
(e) => !r.has(e.aId) && !r.has(e.bId) && !(e.objectId && o.has(e.objectId))
|
|
280
|
+
);
|
|
281
|
+
}
|
|
282
|
+
t.portals && (t.portals = t.portals.filter(
|
|
283
|
+
(r) => !o.has(r.a) && !o.has(r.b) && !(r.openingId && o.has(r.openingId))
|
|
284
|
+
));
|
|
285
|
+
const f = new Set((t.portals ?? []).map((r) => r.id));
|
|
286
|
+
for (const r of t.zones ?? []) r.spaceIds = r.spaceIds.filter((e) => !o.has(e));
|
|
287
|
+
for (const r of t.portalGroups ?? []) r.portalIds = r.portalIds.filter((e) => f.has(e));
|
|
288
|
+
for (const r of t.buildings) ((d = r.roof) == null ? void 0 : d.floorId) === n && (r.roof = void 0);
|
|
289
|
+
return t.initialFloorId === n && (t.initialFloorId = void 0), i;
|
|
290
|
+
}
|
|
291
|
+
function Wt(t, n) {
|
|
292
|
+
var f, d, r;
|
|
293
|
+
const s = t.floors.find((e) => e.id === n), o = G(), a = /* @__PURE__ */ new Map(), i = (e) => (a.has(e) || a.set(e, G()), a.get(e));
|
|
294
|
+
return t.floors.push({
|
|
295
|
+
...s,
|
|
296
|
+
id: o,
|
|
297
|
+
name: `${s.name} copy`,
|
|
298
|
+
elevation: Math.max(
|
|
299
|
+
...t.floors.filter((e) => e.buildingId === s.buildingId).map((e) => e.elevation + e.height)
|
|
300
|
+
)
|
|
301
|
+
}), t.junctions.filter((e) => e.floorId === n).forEach((e) => t.junctions.push({ ...structuredClone(e), id: i(e.id), floorId: o })), t.barriers.filter((e) => e.floorId === n).forEach(
|
|
302
|
+
(e) => t.barriers.push({
|
|
303
|
+
...e,
|
|
304
|
+
id: i(e.id),
|
|
305
|
+
floorId: o,
|
|
306
|
+
startId: i(e.startId),
|
|
307
|
+
endId: i(e.endId)
|
|
308
|
+
})
|
|
309
|
+
), t.objects.filter((e) => e.floorId === n).forEach(
|
|
310
|
+
(e) => {
|
|
311
|
+
var h, c;
|
|
312
|
+
return t.objects.push({
|
|
313
|
+
...structuredClone(e),
|
|
314
|
+
id: i(e.id),
|
|
315
|
+
floorId: o,
|
|
316
|
+
feedId: void 0,
|
|
317
|
+
parentId: e.parentId ? i(e.parentId) : void 0,
|
|
318
|
+
barrierId: e.barrierId ? i(e.barrierId) : void 0,
|
|
319
|
+
servedFloorIds: (h = e.servedFloorIds) == null ? void 0 : h.map((g) => g === n ? o : g),
|
|
320
|
+
geometry: ((c = e.geometry) == null ? void 0 : c.mode) === "boundaries" ? {
|
|
321
|
+
mode: "boundaries",
|
|
322
|
+
loops: e.geometry.loops.map((g) => g.map((N) => ({ ...N, edgeId: i(N.edgeId) })))
|
|
323
|
+
} : e.geometry
|
|
324
|
+
});
|
|
325
|
+
}
|
|
326
|
+
), (f = t.virtualBoundaries) == null || f.filter((e) => e.floorId === n).forEach(
|
|
327
|
+
(e) => t.virtualBoundaries.push({
|
|
328
|
+
...e,
|
|
329
|
+
id: i(e.id),
|
|
330
|
+
floorId: o,
|
|
331
|
+
startId: i(e.startId),
|
|
332
|
+
endId: i(e.endId)
|
|
333
|
+
})
|
|
334
|
+
), t.drawings.filter((e) => e.floorId === n).forEach((e) => t.drawings.push({ ...e, id: G(), floorId: o })), (d = t.navNodes) == null || d.filter((e) => e.floorId === n).forEach(
|
|
335
|
+
(e) => t.navNodes.push({
|
|
336
|
+
...structuredClone(e),
|
|
337
|
+
id: i(e.id),
|
|
338
|
+
floorId: o,
|
|
339
|
+
objectId: e.objectId && a.has(e.objectId) ? a.get(e.objectId) : void 0
|
|
340
|
+
})
|
|
341
|
+
), (r = t.navEdges) == null || r.filter((e) => a.has(e.aId) && a.has(e.bId)).forEach(
|
|
342
|
+
(e) => t.navEdges.push({
|
|
343
|
+
...e,
|
|
344
|
+
id: i(e.id),
|
|
345
|
+
aId: a.get(e.aId),
|
|
346
|
+
bId: a.get(e.bId),
|
|
347
|
+
objectId: e.objectId && a.has(e.objectId) ? a.get(e.objectId) : void 0
|
|
348
|
+
})
|
|
349
|
+
), o;
|
|
350
|
+
}
|
|
351
|
+
const kt = (t) => [
|
|
352
|
+
[0, 0],
|
|
353
|
+
[t.width, 0],
|
|
354
|
+
[t.width, -t.height],
|
|
355
|
+
[0, -t.height]
|
|
356
|
+
].map((n) => it(t.origin, K([n[0] * t.scale, n[1] * t.scale], t.rotation)));
|
|
357
|
+
export {
|
|
358
|
+
F as MIN_SEGMENT,
|
|
359
|
+
st as OPENING_MIN_SEGMENT,
|
|
360
|
+
it as add,
|
|
361
|
+
gt as addBarrier,
|
|
362
|
+
R as barrierEnds,
|
|
363
|
+
C as barrierJoinPoint,
|
|
364
|
+
Ct as barrierStrokeIssue,
|
|
365
|
+
ut as centroid,
|
|
366
|
+
k as closeRing,
|
|
367
|
+
Tt as containedBy,
|
|
368
|
+
u as distance,
|
|
369
|
+
kt as drawingCorners,
|
|
370
|
+
Wt as duplicateFloor,
|
|
371
|
+
_t as footprint,
|
|
372
|
+
Mt as geoOrigin,
|
|
373
|
+
mt as intersects,
|
|
374
|
+
et as joinAt,
|
|
375
|
+
H as junctionIssue,
|
|
376
|
+
Nt as moveOrigin,
|
|
377
|
+
Pt as objectArea,
|
|
378
|
+
At as objectPosition,
|
|
379
|
+
Bt as objectRotation,
|
|
380
|
+
L as openRing,
|
|
381
|
+
Gt as pointInRing,
|
|
382
|
+
It as rectangle,
|
|
383
|
+
Rt as removeBarrier,
|
|
384
|
+
Ot as removeFloor,
|
|
385
|
+
T as ringArea,
|
|
386
|
+
K as rotate,
|
|
387
|
+
D as segmentProjection,
|
|
388
|
+
xt as segmentsCross,
|
|
389
|
+
Ft as slopeElevation,
|
|
390
|
+
$t as splitRoom,
|
|
391
|
+
yt as toLngLat,
|
|
392
|
+
St as toLocal
|
|
393
|
+
};
|
|
394
|
+
//# sourceMappingURL=geometry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"geometry.js","sources":["../../../../src/model/geometry.ts"],"sourcesContent":["import polygonClipping from 'polygon-clipping';\nimport type {\n Barrier,\n Drawing,\n Origin,\n Point,\n ProjectDocument,\n Ring,\n SiteObject,\n Slope,\n VirtualBoundary,\n} from './types';\nimport { uid } from './types';\nimport { boundaryEdges, preserveBoundary, replaceBoundaryUses, splitBoundarySpace } from './boundaries';\nimport { GEOMETRY_EPS, JOIN_EPS, MIN_RING_EDGE, MIN_SPACE_AREA, MIN_WALL_LENGTH } from './precision';\n\nexport const distance = (a: Point, b: Point) => Math.hypot(a[0] - b[0], a[1] - b[1]);\nexport const rotate = (p: Point, degrees: number): Point => {\n const r = (degrees * Math.PI) / 180;\n return [p[0] * Math.cos(r) - p[1] * Math.sin(r), p[0] * Math.sin(r) + p[1] * Math.cos(r)];\n};\n// Local planar frame via an ellipsoidal local-tangent-plane around the origin's lng/lat — accurate to\n// sub-centimetre at building scale with no projection library and no region assumption. `origin` is\n// [lng, lat, bearing?]; origin[2] is the site bearing (clockwise from true north), so a plan can align\n// to a real street grid while its coordinates stay simple and axis-aligned.\nconst DEG = Math.PI / 180,\n WGS84_A = 6378137,\n WGS84_E2 = 0.00669437999014;\nconst metresPerDegree = (lat: number) => {\n const s = Math.sin(lat * DEG) ** 2;\n return {\n lng: DEG * (WGS84_A / Math.sqrt(1 - WGS84_E2 * s)) * Math.cos(lat * DEG),\n lat: (DEG * (WGS84_A * (1 - WGS84_E2))) / (1 - WGS84_E2 * s) ** 1.5,\n };\n};\nexport const geoOrigin = (lngLat: Point, bearing = 0): Origin =>\n bearing ? [lngLat[0], lngLat[1], bearing] : [lngLat[0], lngLat[1]];\n/** Shift a site anchor by a distance on the ground, in metres east and north.\n *\n * Nudging a building into place is a thing you do in metres — \"half a metre that way\" — and the\n * anchor is stored in degrees, where the useful step depends on latitude and differs between the\n * two axes. Deliberately NOT rotated by the site bearing: this moves the site across the world,\n * and the directions that make sense for that are the compass ones, not the plan's own grid. */\nexport const moveOrigin = (origin: Origin, east: number, north: number): Origin => {\n const m = metresPerDegree(origin[1]);\n const moved: Origin = [origin[0] + east / m.lng, origin[1] + north / m.lat];\n return origin[2] ? [moved[0], moved[1], origin[2]] : moved;\n};\nexport const toLocal = (lngLat: Point, origin: Origin): Point => {\n const m = metresPerDegree(origin[1]);\n const d: Point = [(lngLat[0] - origin[0]) * m.lng, (lngLat[1] - origin[1]) * m.lat];\n return origin[2] ? rotate(d, origin[2]) : d;\n};\nexport const toLngLat = (p: Point, origin: Origin): Point => {\n const m = metresPerDegree(origin[1]);\n const r = origin[2] ? rotate(p, -origin[2]) : p;\n return [origin[0] + r[0] / m.lng, origin[1] + r[1] / m.lat];\n};\nexport const add = (a: Point, b: Point): Point => [a[0] + b[0], a[1] + b[1]];\nexport const closeRing = (ring: Ring): Ring =>\n !ring.length ? [] : distance(ring[0], ring[ring.length - 1]) < 1e-8 ? ring : [...ring, ring[0]];\nexport const openRing = (ring: Ring): Ring =>\n ring.length > 1 && distance(ring[0], ring[ring.length - 1]) < 1e-8 ? ring.slice(0, -1) : ring;\nexport const ringArea = (ring: Ring) =>\n Math.abs(\n ring.reduce((sum, p, i) => {\n const q = ring[(i + 1) % ring.length];\n return sum + p[0] * q[1] - q[0] * p[1];\n }, 0),\n ) / 2;\nexport const objectArea = (object: SiteObject) =>\n object.rings\n ? ringArea(object.rings[0]) - object.rings.slice(1).reduce((sum, r) => sum + ringArea(r), 0)\n : object.width * object.depth;\nexport const centroid = (ring: Ring): Point => {\n const points = openRing(ring);\n return [points.reduce((s, p) => s + p[0], 0) / points.length, points.reduce((s, p) => s + p[1], 0) / points.length];\n};\nexport const rectangle = (center: Point, width: number, depth: number, rotation = 0): Ring =>\n closeRing(\n (\n [\n [-width / 2, -depth / 2],\n [width / 2, -depth / 2],\n [width / 2, depth / 2],\n [-width / 2, depth / 2],\n ] as Point[]\n ).map(p => add(center, rotate(p, rotation))),\n );\n/** Do the two open segments cross? Used for line of sight: a wall between two points blocks it.\n * Touching at an endpoint does not count — walls meet at shared junctions, and a sightline grazing\n * such a corner is not obstructed by it. */\nexport function segmentsCross(a: Point, b: Point, c: Point, d: Point): boolean {\n const side = (p: Point, q: Point, r: Point) => (q[0] - p[0]) * (r[1] - p[1]) - (q[1] - p[1]) * (r[0] - p[0]);\n const [s1, s2, s3, s4] = [side(a, b, c), side(a, b, d), side(c, d, a), side(c, d, b)];\n const EPS = 1e-9;\n return ((s1 > EPS && s2 < -EPS) || (s1 < -EPS && s2 > EPS)) && ((s3 > EPS && s4 < -EPS) || (s3 < -EPS && s4 > EPS));\n}\nexport function segmentProjection(p: Point, a: Point, b: Point) {\n const length = distance(a, b);\n const t = length\n ? Math.max(0, Math.min(1, ((p[0] - a[0]) * (b[0] - a[0]) + (p[1] - a[1]) * (b[1] - a[1])) / length ** 2))\n : 0;\n const point: Point = [a[0] + (b[0] - a[0]) * t, a[1] + (b[1] - a[1]) * t];\n return { point, t, distance: distance(p, point), length };\n}\n/** Elevation of a sloped area at a point: project onto the slope axis and lerp high → low. Points\n * beyond either end clamp, so a footprint wider than its axis keeps flat aprons at both ends. */\nexport function slopeElevation(slope: Slope, point: Point): number {\n const { t } = segmentProjection(point, slope.axis[0], slope.axis[1]);\n return slope.high + (slope.low - slope.high) * t;\n}\n/** The ground an object covers. Most areas carry an explicit outline; anything placed by size falls\n * back to the rectangle its width, depth and rotation describe. One definition, so the model and the\n * renderer cannot disagree about where a thing is. */\nexport const footprint = (o: SiteObject): Ring[] => o.rings ?? [rectangle(o.position, o.width, o.depth, o.rotation)];\n// Store array indices, not coordinates: transaction drafts move/replace junctions in place. Verify\n// each hit so same-length splices and reordering cannot leave the rendering or snapping cache stale.\nconst junctionIndices = new WeakMap<ProjectDocument['junctions'], { length: number; ids: Map<string, number> }>();\nfunction indexedJunction(junctions: ProjectDocument['junctions'], id: string) {\n let index = junctionIndices.get(junctions);\n const position = index?.ids.get(id);\n if (!index || index.length !== junctions.length || position === undefined || junctions[position]?.id !== id) {\n const ids = new Map<string, number>();\n junctions.forEach((j, i) => {\n if (!ids.has(j.id)) ids.set(j.id, i);\n });\n index = { length: junctions.length, ids };\n junctionIndices.set(junctions, index);\n }\n const at = index.ids.get(id);\n return at === undefined ? undefined : junctions[at];\n}\nexport function barrierEnds(project: ProjectDocument, barrier: Barrier | VirtualBoundary): [Point, Point] {\n return [\n indexedJunction(project.junctions, barrier.startId)!.position,\n indexedJunction(project.junctions, barrier.endId)!.position,\n ];\n}\nexport function objectPosition(project: ProjectDocument, object: SiteObject): Point {\n const barrier = project.barriers.find(b => b.id === object.barrierId);\n if (!barrier) return object.position;\n const [a, b] = barrierEnds(project, barrier);\n const l = distance(a, b);\n const t = l ? (object.offset ?? l / 2) / l : 0;\n return [a[0] + (b[0] - a[0]) * t, a[1] + (b[1] - a[1]) * t];\n}\nexport function objectRotation(project: ProjectDocument, object: SiteObject) {\n const barrier = project.barriers.find(b => b.id === object.barrierId);\n if (!barrier) return object.rotation;\n const [a, b] = barrierEnds(project, barrier);\n return (Math.atan2(b[1] - a[1], b[0] - a[0]) * 180) / Math.PI;\n}\nexport function pointInRing(point: Point, ring: Ring): boolean {\n let inside = false;\n for (let i = 0, j = ring.length - 1; i < ring.length; j = i++) {\n const a = ring[i],\n b = ring[j];\n if (a[1] > point[1] !== b[1] > point[1] && point[0] < ((b[0] - a[0]) * (point[1] - a[1])) / (b[1] - a[1]) + a[0])\n inside = !inside;\n }\n return inside;\n}\nconst cross = (a: Point, b: Point, c: Point) => (b[0] - a[0]) * (c[1] - a[1]) - (b[1] - a[1]) * (c[0] - a[0]);\n/** Whether segments a–b and c–d cross or touch, endpoints included. */\nexport function intersects(a: Point, b: Point, c: Point, d: Point) {\n const on = (p: Point, x: Point, y: Point) =>\n Math.abs(cross(x, y, p)) < 1e-8 * distance(x, y) &&\n p[0] >= Math.min(x[0], y[0]) - 1e-8 &&\n p[0] <= Math.max(x[0], y[0]) + 1e-8 &&\n p[1] >= Math.min(x[1], y[1]) - 1e-8 &&\n p[1] <= Math.max(x[1], y[1]) + 1e-8;\n return (\n (cross(a, b, c) * cross(a, b, d) < 0 && cross(c, d, a) * cross(c, d, b) < 0) ||\n on(c, a, b) ||\n on(d, a, b) ||\n on(a, c, d) ||\n on(b, c, d)\n );\n}\n// Ring and relationship validation moved to validate.ts — the validity layer stands on its own.\nexport function containedBy(child: Ring[], parent: Ring[]): boolean {\n try {\n return polygonClipping.difference(child, parent).every(p => ringArea(p[0] as Ring) < 0.001);\n } catch {\n return false;\n }\n}\nexport function snapPoint(\n project: ProjectDocument,\n floorId: string | null,\n point: Point,\n tolerance: number,\n previous?: Point,\n grid = true,\n /** Direction the segment from `previous` is held to, with its 15° multiples. Default 0 is the site\n * grid; pass `referenceAxis(...).angle` to hold to the building or to a neighbouring wall instead. */\n axis = 0,\n): { point: Point; label: string } {\n let best = tolerance,\n result: Point | null = null,\n label = '';\n let junctionScore = 1;\n const degrees = new Map<string, number>();\n for (const b of boundaryEdges(project))\n for (const id of [b.startId, b.endId]) degrees.set(id, (degrees.get(id) ?? 0) + 1);\n for (const junction of project.junctions.filter(j => j.floorId === floorId)) {\n const d = distance(point, junction.position);\n const degree = degrees.get(junction.id) ?? 0;\n // A T junction attracts the fourth branch before a projection onto an adjacent wall can\n // create a second, almost coincident T. All four branches reuse the same junction identity.\n const score = d / (tolerance * (degree >= 3 ? 1.5 : 1));\n if (score < junctionScore) {\n junctionScore = score;\n result = junction.position;\n label = degree >= 3 ? 'Junction' : 'Endpoint';\n }\n }\n if (result) return { point: result, label };\n const angleLabel = (quarter: number) => {\n const turn = Math.round(quarter * 45);\n const acute = turn > 90 ? 180 - turn : turn;\n return acute === 0 ? 'Parallel' : acute === 90 ? 'Square' : `${acute}°`;\n };\n const held = previous && holdAngle(previous, point, axis, tolerance);\n if (held && previous) {\n const dx = held.point[0] - previous[0],\n dy = held.point[1] - previous[1];\n for (const barrier of boundaryEdges(project).filter(b => b.floorId === floorId)) {\n const [a, b] = barrierEnds(project, barrier);\n const ex = b[0] - a[0],\n ey = b[1] - a[1];\n const denom = dx * ey - dy * ex;\n if (Math.abs(denom) < 1e-9) continue;\n const ax = a[0] - previous[0],\n ay = a[1] - previous[1];\n const t = (ax * ey - ay * ex) / denom,\n u = (ax * dy - ay * dx) / denom;\n if (t <= 0 || u < 0 || u > 1) continue;\n const hit: Point = [previous[0] + dx * t, previous[1] + dy * t];\n const d = distance(point, hit);\n if (d >= best) continue;\n best = d;\n result = barrierJoinPoint(project, hit, floorId);\n label = distance(result, hit) < 1e-6 ? angleLabel(held.quarter) : 'Endpoint';\n }\n if (result) return { point: result, label };\n }\n for (const barrier of boundaryEdges(project).filter(b => b.floorId === floorId)) {\n const projected = segmentProjection(point, ...barrierEnds(project, barrier));\n if (projected.distance < best) {\n best = projected.distance;\n result = barrierJoinPoint(project, projected.point, floorId);\n label = 'On segment';\n }\n }\n if (result) return { point: result, label };\n let p: Point = grid ? [Math.round(point[0] * 2) / 2, Math.round(point[1] * 2) / 2] : point;\n if (previous) {\n const held = holdAngle(previous, p, axis, tolerance);\n if (held) {\n p = held.point;\n label = angleLabel(held.quarter);\n }\n }\n return { point: p, label: label || (grid ? '0.5 m grid' : '') };\n}\n/** Hold a segment to `axis` and every 15° off it (including 45° and 90°). See\n * `referenceAxis` in ./walls for where a meaningful axis comes from; 0 is the site's own grid.\n *\n * The test is perpendicular distance from the candidate ray, not an angle, so the tolerance stays a\n * constant width on screen: a short wall snaps readily and a long one keeps fine control of its far\n * end, which is the behaviour that makes the constraint feel like help rather than a fight. Null when\n * the pointer is near none of them — an angle nobody asked for is worse than no angle at all. */\nconst zero = (v: number) => (Math.abs(v) < 1e-12 ? 0 : v);\nexport function holdAngle(\n previous: Point,\n point: Point,\n axis: number,\n tolerance: number,\n): { point: Point; degrees: number; quarter: number } | null {\n const vx = point[0] - previous[0],\n vy = point[1] - previous[1];\n if (Math.hypot(vx, vy) < 1e-6) return null;\n let best: { point: Point; degrees: number; quarter: number; offset: number } | null = null;\n for (let k = 0; k < 24; k++) {\n const degrees = axis + k * 15,\n rad = (degrees * Math.PI) / 180,\n // cos(90°) comes back as 6e-17 rather than 0, which would leave a wall a hair off the very axis\n // it was just held to — harmless on screen, but it is what gets written to the document.\n dx = zero(Math.cos(rad)),\n dy = zero(Math.sin(rad)),\n along = vx * dx + vy * dy;\n if (along <= 0) continue; // the opposing ray of a pair already covered by its partner\n const offset = Math.abs(vx * dy - vy * dx);\n if (offset >= tolerance || (best && offset >= best.offset)) continue;\n best = { point: [previous[0] + dx * along, previous[1] + dy * along], degrees, quarter: (k % 12) / 3, offset };\n }\n return best && { point: best.point, degrees: best.degrees, quarter: best.quarter };\n}\n/** One centimetre is the model's degeneracy guard, independent of the drawing grid and zoom.\n * Short returns, jambs and staggered junctions are real geometry; their screen handles spread\n * apart when necessary so they remain editable. */\nexport const MIN_SEGMENT = MIN_WALL_LENGTH;\n/** An opening needs a valid wall AND enough length for its actual width. Kept as an exported\n * base limit for callers; there is no additional one-metre restriction on narrow doors/windows. */\nexport const OPENING_MIN_SEGMENT = MIN_SEGMENT;\n/** Automatic joins only absorb sub-millimetre coordinate noise. Interactive snapping has its\n * own screen-based reach, so a deliberate centimetre-scale feature survives with snapping off. */\n\n/** Weld a connection near the end of a wall to that end. The snap preview and the actual\n * junction use the same rule, so an ordinary T-junction cannot leave an uneditable stub. */\nexport function barrierJoinPoint(project: ProjectDocument, point: Point, floorId: string | null): Point {\n const existing = project.junctions.find(j => j.floorId === floorId && distance(j.position, point) < JOIN_EPS);\n if (existing) return existing.position;\n for (const barrier of project.barriers) {\n if (barrier.floorId !== floorId) continue;\n const [a, b] = barrierEnds(project, barrier);\n const hit = segmentProjection(point, a, b);\n if (hit.distance > JOIN_EPS) continue;\n const nearest = hit.t <= 0.5 ? a : b;\n if (distance(hit.point, nearest) < MIN_SEGMENT - 1e-6) return nearest;\n }\n return point;\n}\n\n/** A preview can check a connection without partially splitting any walls. */\nexport function junctionIssue(project: ProjectDocument, point: Point, floorId: string | null): string | null {\n point = barrierJoinPoint(project, point, floorId);\n if (project.junctions.some(j => j.floorId === floorId && distance(j.position, point) < JOIN_EPS)) return null;\n for (const barrier of project.barriers.filter(b => b.floorId === floorId)) {\n const [a, b] = barrierEnds(project, barrier);\n const hit = segmentProjection(point, a, b);\n if (hit.distance > JOIN_EPS || hit.t <= 0 || hit.t >= 1) continue;\n const cut = distance(a, point);\n for (const o of project.objects.filter(o => o.barrierId === barrier.id)) {\n if (Math.abs((o.offset ?? 0) - cut) < o.width / 2) return 'A junction cannot split an opening.';\n if (((o.offset ?? 0) < cut ? cut : distance(point, b)) < OPENING_MIN_SEGMENT - 1e-6)\n return `Leave at least ${OPENING_MIN_SEGMENT} m of wall around an opening.`;\n }\n }\n return null;\n}\n\n/** Preflight the complete stroke, including openings crossed between its endpoints. */\nexport function barrierStrokeIssue(\n project: ProjectDocument,\n a: Point,\n b: Point,\n floorId: string | null,\n): string | null {\n a = barrierJoinPoint(project, a, floorId);\n b = barrierJoinPoint(project, b, floorId);\n const atStart = junctionIssue(project, a, floorId) ?? junctionIssue(project, b, floorId);\n if (atStart) return atStart;\n const ux = b[0] - a[0],\n uy = b[1] - a[1];\n const length = distance(a, b),\n cuts = [0, length];\n const tooShort = (span: number, minimum: number) => span > GEOMETRY_EPS && span < minimum - GEOMETRY_EPS;\n for (const wall of boundaryEdges(project).filter(w => w.floorId === floorId)) {\n const [c, d] = barrierEnds(project, wall),\n vx = d[0] - c[0],\n vy = d[1] - c[1];\n const det = ux * vy - uy * vx;\n if (Math.abs(det) < 1e-12 * length * distance(c, d)) {\n for (const q of [c, d]) {\n const hit = segmentProjection(q, a, b);\n if (hit.distance <= GEOMETRY_EPS) cuts.push(hit.t * length);\n }\n continue;\n }\n const t = ((c[0] - a[0]) * vy - (c[1] - a[1]) * vx) / det;\n const s = ((c[0] - a[0]) * uy - (c[1] - a[1]) * ux) / det;\n if (t < 0 || t > 1 || s < 0 || s > 1) continue;\n cuts.push(t * length);\n if (tooShort(Math.min(s, 1 - s) * distance(c, d), 'kind' in wall ? MIN_SEGMENT : MIN_RING_EDGE))\n return 'That crossing would leave a boundary segment too short.';\n const issue = junctionIssue(project, [a[0] + t * ux, a[1] + t * uy], floorId);\n if (issue) return issue;\n }\n cuts.sort((x, y) => x - y);\n if (cuts.some((cut, i) => i > 0 && tooShort(cut - cuts[i - 1], MIN_SEGMENT)))\n return 'That crossing would leave a boundary segment too short.';\n return null;\n}\n\nexport function joinAt(project: ProjectDocument, point: Point, floorId: string | null): string {\n point = barrierJoinPoint(project, point, floorId);\n const existing = project.junctions.find(j => j.floorId === floorId && distance(j.position, point) < JOIN_EPS);\n if (existing) return existing.id;\n const issue = junctionIssue(project, point, floorId);\n if (issue) throw new Error(issue);\n const id = uid();\n project.junctions.push({ id, floorId, position: point });\n for (const barrier of [...project.barriers].filter(b => b.floorId === floorId)) {\n const [a, b] = barrierEnds(project, barrier);\n const hit = segmentProjection(point, a, b);\n if (hit.distance > JOIN_EPS || hit.t <= 0 || hit.t >= 1) continue;\n const cut = distance(a, point);\n const attachments = project.objects.filter(o => o.barrierId === barrier.id);\n const newId = uid();\n const oldEnd = barrier.endId;\n barrier.endId = id;\n project.barriers.push({ ...barrier, id: newId, startId: id, endId: oldEnd });\n replaceBoundaryUses(project, barrier.id, [{ edgeId: barrier.id }, { edgeId: newId }]);\n attachments.forEach(o => {\n if ((o.offset ?? 0) > cut) {\n o.barrierId = newId;\n o.offset = (o.offset ?? 0) - cut;\n }\n });\n }\n return id;\n}\n/** Take a wall out of the document, with everything that only existed because it was there.\n *\n * A wall is never alone: doors and windows hang in it, junctions exist to hold its ends, and route\n * nodes may be bound to those openings. Removing the barrier alone leaves each of those pointing at\n * something that is gone, and the document refuses the whole edit — so the delete appears to do\n * nothing at all, which is worse than either outcome. Everything that removes a wall goes through\n * here so that cannot happen in one place and not another.\n *\n * A junction survives if any other wall still ends there; the ontology is pruned by the caller,\n * which knows whether spaces are also being merged. */\nexport function removeBarrier(project: ProjectDocument, barrierId: string) {\n const removed = project.barriers.find(b => b.id === barrierId);\n if (removed) preserveBoundary(project, removed);\n const openings = new Set(project.objects.filter(o => o.barrierId === barrierId).map(o => o.id));\n project.objects = project.objects.filter(o => !openings.has(o.id));\n for (const o of project.objects) if (o.parentId && openings.has(o.parentId)) o.parentId = undefined;\n project.barriers = project.barriers.filter(b => b.id !== barrierId);\n project.junctions = project.junctions.filter(j =>\n boundaryEdges(project).some(b => b.startId === j.id || b.endId === j.id),\n );\n if (project.navNodes?.length) {\n const alive = new Set(project.objects.map(o => o.id));\n project.navNodes = project.navNodes.filter(n => n.objectId === undefined || alive.has(n.objectId));\n const nodes = new Set(project.navNodes.map(n => n.id));\n project.navEdges = (project.navEdges ?? []).filter(\n e => nodes.has(e.aId) && nodes.has(e.bId) && (e.objectId === undefined || alive.has(e.objectId)),\n );\n }\n}\n\nexport function addBarrier(\n project: ProjectDocument,\n a: Point,\n b: Point,\n floorId: string | null,\n kind: 'wall' | 'fence',\n) {\n if (distance(a, b) < MIN_SEGMENT - 1e-6) throw new Error(`A segment must be at least ${MIN_SEGMENT} m long.`);\n a = barrierJoinPoint(project, a, floorId);\n b = barrierJoinPoint(project, b, floorId);\n // Snapping can collapse a stroke back onto its start. Repeated clicks are harmless.\n if (distance(a, b) < MIN_SEGMENT - 1e-6) return;\n const startId = joinAt(project, a, floorId),\n endId = joinAt(project, b, floorId);\n if (\n startId === endId ||\n project.barriers.some(\n w =>\n w.floorId === floorId &&\n w.kind === kind &&\n ((w.startId === startId && w.endId === endId) || (w.startId === endId && w.endId === startId)),\n )\n )\n return;\n const barrier: Barrier = {\n id: uid(),\n floorId,\n startId,\n endId,\n kind,\n name: kind === 'wall' ? 'Wall' : 'Site fence',\n thickness: kind === 'wall' ? 0.3 : 0.1,\n height: kind === 'wall' ? 3.5 : 2,\n };\n project.barriers.push(barrier);\n return barrier;\n}\n// Splits a room/zone along the infinite line drawn through `pa`→`pb`. Because the line is treated as\n// unbounded, the stroke may start and end well past the walls — the room is divided wherever the line\n// actually crosses it, so precise clicks on the walls are not required. Holes are supported: each half\n// keeps the portion of any hole on its side (a hole straddling the cut merges into that half's\n// boundary), and the partition wall is built only across solid spans, skipping courtyards. By\n// convention the original keeps the right-hand side of the pa→pb direction and the twin takes the left\n// (the twin is what the editor selects after the cut).\nexport function splitRoom(\n project: ProjectDocument,\n roomId: string,\n pa: Point,\n pb: Point,\n /** Build the partition wall along the cut. False when a wall already exists there — splitting a\n * space *because* someone drew a wall must not draw a second one on top of it. */\n wall = true,\n): string {\n const o = project.objects.find(x => x.id === roomId);\n if (!o?.rings?.length) throw new Error('Pick a room or zone to split.');\n if (o.geometry?.mode === 'boundaries') return splitBoundarySpace(project, o, pa, pb, wall);\n const len = distance(pa, pb);\n if (len < 1e-6) throw new Error('Draw a line across the room to split it.');\n const dir: Point = [(pb[0] - pa[0]) / len, (pb[1] - pa[1]) / len];\n const normal: Point = [dir[1], -dir[0]]; // unit normal pointing to the right-hand side of travel\n\n // A cut long enough to reach past the whole room, so overshooting the walls is harmless.\n const poly = o.rings.map(closeRing);\n const reach = Math.max(len, ...poly.flat().map(p => distance(pa, p))) * 4 + 10;\n const c0: Point = [pa[0] - dir[0] * reach, pa[1] - dir[1] * reach];\n const c1: Point = [pa[0] + dir[0] * reach, pa[1] + dir[1] * reach];\n const halfPlane = (side: 1 | -1): Ring =>\n closeRing([\n c0,\n c1,\n [c1[0] + normal[0] * reach * side, c1[1] + normal[1] * reach * side],\n [c0[0] + normal[0] * reach * side, c0[1] + normal[1] * reach * side],\n ]);\n // Intersect the room (outer + holes) with a half-plane; keep the largest resulting polygon.\n const clip = (side: 1 | -1): Ring[] => {\n const pieces = polygonClipping.intersection(poly as Ring[], [halfPlane(side)]) as unknown as Ring[][];\n if (!pieces.length) throw new Error('The cut must cross the room from one wall to the opposite wall.');\n const netArea = (pg: Ring[]) => ringArea(pg[0]) - pg.slice(1).reduce((sum, r) => sum + ringArea(r), 0);\n const usable = pieces.filter(pg => netArea(pg) >= MIN_SPACE_AREA).sort((a, b) => netArea(b) - netArea(a));\n if (!usable.length) throw new Error(`Each split space needs at least ${MIN_SPACE_AREA} m² of usable area.`);\n if (usable.length > 1)\n throw new Error('That cut would leave disconnected pieces — draw a single straight line across the room.');\n return usable[0].map(closeRing);\n };\n // Only weld numerical duplicates. Removing a real cut vertex changes the boundary and can\n // lose floor area or erase a small notch; the wall minimum and drawing grid do not govern rings.\n const drawnKey = (p: Point) => `${p[0].toFixed(4)},${p[1].toFixed(4)}`;\n const drawn = new Set(poly.flat().map(drawnKey));\n const weld = (rings: Ring[]): Ring[] =>\n rings.map(closed => {\n const r = openRing(closed);\n const kept = r.filter((p, i) => {\n if (drawn.has(drawnKey(p))) return true;\n const prev = r[(i + r.length - 1) % r.length],\n next = r[(i + 1) % r.length];\n if (drawn.has(drawnKey(prev)) && distance(p, prev) < JOIN_EPS) return false;\n if (drawn.has(drawnKey(next)) && distance(p, next) < JOIN_EPS) return false;\n return true;\n });\n // Removing a cut vertex can connect across a concave notch or reverse a boundary edge.\n // Keep the clipper's valid boundary if that shortcut would cross another edge.\n const crossing = kept.some((p, i) =>\n kept.some(\n (q, j) =>\n j > i + 1 &&\n !(i === 0 && j === kept.length - 1) &&\n intersects(p, kept[(i + 1) % kept.length], q, kept[(j + 1) % kept.length]),\n ),\n );\n return kept.length >= 3 && ringArea(kept) >= 0.01 && !crossing ? closeRing(kept) : closed;\n });\n const right = weld(clip(1)); // original keeps the right-hand side …\n const left = weld(clip(-1)); // … the twin takes the left\n\n const apply = (target: SiteObject, rings: Ring[]) => {\n target.rings = rings;\n target.position = centroid(rings[0]);\n const outer = openRing(rings[0]);\n const xs = outer.map(p => p[0]),\n ys = outer.map(p => p[1]);\n target.width = Math.max(...xs) - Math.min(...xs);\n target.depth = Math.max(...ys) - Math.min(...ys);\n };\n const twin = structuredClone(o);\n twin.id = uid();\n twin.name = `${o.name} 2`;\n twin.feedId = undefined;\n apply(o, right);\n apply(twin, left);\n project.objects.push(twin);\n\n if (!wall) return twin.id;\n // Partition wall: collect every crossing of the cut line with every ring (outer + holes) as a signed\n // distance along `dir` from `pa`, order them, and wall each solid interval (crossings 0-1, 2-3, …).\n // This skips holes and handles concave rooms the line enters and leaves more than once.\n const crossings: number[] = [];\n for (const ring of poly) {\n const r = openRing(ring);\n for (let i = 0; i < r.length; i++) {\n const a = r[i],\n b = r[(i + 1) % r.length];\n const e: Point = [b[0] - a[0], b[1] - a[1]];\n const denom = dir[0] * e[1] - dir[1] * e[0];\n if (Math.abs(denom) < 1e-12) continue; // edge parallel to the cut\n const qp: Point = [a[0] - pa[0], a[1] - pa[1]];\n const u = (qp[0] * dir[1] - qp[1] * dir[0]) / denom; // param along the edge\n if (u < -1e-9 || u > 1 + 1e-9) continue;\n crossings.push((qp[0] * e[1] - qp[1] * e[0]) / denom); // distance along the cut\n }\n }\n crossings.sort((x, y) => x - y);\n const deduped = crossings.filter((t, i) => i === 0 || t - crossings[i - 1] > 1e-4);\n const from = project.barriers.length;\n for (let i = 0; i + 1 < deduped.length; i += 2) {\n const s: Point = [pa[0] + dir[0] * deduped[i], pa[1] + dir[1] * deduped[i]];\n const e: Point = [pa[0] + dir[0] * deduped[i + 1], pa[1] + dir[1] * deduped[i + 1]];\n if (distance(s, e) >= MIN_SEGMENT - 1e-6) addBarrier(project, s, e, o.floorId, 'wall');\n }\n project.barriers.slice(from).forEach(b => {\n b.name = 'Partition';\n b.thickness = 0.18;\n });\n return twin.id;\n}\n// Clones a floor with everything on it, including its slice of the nav graph: node/edge ids are\n// remapped (bindings follow cloned objects), and cross-floor edges (vertical rides, exits) are\n// dropped — re-run chainVertical on the copy to rejoin it to the shafts.\n/** Delete a floor and everything anchored to it. The cascade is the whole job: a floor owns junctions,\n * barriers, objects and drawings, and those are in turn referenced from elsewhere — openings hang off\n * barriers, cameras watch objects, lifts serve floors, nested zones name a parent, the nav graph binds\n * both, a building may roof this level, and the document may open on it. Anything missed here surfaces\n * later as a validation failure on load, so it is all handled up front.\n * Refuses to remove the last floor: a project must always have one. Returns the ids that were removed. */\nexport function removeFloor(project: ProjectDocument, floorId: string): string[] {\n const floor = project.floors.find(f => f.id === floorId);\n if (!floor) throw new Error('That floor is not part of this project.');\n if (project.floors.length <= 1) throw new Error('A project needs at least one floor.');\n\n const goneObjects = new Set(project.objects.filter(o => o.floorId === floorId).map(o => o.id));\n const goneBarriers = new Set(project.barriers.filter(b => b.floorId === floorId).map(b => b.id));\n const removed = [floorId, ...goneObjects, ...goneBarriers];\n\n project.floors = project.floors.filter(f => f.id !== floorId);\n project.junctions = project.junctions.filter(j => j.floorId !== floorId);\n project.barriers = project.barriers.filter(b => b.floorId !== floorId);\n if (project.virtualBoundaries)\n project.virtualBoundaries = project.virtualBoundaries.filter(b => b.floorId !== floorId);\n project.objects = project.objects.filter(o => o.floorId !== floorId);\n project.drawings = project.drawings.filter(d => d.floorId !== floorId);\n\n for (const o of project.objects) {\n // An opening whose wall is gone would float; a nested zone whose parent is gone becomes its own.\n if (o.barrierId && goneBarriers.has(o.barrierId)) {\n o.barrierId = undefined;\n o.offset = undefined;\n }\n if (o.parentId && goneObjects.has(o.parentId)) o.parentId = undefined;\n if (o.watchedIds) {\n o.watchedIds = o.watchedIds.filter(id => !goneObjects.has(id));\n if (!o.watchedIds.length) o.watchedIds = undefined;\n }\n if (o.servedFloorIds) {\n o.servedFloorIds = o.servedFloorIds.filter(id => id !== floorId);\n if (!o.servedFloorIds.length) o.servedFloorIds = undefined;\n }\n }\n // Nav nodes on the floor go, as do nodes bound to a deleted object; then any edge missing an end.\n if (project.navNodes) {\n const goneNodes = new Set(\n project.navNodes.filter(n => n.floorId === floorId || (n.objectId && goneObjects.has(n.objectId))).map(n => n.id),\n );\n project.navNodes = project.navNodes.filter(n => !goneNodes.has(n.id));\n project.navEdges = (project.navEdges ?? []).filter(\n e => !goneNodes.has(e.aId) && !goneNodes.has(e.bId) && !(e.objectId && goneObjects.has(e.objectId)),\n );\n }\n // The ontology references those objects too. Kept inline rather than calling model/topology's\n // pruneOntology, because topology imports this module and the cycle is not worth the reuse.\n if (project.portals)\n project.portals = project.portals.filter(\n p => !goneObjects.has(p.a) && !goneObjects.has(p.b) && !(p.openingId && goneObjects.has(p.openingId)),\n );\n const livePortals = new Set((project.portals ?? []).map(p => p.id));\n for (const zone of project.zones ?? []) zone.spaceIds = zone.spaceIds.filter(id => !goneObjects.has(id));\n for (const group of project.portalGroups ?? []) group.portalIds = group.portalIds.filter(id => livePortals.has(id));\n for (const b of project.buildings) if (b.roof?.floorId === floorId) b.roof = undefined;\n if (project.initialFloorId === floorId) project.initialFloorId = undefined;\n return removed;\n}\nexport function duplicateFloor(project: ProjectDocument, floorId: string): string {\n const floor = project.floors.find(f => f.id === floorId)!;\n const newId = uid();\n const map = new Map<string, string>();\n const cloneId = (id: string) => {\n if (!map.has(id)) map.set(id, uid());\n return map.get(id)!;\n };\n project.floors.push({\n ...floor,\n id: newId,\n name: `${floor.name} copy`,\n elevation: Math.max(\n ...project.floors.filter(f => f.buildingId === floor.buildingId).map(f => f.elevation + f.height),\n ),\n });\n project.junctions\n .filter(j => j.floorId === floorId)\n .forEach(j => project.junctions.push({ ...structuredClone(j), id: cloneId(j.id), floorId: newId }));\n project.barriers\n .filter(b => b.floorId === floorId)\n .forEach(b =>\n project.barriers.push({\n ...b,\n id: cloneId(b.id),\n floorId: newId,\n startId: cloneId(b.startId),\n endId: cloneId(b.endId),\n }),\n );\n project.objects\n .filter(o => o.floorId === floorId)\n .forEach(o =>\n project.objects.push({\n ...structuredClone(o),\n id: cloneId(o.id),\n floorId: newId,\n feedId: undefined,\n parentId: o.parentId ? cloneId(o.parentId) : undefined,\n barrierId: o.barrierId ? cloneId(o.barrierId) : undefined,\n servedFloorIds: o.servedFloorIds?.map(id => (id === floorId ? newId : id)),\n geometry:\n o.geometry?.mode === 'boundaries'\n ? {\n mode: 'boundaries',\n loops: o.geometry.loops.map(l => l.map(u => ({ ...u, edgeId: cloneId(u.edgeId) }))),\n }\n : o.geometry,\n }),\n );\n project.virtualBoundaries\n ?.filter(b => b.floorId === floorId)\n .forEach(b =>\n project.virtualBoundaries!.push({\n ...b,\n id: cloneId(b.id),\n floorId: newId,\n startId: cloneId(b.startId),\n endId: cloneId(b.endId),\n }),\n );\n project.drawings\n .filter(d => d.floorId === floorId)\n .forEach(d => project.drawings.push({ ...d, id: uid(), floorId: newId }));\n project.navNodes\n ?.filter(n => n.floorId === floorId)\n .forEach(n =>\n project.navNodes!.push({\n ...structuredClone(n),\n id: cloneId(n.id),\n floorId: newId,\n objectId: n.objectId && map.has(n.objectId) ? map.get(n.objectId)! : undefined,\n }),\n );\n project.navEdges\n ?.filter(e => map.has(e.aId) && map.has(e.bId))\n .forEach(e =>\n project.navEdges!.push({\n ...e,\n id: cloneId(e.id),\n aId: map.get(e.aId)!,\n bId: map.get(e.bId)!,\n objectId: e.objectId && map.has(e.objectId) ? map.get(e.objectId)! : undefined,\n }),\n );\n return newId;\n}\nexport function alignDrawing(\n imagePoints: [Point, Point],\n mapPoints: [Point, Point],\n): Pick<Drawing, 'origin' | 'scale' | 'rotation'> {\n const flipped: [Point, Point] = imagePoints.map(p => [p[0], -p[1]] as Point) as [Point, Point];\n const dl = distance(...flipped),\n ml = distance(...mapPoints);\n if (dl < 1 || ml < 0.01) throw new Error('Choose two distinct points.');\n const rotation =\n ((Math.atan2(mapPoints[1][1] - mapPoints[0][1], mapPoints[1][0] - mapPoints[0][0]) -\n Math.atan2(flipped[1][1] - flipped[0][1], flipped[1][0] - flipped[0][0])) *\n 180) /\n Math.PI;\n const scale = ml / dl;\n const offset = rotate([flipped[0][0] * scale, flipped[0][1] * scale], rotation);\n return { origin: [mapPoints[0][0] - offset[0], mapPoints[0][1] - offset[1]], scale, rotation };\n}\nexport const drawingCorners = (d: Drawing): Point[] =>\n (\n [\n [0, 0],\n [d.width, 0],\n [d.width, -d.height],\n [0, -d.height],\n ] as Point[]\n ).map(p => add(d.origin, rotate([p[0] * d.scale, p[1] * d.scale], d.rotation)));\n"],"names":["distance","a","b","rotate","p","degrees","r","DEG","WGS84_A","WGS84_E2","metresPerDegree","lat","s","geoOrigin","lngLat","bearing","moveOrigin","origin","east","north","m","moved","toLocal","d","toLngLat","add","closeRing","ring","openRing","ringArea","sum","i","q","objectArea","object","centroid","points","rectangle","center","width","depth","rotation","segmentsCross","c","side","s1","s2","s3","s4","EPS","segmentProjection","length","t","point","slopeElevation","slope","footprint","o","junctionIndices","indexedJunction","junctions","id","index","position","_a","ids","j","at","barrierEnds","project","barrier","objectPosition","l","objectRotation","pointInRing","inside","cross","intersects","on","x","y","containedBy","child","parent","polygonClipping","MIN_SEGMENT","MIN_WALL_LENGTH","OPENING_MIN_SEGMENT","barrierJoinPoint","floorId","existing","JOIN_EPS","hit","nearest","junctionIssue","cut","barrierStrokeIssue","atStart","ux","uy","cuts","tooShort","span","minimum","GEOMETRY_EPS","wall","boundaryEdges","w","vx","vy","det","MIN_RING_EDGE","issue","joinAt","uid","attachments","newId","oldEnd","replaceBoundaryUses","removeBarrier","barrierId","removed","preserveBoundary","openings","alive","n","nodes","e","addBarrier","kind","startId","endId","splitRoom","roomId","pa","pb","_b","splitBoundarySpace","len","dir","normal","poly","reach","c0","c1","halfPlane","clip","pieces","netArea","pg","usable","MIN_SPACE_AREA","drawnKey","drawn","weld","rings","closed","kept","prev","next","crossing","right","left","apply","target","outer","xs","ys","twin","crossings","denom","qp","u","deduped","from","removeFloor","f","goneObjects","goneBarriers","goneNodes","livePortals","zone","group","duplicateFloor","floor","map","cloneId","_c","drawingCorners"],"mappings":"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"}
|