@pascal-app/core 0.8.0 → 0.9.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.
Files changed (471) hide show
  1. package/dist/events/bus.d.ts +67 -13
  2. package/dist/events/bus.d.ts.map +1 -1
  3. package/dist/hooks/scene-registry/item-clip-registry.d.ts +18 -0
  4. package/dist/hooks/scene-registry/item-clip-registry.d.ts.map +1 -0
  5. package/dist/hooks/scene-registry/item-clip-registry.js +10 -0
  6. package/dist/hooks/scene-registry/scene-registry.d.ts +14 -23
  7. package/dist/hooks/scene-registry/scene-registry.d.ts.map +1 -1
  8. package/dist/hooks/scene-registry/scene-registry.js +59 -26
  9. package/dist/hooks/scene-registry/scene-registry.test.d.ts +2 -0
  10. package/dist/hooks/scene-registry/scene-registry.test.d.ts.map +1 -0
  11. package/dist/hooks/scene-registry/scene-registry.test.js +26 -0
  12. package/dist/hooks/spatial-grid/floor-placed-elevation.d.ts +14 -0
  13. package/dist/hooks/spatial-grid/floor-placed-elevation.d.ts.map +1 -0
  14. package/dist/hooks/spatial-grid/floor-placed-elevation.js +51 -0
  15. package/dist/hooks/spatial-grid/floor-placed-elevation.test.d.ts +2 -0
  16. package/dist/hooks/spatial-grid/floor-placed-elevation.test.d.ts.map +1 -0
  17. package/dist/hooks/spatial-grid/floor-placed-elevation.test.js +366 -0
  18. package/dist/hooks/spatial-grid/spatial-grid-manager.d.ts +79 -11
  19. package/dist/hooks/spatial-grid/spatial-grid-manager.d.ts.map +1 -1
  20. package/dist/hooks/spatial-grid/spatial-grid-manager.js +508 -141
  21. package/dist/hooks/spatial-grid/spatial-grid-sync.d.ts +28 -1
  22. package/dist/hooks/spatial-grid/spatial-grid-sync.d.ts.map +1 -1
  23. package/dist/hooks/spatial-grid/spatial-grid-sync.js +109 -18
  24. package/dist/hooks/spatial-grid/wall-slab-overlap.test.d.ts +2 -0
  25. package/dist/hooks/spatial-grid/wall-slab-overlap.test.d.ts.map +1 -0
  26. package/dist/hooks/spatial-grid/wall-slab-overlap.test.js +363 -0
  27. package/dist/index.d.ts +36 -8
  28. package/dist/index.d.ts.map +1 -1
  29. package/dist/index.js +33 -6
  30. package/dist/lib/level-name.d.ts +4 -0
  31. package/dist/lib/level-name.d.ts.map +1 -0
  32. package/dist/lib/level-name.js +10 -0
  33. package/dist/lib/measurement-geometry.d.ts +19 -0
  34. package/dist/lib/measurement-geometry.d.ts.map +1 -0
  35. package/dist/lib/measurement-geometry.js +232 -0
  36. package/dist/lib/measurement-geometry.test.d.ts +2 -0
  37. package/dist/lib/measurement-geometry.test.d.ts.map +1 -0
  38. package/dist/lib/measurement-geometry.test.js +102 -0
  39. package/dist/lib/polygon-geometry.d.ts +0 -1
  40. package/dist/lib/polygon-geometry.d.ts.map +1 -1
  41. package/dist/lib/polygon-geometry.js +0 -18
  42. package/dist/lib/polygon-relations.d.ts +10 -0
  43. package/dist/lib/polygon-relations.d.ts.map +1 -0
  44. package/dist/lib/polygon-relations.js +73 -0
  45. package/dist/lib/selection-proxy.d.ts +4 -0
  46. package/dist/lib/selection-proxy.d.ts.map +1 -0
  47. package/dist/lib/selection-proxy.js +12 -0
  48. package/dist/lib/slab-polygon.d.ts +31 -2
  49. package/dist/lib/slab-polygon.d.ts.map +1 -1
  50. package/dist/lib/slab-polygon.js +525 -31
  51. package/dist/lib/slab-polygon.test.d.ts +2 -0
  52. package/dist/lib/slab-polygon.test.d.ts.map +1 -0
  53. package/dist/lib/slab-polygon.test.js +635 -0
  54. package/dist/lib/slots.d.ts +14 -0
  55. package/dist/lib/slots.d.ts.map +1 -0
  56. package/dist/lib/slots.js +26 -0
  57. package/dist/lib/space-detection-pause.test.d.ts +2 -0
  58. package/dist/lib/space-detection-pause.test.d.ts.map +1 -0
  59. package/dist/lib/space-detection-pause.test.js +42 -0
  60. package/dist/lib/space-detection.d.ts +54 -2
  61. package/dist/lib/space-detection.d.ts.map +1 -1
  62. package/dist/lib/space-detection.js +599 -124
  63. package/dist/lib/space-detection.test.d.ts +2 -0
  64. package/dist/lib/space-detection.test.d.ts.map +1 -0
  65. package/dist/lib/space-detection.test.js +376 -0
  66. package/dist/lib/wall-distance.d.ts +60 -0
  67. package/dist/lib/wall-distance.d.ts.map +1 -0
  68. package/dist/lib/wall-distance.js +85 -0
  69. package/dist/lib/zone-quantities.d.ts +21 -0
  70. package/dist/lib/zone-quantities.d.ts.map +1 -0
  71. package/dist/lib/zone-quantities.js +183 -0
  72. package/dist/lib/zone-quantities.test.d.ts +2 -0
  73. package/dist/lib/zone-quantities.test.d.ts.map +1 -0
  74. package/dist/lib/zone-quantities.test.js +82 -0
  75. package/dist/material-library.d.ts +20 -1
  76. package/dist/material-library.d.ts.map +1 -1
  77. package/dist/material-library.js +3737 -200
  78. package/dist/registry/__bench__/relations-resolver.bench.d.ts +15 -0
  79. package/dist/registry/__bench__/relations-resolver.bench.d.ts.map +1 -0
  80. package/dist/registry/__bench__/relations-resolver.bench.js +170 -0
  81. package/dist/registry/handles.d.ts +394 -0
  82. package/dist/registry/handles.d.ts.map +1 -0
  83. package/dist/registry/handles.js +24 -0
  84. package/dist/registry/index.d.ts +7 -0
  85. package/dist/registry/index.d.ts.map +1 -0
  86. package/dist/registry/index.js +4 -0
  87. package/dist/registry/registry.d.ts +136 -0
  88. package/dist/registry/registry.d.ts.map +1 -0
  89. package/dist/registry/registry.js +282 -0
  90. package/dist/registry/registry.test.d.ts +2 -0
  91. package/dist/registry/registry.test.d.ts.map +1 -0
  92. package/dist/registry/registry.test.js +196 -0
  93. package/dist/registry/relations-resolver.d.ts +42 -0
  94. package/dist/registry/relations-resolver.d.ts.map +1 -0
  95. package/dist/registry/relations-resolver.js +77 -0
  96. package/dist/registry/relations-resolver.test.d.ts +2 -0
  97. package/dist/registry/relations-resolver.test.d.ts.map +1 -0
  98. package/dist/registry/relations-resolver.test.js +183 -0
  99. package/dist/registry/scene-api.d.ts +44 -0
  100. package/dist/registry/scene-api.d.ts.map +1 -0
  101. package/dist/registry/scene-api.js +111 -0
  102. package/dist/registry/scene-api.test.d.ts +2 -0
  103. package/dist/registry/scene-api.test.d.ts.map +1 -0
  104. package/dist/registry/scene-api.test.js +183 -0
  105. package/dist/registry/subtree.d.ts +67 -0
  106. package/dist/registry/subtree.d.ts.map +1 -0
  107. package/dist/registry/subtree.js +123 -0
  108. package/dist/registry/subtree.test.d.ts +2 -0
  109. package/dist/registry/subtree.test.d.ts.map +1 -0
  110. package/dist/registry/subtree.test.js +163 -0
  111. package/dist/registry/types.d.ts +2099 -0
  112. package/dist/registry/types.d.ts.map +1 -0
  113. package/dist/registry/types.js +1 -0
  114. package/dist/schema/index.d.ts +35 -4
  115. package/dist/schema/index.d.ts.map +1 -1
  116. package/dist/schema/index.js +32 -4
  117. package/dist/schema/material.d.ts +13 -2
  118. package/dist/schema/material.d.ts.map +1 -1
  119. package/dist/schema/material.js +17 -5
  120. package/dist/schema/material.test.d.ts +2 -0
  121. package/dist/schema/material.test.d.ts.map +1 -0
  122. package/dist/schema/material.test.js +43 -0
  123. package/dist/schema/nodes/box-vent.d.ts +74 -0
  124. package/dist/schema/nodes/box-vent.d.ts.map +1 -0
  125. package/dist/schema/nodes/box-vent.js +63 -0
  126. package/dist/schema/nodes/building.d.ts +1 -1
  127. package/dist/schema/nodes/building.d.ts.map +1 -1
  128. package/dist/schema/nodes/building.js +3 -2
  129. package/dist/schema/nodes/cabinet.d.ts +534 -0
  130. package/dist/schema/nodes/cabinet.d.ts.map +1 -0
  131. package/dist/schema/nodes/cabinet.js +137 -0
  132. package/dist/schema/nodes/ceiling.d.ts +5 -2
  133. package/dist/schema/nodes/ceiling.d.ts.map +1 -1
  134. package/dist/schema/nodes/ceiling.js +5 -1
  135. package/dist/schema/nodes/chimney.d.ts +158 -0
  136. package/dist/schema/nodes/chimney.d.ts.map +1 -0
  137. package/dist/schema/nodes/chimney.js +67 -0
  138. package/dist/schema/nodes/column.d.ts +600 -7
  139. package/dist/schema/nodes/column.d.ts.map +1 -1
  140. package/dist/schema/nodes/column.js +589 -6
  141. package/dist/schema/nodes/cupola.d.ts +66 -0
  142. package/dist/schema/nodes/cupola.d.ts.map +1 -0
  143. package/dist/schema/nodes/cupola.js +28 -0
  144. package/dist/schema/nodes/door.d.ts +13 -5
  145. package/dist/schema/nodes/door.d.ts.map +1 -1
  146. package/dist/schema/nodes/door.js +12 -0
  147. package/dist/schema/nodes/dormer.d.ts +228 -0
  148. package/dist/schema/nodes/dormer.d.ts.map +1 -0
  149. package/dist/schema/nodes/dormer.js +119 -0
  150. package/dist/schema/nodes/downspout.d.ts +75 -0
  151. package/dist/schema/nodes/downspout.d.ts.map +1 -0
  152. package/dist/schema/nodes/downspout.js +63 -0
  153. package/dist/schema/nodes/duct-fitting.d.ts +91 -0
  154. package/dist/schema/nodes/duct-fitting.d.ts.map +1 -0
  155. package/dist/schema/nodes/duct-fitting.js +92 -0
  156. package/dist/schema/nodes/duct-segment.d.ts +61 -0
  157. package/dist/schema/nodes/duct-segment.d.ts.map +1 -0
  158. package/dist/schema/nodes/duct-segment.js +73 -0
  159. package/dist/schema/nodes/duct-terminal.d.ts +57 -0
  160. package/dist/schema/nodes/duct-terminal.d.ts.map +1 -0
  161. package/dist/schema/nodes/duct-terminal.js +51 -0
  162. package/dist/schema/nodes/elevator.d.ts +106 -0
  163. package/dist/schema/nodes/elevator.d.ts.map +1 -0
  164. package/dist/schema/nodes/elevator.js +57 -0
  165. package/dist/schema/nodes/eyebrow-vent.d.ts +68 -0
  166. package/dist/schema/nodes/eyebrow-vent.d.ts.map +1 -0
  167. package/dist/schema/nodes/eyebrow-vent.js +40 -0
  168. package/dist/schema/nodes/fence.d.ts +19 -2
  169. package/dist/schema/nodes/fence.d.ts.map +1 -1
  170. package/dist/schema/nodes/fence.js +27 -2
  171. package/dist/schema/nodes/gutter.d.ts +84 -0
  172. package/dist/schema/nodes/gutter.d.ts.map +1 -0
  173. package/dist/schema/nodes/gutter.js +76 -0
  174. package/dist/schema/nodes/hvac-equipment.d.ts +63 -0
  175. package/dist/schema/nodes/hvac-equipment.d.ts.map +1 -0
  176. package/dist/schema/nodes/hvac-equipment.js +55 -0
  177. package/dist/schema/nodes/item.d.ts +12 -0
  178. package/dist/schema/nodes/item.d.ts.map +1 -1
  179. package/dist/schema/nodes/item.js +20 -0
  180. package/dist/schema/nodes/level.d.ts +1 -1
  181. package/dist/schema/nodes/level.d.ts.map +1 -1
  182. package/dist/schema/nodes/level.js +4 -0
  183. package/dist/schema/nodes/lineset.d.ts +42 -0
  184. package/dist/schema/nodes/lineset.d.ts.map +1 -0
  185. package/dist/schema/nodes/lineset.js +38 -0
  186. package/dist/schema/nodes/liquid-line.d.ts +34 -0
  187. package/dist/schema/nodes/liquid-line.d.ts.map +1 -0
  188. package/dist/schema/nodes/liquid-line.js +24 -0
  189. package/dist/schema/nodes/measurement.d.ts +306 -0
  190. package/dist/schema/nodes/measurement.d.ts.map +1 -0
  191. package/dist/schema/nodes/measurement.js +87 -0
  192. package/dist/schema/nodes/measurement.test.d.ts +2 -0
  193. package/dist/schema/nodes/measurement.test.d.ts.map +1 -0
  194. package/dist/schema/nodes/measurement.test.js +139 -0
  195. package/dist/schema/nodes/pipe-fitting.d.ts +56 -0
  196. package/dist/schema/nodes/pipe-fitting.d.ts.map +1 -0
  197. package/dist/schema/nodes/pipe-fitting.js +45 -0
  198. package/dist/schema/nodes/pipe-segment.d.ts +48 -0
  199. package/dist/schema/nodes/pipe-segment.d.ts.map +1 -0
  200. package/dist/schema/nodes/pipe-segment.js +36 -0
  201. package/dist/schema/nodes/pipe-trap.d.ts +43 -0
  202. package/dist/schema/nodes/pipe-trap.d.ts.map +1 -0
  203. package/dist/schema/nodes/pipe-trap.js +36 -0
  204. package/dist/schema/nodes/ridge-vent-defaults.test.d.ts +2 -0
  205. package/dist/schema/nodes/ridge-vent-defaults.test.d.ts.map +1 -0
  206. package/dist/schema/nodes/ridge-vent-defaults.test.js +205 -0
  207. package/dist/schema/nodes/ridge-vent.d.ts +82 -0
  208. package/dist/schema/nodes/ridge-vent.d.ts.map +1 -0
  209. package/dist/schema/nodes/ridge-vent.js +248 -0
  210. package/dist/schema/nodes/roof-segment-shape.d.ts +90 -0
  211. package/dist/schema/nodes/roof-segment-shape.d.ts.map +1 -0
  212. package/dist/schema/nodes/roof-segment-shape.js +318 -0
  213. package/dist/schema/nodes/roof-segment-shape.test.d.ts +2 -0
  214. package/dist/schema/nodes/roof-segment-shape.test.d.ts.map +1 -0
  215. package/dist/schema/nodes/roof-segment-shape.test.js +175 -0
  216. package/dist/schema/nodes/roof-segment-surface.test.d.ts +2 -0
  217. package/dist/schema/nodes/roof-segment-surface.test.d.ts.map +1 -0
  218. package/dist/schema/nodes/roof-segment-surface.test.js +48 -0
  219. package/dist/schema/nodes/roof-segment-trim.test.d.ts +2 -0
  220. package/dist/schema/nodes/roof-segment-trim.test.d.ts.map +1 -0
  221. package/dist/schema/nodes/roof-segment-trim.test.js +107 -0
  222. package/dist/schema/nodes/roof-segment-walls.d.ts +101 -0
  223. package/dist/schema/nodes/roof-segment-walls.d.ts.map +1 -0
  224. package/dist/schema/nodes/roof-segment-walls.js +330 -0
  225. package/dist/schema/nodes/roof-segment-walls.test.d.ts +2 -0
  226. package/dist/schema/nodes/roof-segment-walls.test.d.ts.map +1 -0
  227. package/dist/schema/nodes/roof-segment-walls.test.js +92 -0
  228. package/dist/schema/nodes/roof-segment.d.ts +273 -3
  229. package/dist/schema/nodes/roof-segment.d.ts.map +1 -1
  230. package/dist/schema/nodes/roof-segment.js +539 -3
  231. package/dist/schema/nodes/roof.d.ts +8 -8
  232. package/dist/schema/nodes/roof.d.ts.map +1 -1
  233. package/dist/schema/nodes/roof.js +4 -16
  234. package/dist/schema/nodes/shelf.d.ts +106 -0
  235. package/dist/schema/nodes/shelf.d.ts.map +1 -0
  236. package/dist/schema/nodes/shelf.js +90 -0
  237. package/dist/schema/nodes/site.d.ts +1 -122
  238. package/dist/schema/nodes/site.d.ts.map +1 -1
  239. package/dist/schema/nodes/site.js +2 -6
  240. package/dist/schema/nodes/skylight.d.ts +279 -0
  241. package/dist/schema/nodes/skylight.d.ts.map +1 -0
  242. package/dist/schema/nodes/skylight.js +152 -0
  243. package/dist/schema/nodes/slab.d.ts +5 -2
  244. package/dist/schema/nodes/slab.d.ts.map +1 -1
  245. package/dist/schema/nodes/slab.js +5 -1
  246. package/dist/schema/nodes/solar-panel.d.ts +117 -0
  247. package/dist/schema/nodes/solar-panel.d.ts.map +1 -0
  248. package/dist/schema/nodes/solar-panel.js +47 -0
  249. package/dist/schema/nodes/stair-segment.d.ts +4 -4
  250. package/dist/schema/nodes/stair.d.ts +13 -12
  251. package/dist/schema/nodes/stair.d.ts.map +1 -1
  252. package/dist/schema/nodes/stair.js +3 -0
  253. package/dist/schema/nodes/surface-hole-metadata.d.ts +2 -0
  254. package/dist/schema/nodes/surface-hole-metadata.d.ts.map +1 -1
  255. package/dist/schema/nodes/surface-hole-metadata.js +3 -1
  256. package/dist/schema/nodes/turbine-vent.d.ts +68 -0
  257. package/dist/schema/nodes/turbine-vent.d.ts.map +1 -0
  258. package/dist/schema/nodes/turbine-vent.js +41 -0
  259. package/dist/schema/nodes/wall.d.ts +245 -6
  260. package/dist/schema/nodes/wall.d.ts.map +1 -1
  261. package/dist/schema/nodes/wall.js +257 -0
  262. package/dist/schema/nodes/wall.test.d.ts +2 -0
  263. package/dist/schema/nodes/wall.test.d.ts.map +1 -0
  264. package/dist/schema/nodes/wall.test.js +208 -0
  265. package/dist/schema/nodes/window.d.ts +11 -3
  266. package/dist/schema/nodes/window.d.ts.map +1 -1
  267. package/dist/schema/nodes/window.js +12 -0
  268. package/dist/schema/nodes/zone.d.ts +2 -0
  269. package/dist/schema/nodes/zone.d.ts.map +1 -1
  270. package/dist/schema/nodes/zone.js +6 -0
  271. package/dist/schema/scene-material.d.ts +41 -0
  272. package/dist/schema/scene-material.d.ts.map +1 -0
  273. package/dist/schema/scene-material.js +9 -0
  274. package/dist/schema/types.d.ts +2850 -655
  275. package/dist/schema/types.d.ts.map +1 -1
  276. package/dist/schema/types.js +49 -0
  277. package/dist/services/alignment-anchors.d.ts +100 -0
  278. package/dist/services/alignment-anchors.d.ts.map +1 -0
  279. package/dist/services/alignment-anchors.js +312 -0
  280. package/dist/services/alignment-anchors.test.d.ts +2 -0
  281. package/dist/services/alignment-anchors.test.d.ts.map +1 -0
  282. package/dist/services/alignment-anchors.test.js +383 -0
  283. package/dist/services/alignment.d.ts +131 -0
  284. package/dist/services/alignment.d.ts.map +1 -0
  285. package/dist/services/alignment.js +171 -0
  286. package/dist/services/alignment.test.d.ts +2 -0
  287. package/dist/services/alignment.test.d.ts.map +1 -0
  288. package/dist/services/alignment.test.js +92 -0
  289. package/dist/services/drag-session.d.ts +47 -0
  290. package/dist/services/drag-session.d.ts.map +1 -0
  291. package/dist/services/drag-session.js +100 -0
  292. package/dist/services/drag-session.test.d.ts +2 -0
  293. package/dist/services/drag-session.test.d.ts.map +1 -0
  294. package/dist/services/drag-session.test.js +219 -0
  295. package/dist/services/hosting.d.ts +88 -0
  296. package/dist/services/hosting.d.ts.map +1 -0
  297. package/dist/services/hosting.js +131 -0
  298. package/dist/services/hosting.test.d.ts +2 -0
  299. package/dist/services/hosting.test.d.ts.map +1 -0
  300. package/dist/services/hosting.test.js +230 -0
  301. package/dist/services/index.d.ts +13 -0
  302. package/dist/services/index.d.ts.map +1 -0
  303. package/dist/services/index.js +12 -0
  304. package/dist/services/level-height.d.ts +28 -0
  305. package/dist/services/level-height.d.ts.map +1 -0
  306. package/dist/services/level-height.js +62 -0
  307. package/dist/services/movement.d.ts +48 -0
  308. package/dist/services/movement.d.ts.map +1 -0
  309. package/dist/services/movement.js +65 -0
  310. package/dist/services/movement.test.d.ts +2 -0
  311. package/dist/services/movement.test.d.ts.map +1 -0
  312. package/dist/services/movement.test.js +133 -0
  313. package/dist/services/opening-guides.d.ts +141 -0
  314. package/dist/services/opening-guides.d.ts.map +1 -0
  315. package/dist/services/opening-guides.js +267 -0
  316. package/dist/services/opening-guides.test.d.ts +2 -0
  317. package/dist/services/opening-guides.test.d.ts.map +1 -0
  318. package/dist/services/opening-guides.test.js +208 -0
  319. package/dist/services/port-connectivity.d.ts +115 -0
  320. package/dist/services/port-connectivity.d.ts.map +1 -0
  321. package/dist/services/port-connectivity.js +300 -0
  322. package/dist/services/port-connectivity.test.d.ts +2 -0
  323. package/dist/services/port-connectivity.test.d.ts.map +1 -0
  324. package/dist/services/port-connectivity.test.js +297 -0
  325. package/dist/services/riser-diagram.d.ts +40 -0
  326. package/dist/services/riser-diagram.d.ts.map +1 -0
  327. package/dist/services/riser-diagram.js +110 -0
  328. package/dist/services/riser-diagram.test.d.ts +2 -0
  329. package/dist/services/riser-diagram.test.d.ts.map +1 -0
  330. package/dist/services/riser-diagram.test.js +66 -0
  331. package/dist/services/single-undo-dance.test.d.ts +2 -0
  332. package/dist/services/single-undo-dance.test.d.ts.map +1 -0
  333. package/dist/services/single-undo-dance.test.js +210 -0
  334. package/dist/services/snap.d.ts +80 -0
  335. package/dist/services/snap.d.ts.map +1 -0
  336. package/dist/services/snap.js +140 -0
  337. package/dist/services/snap.test.d.ts +2 -0
  338. package/dist/services/snap.test.d.ts.map +1 -0
  339. package/dist/services/snap.test.js +137 -0
  340. package/dist/services/system-graph.d.ts +30 -0
  341. package/dist/services/system-graph.d.ts.map +1 -0
  342. package/dist/services/system-graph.js +164 -0
  343. package/dist/services/system-graph.test.d.ts +2 -0
  344. package/dist/services/system-graph.test.d.ts.map +1 -0
  345. package/dist/services/system-graph.test.js +138 -0
  346. package/dist/services/validate-dwv.d.ts +32 -0
  347. package/dist/services/validate-dwv.d.ts.map +1 -0
  348. package/dist/services/validate-dwv.js +118 -0
  349. package/dist/services/validate-dwv.test.d.ts +2 -0
  350. package/dist/services/validate-dwv.test.d.ts.map +1 -0
  351. package/dist/services/validate-dwv.test.js +109 -0
  352. package/dist/solar-panel-presets.d.ts +17 -0
  353. package/dist/solar-panel-presets.d.ts.map +1 -0
  354. package/dist/solar-panel-presets.js +43 -0
  355. package/dist/store/actions/node-actions.d.ts +14 -2
  356. package/dist/store/actions/node-actions.d.ts.map +1 -1
  357. package/dist/store/actions/node-actions.js +585 -15
  358. package/dist/store/actions/node-mutation-sanitize.test.d.ts +2 -0
  359. package/dist/store/actions/node-mutation-sanitize.test.d.ts.map +1 -0
  360. package/dist/store/actions/node-mutation-sanitize.test.js +147 -0
  361. package/dist/store/actions/reparent.test.d.ts +2 -0
  362. package/dist/store/actions/reparent.test.d.ts.map +1 -0
  363. package/dist/store/actions/reparent.test.js +212 -0
  364. package/dist/store/actions/ridge-vent-update.test.d.ts +2 -0
  365. package/dist/store/actions/ridge-vent-update.test.d.ts.map +1 -0
  366. package/dist/store/actions/ridge-vent-update.test.js +264 -0
  367. package/dist/store/history-control.d.ts +11 -0
  368. package/dist/store/history-control.d.ts.map +1 -1
  369. package/dist/store/history-control.js +33 -0
  370. package/dist/store/use-interactive.d.ts +39 -0
  371. package/dist/store/use-interactive.d.ts.map +1 -1
  372. package/dist/store/use-interactive.js +75 -0
  373. package/dist/store/use-live-node-overrides.d.ts +22 -0
  374. package/dist/store/use-live-node-overrides.d.ts.map +1 -0
  375. package/dist/store/use-live-node-overrides.js +59 -0
  376. package/dist/store/use-scene-dirty-tracking.test.d.ts +2 -0
  377. package/dist/store/use-scene-dirty-tracking.test.d.ts.map +1 -0
  378. package/dist/store/use-scene-dirty-tracking.test.js +68 -0
  379. package/dist/store/use-scene-elevator-migration.test.d.ts +2 -0
  380. package/dist/store/use-scene-elevator-migration.test.d.ts.map +1 -0
  381. package/dist/store/use-scene-elevator-migration.test.js +109 -0
  382. package/dist/store/use-scene-measurement-roundtrip.test.d.ts +2 -0
  383. package/dist/store/use-scene-measurement-roundtrip.test.d.ts.map +1 -0
  384. package/dist/store/use-scene-measurement-roundtrip.test.js +97 -0
  385. package/dist/store/use-scene-plugins.test.d.ts +2 -0
  386. package/dist/store/use-scene-plugins.test.d.ts.map +1 -0
  387. package/dist/store/use-scene-plugins.test.js +51 -0
  388. package/dist/store/use-scene-wall-slot-migration.test.d.ts +2 -0
  389. package/dist/store/use-scene-wall-slot-migration.test.d.ts.map +1 -0
  390. package/dist/store/use-scene-wall-slot-migration.test.js +210 -0
  391. package/dist/store/use-scene-window-migration.test.d.ts +2 -0
  392. package/dist/store/use-scene-window-migration.test.d.ts.map +1 -0
  393. package/dist/store/use-scene-window-migration.test.js +85 -0
  394. package/dist/store/use-scene.d.ts +28 -2
  395. package/dist/store/use-scene.d.ts.map +1 -1
  396. package/dist/store/use-scene.js +546 -49
  397. package/dist/systems/elevator/elevator-dispatch.d.ts +12 -0
  398. package/dist/systems/elevator/elevator-dispatch.d.ts.map +1 -0
  399. package/dist/systems/elevator/elevator-dispatch.js +57 -0
  400. package/dist/systems/elevator/elevator-geometry.d.ts +15 -0
  401. package/dist/systems/elevator/elevator-geometry.d.ts.map +1 -0
  402. package/dist/systems/elevator/elevator-geometry.js +50 -0
  403. package/dist/systems/elevator/elevator-opening-sync.d.ts +6 -0
  404. package/dist/systems/elevator/elevator-opening-sync.d.ts.map +1 -0
  405. package/dist/systems/elevator/elevator-opening-sync.js +218 -0
  406. package/dist/systems/elevator/elevator-opening-sync.test.d.ts +2 -0
  407. package/dist/systems/elevator/elevator-opening-sync.test.d.ts.map +1 -0
  408. package/dist/systems/elevator/elevator-opening-sync.test.js +146 -0
  409. package/dist/systems/elevator/elevator-opening-system.d.ts +2 -0
  410. package/dist/systems/elevator/elevator-opening-system.d.ts.map +1 -0
  411. package/dist/systems/elevator/elevator-opening-system.js +48 -0
  412. package/dist/systems/elevator/elevator-runtime-system.d.ts +2 -0
  413. package/dist/systems/elevator/elevator-runtime-system.d.ts.map +1 -0
  414. package/dist/systems/elevator/elevator-runtime-system.js +8 -0
  415. package/dist/systems/elevator/elevator-runtime.d.ts +18 -0
  416. package/dist/systems/elevator/elevator-runtime.d.ts.map +1 -0
  417. package/dist/systems/elevator/elevator-runtime.js +225 -0
  418. package/dist/systems/elevator/elevator-runtime.test.d.ts +2 -0
  419. package/dist/systems/elevator/elevator-runtime.test.d.ts.map +1 -0
  420. package/dist/systems/elevator/elevator-runtime.test.js +64 -0
  421. package/dist/systems/elevator/elevator-service.d.ts +19 -0
  422. package/dist/systems/elevator/elevator-service.d.ts.map +1 -0
  423. package/dist/systems/elevator/elevator-service.js +111 -0
  424. package/dist/systems/fence/fence-centerline.d.ts +12 -0
  425. package/dist/systems/fence/fence-centerline.d.ts.map +1 -0
  426. package/dist/systems/fence/fence-centerline.js +37 -0
  427. package/dist/systems/fence/fence-spline.d.ts +39 -0
  428. package/dist/systems/fence/fence-spline.d.ts.map +1 -0
  429. package/dist/systems/fence/fence-spline.js +196 -0
  430. package/dist/systems/fence/fence-spline.test.d.ts +2 -0
  431. package/dist/systems/fence/fence-spline.test.d.ts.map +1 -0
  432. package/dist/systems/fence/fence-spline.test.js +136 -0
  433. package/dist/systems/stair/stair-footprint.d.ts +44 -0
  434. package/dist/systems/stair/stair-footprint.d.ts.map +1 -0
  435. package/dist/systems/stair/stair-footprint.js +178 -0
  436. package/dist/systems/stair/stair-opening-preview.d.ts +2447 -0
  437. package/dist/systems/stair/stair-opening-preview.d.ts.map +1 -0
  438. package/dist/systems/stair/stair-opening-preview.js +93 -0
  439. package/dist/systems/stair/stair-opening-preview.test.d.ts +2 -0
  440. package/dist/systems/stair/stair-opening-preview.test.d.ts.map +1 -0
  441. package/dist/systems/stair/stair-opening-preview.test.js +80 -0
  442. package/dist/systems/stair/stair-opening-sync.d.ts.map +1 -1
  443. package/dist/systems/stair/stair-opening-sync.js +155 -147
  444. package/dist/systems/stair/stair-opening-sync.test.js +424 -2
  445. package/dist/systems/stair/stair-opening-system.d.ts +2 -0
  446. package/dist/systems/stair/stair-opening-system.d.ts.map +1 -0
  447. package/dist/systems/stair/stair-opening-system.js +104 -0
  448. package/dist/systems/wall/wall-mitering.d.ts.map +1 -1
  449. package/dist/systems/wall/wall-mitering.js +38 -2
  450. package/dist/systems/wall/wall-mitering.test.d.ts +2 -0
  451. package/dist/systems/wall/wall-mitering.test.d.ts.map +1 -0
  452. package/dist/systems/wall/wall-mitering.test.js +63 -0
  453. package/dist/systems/wall/wall-move.d.ts +48 -0
  454. package/dist/systems/wall/wall-move.d.ts.map +1 -0
  455. package/dist/systems/wall/wall-move.js +193 -0
  456. package/dist/utils/clone-scene-graph.d.ts +7 -4
  457. package/dist/utils/clone-scene-graph.d.ts.map +1 -1
  458. package/dist/utils/clone-scene-graph.js +29 -7
  459. package/dist/utils/clone-scene-graph.test.d.ts +2 -0
  460. package/dist/utils/clone-scene-graph.test.d.ts.map +1 -0
  461. package/dist/utils/clone-scene-graph.test.js +62 -0
  462. package/dist/utils/heal-scene-graph.d.ts +18 -0
  463. package/dist/utils/heal-scene-graph.d.ts.map +1 -0
  464. package/dist/utils/heal-scene-graph.js +90 -0
  465. package/dist/utils/heal-scene-graph.test.d.ts +2 -0
  466. package/dist/utils/heal-scene-graph.test.d.ts.map +1 -0
  467. package/dist/utils/heal-scene-graph.test.js +88 -0
  468. package/dist/validation/validate-build-json.d.ts +44 -0
  469. package/dist/validation/validate-build-json.d.ts.map +1 -0
  470. package/dist/validation/validate-build-json.js +256 -0
  471. package/package.json +11 -4
@@ -0,0 +1,12 @@
1
+ import type { AnyNode, AnyNodeId } from '../../schema';
2
+ import type { ElevatorInteractiveState } from '../../store/use-interactive';
3
+ type ElevatorRuntimeMap = Record<AnyNodeId, ElevatorInteractiveState>;
4
+ type ResolveElevatorDispatchTargetArgs = {
5
+ elevators: ElevatorRuntimeMap;
6
+ levelId: AnyNodeId;
7
+ nodes: Record<string, AnyNode>;
8
+ requestedElevatorId: AnyNodeId;
9
+ };
10
+ export declare function resolveElevatorDispatchTarget({ elevators, levelId, nodes, requestedElevatorId, }: ResolveElevatorDispatchTargetArgs): AnyNodeId;
11
+ export {};
12
+ //# sourceMappingURL=elevator-dispatch.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"elevator-dispatch.d.ts","sourceRoot":"","sources":["../../../src/systems/elevator/elevator-dispatch.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,SAAS,EAAgB,MAAM,cAAc,CAAA;AACpE,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,6BAA6B,CAAA;AAG3E,KAAK,kBAAkB,GAAG,MAAM,CAAC,SAAS,EAAE,wBAAwB,CAAC,CAAA;AAErE,KAAK,iCAAiC,GAAG;IACvC,SAAS,EAAE,kBAAkB,CAAA;IAC7B,OAAO,EAAE,SAAS,CAAA;IAClB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAC9B,mBAAmB,EAAE,SAAS,CAAA;CAC/B,CAAA;AAsCD,wBAAgB,6BAA6B,CAAC,EAC5C,SAAS,EACT,OAAO,EACP,KAAK,EACL,mBAAmB,GACpB,EAAE,iCAAiC,GAAG,SAAS,CAmC/C"}
@@ -0,0 +1,57 @@
1
+ import { resolveElevatorServiceLevels } from './elevator-service';
2
+ function getRuntimeLevelId(runtime, elevator) {
3
+ return runtime?.currentLevelId ?? elevator.defaultLevelId ?? elevator.fromLevelId ?? null;
4
+ }
5
+ function scoreDispatchCandidate({ elevator, elevators, levelId, nodes, }) {
6
+ if ((elevator.disabledLevelIds ?? []).includes(levelId))
7
+ return null;
8
+ if ((elevator.serviceOnlyLevelIds ?? []).includes(levelId))
9
+ return null;
10
+ const serviceLevels = resolveElevatorServiceLevels(elevator, nodes);
11
+ const targetIndex = serviceLevels.findIndex((level) => level.id === levelId);
12
+ if (targetIndex < 0)
13
+ return null;
14
+ const runtime = elevators[elevator.id];
15
+ const runtimeLevelId = getRuntimeLevelId(runtime, elevator);
16
+ const currentIndex = runtimeLevelId
17
+ ? serviceLevels.findIndex((level) => level.id === runtimeLevelId)
18
+ : -1;
19
+ const resolvedCurrentIndex = currentIndex >= 0 ? currentIndex : 0;
20
+ const distance = Math.abs(targetIndex - resolvedCurrentIndex);
21
+ const queuePenalty = (runtime?.queue.length ?? 0) * 2 + (runtime?.targetLevelId ? 1 : 0);
22
+ const motionPenalty = runtime?.phase === 'moving' || runtime?.phase === 'closing' ? 0.5 : 0;
23
+ const openPenalty = runtime?.phase === 'open' || runtime?.phase === 'opening' ? 0.2 : 0;
24
+ return distance + queuePenalty + motionPenalty + openPenalty;
25
+ }
26
+ export function resolveElevatorDispatchTarget({ elevators, levelId, nodes, requestedElevatorId, }) {
27
+ const requestedElevator = nodes[requestedElevatorId];
28
+ if (!(requestedElevator?.type === 'elevator' && requestedElevator.parentId)) {
29
+ return requestedElevatorId;
30
+ }
31
+ const building = nodes[requestedElevator.parentId];
32
+ if (building?.type !== 'building') {
33
+ return requestedElevatorId;
34
+ }
35
+ let bestElevatorId = null;
36
+ let bestScore = Number.POSITIVE_INFINITY;
37
+ for (const childId of building.children) {
38
+ const candidate = nodes[childId];
39
+ if (!(candidate?.type === 'elevator' && candidate.visible !== false))
40
+ continue;
41
+ const score = scoreDispatchCandidate({
42
+ elevator: candidate,
43
+ elevators,
44
+ levelId,
45
+ nodes,
46
+ });
47
+ if (score === null)
48
+ continue;
49
+ const tieBreaker = candidate.id === requestedElevatorId ? -0.01 : 0;
50
+ const finalScore = score + tieBreaker;
51
+ if (finalScore < bestScore) {
52
+ bestScore = finalScore;
53
+ bestElevatorId = candidate.id;
54
+ }
55
+ }
56
+ return bestElevatorId ?? requestedElevatorId;
57
+ }
@@ -0,0 +1,15 @@
1
+ import type { ElevatorDoorPanelStyle, ElevatorDoorStyle, ElevatorNode, ElevatorShaftStyle } from '../../schema';
2
+ export type ElevatorDoorSide = 'left' | 'right';
3
+ export declare function getResolvedElevatorDoorStyle(doorStyle: ElevatorNode['doorStyle'] | undefined): ElevatorDoorStyle;
4
+ export declare function getResolvedElevatorDoorPanelStyle(doorPanelStyle: ElevatorNode['doorPanelStyle'] | undefined): ElevatorDoorPanelStyle;
5
+ export declare function getResolvedElevatorShaftStyle(shaftStyle: ElevatorNode['shaftStyle'] | undefined): ElevatorShaftStyle;
6
+ export declare function getElevatorDoorLeafSides(doorStyle: ElevatorNode['doorStyle'] | undefined): ElevatorDoorSide[];
7
+ export declare function getElevatorDoorLeafX(side: ElevatorDoorSide, openingWidth: number, doorOpen: number, doorStyle: ElevatorNode['doorStyle'] | undefined): number;
8
+ export declare function getElevatorDoorLeafWidth(openingWidth: number, doorStyle: ElevatorNode['doorStyle'] | undefined): number;
9
+ export declare function getElevatorCabWidth(node: ElevatorNode): number;
10
+ export declare function getElevatorCabDepth(node: ElevatorNode): number;
11
+ export declare function getElevatorShaftWallThickness(node: ElevatorNode): number;
12
+ export declare function getElevatorShaftWidth(node: ElevatorNode, cabWidth?: number): number;
13
+ export declare function getElevatorShaftDepth(node: ElevatorNode, cabDepth?: number): number;
14
+ export declare function getElevatorCabCenterZ(node: ElevatorNode): number;
15
+ //# sourceMappingURL=elevator-geometry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"elevator-geometry.d.ts","sourceRoot":"","sources":["../../../src/systems/elevator/elevator-geometry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,sBAAsB,EACtB,iBAAiB,EACjB,YAAY,EACZ,kBAAkB,EACnB,MAAM,cAAc,CAAA;AAErB,MAAM,MAAM,gBAAgB,GAAG,MAAM,GAAG,OAAO,CAAA;AAI/C,wBAAgB,4BAA4B,CAC1C,SAAS,EAAE,YAAY,CAAC,WAAW,CAAC,GAAG,SAAS,GAC/C,iBAAiB,CAEnB;AAED,wBAAgB,iCAAiC,CAC/C,cAAc,EAAE,YAAY,CAAC,gBAAgB,CAAC,GAAG,SAAS,GACzD,sBAAsB,CAExB;AAED,wBAAgB,6BAA6B,CAC3C,UAAU,EAAE,YAAY,CAAC,YAAY,CAAC,GAAG,SAAS,GACjD,kBAAkB,CAEpB;AAED,wBAAgB,wBAAwB,CACtC,SAAS,EAAE,YAAY,CAAC,WAAW,CAAC,GAAG,SAAS,GAC/C,gBAAgB,EAAE,CAKpB;AAED,wBAAgB,oBAAoB,CAClC,IAAI,EAAE,gBAAgB,EACtB,YAAY,EAAE,MAAM,EACpB,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,YAAY,CAAC,WAAW,CAAC,GAAG,SAAS,UAUjD;AAED,wBAAgB,wBAAwB,CACtC,YAAY,EAAE,MAAM,EACpB,SAAS,EAAE,YAAY,CAAC,WAAW,CAAC,GAAG,SAAS,UAKjD;AAED,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,YAAY,UAErD;AAED,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,YAAY,UAErD;AAED,wBAAgB,6BAA6B,CAAC,IAAI,EAAE,YAAY,UAE/D;AAED,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,YAAY,EAAE,QAAQ,SAA4B,UAE7F;AAED,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,YAAY,EAAE,QAAQ,SAA4B,UAE7F;AAED,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,YAAY,UAEvD"}
@@ -0,0 +1,50 @@
1
+ const DEFAULT_ELEVATOR_SHAFT_WALL_THICKNESS = 0.09;
2
+ export function getResolvedElevatorDoorStyle(doorStyle) {
3
+ return doorStyle ?? 'center-opening';
4
+ }
5
+ export function getResolvedElevatorDoorPanelStyle(doorPanelStyle) {
6
+ return doorPanelStyle ?? 'glass-frame';
7
+ }
8
+ export function getResolvedElevatorShaftStyle(shaftStyle) {
9
+ return shaftStyle ?? 'solid';
10
+ }
11
+ export function getElevatorDoorLeafSides(doorStyle) {
12
+ const resolvedDoorStyle = getResolvedElevatorDoorStyle(doorStyle);
13
+ if (resolvedDoorStyle === 'single-left')
14
+ return ['left'];
15
+ if (resolvedDoorStyle === 'single-right')
16
+ return ['right'];
17
+ return ['left', 'right'];
18
+ }
19
+ export function getElevatorDoorLeafX(side, openingWidth, doorOpen, doorStyle) {
20
+ const resolvedDoorStyle = getResolvedElevatorDoorStyle(doorStyle);
21
+ if (resolvedDoorStyle === 'center-opening') {
22
+ const direction = side === 'left' ? -1 : 1;
23
+ return direction * (openingWidth / 4 + doorOpen * openingWidth * 0.34);
24
+ }
25
+ const direction = resolvedDoorStyle === 'single-left' ? -1 : 1;
26
+ return direction * doorOpen * openingWidth * 0.68;
27
+ }
28
+ export function getElevatorDoorLeafWidth(openingWidth, doorStyle) {
29
+ return getResolvedElevatorDoorStyle(doorStyle) === 'center-opening'
30
+ ? Math.max(openingWidth / 2 - 0.018, 0.12)
31
+ : Math.max(openingWidth - 0.018, 0.18);
32
+ }
33
+ export function getElevatorCabWidth(node) {
34
+ return Math.max(node.width, 0.8);
35
+ }
36
+ export function getElevatorCabDepth(node) {
37
+ return Math.max(node.depth, 0.8);
38
+ }
39
+ export function getElevatorShaftWallThickness(node) {
40
+ return Math.max(node.shaftWallThickness ?? DEFAULT_ELEVATOR_SHAFT_WALL_THICKNESS, 0.04);
41
+ }
42
+ export function getElevatorShaftWidth(node, cabWidth = getElevatorCabWidth(node)) {
43
+ return Math.max(node.shaftWidth ?? cabWidth, cabWidth, 0.8);
44
+ }
45
+ export function getElevatorShaftDepth(node, cabDepth = getElevatorCabDepth(node)) {
46
+ return Math.max(node.shaftDepth ?? cabDepth, cabDepth, 0.8);
47
+ }
48
+ export function getElevatorCabCenterZ(node) {
49
+ return -getElevatorShaftDepth(node) / 2 + getElevatorCabDepth(node) / 2;
50
+ }
@@ -0,0 +1,6 @@
1
+ import type { AnyNode, AnyNodeId, CeilingNode, SlabNode } from '../../schema';
2
+ export declare function syncAutoElevatorOpenings(nodes: Record<string, AnyNode>): {
3
+ id: AnyNodeId;
4
+ data: Partial<SlabNode | CeilingNode>;
5
+ }[];
6
+ //# sourceMappingURL=elevator-opening-sync.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"elevator-opening-sync.d.ts","sourceRoot":"","sources":["../../../src/systems/elevator/elevator-opening-sync.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,OAAO,EACP,SAAS,EACT,WAAW,EAEX,QAAQ,EAET,MAAM,cAAc,CAAA;AA8JrB,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;QAQ1C,SAAS;UAAQ,OAAO,CAAC,QAAQ,GAAG,WAAW,CAAC;IAmG5E"}
@@ -0,0 +1,218 @@
1
+ import { resolveLevelId } from '../../hooks/spatial-grid/spatial-grid-sync';
2
+ import { resolveElevatorServiceLevels } from './elevator-service';
3
+ const ELEVATOR_OPENING_PADDING = 0.08;
4
+ const DEFAULT_ELEVATOR_SHAFT_WALL_THICKNESS = 0.09;
5
+ function pointsEqual(a, b, tolerance = 1e-5) {
6
+ const dx = a[0] - b[0];
7
+ const dz = a[1] - b[1];
8
+ return dx * dx + dz * dz <= tolerance * tolerance;
9
+ }
10
+ function polygonsEqual(left, right) {
11
+ if (left.length !== right.length)
12
+ return false;
13
+ return left.every((polygon, polygonIndex) => {
14
+ const other = right[polygonIndex];
15
+ if (!(other && polygon.length === other.length))
16
+ return false;
17
+ return polygon.every((point, pointIndex) => {
18
+ const otherPoint = other[pointIndex];
19
+ if (!otherPoint)
20
+ return false;
21
+ return pointsEqual(point, otherPoint);
22
+ });
23
+ });
24
+ }
25
+ function metadataEqual(left, right) {
26
+ if (left.length !== right.length)
27
+ return false;
28
+ return left.every((entry, index) => entry.source === right[index]?.source &&
29
+ (entry.elevatorId ?? null) === (right[index]?.elevatorId ?? null) &&
30
+ (entry.stairId ?? null) === (right[index]?.stairId ?? null));
31
+ }
32
+ function normalizeExistingMetadata(holes, metadata) {
33
+ return holes.map((_, index) => metadata?.[index] ?? { source: 'manual' });
34
+ }
35
+ function rotateXZ(x, z, angle) {
36
+ const cos = Math.cos(angle);
37
+ const sin = Math.sin(angle);
38
+ return [x * cos + z * sin, -x * sin + z * cos];
39
+ }
40
+ function pointOnSegment(point, a, b, tolerance = 1e-6) {
41
+ const cross = (point[1] - a[1]) * (b[0] - a[0]) - (point[0] - a[0]) * (b[1] - a[1]);
42
+ if (Math.abs(cross) > tolerance)
43
+ return false;
44
+ const dot = (point[0] - a[0]) * (b[0] - a[0]) + (point[1] - a[1]) * (b[1] - a[1]);
45
+ if (dot < -tolerance)
46
+ return false;
47
+ const lenSq = (b[0] - a[0]) ** 2 + (b[1] - a[1]) ** 2;
48
+ return dot <= lenSq + tolerance;
49
+ }
50
+ function pointInPolygon(point, polygon) {
51
+ if (polygon.length < 3)
52
+ return false;
53
+ let inside = false;
54
+ const [x, z] = point;
55
+ for (let i = 0, j = polygon.length - 1; i < polygon.length; j = i++) {
56
+ const a = polygon[i];
57
+ const b = polygon[j];
58
+ if (pointOnSegment(point, a, b))
59
+ return true;
60
+ const intersects = a[1] > z !== b[1] > z && x < ((b[0] - a[0]) * (z - a[1])) / (b[1] - a[1]) + a[0];
61
+ if (intersects)
62
+ inside = !inside;
63
+ }
64
+ return inside;
65
+ }
66
+ function polygonContainsPolygon(outer, inner) {
67
+ return inner.every((point) => pointInPolygon(point, outer));
68
+ }
69
+ function isCoveredByExistingHole(existingHoles, autoHole) {
70
+ return existingHoles.some((existingHole) => polygonContainsPolygon(existingHole, autoHole));
71
+ }
72
+ function getServedLevelRange(elevator, nodes) {
73
+ const servedLevels = resolveElevatorServiceLevels(elevator, nodes);
74
+ if (servedLevels.length < 2)
75
+ return null;
76
+ const levelNumbers = servedLevels.map((level) => level.level);
77
+ return {
78
+ max: Math.max(...levelNumbers),
79
+ min: Math.min(...levelNumbers),
80
+ sortedServedLevels: servedLevels,
81
+ };
82
+ }
83
+ function getLevelNumber(levelId, nodes) {
84
+ if (!levelId)
85
+ return undefined;
86
+ const node = nodes[levelId];
87
+ return node?.type === 'level' ? node.level : undefined;
88
+ }
89
+ function shouldApplyElevatorToSlab(elevator, slabLevelId, nodes) {
90
+ const range = getServedLevelRange(elevator, nodes);
91
+ if (!range)
92
+ return false;
93
+ const slabLevel = getLevelNumber(slabLevelId, nodes);
94
+ if (slabLevel !== undefined) {
95
+ return slabLevel > range.min && slabLevel <= range.max;
96
+ }
97
+ const servedIndex = range.sortedServedLevels.findIndex((level) => level.id === slabLevelId);
98
+ return servedIndex > 0;
99
+ }
100
+ function shouldApplyElevatorToCeiling(elevator, ceilingLevelId, nodes) {
101
+ const range = getServedLevelRange(elevator, nodes);
102
+ if (!range)
103
+ return false;
104
+ const ceilingLevel = getLevelNumber(ceilingLevelId, nodes);
105
+ if (ceilingLevel !== undefined) {
106
+ return ceilingLevel >= range.min && ceilingLevel < range.max;
107
+ }
108
+ const servedIndex = range.sortedServedLevels.findIndex((level) => level.id === ceilingLevelId);
109
+ return servedIndex >= 0 && servedIndex < range.sortedServedLevels.length - 1;
110
+ }
111
+ function getElevatorOpeningPolygon(elevator) {
112
+ const wallThickness = Math.max(elevator.shaftWallThickness ?? DEFAULT_ELEVATOR_SHAFT_WALL_THICKNESS, 0.04);
113
+ const shaftWidth = Math.max(elevator.shaftWidth ?? elevator.width, elevator.width, 0.8);
114
+ const shaftDepth = Math.max(elevator.shaftDepth ?? elevator.depth, elevator.depth, 0.8);
115
+ const halfWidth = shaftWidth / 2 + wallThickness + ELEVATOR_OPENING_PADDING;
116
+ const halfDepth = shaftDepth / 2 + wallThickness + ELEVATOR_OPENING_PADDING;
117
+ const corners = [
118
+ [-halfWidth, -halfDepth],
119
+ [halfWidth, -halfDepth],
120
+ [halfWidth, halfDepth],
121
+ [-halfWidth, halfDepth],
122
+ ];
123
+ return corners.map(([x, z]) => {
124
+ const [rotatedX, rotatedZ] = rotateXZ(x, z, elevator.rotation ?? 0);
125
+ return [elevator.position[0] + rotatedX, elevator.position[2] + rotatedZ];
126
+ });
127
+ }
128
+ export function syncAutoElevatorOpenings(nodes) {
129
+ const elevators = Object.values(nodes).filter((node) => node.type === 'elevator' && node.visible !== false);
130
+ const slabs = Object.values(nodes).filter((node) => node.type === 'slab');
131
+ const ceilings = Object.values(nodes).filter((node) => node.type === 'ceiling');
132
+ const updates = [];
133
+ for (const slab of slabs) {
134
+ const slabLevelId = resolveLevelId(slab, nodes);
135
+ const existingHoles = slab.holes ?? [];
136
+ const existingMetadata = normalizeExistingMetadata(existingHoles, slab.holeMetadata);
137
+ const preservedHoles = existingHoles
138
+ .map((polygon, index) => ({ metadata: existingMetadata[index], polygon }))
139
+ .filter((entry) => entry.metadata.source !== 'elevator');
140
+ const manualHoles = preservedHoles.filter((entry) => entry.metadata.source !== 'stair');
141
+ const stairHoles = preservedHoles.filter((entry) => entry.metadata.source === 'stair');
142
+ const preservedHolePolygons = preservedHoles.map((entry) => entry.polygon);
143
+ const elevatorHoles = elevators
144
+ .filter((elevator) => shouldApplyElevatorToSlab(elevator, slabLevelId, nodes))
145
+ .map((elevator) => ({
146
+ polygon: getElevatorOpeningPolygon(elevator),
147
+ metadata: {
148
+ elevatorId: elevator.id,
149
+ source: 'elevator',
150
+ },
151
+ }))
152
+ .filter((hole) => polygonContainsPolygon(slab.polygon, hole.polygon))
153
+ .filter((hole) => !isCoveredByExistingHole(preservedHolePolygons, hole.polygon));
154
+ const nextHoles = [
155
+ ...manualHoles.map((hole) => hole.polygon),
156
+ ...elevatorHoles.map((hole) => hole.polygon),
157
+ ...stairHoles.map((hole) => hole.polygon),
158
+ ];
159
+ const nextMetadata = [
160
+ ...manualHoles.map((hole) => ({ ...hole.metadata })),
161
+ ...elevatorHoles.map((hole) => hole.metadata),
162
+ ...stairHoles.map((hole) => ({ ...hole.metadata })),
163
+ ];
164
+ if (!polygonsEqual(existingHoles, nextHoles) ||
165
+ !metadataEqual(existingMetadata, nextMetadata)) {
166
+ updates.push({
167
+ id: slab.id,
168
+ data: {
169
+ holes: nextHoles,
170
+ holeMetadata: nextMetadata,
171
+ },
172
+ });
173
+ }
174
+ }
175
+ for (const ceiling of ceilings) {
176
+ const ceilingLevelId = resolveLevelId(ceiling, nodes);
177
+ const existingHoles = ceiling.holes ?? [];
178
+ const existingMetadata = normalizeExistingMetadata(existingHoles, ceiling.holeMetadata);
179
+ const preservedHoles = existingHoles
180
+ .map((polygon, index) => ({ metadata: existingMetadata[index], polygon }))
181
+ .filter((entry) => entry.metadata.source !== 'elevator');
182
+ const manualHoles = preservedHoles.filter((entry) => entry.metadata.source !== 'stair');
183
+ const stairHoles = preservedHoles.filter((entry) => entry.metadata.source === 'stair');
184
+ const preservedHolePolygons = preservedHoles.map((entry) => entry.polygon);
185
+ const elevatorHoles = elevators
186
+ .filter((elevator) => shouldApplyElevatorToCeiling(elevator, ceilingLevelId, nodes))
187
+ .map((elevator) => ({
188
+ polygon: getElevatorOpeningPolygon(elevator),
189
+ metadata: {
190
+ elevatorId: elevator.id,
191
+ source: 'elevator',
192
+ },
193
+ }))
194
+ .filter((hole) => polygonContainsPolygon(ceiling.polygon, hole.polygon))
195
+ .filter((hole) => !isCoveredByExistingHole(preservedHolePolygons, hole.polygon));
196
+ const nextHoles = [
197
+ ...manualHoles.map((hole) => hole.polygon),
198
+ ...elevatorHoles.map((hole) => hole.polygon),
199
+ ...stairHoles.map((hole) => hole.polygon),
200
+ ];
201
+ const nextMetadata = [
202
+ ...manualHoles.map((hole) => ({ ...hole.metadata })),
203
+ ...elevatorHoles.map((hole) => hole.metadata),
204
+ ...stairHoles.map((hole) => ({ ...hole.metadata })),
205
+ ];
206
+ if (!polygonsEqual(existingHoles, nextHoles) ||
207
+ !metadataEqual(existingMetadata, nextMetadata)) {
208
+ updates.push({
209
+ id: ceiling.id,
210
+ data: {
211
+ holes: nextHoles,
212
+ holeMetadata: nextMetadata,
213
+ },
214
+ });
215
+ }
216
+ }
217
+ return updates;
218
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=elevator-opening-sync.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"elevator-opening-sync.test.d.ts","sourceRoot":"","sources":["../../../src/systems/elevator/elevator-opening-sync.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,146 @@
1
+ import { describe, expect, test } from 'bun:test';
2
+ import { BuildingNode, CeilingNode, ElevatorNode, LevelNode, SlabNode } from '../../schema';
3
+ import { syncAutoElevatorOpenings } from './elevator-opening-sync';
4
+ describe('syncAutoElevatorOpenings', () => {
5
+ test('does not add elevator holes when a manual surface hole already covers them', () => {
6
+ const building = BuildingNode.parse({ name: 'Building' });
7
+ const ground = LevelNode.parse({ name: 'Ground', level: 0, parentId: building.id });
8
+ const upper = LevelNode.parse({ name: 'Upper', level: 1, parentId: building.id });
9
+ const elevator = ElevatorNode.parse({
10
+ name: 'Elevator',
11
+ parentId: building.id,
12
+ position: [2, 0, 1.5],
13
+ width: 1.6,
14
+ depth: 1.6,
15
+ });
16
+ const buildingWithChildren = {
17
+ ...building,
18
+ children: [ground.id, upper.id, elevator.id],
19
+ };
20
+ const manualOpening = [
21
+ [1, 0.5],
22
+ [3, 0.5],
23
+ [3, 2.5],
24
+ [1, 2.5],
25
+ ];
26
+ const sourceCeiling = CeilingNode.parse({
27
+ name: 'Source Ceiling',
28
+ parentId: ground.id,
29
+ polygon: [
30
+ [0, 0],
31
+ [4, 0],
32
+ [4, 3],
33
+ [0, 3],
34
+ ],
35
+ holes: [manualOpening],
36
+ holeMetadata: [{ source: 'manual' }],
37
+ });
38
+ const upperSlab = SlabNode.parse({
39
+ name: 'Upper Slab',
40
+ parentId: upper.id,
41
+ polygon: [
42
+ [0, 0],
43
+ [4, 0],
44
+ [4, 3],
45
+ [0, 3],
46
+ ],
47
+ holes: [manualOpening],
48
+ holeMetadata: [{ source: 'manual' }],
49
+ });
50
+ const nodes = Object.fromEntries([buildingWithChildren, ground, upper, elevator, sourceCeiling, upperSlab].map((node) => [
51
+ node.id,
52
+ node,
53
+ ]));
54
+ const updates = syncAutoElevatorOpenings(nodes);
55
+ expect(updates.find((update) => update.id === upperSlab.id)).toBeUndefined();
56
+ expect(updates.find((update) => update.id === sourceCeiling.id)).toBeUndefined();
57
+ });
58
+ test('adds elevator holes when an existing manual hole is too small', () => {
59
+ const building = BuildingNode.parse({ name: 'Building' });
60
+ const ground = LevelNode.parse({ name: 'Ground', level: 0, parentId: building.id });
61
+ const upper = LevelNode.parse({ name: 'Upper', level: 1, parentId: building.id });
62
+ const elevator = ElevatorNode.parse({
63
+ name: 'Elevator',
64
+ parentId: building.id,
65
+ position: [2, 0, 1.5],
66
+ width: 1.6,
67
+ depth: 1.6,
68
+ });
69
+ const buildingWithChildren = {
70
+ ...building,
71
+ children: [ground.id, upper.id, elevator.id],
72
+ };
73
+ const smallManualOpening = [
74
+ [1.7, 1.2],
75
+ [2.3, 1.2],
76
+ [2.3, 1.8],
77
+ [1.7, 1.8],
78
+ ];
79
+ const upperSlab = SlabNode.parse({
80
+ name: 'Upper Slab',
81
+ parentId: upper.id,
82
+ polygon: [
83
+ [0, 0],
84
+ [4, 0],
85
+ [4, 3],
86
+ [0, 3],
87
+ ],
88
+ holes: [smallManualOpening],
89
+ holeMetadata: [{ source: 'manual' }],
90
+ });
91
+ const nodes = Object.fromEntries([buildingWithChildren, ground, upper, elevator, upperSlab].map((node) => [node.id, node]));
92
+ const updates = syncAutoElevatorOpenings(nodes);
93
+ const slabUpdate = updates.find((update) => update.id === upperSlab.id);
94
+ expect(slabUpdate?.data.holes).toHaveLength(2);
95
+ expect(slabUpdate?.data.holes?.[0]).toEqual(smallManualOpening);
96
+ expect(slabUpdate?.data.holeMetadata).toEqual([
97
+ { source: 'manual' },
98
+ { source: 'elevator', elevatorId: elevator.id },
99
+ ]);
100
+ });
101
+ test('removes stale auto elevator holes when a manual hole overlaps the elevator opening', () => {
102
+ const building = BuildingNode.parse({ name: 'Building' });
103
+ const ground = LevelNode.parse({ name: 'Ground', level: 0, parentId: building.id });
104
+ const upper = LevelNode.parse({ name: 'Upper', level: 1, parentId: building.id });
105
+ const elevator = ElevatorNode.parse({
106
+ name: 'Elevator',
107
+ parentId: building.id,
108
+ position: [2, 0, 1.5],
109
+ width: 1.6,
110
+ depth: 1.6,
111
+ });
112
+ const buildingWithChildren = {
113
+ ...building,
114
+ children: [ground.id, upper.id, elevator.id],
115
+ };
116
+ const manualOpening = [
117
+ [1, 0.5],
118
+ [3, 0.5],
119
+ [3, 2.5],
120
+ [1, 2.5],
121
+ ];
122
+ const staleAutoOpening = [
123
+ [1.12, 0.62],
124
+ [2.88, 0.62],
125
+ [2.88, 2.38],
126
+ [1.12, 2.38],
127
+ ];
128
+ const upperSlab = SlabNode.parse({
129
+ name: 'Upper Slab',
130
+ parentId: upper.id,
131
+ polygon: [
132
+ [0, 0],
133
+ [4, 0],
134
+ [4, 3],
135
+ [0, 3],
136
+ ],
137
+ holes: [manualOpening, staleAutoOpening],
138
+ holeMetadata: [{ source: 'manual' }, { source: 'elevator', elevatorId: elevator.id }],
139
+ });
140
+ const nodes = Object.fromEntries([buildingWithChildren, ground, upper, elevator, upperSlab].map((node) => [node.id, node]));
141
+ const updates = syncAutoElevatorOpenings(nodes);
142
+ const slabUpdate = updates.find((update) => update.id === upperSlab.id);
143
+ expect(slabUpdate?.data.holes).toEqual([manualOpening]);
144
+ expect(slabUpdate?.data.holeMetadata).toEqual([{ source: 'manual' }]);
145
+ });
146
+ });
@@ -0,0 +1,2 @@
1
+ export declare const ElevatorOpeningSystem: () => null;
2
+ //# sourceMappingURL=elevator-opening-system.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"elevator-opening-system.d.ts","sourceRoot":"","sources":["../../../src/systems/elevator/elevator-opening-system.tsx"],"names":[],"mappings":"AAkCA,eAAO,MAAM,qBAAqB,YAuBjC,CAAA"}
@@ -0,0 +1,48 @@
1
+ 'use client';
2
+ import { useEffect, useRef } from 'react';
3
+ import useScene from '../../store/use-scene';
4
+ import { syncAutoElevatorOpenings } from './elevator-opening-sync';
5
+ function isOpeningRelevantNode(node) {
6
+ return (node?.type === 'building' ||
7
+ node?.type === 'ceiling' ||
8
+ node?.type === 'elevator' ||
9
+ node?.type === 'level' ||
10
+ node?.type === 'slab');
11
+ }
12
+ function hasOpeningRelevantNodeChange(nextNodes, prevNodes) {
13
+ if (nextNodes === prevNodes)
14
+ return false;
15
+ const ids = new Set([...Object.keys(nextNodes), ...Object.keys(prevNodes)]);
16
+ for (const id of ids) {
17
+ const nextNode = nextNodes[id];
18
+ const prevNode = prevNodes[id];
19
+ if (nextNode === prevNode)
20
+ continue;
21
+ if (isOpeningRelevantNode(nextNode) || isOpeningRelevantNode(prevNode))
22
+ return true;
23
+ }
24
+ return false;
25
+ }
26
+ export const ElevatorOpeningSystem = () => {
27
+ const syncingAutoOpeningsRef = useRef(false);
28
+ useEffect(() => {
29
+ const applyUpdates = (updates) => {
30
+ if (updates.length === 0)
31
+ return;
32
+ syncingAutoOpeningsRef.current = true;
33
+ useScene.getState().updateNodes(updates);
34
+ queueMicrotask(() => {
35
+ syncingAutoOpeningsRef.current = false;
36
+ });
37
+ };
38
+ applyUpdates(syncAutoElevatorOpenings(useScene.getState().nodes));
39
+ return useScene.subscribe((state, prevState) => {
40
+ if (syncingAutoOpeningsRef.current)
41
+ return;
42
+ if (!hasOpeningRelevantNodeChange(state.nodes, prevState.nodes))
43
+ return;
44
+ applyUpdates(syncAutoElevatorOpenings(state.nodes));
45
+ });
46
+ }, []);
47
+ return null;
48
+ };
@@ -0,0 +1,2 @@
1
+ export declare function ElevatorRuntimeSystem(): null;
2
+ //# sourceMappingURL=elevator-runtime-system.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"elevator-runtime-system.d.ts","sourceRoot":"","sources":["../../../src/systems/elevator/elevator-runtime-system.tsx"],"names":[],"mappings":"AAGA,wBAAgB,qBAAqB,SAMpC"}
@@ -0,0 +1,8 @@
1
+ import { useFrame } from '@react-three/fiber';
2
+ import { stepElevatorRuntimes } from './elevator-runtime';
3
+ export function ElevatorRuntimeSystem() {
4
+ useFrame(({ clock }, delta) => {
5
+ stepElevatorRuntimes(clock.getElapsedTime() * 1000, delta);
6
+ }, 2);
7
+ return null;
8
+ }
@@ -0,0 +1,18 @@
1
+ import type { AnyNodeId, ElevatorNode } from '../../schema';
2
+ import { type ElevatorInteractiveState } from '../../store/use-interactive';
3
+ import { type ElevatorLevelEntry } from './elevator-service';
4
+ export declare function createElevatorInteractiveState(levelId: AnyNodeId, carY: number): ElevatorInteractiveState;
5
+ export declare function queueElevatorRequest(state: ElevatorInteractiveState, levelId: AnyNodeId): ElevatorInteractiveState;
6
+ export declare function openElevatorDoorState(state: ElevatorInteractiveState): ElevatorInteractiveState;
7
+ export declare function requestElevatorLevel(elevatorId: AnyNodeId, levelId: AnyNodeId): void;
8
+ export declare function openElevatorDoor(elevatorId: AnyNodeId): void;
9
+ export declare function stepElevatorRuntimeState({ defaultEntry, delta, elevator, entries, now, state, }: {
10
+ defaultEntry: ElevatorLevelEntry;
11
+ delta: number;
12
+ elevator: ElevatorNode;
13
+ entries: ElevatorLevelEntry[];
14
+ now: number;
15
+ state: ElevatorInteractiveState;
16
+ }): ElevatorInteractiveState;
17
+ export declare function stepElevatorRuntimes(now: number, delta: number): void;
18
+ //# sourceMappingURL=elevator-runtime.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"elevator-runtime.d.ts","sourceRoot":"","sources":["../../../src/systems/elevator/elevator-runtime.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAW,SAAS,EAAE,YAAY,EAAE,MAAM,cAAc,CAAA;AACpE,OAAO,EAAE,KAAK,wBAAwB,EAAkB,MAAM,6BAA6B,CAAA;AAE3F,OAAO,EAAE,KAAK,kBAAkB,EAAyB,MAAM,oBAAoB,CAAA;AAUnF,wBAAgB,8BAA8B,CAC5C,OAAO,EAAE,SAAS,EAClB,IAAI,EAAE,MAAM,GACX,wBAAwB,CAW1B;AA8BD,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,wBAAwB,EAC/B,OAAO,EAAE,SAAS,GACjB,wBAAwB,CAW1B;AAED,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,wBAAwB,GAAG,wBAAwB,CAQ/F;AAED,wBAAgB,oBAAoB,CAAC,UAAU,EAAE,SAAS,EAAE,OAAO,EAAE,SAAS,QAS7E;AAED,wBAAgB,gBAAgB,CAAC,UAAU,EAAE,SAAS,QASrD;AAED,wBAAgB,wBAAwB,CAAC,EACvC,YAAY,EACZ,KAAK,EACL,QAAQ,EACR,OAAO,EACP,GAAG,EACH,KAAK,GACN,EAAE;IACD,YAAY,EAAE,kBAAkB,CAAA;IAChC,KAAK,EAAE,MAAM,CAAA;IACb,QAAQ,EAAE,YAAY,CAAA;IACtB,OAAO,EAAE,kBAAkB,EAAE,CAAA;IAC7B,GAAG,EAAE,MAAM,CAAA;IACX,KAAK,EAAE,wBAAwB,CAAA;CAChC,GAAG,wBAAwB,CAmH3B;AAED,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,QAsC9D"}