@pascal-app/core 1.0.3 → 1.0.4

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 (1098) hide show
  1. package/dist/agent-operations/__fixtures__/add-object-cases.d.ts +235 -0
  2. package/dist/agent-operations/__fixtures__/add-object-cases.d.ts.map +1 -0
  3. package/dist/agent-operations/__fixtures__/add-object-cases.js +129 -0
  4. package/dist/agent-operations/__fixtures__/build-room-cases.d.ts +4 -0
  5. package/dist/agent-operations/__fixtures__/build-room-cases.d.ts.map +1 -0
  6. package/dist/agent-operations/__fixtures__/build-room-cases.js +635 -0
  7. package/dist/agent-operations/__fixtures__/cases.d.ts +52 -0
  8. package/dist/agent-operations/__fixtures__/cases.d.ts.map +1 -0
  9. package/dist/agent-operations/__fixtures__/cases.js +689 -0
  10. package/dist/agent-operations/__fixtures__/find-by-type-cases.d.ts +7 -0
  11. package/dist/agent-operations/__fixtures__/find-by-type-cases.d.ts.map +1 -0
  12. package/dist/agent-operations/__fixtures__/find-by-type-cases.js +21 -0
  13. package/dist/agent-operations/__fixtures__/place-items-cases.d.ts +17 -0
  14. package/dist/agent-operations/__fixtures__/place-items-cases.d.ts.map +1 -0
  15. package/dist/agent-operations/__fixtures__/place-items-cases.js +506 -0
  16. package/dist/agent-operations/__fixtures__/room-cases.d.ts +3 -0
  17. package/dist/agent-operations/__fixtures__/room-cases.d.ts.map +1 -0
  18. package/dist/agent-operations/__fixtures__/room-cases.js +338 -0
  19. package/dist/agent-operations/__fixtures__/search-assets-cases.d.ts +5 -0
  20. package/dist/agent-operations/__fixtures__/search-assets-cases.d.ts.map +1 -0
  21. package/dist/agent-operations/__fixtures__/search-assets-cases.js +137 -0
  22. package/dist/agent-operations/__fixtures__/structure-cases.d.ts +6 -0
  23. package/dist/agent-operations/__fixtures__/structure-cases.d.ts.map +1 -0
  24. package/dist/agent-operations/__fixtures__/structure-cases.js +588 -0
  25. package/dist/agent-operations/__fixtures__/verify-scene-cases.d.ts +3 -0
  26. package/dist/agent-operations/__fixtures__/verify-scene-cases.d.ts.map +1 -0
  27. package/dist/agent-operations/__fixtures__/verify-scene-cases.js +302 -0
  28. package/dist/agent-operations/achieved.d.ts +16 -0
  29. package/dist/agent-operations/achieved.d.ts.map +1 -0
  30. package/dist/agent-operations/achieved.js +28 -0
  31. package/dist/agent-operations/add-column.d.ts +23 -0
  32. package/dist/agent-operations/add-column.d.ts.map +1 -0
  33. package/dist/agent-operations/add-column.js +97 -0
  34. package/dist/agent-operations/add-level.d.ts +14 -0
  35. package/dist/agent-operations/add-level.d.ts.map +1 -0
  36. package/dist/agent-operations/add-level.js +94 -0
  37. package/dist/agent-operations/add-object.d.ts +114 -0
  38. package/dist/agent-operations/add-object.d.ts.map +1 -0
  39. package/dist/agent-operations/add-object.js +361 -0
  40. package/dist/agent-operations/add-wall.d.ts +15 -0
  41. package/dist/agent-operations/add-wall.d.ts.map +1 -0
  42. package/dist/agent-operations/add-wall.js +47 -0
  43. package/dist/agent-operations/apply-changes.d.ts +16 -0
  44. package/dist/agent-operations/apply-changes.d.ts.map +1 -0
  45. package/dist/agent-operations/apply-changes.js +93 -0
  46. package/dist/agent-operations/apply-outcome.d.ts +15 -0
  47. package/dist/agent-operations/apply-outcome.d.ts.map +1 -0
  48. package/dist/agent-operations/apply-outcome.js +18 -0
  49. package/dist/agent-operations/collections.d.ts +28 -0
  50. package/dist/agent-operations/collections.d.ts.map +1 -0
  51. package/dist/agent-operations/collections.js +130 -0
  52. package/dist/agent-operations/create-room.d.ts +36 -0
  53. package/dist/agent-operations/create-room.d.ts.map +1 -0
  54. package/dist/agent-operations/create-room.js +177 -0
  55. package/dist/agent-operations/create-stair.d.ts +33 -0
  56. package/dist/agent-operations/create-stair.d.ts.map +1 -0
  57. package/dist/agent-operations/create-stair.js +247 -0
  58. package/dist/agent-operations/delete-node.d.ts +6 -0
  59. package/dist/agent-operations/delete-node.d.ts.map +1 -0
  60. package/dist/agent-operations/delete-node.js +9 -0
  61. package/dist/agent-operations/door-clearance.d.ts +135 -0
  62. package/dist/agent-operations/door-clearance.d.ts.map +1 -0
  63. package/dist/agent-operations/door-clearance.js +334 -0
  64. package/dist/agent-operations/duplicate-level.d.ts +12 -0
  65. package/dist/agent-operations/duplicate-level.d.ts.map +1 -0
  66. package/dist/agent-operations/duplicate-level.js +54 -0
  67. package/dist/agent-operations/find-by-type.d.ts +11 -0
  68. package/dist/agent-operations/find-by-type.d.ts.map +1 -0
  69. package/dist/agent-operations/find-by-type.js +94 -0
  70. package/dist/agent-operations/furnish-room.d.ts +18 -0
  71. package/dist/agent-operations/furnish-room.d.ts.map +1 -0
  72. package/dist/agent-operations/furnish-room.js +259 -0
  73. package/dist/agent-operations/get-node.d.ts +9 -0
  74. package/dist/agent-operations/get-node.d.ts.map +1 -0
  75. package/dist/agent-operations/get-node.js +33 -0
  76. package/dist/agent-operations/hosted-services.d.ts +13 -0
  77. package/dist/agent-operations/hosted-services.d.ts.map +1 -0
  78. package/dist/agent-operations/hosted-services.js +22 -0
  79. package/dist/agent-operations/index.d.ts +277 -0
  80. package/dist/agent-operations/index.d.ts.map +1 -0
  81. package/dist/agent-operations/index.js +80 -0
  82. package/dist/agent-operations/layout-clearance.d.ts +108 -0
  83. package/dist/agent-operations/layout-clearance.d.ts.map +1 -0
  84. package/dist/agent-operations/layout-clearance.js +190 -0
  85. package/dist/agent-operations/level-reads.d.ts +33 -0
  86. package/dist/agent-operations/level-reads.d.ts.map +1 -0
  87. package/dist/agent-operations/level-reads.js +161 -0
  88. package/dist/agent-operations/level-target.d.ts +11 -0
  89. package/dist/agent-operations/level-target.d.ts.map +1 -0
  90. package/dist/agent-operations/level-target.js +29 -0
  91. package/dist/agent-operations/list-levels.d.ts +4 -0
  92. package/dist/agent-operations/list-levels.d.ts.map +1 -0
  93. package/dist/agent-operations/list-levels.js +31 -0
  94. package/dist/agent-operations/material-preset.d.ts +11 -0
  95. package/dist/agent-operations/material-preset.d.ts.map +1 -0
  96. package/dist/agent-operations/material-preset.js +74 -0
  97. package/dist/agent-operations/material-refs.d.ts +24 -0
  98. package/dist/agent-operations/material-refs.d.ts.map +1 -0
  99. package/dist/agent-operations/material-refs.js +100 -0
  100. package/dist/agent-operations/node-patch.d.ts +3 -0
  101. package/dist/agent-operations/node-patch.d.ts.map +1 -0
  102. package/dist/agent-operations/node-patch.js +114 -0
  103. package/dist/agent-operations/paint.d.ts +21 -0
  104. package/dist/agent-operations/paint.d.ts.map +1 -0
  105. package/dist/agent-operations/paint.js +219 -0
  106. package/dist/agent-operations/place-items.d.ts +20 -0
  107. package/dist/agent-operations/place-items.d.ts.map +1 -0
  108. package/dist/agent-operations/place-items.js +226 -0
  109. package/dist/agent-operations/plan-geometry.d.ts +24 -0
  110. package/dist/agent-operations/plan-geometry.d.ts.map +1 -0
  111. package/dist/agent-operations/plan-geometry.js +94 -0
  112. package/dist/agent-operations/room-structure.d.ts +87 -0
  113. package/dist/agent-operations/room-structure.d.ts.map +1 -0
  114. package/dist/agent-operations/room-structure.js +144 -0
  115. package/dist/agent-operations/scene-materials.d.ts +15 -0
  116. package/dist/agent-operations/scene-materials.d.ts.map +1 -0
  117. package/dist/agent-operations/scene-materials.js +62 -0
  118. package/dist/agent-operations/scene-measure.d.ts +73 -0
  119. package/dist/agent-operations/scene-measure.d.ts.map +1 -0
  120. package/dist/agent-operations/scene-measure.js +73 -0
  121. package/dist/agent-operations/scene-queries.d.ts +4510 -0
  122. package/dist/agent-operations/scene-queries.d.ts.map +1 -0
  123. package/dist/agent-operations/scene-queries.js +84 -0
  124. package/dist/agent-operations/scene-view.d.ts +98 -0
  125. package/dist/agent-operations/scene-view.d.ts.map +1 -0
  126. package/dist/agent-operations/scene-view.js +559 -0
  127. package/dist/agent-operations/search-assets.d.ts +14 -0
  128. package/dist/agent-operations/search-assets.d.ts.map +1 -0
  129. package/dist/agent-operations/search-assets.js +42 -0
  130. package/dist/agent-operations/search-materials.d.ts +12 -0
  131. package/dist/agent-operations/search-materials.d.ts.map +1 -0
  132. package/dist/agent-operations/search-materials.js +111 -0
  133. package/dist/agent-operations/stairs.d.ts +5 -0
  134. package/dist/agent-operations/stairs.d.ts.map +1 -0
  135. package/dist/agent-operations/stairs.js +70 -0
  136. package/dist/agent-operations/types.d.ts +59 -0
  137. package/dist/agent-operations/types.d.ts.map +1 -0
  138. package/dist/agent-operations/types.js +1 -0
  139. package/dist/agent-operations/verify-scene.d.ts +50 -0
  140. package/dist/agent-operations/verify-scene.d.ts.map +1 -0
  141. package/dist/agent-operations/verify-scene.js +369 -0
  142. package/dist/agent-operations/wall-opening.d.ts +65 -0
  143. package/dist/agent-operations/wall-opening.d.ts.map +1 -0
  144. package/dist/agent-operations/wall-opening.js +55 -0
  145. package/dist/agent-tools/achieved.d.ts +9 -0
  146. package/dist/agent-tools/achieved.d.ts.map +1 -0
  147. package/dist/agent-tools/achieved.js +8 -0
  148. package/dist/agent-tools/add-object.d.ts +43 -0
  149. package/dist/agent-tools/add-object.d.ts.map +1 -0
  150. package/dist/agent-tools/add-object.js +86 -0
  151. package/dist/agent-tools/assets.d.ts +13 -0
  152. package/dist/agent-tools/assets.d.ts.map +1 -0
  153. package/dist/agent-tools/assets.js +18 -0
  154. package/dist/agent-tools/clear-scene.d.ts +10 -0
  155. package/dist/agent-tools/clear-scene.d.ts.map +1 -0
  156. package/dist/agent-tools/clear-scene.js +9 -0
  157. package/dist/agent-tools/collections.d.ts +35 -0
  158. package/dist/agent-tools/collections.d.ts.map +1 -0
  159. package/dist/agent-tools/collections.js +31 -0
  160. package/dist/agent-tools/columns.d.ts +44 -0
  161. package/dist/agent-tools/columns.d.ts.map +1 -0
  162. package/dist/agent-tools/columns.js +59 -0
  163. package/dist/agent-tools/contract.d.ts +68 -0
  164. package/dist/agent-tools/contract.d.ts.map +1 -0
  165. package/dist/agent-tools/contract.js +1 -0
  166. package/dist/agent-tools/create-room.d.ts +63 -0
  167. package/dist/agent-tools/create-room.d.ts.map +1 -0
  168. package/dist/agent-tools/create-room.js +90 -0
  169. package/dist/agent-tools/find-by-type.d.ts +11 -0
  170. package/dist/agent-tools/find-by-type.d.ts.map +1 -0
  171. package/dist/agent-tools/find-by-type.js +14 -0
  172. package/dist/agent-tools/furnish-room.d.ts +26 -0
  173. package/dist/agent-tools/furnish-room.d.ts.map +1 -0
  174. package/dist/agent-tools/furnish-room.js +35 -0
  175. package/dist/agent-tools/hosted-services.d.ts +402 -0
  176. package/dist/agent-tools/hosted-services.d.ts.map +1 -0
  177. package/dist/agent-tools/hosted-services.js +148 -0
  178. package/dist/agent-tools/index.d.ts +864 -0
  179. package/dist/agent-tools/index.d.ts.map +1 -0
  180. package/dist/agent-tools/index.js +82 -0
  181. package/dist/agent-tools/levels.d.ts +72 -0
  182. package/dist/agent-tools/levels.d.ts.map +1 -0
  183. package/dist/agent-tools/levels.js +76 -0
  184. package/dist/agent-tools/measurement.d.ts +37 -0
  185. package/dist/agent-tools/measurement.d.ts.map +1 -0
  186. package/dist/agent-tools/measurement.js +94 -0
  187. package/dist/agent-tools/node-id.d.ts +3 -0
  188. package/dist/agent-tools/node-id.d.ts.map +1 -0
  189. package/dist/agent-tools/node-id.js +2 -0
  190. package/dist/agent-tools/nodes.d.ts +17 -0
  191. package/dist/agent-tools/nodes.d.ts.map +1 -0
  192. package/dist/agent-tools/nodes.js +13 -0
  193. package/dist/agent-tools/paint.d.ts +46 -0
  194. package/dist/agent-tools/paint.d.ts.map +1 -0
  195. package/dist/agent-tools/paint.js +29 -0
  196. package/dist/agent-tools/place-items.d.ts +19 -0
  197. package/dist/agent-tools/place-items.d.ts.map +1 -0
  198. package/dist/agent-tools/place-items.js +29 -0
  199. package/dist/agent-tools/refusal.d.ts +20 -0
  200. package/dist/agent-tools/refusal.d.ts.map +1 -0
  201. package/dist/agent-tools/refusal.js +29 -0
  202. package/dist/agent-tools/room-structure.d.ts +438 -0
  203. package/dist/agent-tools/room-structure.d.ts.map +1 -0
  204. package/dist/agent-tools/room-structure.js +207 -0
  205. package/dist/agent-tools/search-materials.d.ts +20 -0
  206. package/dist/agent-tools/search-materials.d.ts.map +1 -0
  207. package/dist/agent-tools/search-materials.js +32 -0
  208. package/dist/agent-tools/stairs.d.ts +86 -0
  209. package/dist/agent-tools/stairs.d.ts.map +1 -0
  210. package/dist/agent-tools/stairs.js +103 -0
  211. package/dist/agent-tools/verify-scene.d.ts +13 -0
  212. package/dist/agent-tools/verify-scene.d.ts.map +1 -0
  213. package/dist/agent-tools/verify-scene.js +21 -0
  214. package/dist/agent-tools/view-scene.d.ts +43 -0
  215. package/dist/agent-tools/view-scene.d.ts.map +1 -0
  216. package/dist/agent-tools/view-scene.js +80 -0
  217. package/dist/agent-tools/wall-openings.d.ts +163 -0
  218. package/dist/agent-tools/wall-openings.d.ts.map +1 -0
  219. package/dist/agent-tools/wall-openings.js +144 -0
  220. package/dist/agent-tools/walls.d.ts +21 -0
  221. package/dist/agent-tools/walls.d.ts.map +1 -0
  222. package/dist/agent-tools/walls.js +30 -0
  223. package/dist/agent-tools/write-target.d.ts +12 -0
  224. package/dist/agent-tools/write-target.d.ts.map +1 -0
  225. package/dist/agent-tools/write-target.js +10 -0
  226. package/dist/building/__fixtures__/wall-opening-cases.d.ts +736 -0
  227. package/dist/building/__fixtures__/wall-opening-cases.d.ts.map +1 -0
  228. package/dist/building/__fixtures__/wall-opening-cases.js +307 -0
  229. package/dist/building/door-types.d.ts +22 -0
  230. package/dist/building/door-types.d.ts.map +1 -0
  231. package/dist/building/door-types.js +167 -0
  232. package/dist/building/floor-item-fit.d.ts +38 -0
  233. package/dist/building/floor-item-fit.d.ts.map +1 -0
  234. package/dist/building/floor-item-fit.js +47 -0
  235. package/dist/building/index.d.ts +7 -0
  236. package/dist/building/index.d.ts.map +1 -0
  237. package/dist/building/index.js +6 -0
  238. package/dist/building/level-duplication.d.ts +8983 -0
  239. package/dist/building/level-duplication.d.ts.map +1 -0
  240. package/dist/building/level-duplication.js +314 -0
  241. package/dist/building/opening-style-presets.d.ts +46 -0
  242. package/dist/building/opening-style-presets.d.ts.map +1 -0
  243. package/dist/building/opening-style-presets.js +195 -0
  244. package/dist/building/wall-openings.d.ts +445 -0
  245. package/dist/building/wall-openings.d.ts.map +1 -0
  246. package/dist/building/wall-openings.js +231 -0
  247. package/dist/building/window-types.d.ts +17 -0
  248. package/dist/building/window-types.d.ts.map +1 -0
  249. package/dist/building/window-types.js +31 -0
  250. package/dist/commands/structure/apply-zone-transform.d.ts +23 -0
  251. package/dist/commands/structure/apply-zone-transform.d.ts.map +1 -0
  252. package/dist/commands/structure/apply-zone-transform.js +55 -0
  253. package/dist/commands/structure/create-mezzanine.d.ts +12 -0
  254. package/dist/commands/structure/create-mezzanine.d.ts.map +1 -0
  255. package/dist/commands/structure/create-mezzanine.js +46 -0
  256. package/dist/commands/structure/create-zone.d.ts +32 -0
  257. package/dist/commands/structure/create-zone.d.ts.map +1 -0
  258. package/dist/commands/structure/create-zone.js +126 -0
  259. package/dist/commands/structure/delete-zone.d.ts +51 -0
  260. package/dist/commands/structure/delete-zone.d.ts.map +1 -0
  261. package/dist/commands/structure/delete-zone.js +354 -0
  262. package/dist/commands/structure/divide-zone.d.ts +38 -0
  263. package/dist/commands/structure/divide-zone.d.ts.map +1 -0
  264. package/dist/commands/structure/divide-zone.js +186 -0
  265. package/dist/commands/structure/duplicate-zone.d.ts +7 -0
  266. package/dist/commands/structure/duplicate-zone.d.ts.map +1 -0
  267. package/dist/commands/structure/duplicate-zone.js +21 -0
  268. package/dist/commands/structure/floor-opening.d.ts +36 -0
  269. package/dist/commands/structure/floor-opening.d.ts.map +1 -0
  270. package/dist/commands/structure/floor-opening.js +124 -0
  271. package/dist/commands/structure/index.d.ts +22 -0
  272. package/dist/commands/structure/index.d.ts.map +1 -0
  273. package/dist/commands/structure/index.js +20 -0
  274. package/dist/commands/structure/lock-outside-faces.d.ts +12 -0
  275. package/dist/commands/structure/lock-outside-faces.d.ts.map +1 -0
  276. package/dist/commands/structure/lock-outside-faces.js +32 -0
  277. package/dist/commands/structure/merge-zones.d.ts +5 -0
  278. package/dist/commands/structure/merge-zones.d.ts.map +1 -0
  279. package/dist/commands/structure/merge-zones.js +22 -0
  280. package/dist/commands/structure/mezzanine-content.d.ts +16 -0
  281. package/dist/commands/structure/mezzanine-content.d.ts.map +1 -0
  282. package/dist/commands/structure/mezzanine-content.js +109 -0
  283. package/dist/commands/structure/plan-mezzanine-stair.d.ts +7 -0
  284. package/dist/commands/structure/plan-mezzanine-stair.d.ts.map +1 -0
  285. package/dist/commands/structure/plan-mezzanine-stair.js +127 -0
  286. package/dist/commands/structure/plan-wall-deletion.d.ts +9 -0
  287. package/dist/commands/structure/plan-wall-deletion.d.ts.map +1 -0
  288. package/dist/commands/structure/plan-wall-deletion.js +151 -0
  289. package/dist/commands/structure/rebase-floor-reference.d.ts +7 -0
  290. package/dist/commands/structure/rebase-floor-reference.d.ts.map +1 -0
  291. package/dist/commands/structure/rebase-floor-reference.js +90 -0
  292. package/dist/commands/structure/resize-mezzanine.d.ts +8 -0
  293. package/dist/commands/structure/resize-mezzanine.d.ts.map +1 -0
  294. package/dist/commands/structure/resize-mezzanine.js +43 -0
  295. package/dist/commands/structure/rotate-zone.d.ts +8 -0
  296. package/dist/commands/structure/rotate-zone.d.ts.map +1 -0
  297. package/dist/commands/structure/rotate-zone.js +28 -0
  298. package/dist/commands/structure/set-floor-foundation.d.ts +62 -0
  299. package/dist/commands/structure/set-floor-foundation.d.ts.map +1 -0
  300. package/dist/commands/structure/set-floor-foundation.js +162 -0
  301. package/dist/commands/structure/set-room-floor-construction.d.ts +8 -0
  302. package/dist/commands/structure/set-room-floor-construction.d.ts.map +1 -0
  303. package/dist/commands/structure/set-room-floor-construction.js +72 -0
  304. package/dist/commands/structure/set-wall-geometry.d.ts +10 -0
  305. package/dist/commands/structure/set-wall-geometry.d.ts.map +1 -0
  306. package/dist/commands/structure/set-wall-geometry.js +52 -0
  307. package/dist/commands/structure/set-zone-edges.d.ts +14 -0
  308. package/dist/commands/structure/set-zone-edges.d.ts.map +1 -0
  309. package/dist/commands/structure/set-zone-edges.js +143 -0
  310. package/dist/commands/structure/set-zone-intent.d.ts +39 -0
  311. package/dist/commands/structure/set-zone-intent.d.ts.map +1 -0
  312. package/dist/commands/structure/set-zone-intent.js +125 -0
  313. package/dist/commands/structure/shared.d.ts +4512 -0
  314. package/dist/commands/structure/shared.d.ts.map +1 -0
  315. package/dist/commands/structure/shared.js +102 -0
  316. package/dist/commands/structure/transform-zone.d.ts +23 -0
  317. package/dist/commands/structure/transform-zone.d.ts.map +1 -0
  318. package/dist/commands/structure/transform-zone.js +472 -0
  319. package/dist/commands/structure/validate-mezzanine.d.ts +5 -0
  320. package/dist/commands/structure/validate-mezzanine.d.ts.map +1 -0
  321. package/dist/commands/structure/validate-mezzanine.js +46 -0
  322. package/dist/commands/structure/zone-crossings.d.ts +8 -0
  323. package/dist/commands/structure/zone-crossings.d.ts.map +1 -0
  324. package/dist/commands/structure/zone-crossings.js +162 -0
  325. package/dist/commands/structure/zone-drop.d.ts +4 -0
  326. package/dist/commands/structure/zone-drop.d.ts.map +1 -0
  327. package/dist/commands/structure/zone-drop.js +68 -0
  328. package/dist/commands/structure/zone-insertion.d.ts +4 -0
  329. package/dist/commands/structure/zone-insertion.d.ts.map +1 -0
  330. package/dist/commands/structure/zone-insertion.js +200 -0
  331. package/dist/commands/structure/zone-transform-content.d.ts +6 -0
  332. package/dist/commands/structure/zone-transform-content.d.ts.map +1 -0
  333. package/dist/commands/structure/zone-transform-content.js +117 -0
  334. package/dist/commands/structure/zone-wall-merge.d.ts +4977 -0
  335. package/dist/commands/structure/zone-wall-merge.d.ts.map +1 -0
  336. package/dist/commands/structure/zone-wall-merge.js +135 -0
  337. package/dist/contracts/reference-discovery.d.ts +18 -0
  338. package/dist/contracts/reference-discovery.d.ts.map +1 -0
  339. package/dist/contracts/reference-discovery.js +100 -0
  340. package/dist/contracts/reference-inventory.d.ts +44 -0
  341. package/dist/contracts/reference-inventory.d.ts.map +1 -0
  342. package/dist/contracts/reference-inventory.js +872 -0
  343. package/dist/events/bus.d.ts +70 -9
  344. package/dist/events/bus.d.ts.map +1 -1
  345. package/dist/hooks/scene-registry/item-clip-registry.d.ts +6 -3
  346. package/dist/hooks/scene-registry/item-clip-registry.d.ts.map +1 -1
  347. package/dist/hooks/scene-registry/item-clip-registry.js +2 -1
  348. package/dist/hooks/spatial-grid/floor-placed-elevation.d.ts.map +1 -1
  349. package/dist/hooks/spatial-grid/floor-placed-elevation.js +15 -1
  350. package/dist/hooks/spatial-grid/spatial-grid-manager.d.ts +3 -2
  351. package/dist/hooks/spatial-grid/spatial-grid-manager.d.ts.map +1 -1
  352. package/dist/hooks/spatial-grid/spatial-grid-manager.js +53 -66
  353. package/dist/hooks/spatial-grid/spatial-grid-sync.d.ts +1612 -127
  354. package/dist/hooks/spatial-grid/spatial-grid-sync.d.ts.map +1 -1
  355. package/dist/hooks/spatial-grid/spatial-grid-sync.js +86 -83
  356. package/dist/hooks/spatial-grid/support-host-patch.d.ts +1 -0
  357. package/dist/hooks/spatial-grid/support-host-patch.d.ts.map +1 -1
  358. package/dist/hooks/spatial-grid/support-host-patch.js +12 -5
  359. package/dist/index.d.ts +80 -13
  360. package/dist/index.d.ts.map +1 -1
  361. package/dist/index.js +75 -11
  362. package/dist/lib/__bench__/near-linear-walls.d.ts +2 -0
  363. package/dist/lib/__bench__/near-linear-walls.d.ts.map +1 -0
  364. package/dist/lib/__bench__/near-linear-walls.js +24 -0
  365. package/dist/lib/__bench__/structure-preview.bench.d.ts +2 -0
  366. package/dist/lib/__bench__/structure-preview.bench.d.ts.map +1 -0
  367. package/dist/lib/__bench__/structure-preview.bench.js +72 -0
  368. package/dist/lib/__fixtures__/mezzanine.d.ts +13968 -0
  369. package/dist/lib/__fixtures__/mezzanine.d.ts.map +1 -0
  370. package/dist/lib/__fixtures__/mezzanine.js +43 -0
  371. package/dist/lib/absorb-wall-separators.d.ts +4483 -0
  372. package/dist/lib/absorb-wall-separators.d.ts.map +1 -0
  373. package/dist/lib/absorb-wall-separators.js +65 -0
  374. package/dist/lib/angle-accumulator.d.ts +3 -0
  375. package/dist/lib/angle-accumulator.d.ts.map +1 -0
  376. package/dist/lib/angle-accumulator.js +13 -0
  377. package/dist/lib/artifact-store.d.ts +31 -0
  378. package/dist/lib/artifact-store.d.ts.map +1 -0
  379. package/dist/lib/artifact-store.js +42 -0
  380. package/dist/lib/assembly-stack.d.ts +54 -0
  381. package/dist/lib/assembly-stack.d.ts.map +1 -0
  382. package/dist/lib/assembly-stack.js +52 -0
  383. package/dist/lib/asset-storage.d.ts.map +1 -1
  384. package/dist/lib/asset-storage.js +3 -0
  385. package/dist/lib/canonical-opening-ring.d.ts +3 -0
  386. package/dist/lib/canonical-opening-ring.d.ts.map +1 -0
  387. package/dist/lib/canonical-opening-ring.js +14 -0
  388. package/dist/lib/ceiling-children.d.ts +8 -0
  389. package/dist/lib/ceiling-children.d.ts.map +1 -0
  390. package/dist/lib/ceiling-children.js +36 -0
  391. package/dist/lib/ceiling-surface.d.ts +40 -0
  392. package/dist/lib/ceiling-surface.d.ts.map +1 -0
  393. package/dist/lib/ceiling-surface.js +65 -0
  394. package/dist/lib/cutter-host.d.ts +5 -0
  395. package/dist/lib/cutter-host.d.ts.map +1 -0
  396. package/dist/lib/cutter-host.js +30 -0
  397. package/dist/lib/floor-construction-lift.d.ts +4 -0
  398. package/dist/lib/floor-construction-lift.d.ts.map +1 -0
  399. package/dist/lib/floor-construction-lift.js +54 -0
  400. package/dist/lib/floor-footprint-key.d.ts +3 -0
  401. package/dist/lib/floor-footprint-key.d.ts.map +1 -0
  402. package/dist/lib/floor-footprint-key.js +9 -0
  403. package/dist/lib/floor-footprint-name.d.ts +11 -0
  404. package/dist/lib/floor-footprint-name.d.ts.map +1 -0
  405. package/dist/lib/floor-footprint-name.js +52 -0
  406. package/dist/lib/floor-foundation-datum.d.ts +31 -0
  407. package/dist/lib/floor-foundation-datum.d.ts.map +1 -0
  408. package/dist/lib/floor-foundation-datum.js +226 -0
  409. package/dist/lib/floor-foundation-stack.d.ts +16 -0
  410. package/dist/lib/floor-foundation-stack.d.ts.map +1 -0
  411. package/dist/lib/floor-foundation-stack.js +214 -0
  412. package/dist/lib/floor-intent-changes.d.ts +10 -0
  413. package/dist/lib/floor-intent-changes.d.ts.map +1 -0
  414. package/dist/lib/floor-intent-changes.js +461 -0
  415. package/dist/lib/floor-opening-footprints.d.ts +24 -0
  416. package/dist/lib/floor-opening-footprints.d.ts.map +1 -0
  417. package/dist/lib/floor-opening-footprints.js +127 -0
  418. package/dist/lib/floor-opening-intent.d.ts +16 -0
  419. package/dist/lib/floor-opening-intent.d.ts.map +1 -0
  420. package/dist/lib/floor-opening-intent.js +82 -0
  421. package/dist/lib/floor-plate-id.d.ts +5 -0
  422. package/dist/lib/floor-plate-id.d.ts.map +1 -0
  423. package/dist/lib/floor-plate-id.js +20 -0
  424. package/dist/lib/floor-plate-paint.d.ts +8 -0
  425. package/dist/lib/floor-plate-paint.d.ts.map +1 -0
  426. package/dist/lib/floor-plate-paint.js +11 -0
  427. package/dist/lib/floor-plates.d.ts +211 -0
  428. package/dist/lib/floor-plates.d.ts.map +1 -0
  429. package/dist/lib/floor-plates.js +729 -0
  430. package/dist/lib/floor-room-faces.d.ts +5 -0
  431. package/dist/lib/floor-room-faces.d.ts.map +1 -0
  432. package/dist/lib/floor-room-faces.js +29 -0
  433. package/dist/lib/floor-step-finish.d.ts +49 -0
  434. package/dist/lib/floor-step-finish.d.ts.map +1 -0
  435. package/dist/lib/floor-step-finish.js +128 -0
  436. package/dist/lib/geometry-script-node.d.ts +82 -0
  437. package/dist/lib/geometry-script-node.d.ts.map +1 -0
  438. package/dist/lib/geometry-script-node.js +147 -0
  439. package/dist/lib/geometry-surfaces.d.ts +61 -0
  440. package/dist/lib/geometry-surfaces.d.ts.map +1 -0
  441. package/dist/lib/geometry-surfaces.js +156 -0
  442. package/dist/lib/item-slab-support.d.ts +14 -0
  443. package/dist/lib/item-slab-support.d.ts.map +1 -0
  444. package/dist/lib/item-slab-support.js +40 -0
  445. package/dist/lib/level-footprints.d.ts +23 -0
  446. package/dist/lib/level-footprints.d.ts.map +1 -0
  447. package/dist/lib/level-footprints.js +398 -0
  448. package/dist/lib/level-name.d.ts +7 -0
  449. package/dist/lib/level-name.d.ts.map +1 -1
  450. package/dist/lib/level-name.js +11 -3
  451. package/dist/lib/new-zone.d.ts +10 -0
  452. package/dist/lib/new-zone.d.ts.map +1 -0
  453. package/dist/lib/new-zone.js +10 -0
  454. package/dist/lib/node-ancestry.d.ts +30 -0
  455. package/dist/lib/node-ancestry.d.ts.map +1 -0
  456. package/dist/lib/node-ancestry.js +76 -0
  457. package/dist/lib/object-cuts.d.ts +11 -0
  458. package/dist/lib/object-cuts.d.ts.map +1 -0
  459. package/dist/lib/object-cuts.js +63 -0
  460. package/dist/lib/opening-floor-datum.d.ts +24 -0
  461. package/dist/lib/opening-floor-datum.d.ts.map +1 -0
  462. package/dist/lib/opening-floor-datum.js +145 -0
  463. package/dist/lib/own-floor-intent.d.ts +15 -0
  464. package/dist/lib/own-floor-intent.d.ts.map +1 -0
  465. package/dist/lib/own-floor-intent.js +201 -0
  466. package/dist/lib/plate-reference.d.ts +3 -0
  467. package/dist/lib/plate-reference.d.ts.map +1 -0
  468. package/dist/lib/plate-reference.js +91 -0
  469. package/dist/lib/plate-surface.d.ts +120 -0
  470. package/dist/lib/plate-surface.d.ts.map +1 -0
  471. package/dist/lib/plate-surface.js +725 -0
  472. package/dist/lib/polygon-boolean.d.ts +17 -0
  473. package/dist/lib/polygon-boolean.d.ts.map +1 -0
  474. package/dist/lib/polygon-boolean.js +195 -0
  475. package/dist/lib/polygon-label.d.ts +7 -0
  476. package/dist/lib/polygon-label.d.ts.map +1 -0
  477. package/dist/lib/polygon-label.js +94 -0
  478. package/dist/lib/room-drawn-floor.d.ts +29 -0
  479. package/dist/lib/room-drawn-floor.d.ts.map +1 -0
  480. package/dist/lib/room-drawn-floor.js +88 -0
  481. package/dist/lib/room-floor-choices.d.ts +11 -0
  482. package/dist/lib/room-floor-choices.d.ts.map +1 -0
  483. package/dist/lib/room-floor-choices.js +60 -0
  484. package/dist/lib/room-floor-feasibility.d.ts +25 -0
  485. package/dist/lib/room-floor-feasibility.d.ts.map +1 -0
  486. package/dist/lib/room-floor-feasibility.js +293 -0
  487. package/dist/lib/room-floor-plate.d.ts +3 -0
  488. package/dist/lib/room-floor-plate.d.ts.map +1 -0
  489. package/dist/lib/room-floor-plate.js +4 -0
  490. package/dist/lib/room-graph.d.ts +79 -0
  491. package/dist/lib/room-graph.d.ts.map +1 -0
  492. package/dist/lib/room-graph.js +1265 -0
  493. package/dist/lib/room-name.d.ts +10 -0
  494. package/dist/lib/room-name.d.ts.map +1 -0
  495. package/dist/lib/room-name.js +22 -0
  496. package/dist/lib/room-topology-index.d.ts +53 -5
  497. package/dist/lib/room-topology-index.d.ts.map +1 -1
  498. package/dist/lib/room-topology-index.js +176 -30
  499. package/dist/lib/room-vertical-placement.d.ts +12 -0
  500. package/dist/lib/room-vertical-placement.d.ts.map +1 -0
  501. package/dist/lib/room-vertical-placement.js +28 -0
  502. package/dist/lib/room-zone-adoption.d.ts +74 -0
  503. package/dist/lib/room-zone-adoption.d.ts.map +1 -0
  504. package/dist/lib/room-zone-adoption.js +150 -0
  505. package/dist/lib/setback-envelope.d.ts +73 -0
  506. package/dist/lib/setback-envelope.d.ts.map +1 -0
  507. package/dist/lib/setback-envelope.js +506 -0
  508. package/dist/lib/slab-polygon.d.ts.map +1 -1
  509. package/dist/lib/slab-polygon.js +33 -12
  510. package/dist/lib/slots.d.ts +20 -0
  511. package/dist/lib/slots.d.ts.map +1 -1
  512. package/dist/lib/slots.js +44 -0
  513. package/dist/lib/space-detection.d.ts +14 -94
  514. package/dist/lib/space-detection.d.ts.map +1 -1
  515. package/dist/lib/space-detection.js +244 -1616
  516. package/dist/lib/structure-commit.d.ts +38 -0
  517. package/dist/lib/structure-commit.d.ts.map +1 -0
  518. package/dist/lib/structure-commit.js +52 -0
  519. package/dist/lib/structure-kernel.d.ts +66 -0
  520. package/dist/lib/structure-kernel.d.ts.map +1 -0
  521. package/dist/lib/structure-kernel.js +735 -0
  522. package/dist/lib/structure-reconcile.d.ts +15 -0
  523. package/dist/lib/structure-reconcile.d.ts.map +1 -0
  524. package/dist/lib/structure-reconcile.js +218 -0
  525. package/dist/lib/terrain-contours.d.ts +29 -0
  526. package/dist/lib/terrain-contours.d.ts.map +1 -0
  527. package/dist/lib/terrain-contours.js +199 -0
  528. package/dist/lib/terrain-source-persisted.d.ts +42 -0
  529. package/dist/lib/terrain-source-persisted.d.ts.map +1 -0
  530. package/dist/lib/terrain-source-persisted.js +68 -0
  531. package/dist/lib/terrain-source.d.ts +2 -40
  532. package/dist/lib/terrain-source.d.ts.map +1 -1
  533. package/dist/lib/terrain-source.js +2 -68
  534. package/dist/lib/terrain-support-query.d.ts +83 -0
  535. package/dist/lib/terrain-support-query.d.ts.map +1 -0
  536. package/dist/lib/terrain-support-query.js +187 -0
  537. package/dist/lib/terrain-support.d.ts +1 -77
  538. package/dist/lib/terrain-support.d.ts.map +1 -1
  539. package/dist/lib/terrain-support.js +3 -181
  540. package/dist/lib/unit-containment.js +2 -2
  541. package/dist/lib/unit-report.d.ts.map +1 -1
  542. package/dist/lib/unit-report.js +5 -4
  543. package/dist/lib/zone-colors.d.ts +11 -0
  544. package/dist/lib/zone-colors.d.ts.map +1 -0
  545. package/dist/lib/zone-colors.js +32 -0
  546. package/dist/lib/zone-quantities.d.ts.map +1 -1
  547. package/dist/lib/zone-quantities.js +113 -223
  548. package/dist/material-library.d.ts +9 -1
  549. package/dist/material-library.d.ts.map +1 -1
  550. package/dist/material-library.js +550 -1
  551. package/dist/node-slots/block.d.ts +7 -0
  552. package/dist/node-slots/block.d.ts.map +1 -0
  553. package/dist/node-slots/block.js +27 -0
  554. package/dist/node-slots/cabinet.d.ts +4 -0
  555. package/dist/node-slots/cabinet.d.ts.map +1 -0
  556. package/dist/node-slots/cabinet.js +24 -0
  557. package/dist/node-slots/ceiling.d.ts +6 -0
  558. package/dist/node-slots/ceiling.d.ts.map +1 -0
  559. package/dist/node-slots/ceiling.js +7 -0
  560. package/dist/node-slots/column.d.ts +9 -0
  561. package/dist/node-slots/column.d.ts.map +1 -0
  562. package/dist/node-slots/column.js +24 -0
  563. package/dist/node-slots/door.d.ts +9 -0
  564. package/dist/node-slots/door.d.ts.map +1 -0
  565. package/dist/node-slots/door.js +20 -0
  566. package/dist/node-slots/duct.d.ts +5 -0
  567. package/dist/node-slots/duct.d.ts.map +1 -0
  568. package/dist/node-slots/duct.js +5 -0
  569. package/dist/node-slots/elevator.d.ts +9 -0
  570. package/dist/node-slots/elevator.d.ts.map +1 -0
  571. package/dist/node-slots/elevator.js +17 -0
  572. package/dist/node-slots/fence.d.ts +10 -0
  573. package/dist/node-slots/fence.d.ts.map +1 -0
  574. package/dist/node-slots/fence.js +23 -0
  575. package/dist/node-slots/index.d.ts +25 -0
  576. package/dist/node-slots/index.d.ts.map +1 -0
  577. package/dist/node-slots/index.js +92 -0
  578. package/dist/node-slots/lean-to-extension.d.ts +5 -0
  579. package/dist/node-slots/lean-to-extension.d.ts.map +1 -0
  580. package/dist/node-slots/lean-to-extension.js +15 -0
  581. package/dist/node-slots/procedural-item.d.ts +4 -0
  582. package/dist/node-slots/procedural-item.d.ts.map +1 -0
  583. package/dist/node-slots/procedural-item.js +3 -0
  584. package/dist/node-slots/roof-accessories.d.ts +9 -0
  585. package/dist/node-slots/roof-accessories.d.ts.map +1 -0
  586. package/dist/node-slots/roof-accessories.js +34 -0
  587. package/dist/node-slots/shelf.d.ts +9 -0
  588. package/dist/node-slots/shelf.d.ts.map +1 -0
  589. package/dist/node-slots/shelf.js +30 -0
  590. package/dist/node-slots/slab.d.ts +7 -0
  591. package/dist/node-slots/slab.d.ts.map +1 -0
  592. package/dist/node-slots/slab.js +21 -0
  593. package/dist/node-slots/stair.d.ts +8 -0
  594. package/dist/node-slots/stair.d.ts.map +1 -0
  595. package/dist/node-slots/stair.js +17 -0
  596. package/dist/node-slots/wall.d.ts +12 -0
  597. package/dist/node-slots/wall.d.ts.map +1 -0
  598. package/dist/node-slots/wall.js +55 -0
  599. package/dist/node-slots/window.d.ts +5 -0
  600. package/dist/node-slots/window.d.ts.map +1 -0
  601. package/dist/node-slots/window.js +11 -0
  602. package/dist/procedural-items/design-placement.d.ts +49 -0
  603. package/dist/procedural-items/design-placement.d.ts.map +1 -0
  604. package/dist/procedural-items/design-placement.js +129 -0
  605. package/dist/procedural-items/design.d.ts +261 -0
  606. package/dist/procedural-items/design.d.ts.map +1 -0
  607. package/dist/procedural-items/design.js +707 -0
  608. package/dist/procedural-items/fixtures.d.ts +464 -24
  609. package/dist/procedural-items/fixtures.d.ts.map +1 -1
  610. package/dist/procedural-items/index.d.ts +5 -0
  611. package/dist/procedural-items/index.d.ts.map +1 -1
  612. package/dist/procedural-items/index.js +5 -0
  613. package/dist/procedural-items/integration.d.ts +127 -6
  614. package/dist/procedural-items/integration.d.ts.map +1 -1
  615. package/dist/procedural-items/joints.d.ts +56 -0
  616. package/dist/procedural-items/joints.d.ts.map +1 -0
  617. package/dist/procedural-items/joints.js +251 -0
  618. package/dist/procedural-items/library-colors.d.ts +12 -0
  619. package/dist/procedural-items/library-colors.d.ts.map +1 -1
  620. package/dist/procedural-items/library-colors.js +37 -3
  621. package/dist/procedural-items/motion-controller.d.ts +29 -0
  622. package/dist/procedural-items/motion-controller.d.ts.map +1 -0
  623. package/dist/procedural-items/motion-controller.js +130 -0
  624. package/dist/procedural-items/node.d.ts +490 -24
  625. package/dist/procedural-items/node.d.ts.map +1 -1
  626. package/dist/procedural-items/query.d.ts +18 -1
  627. package/dist/procedural-items/query.d.ts.map +1 -1
  628. package/dist/procedural-items/query.js +78 -39
  629. package/dist/procedural-items/recipe.d.ts +258 -14
  630. package/dist/procedural-items/recipe.d.ts.map +1 -1
  631. package/dist/procedural-items/recipe.js +933 -61
  632. package/dist/procedural-items/section.d.ts +27 -0
  633. package/dist/procedural-items/section.d.ts.map +1 -0
  634. package/dist/procedural-items/section.js +237 -0
  635. package/dist/procedural-items/spatial.d.ts +21 -0
  636. package/dist/procedural-items/spatial.d.ts.map +1 -1
  637. package/dist/procedural-items/spatial.js +90 -0
  638. package/dist/registry/handles.d.ts +2 -0
  639. package/dist/registry/handles.d.ts.map +1 -1
  640. package/dist/registry/index.d.ts +6 -4
  641. package/dist/registry/index.d.ts.map +1 -1
  642. package/dist/registry/index.js +4 -2
  643. package/dist/registry/mechanism.d.ts +9 -0
  644. package/dist/registry/mechanism.d.ts.map +1 -0
  645. package/dist/registry/mechanism.js +21 -0
  646. package/dist/registry/registry.d.ts +6 -3
  647. package/dist/registry/registry.d.ts.map +1 -1
  648. package/dist/registry/registry.js +59 -22
  649. package/dist/registry/scene-api.d.ts +20 -0
  650. package/dist/registry/scene-api.d.ts.map +1 -1
  651. package/dist/registry/scene-api.js +26 -13
  652. package/dist/registry/subtree.d.ts +8 -0
  653. package/dist/registry/subtree.d.ts.map +1 -1
  654. package/dist/registry/subtree.js +53 -0
  655. package/dist/registry/types.d.ts +340 -11
  656. package/dist/registry/types.d.ts.map +1 -1
  657. package/dist/schema/__fixtures__/node-fixtures.d.ts.map +1 -1
  658. package/dist/schema/__fixtures__/node-fixtures.js +2 -0
  659. package/dist/schema/assembly.d.ts +153 -0
  660. package/dist/schema/assembly.d.ts.map +1 -0
  661. package/dist/schema/assembly.js +155 -0
  662. package/dist/schema/asset-url.d.ts +2 -1
  663. package/dist/schema/asset-url.d.ts.map +1 -1
  664. package/dist/schema/asset-url.js +5 -2
  665. package/dist/schema/base.d.ts +26 -0
  666. package/dist/schema/base.d.ts.map +1 -1
  667. package/dist/schema/base.js +2 -0
  668. package/dist/schema/collection-templates.d.ts +46 -0
  669. package/dist/schema/collection-templates.d.ts.map +1 -0
  670. package/dist/schema/collection-templates.js +14 -0
  671. package/dist/schema/collections.d.ts +7 -0
  672. package/dist/schema/collections.d.ts.map +1 -1
  673. package/dist/schema/cut.d.ts +29 -0
  674. package/dist/schema/cut.d.ts.map +1 -0
  675. package/dist/schema/cut.js +50 -0
  676. package/dist/schema/geometry-metadata.d.ts +51 -0
  677. package/dist/schema/geometry-metadata.d.ts.map +1 -0
  678. package/dist/schema/geometry-metadata.js +57 -0
  679. package/dist/schema/geometry-source.d.ts +250 -0
  680. package/dist/schema/geometry-source.d.ts.map +1 -0
  681. package/dist/schema/geometry-source.js +130 -0
  682. package/dist/schema/index.d.ts +19 -7
  683. package/dist/schema/index.d.ts.map +1 -1
  684. package/dist/schema/index.js +21 -5
  685. package/dist/schema/nodes/block.d.ts +26 -0
  686. package/dist/schema/nodes/block.d.ts.map +1 -1
  687. package/dist/schema/nodes/block.js +1 -1
  688. package/dist/schema/nodes/box-vent.d.ts +26 -0
  689. package/dist/schema/nodes/box-vent.d.ts.map +1 -1
  690. package/dist/schema/nodes/building.d.ts +26 -0
  691. package/dist/schema/nodes/building.d.ts.map +1 -1
  692. package/dist/schema/nodes/cabinet.d.ts +61 -9
  693. package/dist/schema/nodes/cabinet.d.ts.map +1 -1
  694. package/dist/schema/nodes/ceiling.d.ts +37 -0
  695. package/dist/schema/nodes/ceiling.d.ts.map +1 -1
  696. package/dist/schema/nodes/ceiling.js +8 -0
  697. package/dist/schema/nodes/chimney.d.ts +26 -0
  698. package/dist/schema/nodes/chimney.d.ts.map +1 -1
  699. package/dist/schema/nodes/column.d.ts +126 -0
  700. package/dist/schema/nodes/column.d.ts.map +1 -1
  701. package/dist/schema/nodes/column.js +2 -0
  702. package/dist/schema/nodes/construction-dimension.d.ts +26 -0
  703. package/dist/schema/nodes/construction-dimension.d.ts.map +1 -1
  704. package/dist/schema/nodes/cupola.d.ts +26 -0
  705. package/dist/schema/nodes/cupola.d.ts.map +1 -1
  706. package/dist/schema/nodes/curtain-wall.d.ts +5 -5
  707. package/dist/schema/nodes/door.d.ts +139 -20
  708. package/dist/schema/nodes/door.d.ts.map +1 -1
  709. package/dist/schema/nodes/door.js +18 -33
  710. package/dist/schema/nodes/dormer.d.ts +28 -2
  711. package/dist/schema/nodes/dormer.d.ts.map +1 -1
  712. package/dist/schema/nodes/downspout.d.ts +27 -1
  713. package/dist/schema/nodes/downspout.d.ts.map +1 -1
  714. package/dist/schema/nodes/duct-fitting.d.ts +27 -1
  715. package/dist/schema/nodes/duct-fitting.d.ts.map +1 -1
  716. package/dist/schema/nodes/duct-segment.d.ts +27 -1
  717. package/dist/schema/nodes/duct-segment.d.ts.map +1 -1
  718. package/dist/schema/nodes/duct-terminal.d.ts +26 -0
  719. package/dist/schema/nodes/duct-terminal.d.ts.map +1 -1
  720. package/dist/schema/nodes/elevator.d.ts +26 -0
  721. package/dist/schema/nodes/elevator.d.ts.map +1 -1
  722. package/dist/schema/nodes/eyebrow-vent.d.ts +26 -0
  723. package/dist/schema/nodes/eyebrow-vent.d.ts.map +1 -1
  724. package/dist/schema/nodes/fence-feature.d.ts +141 -0
  725. package/dist/schema/nodes/fence-feature.d.ts.map +1 -0
  726. package/dist/schema/nodes/fence-feature.js +21 -0
  727. package/dist/schema/nodes/fence.d.ts +186 -0
  728. package/dist/schema/nodes/fence.d.ts.map +1 -1
  729. package/dist/schema/nodes/fence.js +92 -7
  730. package/dist/schema/nodes/floor-opening.d.ts +61 -0
  731. package/dist/schema/nodes/floor-opening.d.ts.map +1 -0
  732. package/dist/schema/nodes/floor-opening.js +17 -0
  733. package/dist/schema/nodes/guide.d.ts +26 -0
  734. package/dist/schema/nodes/guide.d.ts.map +1 -1
  735. package/dist/schema/nodes/gutter.d.ts +26 -0
  736. package/dist/schema/nodes/gutter.d.ts.map +1 -1
  737. package/dist/schema/nodes/hvac-equipment.d.ts +26 -0
  738. package/dist/schema/nodes/hvac-equipment.d.ts.map +1 -1
  739. package/dist/schema/nodes/imported-mesh.d.ts +26 -0
  740. package/dist/schema/nodes/imported-mesh.d.ts.map +1 -1
  741. package/dist/schema/nodes/item.d.ts +153 -2
  742. package/dist/schema/nodes/item.d.ts.map +1 -1
  743. package/dist/schema/nodes/item.js +13 -0
  744. package/dist/schema/nodes/lean-to-extension.d.ts +26 -0
  745. package/dist/schema/nodes/lean-to-extension.d.ts.map +1 -1
  746. package/dist/schema/nodes/level.d.ts +27 -1
  747. package/dist/schema/nodes/level.d.ts.map +1 -1
  748. package/dist/schema/nodes/lineset.d.ts +26 -0
  749. package/dist/schema/nodes/lineset.d.ts.map +1 -1
  750. package/dist/schema/nodes/liquid-line.d.ts +26 -0
  751. package/dist/schema/nodes/liquid-line.d.ts.map +1 -1
  752. package/dist/schema/nodes/measurement.d.ts +26 -0
  753. package/dist/schema/nodes/measurement.d.ts.map +1 -1
  754. package/dist/schema/nodes/opening-types.d.ts +41 -0
  755. package/dist/schema/nodes/opening-types.d.ts.map +1 -0
  756. package/dist/schema/nodes/opening-types.js +48 -0
  757. package/dist/schema/nodes/pipe-fitting.d.ts +26 -0
  758. package/dist/schema/nodes/pipe-fitting.d.ts.map +1 -1
  759. package/dist/schema/nodes/pipe-segment.d.ts +26 -0
  760. package/dist/schema/nodes/pipe-segment.d.ts.map +1 -1
  761. package/dist/schema/nodes/pipe-trap.d.ts +26 -0
  762. package/dist/schema/nodes/pipe-trap.d.ts.map +1 -1
  763. package/dist/schema/nodes/ridge-vent.d.ts +26 -0
  764. package/dist/schema/nodes/ridge-vent.d.ts.map +1 -1
  765. package/dist/schema/nodes/roof-segment-walls.d.ts.map +1 -1
  766. package/dist/schema/nodes/roof-segment-walls.js +2 -1
  767. package/dist/schema/nodes/roof-segment.d.ts +30 -2
  768. package/dist/schema/nodes/roof-segment.d.ts.map +1 -1
  769. package/dist/schema/nodes/roof-segment.js +9 -0
  770. package/dist/schema/nodes/roof.d.ts +101 -0
  771. package/dist/schema/nodes/roof.d.ts.map +1 -1
  772. package/dist/schema/nodes/roof.js +6 -0
  773. package/dist/schema/nodes/scan.d.ts +26 -0
  774. package/dist/schema/nodes/scan.d.ts.map +1 -1
  775. package/dist/schema/nodes/separator.d.ts +50 -0
  776. package/dist/schema/nodes/separator.d.ts.map +1 -0
  777. package/dist/schema/nodes/separator.js +8 -0
  778. package/dist/schema/nodes/shelf.d.ts +26 -0
  779. package/dist/schema/nodes/shelf.d.ts.map +1 -1
  780. package/dist/schema/nodes/site.d.ts +192 -0
  781. package/dist/schema/nodes/site.d.ts.map +1 -1
  782. package/dist/schema/nodes/site.js +178 -1
  783. package/dist/schema/nodes/skylight.d.ts +30 -4
  784. package/dist/schema/nodes/skylight.d.ts.map +1 -1
  785. package/dist/schema/nodes/slab.d.ts +84 -0
  786. package/dist/schema/nodes/slab.d.ts.map +1 -1
  787. package/dist/schema/nodes/slab.js +37 -2
  788. package/dist/schema/nodes/solar-panel.d.ts +26 -0
  789. package/dist/schema/nodes/solar-panel.d.ts.map +1 -1
  790. package/dist/schema/nodes/spawn.d.ts +26 -0
  791. package/dist/schema/nodes/spawn.d.ts.map +1 -1
  792. package/dist/schema/nodes/stair-construction.d.ts +21 -0
  793. package/dist/schema/nodes/stair-construction.d.ts.map +1 -0
  794. package/dist/schema/nodes/stair-construction.js +13 -0
  795. package/dist/schema/nodes/stair-design-targets.d.ts +9 -0
  796. package/dist/schema/nodes/stair-design-targets.d.ts.map +1 -0
  797. package/dist/schema/nodes/stair-design-targets.js +7 -0
  798. package/dist/schema/nodes/stair-segment.d.ts +72 -4
  799. package/dist/schema/nodes/stair-segment.d.ts.map +1 -1
  800. package/dist/schema/nodes/stair-segment.js +13 -0
  801. package/dist/schema/nodes/stair.d.ts +119 -2
  802. package/dist/schema/nodes/stair.d.ts.map +1 -1
  803. package/dist/schema/nodes/stair.js +59 -2
  804. package/dist/schema/nodes/structural-grid.d.ts +26 -0
  805. package/dist/schema/nodes/structural-grid.d.ts.map +1 -1
  806. package/dist/schema/nodes/surface-hole-metadata.d.ts +3 -0
  807. package/dist/schema/nodes/surface-hole-metadata.d.ts.map +1 -1
  808. package/dist/schema/nodes/surface-hole-metadata.js +2 -1
  809. package/dist/schema/nodes/surface-paint-region.d.ts +14 -0
  810. package/dist/schema/nodes/surface-paint-region.d.ts.map +1 -0
  811. package/dist/schema/nodes/surface-paint-region.js +12 -0
  812. package/dist/schema/nodes/turbine-vent.d.ts +26 -0
  813. package/dist/schema/nodes/turbine-vent.d.ts.map +1 -1
  814. package/dist/schema/nodes/unit.d.ts +26 -0
  815. package/dist/schema/nodes/unit.d.ts.map +1 -1
  816. package/dist/schema/nodes/wall.d.ts +352 -61
  817. package/dist/schema/nodes/wall.d.ts.map +1 -1
  818. package/dist/schema/nodes/wall.js +185 -186
  819. package/dist/schema/nodes/window.d.ts +139 -20
  820. package/dist/schema/nodes/window.d.ts.map +1 -1
  821. package/dist/schema/nodes/window.js +12 -14
  822. package/dist/schema/nodes/zone.d.ts +69 -1
  823. package/dist/schema/nodes/zone.d.ts.map +1 -1
  824. package/dist/schema/nodes/zone.js +46 -0
  825. package/dist/schema/provenance.d.ts +118 -0
  826. package/dist/schema/provenance.d.ts.map +1 -0
  827. package/dist/schema/provenance.js +76 -0
  828. package/dist/schema/source-ref.d.ts +23 -0
  829. package/dist/schema/source-ref.d.ts.map +1 -0
  830. package/dist/schema/source-ref.js +29 -0
  831. package/dist/schema/types.d.ts +3317 -68
  832. package/dist/schema/types.d.ts.map +1 -1
  833. package/dist/schema/types.js +7 -0
  834. package/dist/services/alignment-anchors.d.ts +2 -1
  835. package/dist/services/alignment-anchors.d.ts.map +1 -1
  836. package/dist/services/alignment-anchors.js +9 -6
  837. package/dist/services/index.d.ts +1 -1
  838. package/dist/services/index.d.ts.map +1 -1
  839. package/dist/services/index.js +1 -1
  840. package/dist/services/level-height.d.ts.map +1 -1
  841. package/dist/services/level-height.js +6 -4
  842. package/dist/services/storey.d.ts +21 -1
  843. package/dist/services/storey.d.ts.map +1 -1
  844. package/dist/services/storey.js +94 -8
  845. package/dist/services/surface-hosting.d.ts.map +1 -1
  846. package/dist/services/surface-hosting.js +4 -1
  847. package/dist/store/actions/node-actions.d.ts +4563 -8
  848. package/dist/store/actions/node-actions.d.ts.map +1 -1
  849. package/dist/store/actions/node-actions.js +495 -174
  850. package/dist/store/derived-node-guard.d.ts +84 -0
  851. package/dist/store/derived-node-guard.d.ts.map +1 -0
  852. package/dist/store/derived-node-guard.js +586 -0
  853. package/dist/store/history-control.d.ts +34 -0
  854. package/dist/store/history-control.d.ts.map +1 -1
  855. package/dist/store/history-control.js +99 -1
  856. package/dist/store/history-drafts.d.ts +48 -0
  857. package/dist/store/history-drafts.d.ts.map +1 -0
  858. package/dist/store/history-drafts.js +403 -0
  859. package/dist/store/history-invalidation.d.ts.map +1 -1
  860. package/dist/store/history-invalidation.js +1 -0
  861. package/dist/store/item-interaction.d.ts +28 -0
  862. package/dist/store/item-interaction.d.ts.map +1 -0
  863. package/dist/store/item-interaction.js +34 -0
  864. package/dist/store/registered-node-defaults.d.ts +11 -0
  865. package/dist/store/registered-node-defaults.d.ts.map +1 -0
  866. package/dist/store/registered-node-defaults.js +25 -0
  867. package/dist/store/scene-annotations.d.ts +8969 -0
  868. package/dist/store/scene-annotations.d.ts.map +1 -0
  869. package/dist/store/scene-annotations.js +107 -0
  870. package/dist/store/use-interactive.d.ts +23 -1
  871. package/dist/store/use-interactive.d.ts.map +1 -1
  872. package/dist/store/use-interactive.js +128 -5
  873. package/dist/store/use-scene.d.ts +68 -12
  874. package/dist/store/use-scene.d.ts.map +1 -1
  875. package/dist/store/use-scene.js +416 -305
  876. package/dist/systems/elevator/elevator-opening-sync.d.ts.map +1 -1
  877. package/dist/systems/elevator/elevator-opening-sync.js +4 -6
  878. package/dist/systems/elevator/elevator-opening-system.d.ts.map +1 -1
  879. package/dist/systems/elevator/elevator-opening-system.js +12 -6
  880. package/dist/systems/elevator/elevator-service.d.ts.map +1 -1
  881. package/dist/systems/elevator/elevator-service.js +8 -3
  882. package/dist/systems/fence/fence-centerline.d.ts.map +1 -1
  883. package/dist/systems/fence/fence-centerline.js +6 -5
  884. package/dist/systems/fence/fence-features.d.ts +36 -0
  885. package/dist/systems/fence/fence-features.d.ts.map +1 -0
  886. package/dist/systems/fence/fence-features.js +105 -0
  887. package/dist/systems/fence/fence-spline.d.ts +8 -5
  888. package/dist/systems/fence/fence-spline.d.ts.map +1 -1
  889. package/dist/systems/fence/fence-spline.js +51 -16
  890. package/dist/systems/owned-floor-openings.d.ts +9 -0
  891. package/dist/systems/owned-floor-openings.d.ts.map +1 -0
  892. package/dist/systems/owned-floor-openings.js +326 -0
  893. package/dist/systems/reconcile-owned-floor-openings.d.ts +3 -0
  894. package/dist/systems/reconcile-owned-floor-openings.d.ts.map +1 -0
  895. package/dist/systems/reconcile-owned-floor-openings.js +25 -0
  896. package/dist/systems/slab/__fixtures__/doorway-steps.d.ts +8 -0
  897. package/dist/systems/slab/__fixtures__/doorway-steps.d.ts.map +1 -0
  898. package/dist/systems/slab/__fixtures__/doorway-steps.js +62 -0
  899. package/dist/systems/slab/__fixtures__/floor-step.d.ts +5636 -0
  900. package/dist/systems/slab/__fixtures__/floor-step.d.ts.map +1 -0
  901. package/dist/systems/slab/__fixtures__/floor-step.js +66 -0
  902. package/dist/systems/slab/__fixtures__/raised-room.d.ts +5775 -0
  903. package/dist/systems/slab/__fixtures__/raised-room.d.ts.map +1 -0
  904. package/dist/systems/slab/__fixtures__/raised-room.js +54 -0
  905. package/dist/systems/slab/ensure-slab-openings.d.ts +9 -0
  906. package/dist/systems/slab/ensure-slab-openings.d.ts.map +1 -0
  907. package/dist/systems/slab/ensure-slab-openings.js +41 -0
  908. package/dist/systems/slab/slab-support.d.ts +25 -6
  909. package/dist/systems/slab/slab-support.d.ts.map +1 -1
  910. package/dist/systems/slab/slab-support.js +471 -54
  911. package/dist/systems/stair/stair-base-elevation.d.ts +3 -0
  912. package/dist/systems/stair/stair-base-elevation.d.ts.map +1 -0
  913. package/dist/systems/stair/stair-base-elevation.js +49 -0
  914. package/dist/systems/stair/stair-clearance.d.ts +39 -0
  915. package/dist/systems/stair/stair-clearance.d.ts.map +1 -0
  916. package/dist/systems/stair/stair-clearance.js +508 -0
  917. package/dist/systems/stair/stair-construction.d.ts +37 -0
  918. package/dist/systems/stair/stair-construction.d.ts.map +1 -0
  919. package/dist/systems/stair/stair-construction.js +314 -0
  920. package/dist/systems/stair/stair-detail-budget.d.ts +13 -0
  921. package/dist/systems/stair/stair-detail-budget.d.ts.map +1 -0
  922. package/dist/systems/stair/stair-detail-budget.js +64 -0
  923. package/dist/systems/stair/stair-flight.d.ts +2 -2
  924. package/dist/systems/stair/stair-flight.d.ts.map +1 -1
  925. package/dist/systems/stair/stair-flight.js +4 -3
  926. package/dist/systems/stair/stair-floor-footprints.d.ts +7 -0
  927. package/dist/systems/stair/stair-floor-footprints.d.ts.map +1 -0
  928. package/dist/systems/stair/stair-floor-footprints.js +113 -0
  929. package/dist/systems/stair/stair-footprint.d.ts +3 -1
  930. package/dist/systems/stair/stair-footprint.d.ts.map +1 -1
  931. package/dist/systems/stair/stair-footprint.js +97 -44
  932. package/dist/systems/stair/stair-layout.d.ts +39 -0
  933. package/dist/systems/stair/stair-layout.d.ts.map +1 -0
  934. package/dist/systems/stair/stair-layout.js +58 -0
  935. package/dist/systems/stair/stair-opening-preview.d.ts +1612 -80
  936. package/dist/systems/stair/stair-opening-preview.d.ts.map +1 -1
  937. package/dist/systems/stair/stair-opening-sync.d.ts +8 -2
  938. package/dist/systems/stair/stair-opening-sync.d.ts.map +1 -1
  939. package/dist/systems/stair/stair-opening-sync.js +136 -315
  940. package/dist/systems/stair/stair-opening-system.d.ts.map +1 -1
  941. package/dist/systems/stair/stair-opening-system.js +40 -8
  942. package/dist/systems/stair/stair-presets.d.ts +276 -0
  943. package/dist/systems/stair/stair-presets.d.ts.map +1 -0
  944. package/dist/systems/stair/stair-presets.js +151 -0
  945. package/dist/systems/stair/stair-rail-budget.d.ts +6 -0
  946. package/dist/systems/stair/stair-rail-budget.d.ts.map +1 -0
  947. package/dist/systems/stair/stair-rail-budget.js +36 -0
  948. package/dist/systems/stair/stair-rail-path.d.ts +22 -0
  949. package/dist/systems/stair/stair-rail-path.d.ts.map +1 -0
  950. package/dist/systems/stair/stair-rail-path.js +497 -0
  951. package/dist/systems/stair/stair-rise-edit.d.ts +9 -0
  952. package/dist/systems/stair/stair-rise-edit.d.ts.map +1 -0
  953. package/dist/systems/stair/stair-rise-edit.js +46 -0
  954. package/dist/systems/stair/stair-rise-query.d.ts +24 -0
  955. package/dist/systems/stair/stair-rise-query.d.ts.map +1 -0
  956. package/dist/systems/stair/stair-rise-query.js +125 -0
  957. package/dist/systems/stair/stair-rise.d.ts +4 -19
  958. package/dist/systems/stair/stair-rise.d.ts.map +1 -1
  959. package/dist/systems/stair/stair-rise.js +8 -71
  960. package/dist/systems/stair/stair-sizing.d.ts +414 -0
  961. package/dist/systems/stair/stair-sizing.d.ts.map +1 -0
  962. package/dist/systems/stair/stair-sizing.js +255 -0
  963. package/dist/systems/stair/stair-sweep-edit.d.ts +7 -0
  964. package/dist/systems/stair/stair-sweep-edit.d.ts.map +1 -0
  965. package/dist/systems/stair/stair-sweep-edit.js +8 -0
  966. package/dist/systems/stair/stair-walking-line.d.ts +5 -0
  967. package/dist/systems/stair/stair-walking-line.d.ts.map +1 -0
  968. package/dist/systems/stair/stair-walking-line.js +91 -0
  969. package/dist/systems/stair/stair-winder.d.ts +36 -0
  970. package/dist/systems/stair/stair-winder.d.ts.map +1 -0
  971. package/dist/systems/stair/stair-winder.js +173 -0
  972. package/dist/systems/wall/wall-assembly.d.ts +234 -0
  973. package/dist/systems/wall/wall-assembly.d.ts.map +1 -0
  974. package/dist/systems/wall/wall-assembly.js +854 -0
  975. package/dist/systems/wall/wall-curve.d.ts +2 -1
  976. package/dist/systems/wall/wall-curve.d.ts.map +1 -1
  977. package/dist/systems/wall/wall-curve.js +21 -5
  978. package/dist/systems/wall/wall-finish.d.ts +102 -0
  979. package/dist/systems/wall/wall-finish.d.ts.map +1 -0
  980. package/dist/systems/wall/wall-finish.js +264 -0
  981. package/dist/systems/wall/wall-footprint.d.ts +3 -0
  982. package/dist/systems/wall/wall-footprint.d.ts.map +1 -1
  983. package/dist/systems/wall/wall-footprint.js +15 -13
  984. package/dist/systems/wall/wall-frame.d.ts +45 -0
  985. package/dist/systems/wall/wall-frame.d.ts.map +1 -0
  986. package/dist/systems/wall/wall-frame.js +162 -0
  987. package/dist/systems/wall/wall-layer-bands.d.ts +38 -0
  988. package/dist/systems/wall/wall-layer-bands.d.ts.map +1 -0
  989. package/dist/systems/wall/wall-layer-bands.js +109 -0
  990. package/dist/systems/wall/wall-merge.d.ts +20 -1
  991. package/dist/systems/wall/wall-merge.d.ts.map +1 -1
  992. package/dist/systems/wall/wall-merge.js +189 -18
  993. package/dist/systems/wall/wall-mitering.d.ts +6 -5
  994. package/dist/systems/wall/wall-mitering.d.ts.map +1 -1
  995. package/dist/systems/wall/wall-mitering.js +70 -20
  996. package/dist/systems/wall/wall-operations.d.ts +1 -1
  997. package/dist/systems/wall/wall-operations.d.ts.map +1 -1
  998. package/dist/systems/wall/wall-operations.js +2 -1
  999. package/dist/systems/wall/wall-paint-plan.d.ts +30 -0
  1000. package/dist/systems/wall/wall-paint-plan.d.ts.map +1 -0
  1001. package/dist/systems/wall/wall-paint-plan.js +167 -0
  1002. package/dist/systems/wall/wall-room-sides.d.ts +6 -0
  1003. package/dist/systems/wall/wall-room-sides.d.ts.map +1 -0
  1004. package/dist/systems/wall/wall-room-sides.js +14 -0
  1005. package/dist/systems/wall/wall-step-openings.d.ts +17 -0
  1006. package/dist/systems/wall/wall-step-openings.d.ts.map +1 -0
  1007. package/dist/systems/wall/wall-step-openings.js +32 -0
  1008. package/dist/systems/wall/wall-top.d.ts +2 -6
  1009. package/dist/systems/wall/wall-top.d.ts.map +1 -1
  1010. package/dist/systems/wall/wall-top.js +3 -9
  1011. package/dist/systems/wall/wall-topology.d.ts +21 -0
  1012. package/dist/systems/wall/wall-topology.d.ts.map +1 -1
  1013. package/dist/systems/wall/wall-topology.js +405 -4
  1014. package/dist/utils/clone-scene-graph.d.ts +6 -0
  1015. package/dist/utils/clone-scene-graph.d.ts.map +1 -1
  1016. package/dist/utils/clone-scene-graph.js +123 -15
  1017. package/dist/utils/ensure-scene-openings.d.ts +8965 -0
  1018. package/dist/utils/ensure-scene-openings.d.ts.map +1 -0
  1019. package/dist/utils/ensure-scene-openings.js +29 -0
  1020. package/dist/utils/exterior-threshold-migration.d.ts +4 -0
  1021. package/dist/utils/exterior-threshold-migration.d.ts.map +1 -0
  1022. package/dist/utils/exterior-threshold-migration.js +114 -0
  1023. package/dist/utils/floor-follow-migration.d.ts +3 -0
  1024. package/dist/utils/floor-follow-migration.d.ts.map +1 -0
  1025. package/dist/utils/floor-follow-migration.js +29 -0
  1026. package/dist/utils/floor-opening-migration.d.ts +13 -0
  1027. package/dist/utils/floor-opening-migration.d.ts.map +1 -0
  1028. package/dist/utils/floor-opening-migration.js +148 -0
  1029. package/dist/utils/floor-piece-adoption.d.ts +50 -0
  1030. package/dist/utils/floor-piece-adoption.d.ts.map +1 -0
  1031. package/dist/utils/floor-piece-adoption.js +182 -0
  1032. package/dist/utils/floor-plate-migration.d.ts +4507 -0
  1033. package/dist/utils/floor-plate-migration.d.ts.map +1 -0
  1034. package/dist/utils/floor-plate-migration.js +1360 -0
  1035. package/dist/utils/heal-plan-coordinates.d.ts +2 -0
  1036. package/dist/utils/heal-plan-coordinates.d.ts.map +1 -0
  1037. package/dist/utils/heal-plan-coordinates.js +69 -0
  1038. package/dist/utils/heal-scene-graph.d.ts +20 -6
  1039. package/dist/utils/heal-scene-graph.d.ts.map +1 -1
  1040. package/dist/utils/heal-scene-graph.js +61 -16
  1041. package/dist/utils/legacy-material-slots.d.ts +23 -0
  1042. package/dist/utils/legacy-material-slots.d.ts.map +1 -0
  1043. package/dist/utils/legacy-material-slots.js +120 -0
  1044. package/dist/utils/legacy-opening-datums.d.ts +11 -0
  1045. package/dist/utils/legacy-opening-datums.d.ts.map +1 -0
  1046. package/dist/utils/legacy-opening-datums.js +92 -0
  1047. package/dist/utils/legacy-wall-datums.d.ts +6 -0
  1048. package/dist/utils/legacy-wall-datums.d.ts.map +1 -0
  1049. package/dist/utils/legacy-wall-datums.js +199 -0
  1050. package/dist/utils/load-migration.d.ts +28 -0
  1051. package/dist/utils/load-migration.d.ts.map +1 -0
  1052. package/dist/utils/load-migration.js +89 -0
  1053. package/dist/utils/node-defaults.d.ts +37 -0
  1054. package/dist/utils/node-defaults.d.ts.map +1 -0
  1055. package/dist/utils/node-defaults.js +96 -0
  1056. package/dist/utils/normalize-legacy-structure.d.ts +2 -0
  1057. package/dist/utils/normalize-legacy-structure.d.ts.map +1 -0
  1058. package/dist/utils/normalize-legacy-structure.js +61 -0
  1059. package/dist/utils/omit-undefined.d.ts +2 -0
  1060. package/dist/utils/omit-undefined.d.ts.map +1 -0
  1061. package/dist/utils/omit-undefined.js +17 -0
  1062. package/dist/utils/owned-floor-opening-migration.d.ts +4489 -0
  1063. package/dist/utils/owned-floor-opening-migration.d.ts.map +1 -0
  1064. package/dist/utils/owned-floor-opening-migration.js +365 -0
  1065. package/dist/utils/reconcile-structure-on-load.d.ts +8965 -0
  1066. package/dist/utils/reconcile-structure-on-load.d.ts.map +1 -0
  1067. package/dist/utils/reconcile-structure-on-load.js +307 -0
  1068. package/dist/utils/room-zone-migration.d.ts +18 -0
  1069. package/dist/utils/room-zone-migration.d.ts.map +1 -0
  1070. package/dist/utils/room-zone-migration.js +258 -0
  1071. package/dist/utils/scene-migrations.d.ts +16 -1
  1072. package/dist/utils/scene-migrations.d.ts.map +1 -1
  1073. package/dist/utils/scene-migrations.js +15 -1
  1074. package/dist/utils/structure-id.d.ts +4 -0
  1075. package/dist/utils/structure-id.d.ts.map +1 -0
  1076. package/dist/utils/structure-id.js +115 -0
  1077. package/dist/utils/vertical-scene-migration.d.ts +8 -8
  1078. package/dist/utils/vertical-scene-migration.d.ts.map +1 -1
  1079. package/dist/utils/vertical-scene-migration.js +18 -8
  1080. package/dist/utils/wall-assembly-migration.d.ts +14 -0
  1081. package/dist/utils/wall-assembly-migration.d.ts.map +1 -0
  1082. package/dist/utils/wall-assembly-migration.js +23 -0
  1083. package/dist/utils/wall-face-migration.d.ts +23 -0
  1084. package/dist/utils/wall-face-migration.d.ts.map +1 -0
  1085. package/dist/utils/wall-face-migration.js +246 -0
  1086. package/dist/validation/opening-bounds.d.ts +36 -0
  1087. package/dist/validation/opening-bounds.d.ts.map +1 -0
  1088. package/dist/validation/opening-bounds.js +34 -0
  1089. package/dist/validation/validate-build-json.d.ts +2 -0
  1090. package/dist/validation/validate-build-json.d.ts.map +1 -1
  1091. package/dist/validation/validate-build-json.js +36 -1
  1092. package/package.json +36 -3
  1093. package/dist/services/surface-hosting-procedural-parity.fixtures.d.ts +0 -13
  1094. package/dist/services/surface-hosting-procedural-parity.fixtures.d.ts.map +0 -1
  1095. package/dist/services/surface-hosting-procedural-parity.fixtures.js +0 -4691
  1096. package/dist/services/surface-hosting-shelf-parity.fixtures.d.ts +0 -1060
  1097. package/dist/services/surface-hosting-shelf-parity.fixtures.d.ts.map +0 -1
  1098. package/dist/services/surface-hosting-shelf-parity.fixtures.js +0 -3127
@@ -0,0 +1,1265 @@
1
+ import { getWallArcData, getWallCurveFrameAt, isCurvedWall } from '../systems/wall/wall-curve.js';
2
+ import { getWallBodyCenterOffset, getWallFaceOffsets } from '../systems/wall/wall-frame.js';
3
+ import { area, difference, intersection, union } from './polygon-boolean.js';
4
+ const ROOM_CURVE_TOLERANCE = 0.04;
5
+ const MAX_CURVE_SUBDIVISION_DEPTH = 6;
6
+ export const WALL_JUNCTION_TOLERANCE = 0.08;
7
+ export function pointFromTuple(point) {
8
+ return { x: point[0], y: point[1] };
9
+ }
10
+ export function pointToTuple(point) {
11
+ return [point.x, point.y];
12
+ }
13
+ function pointKey(point) {
14
+ return `${point.x.toFixed(3)},${point.y.toFixed(3)}`;
15
+ }
16
+ export function polygonArea(points) {
17
+ let area = 0;
18
+ for (let i = 0; i < points.length; i++) {
19
+ const a = points[i];
20
+ const b = points[(i + 1) % points.length];
21
+ if (!(a && b))
22
+ continue;
23
+ area += a.x * b.y - b.x * a.y;
24
+ }
25
+ return area / 2;
26
+ }
27
+ function minRotationSignature(keys) {
28
+ if (keys.length === 0)
29
+ return '';
30
+ let best = '';
31
+ for (let i = 0; i < keys.length; i++) {
32
+ const rotated = [...keys.slice(i), ...keys.slice(0, i)];
33
+ const value = rotated.join('|');
34
+ if (!best || value < best)
35
+ best = value;
36
+ }
37
+ return best;
38
+ }
39
+ export function polygonSignature(points) {
40
+ const keys = points.map(pointKey);
41
+ const forward = minRotationSignature(keys);
42
+ const reversed = minRotationSignature([...keys].reverse());
43
+ return forward < reversed ? forward : reversed;
44
+ }
45
+ function samePointWithinTolerance(a, b, tolerance = 1e-4) {
46
+ return Math.hypot(a.x - b.x, a.y - b.y) <= tolerance;
47
+ }
48
+ export function dedupeSequentialPoints(points, tolerance = 1e-4) {
49
+ const deduped = [];
50
+ for (const point of points) {
51
+ const previous = deduped[deduped.length - 1];
52
+ if (previous && samePointWithinTolerance(previous, point, tolerance)) {
53
+ continue;
54
+ }
55
+ deduped.push(point);
56
+ }
57
+ const firstPoint = deduped[0];
58
+ const lastPoint = deduped[deduped.length - 1];
59
+ if (deduped.length > 2 &&
60
+ firstPoint &&
61
+ lastPoint &&
62
+ samePointWithinTolerance(firstPoint, lastPoint, tolerance)) {
63
+ deduped.pop();
64
+ }
65
+ return deduped;
66
+ }
67
+ export function bboxOf(points) {
68
+ let minX = Number.POSITIVE_INFINITY;
69
+ let minY = Number.POSITIVE_INFINITY;
70
+ let maxX = Number.NEGATIVE_INFINITY;
71
+ let maxY = Number.NEGATIVE_INFINITY;
72
+ for (const point of points) {
73
+ minX = Math.min(minX, point.x);
74
+ minY = Math.min(minY, point.y);
75
+ maxX = Math.max(maxX, point.x);
76
+ maxY = Math.max(maxY, point.y);
77
+ }
78
+ return { minX, minY, maxX, maxY };
79
+ }
80
+ function pointLineDistance(point, start, end) {
81
+ const dx = end.x - start.x;
82
+ const dy = end.y - start.y;
83
+ const lengthSquared = dx * dx + dy * dy;
84
+ if (lengthSquared < 1e-9) {
85
+ return Math.hypot(point.x - start.x, point.y - start.y);
86
+ }
87
+ const cross = (point.x - start.x) * dy - (point.y - start.y) * dx;
88
+ return Math.abs(cross) / Math.sqrt(lengthSquared);
89
+ }
90
+ export function sampleWallPointsForRoomDetection(wall, tolerance = ROOM_CURVE_TOLERANCE) {
91
+ const start = { x: wall.start[0], y: wall.start[1] };
92
+ const end = { x: wall.end[0], y: wall.end[1] };
93
+ if (!isCurvedWall(wall)) {
94
+ return [start, end];
95
+ }
96
+ const subdivide = (t0, p0, t1, p1, depth) => {
97
+ const midT = (t0 + t1) / 2;
98
+ const midPoint = getWallCurveFrameAt(wall, midT).point;
99
+ const deviation = pointLineDistance(midPoint, p0, p1);
100
+ if (depth >= MAX_CURVE_SUBDIVISION_DEPTH || deviation <= tolerance) {
101
+ return [p0, p1];
102
+ }
103
+ const left = subdivide(t0, p0, midT, midPoint, depth + 1);
104
+ const right = subdivide(midT, midPoint, t1, p1, depth + 1);
105
+ return [...left.slice(0, -1), ...right];
106
+ };
107
+ return subdivide(0, start, 1, end, 0);
108
+ }
109
+ function segmentProjection(point, start, end) {
110
+ const dx = end.x - start.x;
111
+ const dy = end.y - start.y;
112
+ const lengthSquared = dx * dx + dy * dy;
113
+ if (lengthSquared < 1e-12) {
114
+ return { t: 0, distance: Math.hypot(point.x - start.x, point.y - start.y) };
115
+ }
116
+ const t = ((point.x - start.x) * dx + (point.y - start.y) * dy) / lengthSquared;
117
+ const clampedT = Math.max(0, Math.min(1, t));
118
+ const projX = start.x + clampedT * dx;
119
+ const projY = start.y + clampedT * dy;
120
+ return { t, distance: Math.hypot(point.x - projX, point.y - projY) };
121
+ }
122
+ // Break a straight wall at any junction vertex (another wall's endpoint) that
123
+ // lands on its interior, returning the ordered polyline [start, …splits, end].
124
+ // Splitting at the *vertex* position (not the projection) keeps the split node's
125
+ // key identical to the touching wall's endpoint so the two share a graph node.
126
+ function splitStraightWallAtVertices(start, end, vertices, separator = false) {
127
+ const length = Math.hypot(end.x - start.x, end.y - start.y);
128
+ if (length < 1e-9)
129
+ return [start, end];
130
+ const interior = [];
131
+ for (const vertex of vertices) {
132
+ // Separators have authored/snapped coordinates; proximity must not pull an
133
+ // island into a nearby wall or bend another segment of a multi-point path.
134
+ const tolerance = separator || !vertex.wallEndpoint ? 1e-6 : WALL_JUNCTION_TOLERANCE;
135
+ const { t, distance } = segmentProjection(vertex, start, end);
136
+ if (distance > tolerance)
137
+ continue;
138
+ const along = t * length;
139
+ if (along <= tolerance || along >= length - tolerance)
140
+ continue;
141
+ interior.push({ point: { x: vertex.x, y: vertex.y }, t });
142
+ }
143
+ interior.sort((a, b) => a.t - b.t);
144
+ const ordered = [start];
145
+ let lastKey = pointKey(start);
146
+ for (const { point } of interior) {
147
+ const key = pointKey(point);
148
+ if (key === lastKey)
149
+ continue;
150
+ ordered.push(point);
151
+ lastKey = key;
152
+ }
153
+ if (lastKey !== pointKey(end))
154
+ ordered.push(end);
155
+ return ordered;
156
+ }
157
+ function splitCurvedWallAtVertices(points, vertices, wall) {
158
+ const arc = getWallArcData(wall);
159
+ const stations = [0];
160
+ for (let i = 1; i < points.length; i++) {
161
+ stations.push(stations[i - 1] +
162
+ Math.hypot(points[i].x - points[i - 1].x, points[i].y - points[i - 1].y));
163
+ }
164
+ const length = stations.at(-1);
165
+ const cuts = [
166
+ { point: points[0], station: 0 },
167
+ { point: points.at(-1), station: length },
168
+ ];
169
+ for (const vertex of vertices) {
170
+ // Divide snaps to 64 chord samples; allow their sagitta, not the wall-junction radius.
171
+ const separatorTolerance = arc ? arc.radius * (1 - Math.cos(arc.delta / 128)) + 1e-6 : 1e-6;
172
+ if (!vertex.wallEndpoint &&
173
+ arc &&
174
+ Math.abs(Math.hypot(vertex.x - arc.center.x, vertex.y - arc.center.y) - arc.radius) >
175
+ separatorTolerance)
176
+ continue;
177
+ const endpointTolerance = vertex.wallEndpoint ? WALL_JUNCTION_TOLERANCE : 1e-6;
178
+ let best = { distance: Number.POSITIVE_INFINITY, station: 0 };
179
+ for (let i = 0; i < points.length - 1; i++) {
180
+ const { t, distance } = segmentProjection(vertex, points[i], points[i + 1]);
181
+ if (distance >= best.distance)
182
+ continue;
183
+ best = {
184
+ distance,
185
+ station: stations[i] + Math.max(0, Math.min(1, t)) * (stations[i + 1] - stations[i]),
186
+ };
187
+ }
188
+ if (best.distance > WALL_JUNCTION_TOLERANCE ||
189
+ best.station <= endpointTolerance ||
190
+ best.station >= length - endpointTolerance)
191
+ continue;
192
+ cuts.push({ point: { x: vertex.x, y: vertex.y }, station: best.station });
193
+ }
194
+ cuts.sort((a, b) => a.station - b.station);
195
+ return cuts.slice(0, -1).flatMap((cut, i) => {
196
+ const next = cuts[i + 1];
197
+ if (pointKey(cut.point) === pointKey(next.point))
198
+ return [];
199
+ return [
200
+ dedupeSequentialPoints([
201
+ cut.point,
202
+ ...points.filter((_, j) => stations[j] > cut.station + 1e-8 && stations[j] < next.station - 1e-8),
203
+ next.point,
204
+ ]),
205
+ ];
206
+ });
207
+ }
208
+ // Reference half-edges determine connectivity; body lines keep room geometry invariant
209
+ // when a reference moves beneath an unchanged wall body.
210
+ function roomBodyPolygon(edges) {
211
+ const shifted = edges.map(({ wall, points }) => {
212
+ const offset = wall.type === 'wall' ? getWallBodyCenterOffset(wall) : 0;
213
+ const arc = getWallArcData(wall);
214
+ const frame = getWallCurveFrameAt(wall, 0);
215
+ return points.map((point) => {
216
+ if (offset === 0)
217
+ return point;
218
+ if (arc) {
219
+ const scale = (arc.radius - arc.direction * offset) / arc.radius;
220
+ return {
221
+ x: arc.center.x + (point.x - arc.center.x) * scale,
222
+ y: arc.center.y + (point.y - arc.center.y) * scale,
223
+ };
224
+ }
225
+ return { x: point.x + frame.normal.x * offset, y: point.y + frame.normal.y * offset };
226
+ });
227
+ });
228
+ const result = [];
229
+ for (let i = 0; i < shifted.length; i++) {
230
+ const previous = shifted[(i + shifted.length - 1) % shifted.length];
231
+ const current = shifted[i];
232
+ const a = previous[previous.length - 2];
233
+ const b = previous[previous.length - 1];
234
+ const c = current[0];
235
+ const d = current[1];
236
+ const dx = b.x - a.x, dy = b.y - a.y;
237
+ const ex = d.x - c.x, ey = d.y - c.y;
238
+ const denominator = dx * ey - dy * ex;
239
+ if (Math.abs(denominator) < 1e-9) {
240
+ result.push(b, c);
241
+ }
242
+ else {
243
+ const t = ((c.x - a.x) * ey - (c.y - a.y) * ex) / denominator;
244
+ const intersection = { x: a.x + t * dx, y: a.y + t * dy };
245
+ const limit = 10 *
246
+ Math.max(Math.abs(boundaryBodyOffset(edges[i].wall)), Math.abs(boundaryBodyOffset(edges[(i + edges.length - 1) % edges.length].wall)), 1e-6);
247
+ if (Math.hypot(intersection.x - b.x, intersection.y - b.y) <= limit &&
248
+ Math.hypot(intersection.x - c.x, intersection.y - c.y) <= limit)
249
+ result.push(intersection);
250
+ else
251
+ result.push(b, c);
252
+ }
253
+ result.push(...current.slice(1, -1));
254
+ }
255
+ return dedupeSequentialPoints(result);
256
+ }
257
+ function boundaryBodyOffset(boundary) {
258
+ return boundary.type === 'wall' ? getWallBodyCenterOffset(boundary) : 0;
259
+ }
260
+ /** Largest visible gap between two wall bodies that still reads as a joint. */
261
+ const JOINT_GAP = 0.015;
262
+ /** Farthest a wall end may sit off another wall's reference line and still join its body. */
263
+ export const TEE_REACH = 0.4;
264
+ /**
265
+ * How far apart two boundaries' reference lines may be where they still join: the
266
+ * junction tolerance, or, for walls, as far as their drawn bodies can touch.
267
+ */
268
+ export function junctionReach(a, b) {
269
+ if (a.type !== 'wall' || b.type !== 'wall')
270
+ return WALL_JUNCTION_TOLERANCE;
271
+ // Metre-thick "walls" are blocks or slabs drawn with the wall tool, not joints.
272
+ if (Math.max(a.thickness ?? 0.1, b.thickness ?? 0.1) > 2 * TEE_REACH)
273
+ return WALL_JUNCTION_TOLERANCE;
274
+ return Math.max(WALL_JUNCTION_TOLERANCE, Math.min(TEE_REACH, Math.max(a.thickness ?? 0.1, b.thickness ?? 0.1) / 2 + JOINT_GAP));
275
+ }
276
+ const GRID_CELL = 1;
277
+ const MAX_GRID_CELLS = 256;
278
+ function sampleBoundary(boundary) {
279
+ const points = sampleWallPointsForRoomDetection(boundary);
280
+ const stations = [0];
281
+ for (let i = 1; i < points.length; i++)
282
+ stations.push(stations[i - 1] +
283
+ Math.hypot(points[i].x - points[i - 1].x, points[i].y - points[i - 1].y));
284
+ return { boundary, points, stations, length: stations.at(-1), box: bboxOf(points) };
285
+ }
286
+ function gridKeys(box, margin) {
287
+ const minX = Math.floor((box.minX - margin) / GRID_CELL);
288
+ const maxX = Math.floor((box.maxX + margin) / GRID_CELL);
289
+ const minY = Math.floor((box.minY - margin) / GRID_CELL);
290
+ const maxY = Math.floor((box.maxY + margin) / GRID_CELL);
291
+ if (![minX, maxX, minY, maxY].every(Number.isSafeInteger) ||
292
+ (maxX - minX + 1) * (maxY - minY + 1) > MAX_GRID_CELLS)
293
+ return null;
294
+ const keys = [];
295
+ for (let x = minX; x <= maxX; x++)
296
+ for (let y = minY; y <= maxY; y++)
297
+ keys.push(`${x},${y}`);
298
+ return keys;
299
+ }
300
+ /** Items near a box, bounded by a uniform grid; huge or extreme boxes fall back to a scan. */
301
+ function spatialIndex(items, boxOf) {
302
+ const cells = new Map();
303
+ const wide = [];
304
+ for (const item of items) {
305
+ const keys = gridKeys(boxOf(item), 0);
306
+ if (!keys) {
307
+ wide.push(item);
308
+ continue;
309
+ }
310
+ for (const key of keys) {
311
+ const cell = cells.get(key);
312
+ if (cell)
313
+ cell.push(item);
314
+ else
315
+ cells.set(key, [item]);
316
+ }
317
+ }
318
+ return (box, margin) => {
319
+ const keys = gridKeys(box, margin);
320
+ if (!keys)
321
+ return items;
322
+ const found = new Set(wide);
323
+ for (const key of keys)
324
+ for (const item of cells.get(key) ?? [])
325
+ found.add(item);
326
+ return found;
327
+ };
328
+ }
329
+ function pointBox(point) {
330
+ return { minX: point.x, minY: point.y, maxX: point.x, maxY: point.y };
331
+ }
332
+ function joinsBoundaryInterior(point, sampled) {
333
+ const tolerance = sampled.boundary.type === 'separator' ? 1e-6 : WALL_JUNCTION_TOLERANCE;
334
+ const { points, stations, length } = sampled;
335
+ for (let i = 0; i < points.length - 1; i++) {
336
+ const { t, distance } = segmentProjection(point, points[i], points[i + 1]);
337
+ const along = stations[i] + Math.max(0, Math.min(1, t)) * (stations[i + 1] - stations[i]);
338
+ if (distance <= tolerance && along > tolerance && along < length - tolerance)
339
+ return true;
340
+ }
341
+ return false;
342
+ }
343
+ function sampledCrossings(left, right) {
344
+ const margin = WALL_JUNCTION_TOLERANCE;
345
+ const crossings = [];
346
+ for (let i = 0; i < left.points.length - 1; i++) {
347
+ const p = left.points[i];
348
+ const r = { x: left.points[i + 1].x - p.x, y: left.points[i + 1].y - p.y };
349
+ for (let j = 0; j < right.points.length - 1; j++) {
350
+ const q = right.points[j];
351
+ const u = { x: right.points[j + 1].x - q.x, y: right.points[j + 1].y - q.y };
352
+ const denominator = r.x * u.y - r.y * u.x;
353
+ if (Math.abs(denominator) <= 1e-12)
354
+ continue;
355
+ const t = ((q.x - p.x) * u.y - (q.y - p.y) * u.x) / denominator;
356
+ const v = ((q.x - p.x) * r.y - (q.y - p.y) * r.x) / denominator;
357
+ if (t < 0 || t > 1 || v < 0 || v > 1)
358
+ continue;
359
+ const along = left.stations[i] + t * (left.stations[i + 1] - left.stations[i]);
360
+ const otherAlong = right.stations[j] + v * (right.stations[j + 1] - right.stations[j]);
361
+ if (along > margin &&
362
+ along < left.length - margin &&
363
+ otherAlong > margin &&
364
+ otherAlong < right.length - margin)
365
+ crossings.push({
366
+ point: { x: p.x + t * r.x, y: p.y + t * r.y },
367
+ along,
368
+ otherAlong,
369
+ sine: Math.abs(denominator) / (Math.hypot(r.x, r.y) * Math.hypot(u.x, u.y)),
370
+ });
371
+ }
372
+ }
373
+ return crossings;
374
+ }
375
+ function sampledCross(left, right) {
376
+ return sampledCrossings(left, right).length > 0;
377
+ }
378
+ /**
379
+ * Crossings where a wall end runs a short way past another wall: the stub past the crossing
380
+ * must end free, so a wall passing through another near its corner stays a plain crossing.
381
+ */
382
+ function overshootCrossings(left, right, free) {
383
+ if (left.boundary.type !== 'wall' ||
384
+ right.boundary.type !== 'wall' ||
385
+ isCurvedWall(left.boundary) ||
386
+ isCurvedWall(right.boundary) ||
387
+ Math.max(left.boundary.thickness ?? 0.1, right.boundary.thickness ?? 0.1) > 0.8)
388
+ return [];
389
+ const overshoots = (sampled, along) => (along <= TEE_REACH && free(sampled.points[0])) ||
390
+ (sampled.length - along <= TEE_REACH && free(sampled.points.at(-1)));
391
+ return sampledCrossings(left, right).filter(({ along, otherAlong, sine }) => sine >= Math.SQRT1_2 && (overshoots(left, along) || overshoots(right, otherAlong)));
392
+ }
393
+ /**
394
+ * True when two boundaries cross away from their ends (sample vertices included).
395
+ * Room detection and the incremental topology index share this predicate.
396
+ */
397
+ export function boundariesCross(a, b) {
398
+ return sampledCross(sampleBoundary(a), sampleBoundary(b));
399
+ }
400
+ /** The wall body as drawn: one quad per sampled segment, between its two faces. */
401
+ function bodyOf(sampled) {
402
+ if (sampled.body)
403
+ return sampled.body;
404
+ const wall = sampled.boundary;
405
+ const { a, b } = wall.type === 'wall' ? getWallFaceOffsets(wall) : { a: 0, b: 0 };
406
+ sampled.body = sampled.points.slice(0, -1).flatMap((p, i) => {
407
+ const q = sampled.points[i + 1];
408
+ const length = Math.hypot(q.x - p.x, q.y - p.y);
409
+ if (!(length > 1e-9))
410
+ return [];
411
+ const n = { x: -(q.y - p.y) / length, y: (q.x - p.x) / length };
412
+ return [
413
+ [
414
+ { x: p.x + n.x * a, y: p.y + n.y * a },
415
+ { x: q.x + n.x * a, y: q.y + n.y * a },
416
+ { x: q.x + n.x * b, y: q.y + n.y * b },
417
+ { x: p.x + n.x * b, y: p.y + n.y * b },
418
+ ],
419
+ ];
420
+ });
421
+ return sampled.body;
422
+ }
423
+ function insideQuad(point, quad) {
424
+ let inside = false;
425
+ for (let i = 0, j = quad.length - 1; i < quad.length; j = i++) {
426
+ const a = quad[i];
427
+ const b = quad[j];
428
+ if (a.y > point.y !== b.y > point.y &&
429
+ point.x < ((b.x - a.x) * (point.y - a.y)) / (b.y - a.y) + a.x)
430
+ inside = !inside;
431
+ }
432
+ return inside;
433
+ }
434
+ function quadGap(left, right) {
435
+ if (left.some((p) => insideQuad(p, right)) || right.some((p) => insideQuad(p, left)))
436
+ return 0;
437
+ let gap = Number.POSITIVE_INFINITY;
438
+ for (const [points, other] of [
439
+ [left, right],
440
+ [right, left],
441
+ ])
442
+ for (const p of points)
443
+ for (let i = 0; i < other.length; i++)
444
+ gap = Math.min(gap, segmentProjection(p, other[i], other[(i + 1) % other.length]).distance);
445
+ return gap;
446
+ }
447
+ /** What the user sees: the two drawn wall bodies touch, or nearly, at the joint. */
448
+ function bodyGap(left, right, near, minimumReach = 0) {
449
+ if (left.boundary.type !== 'wall' || right.boundary.type !== 'wall')
450
+ return Infinity;
451
+ const reach = Math.max(minimumReach, WALL_JUNCTION_TOLERANCE +
452
+ Math.max(left.boundary.thickness ?? 0.1, right.boundary.thickness ?? 0.1));
453
+ // Only the stretch of each body around the joint counts, never a touch elsewhere.
454
+ const local = (sampled) => bodyOf(sampled).filter((quad) => {
455
+ const box = bboxOf(quad);
456
+ return (near.x >= box.minX - reach &&
457
+ near.x <= box.maxX + reach &&
458
+ near.y >= box.minY - reach &&
459
+ near.y <= box.maxY + reach);
460
+ });
461
+ const rightQuads = local(right);
462
+ return Math.min(...local(left).flatMap((quad) => rightQuads.map((other) => quadGap(quad, other))));
463
+ }
464
+ function bodiesTouch(left, right, near) {
465
+ return bodyGap(left, right, near) <= JOINT_GAP;
466
+ }
467
+ function halfBody(sampled) {
468
+ return sampled.boundary.type === 'wall' ? (sampled.boundary.thickness ?? 0.1) / 2 : 0;
469
+ }
470
+ /** Unit direction a wall arrives at one of its ends. */
471
+ function endDirection(sampled, end) {
472
+ const { points } = sampled;
473
+ const atStart = pointKey(points[0]) === pointKey(end);
474
+ const [from, to] = atStart ? [points[1], points[0]] : [points.at(-2), points.at(-1)];
475
+ const length = Math.hypot(to.x - from.x, to.y - from.y) || 1;
476
+ return { x: (to.x - from.x) / length, y: (to.y - from.y) / length };
477
+ }
478
+ /** Nearest point of a wall's reference line to `point`, if it lies away from its ends. */
479
+ function interiorFoot(point, sampled) {
480
+ const { points, stations, length } = sampled;
481
+ let best;
482
+ for (let i = 0; i < points.length - 1; i++) {
483
+ const a = points[i];
484
+ const b = points[i + 1];
485
+ const segment = stations[i + 1] - stations[i];
486
+ if (!(segment > 1e-9))
487
+ continue;
488
+ const { t, distance } = segmentProjection(point, a, b);
489
+ const clamped = Math.max(0, Math.min(1, t));
490
+ const along = stations[i] + clamped * segment;
491
+ if (along <= WALL_JUNCTION_TOLERANCE || along >= length - WALL_JUNCTION_TOLERANCE)
492
+ continue;
493
+ if (best && distance >= best.distance)
494
+ continue;
495
+ best = {
496
+ point: { x: a.x + clamped * (b.x - a.x), y: a.y + clamped * (b.y - a.y) },
497
+ distance,
498
+ direction: { x: (b.x - a.x) / segment, y: (b.y - a.y) / segment },
499
+ };
500
+ }
501
+ return best;
502
+ }
503
+ /** Where a straight wall's line meets another straight wall's reference line between its ends. */
504
+ function ownAxisMeet(sampled, other) {
505
+ if (isCurvedWall(sampled.boundary) || isCurvedWall(other.boundary))
506
+ return;
507
+ const [p, p2] = sampled.points;
508
+ const [q, q2] = other.points;
509
+ const r = { x: p2.x - p.x, y: p2.y - p.y };
510
+ const u = { x: q2.x - q.x, y: q2.y - q.y };
511
+ const denominator = r.x * u.y - r.y * u.x;
512
+ if (Math.abs(denominator) < 1e-12)
513
+ return;
514
+ const along = ((q.x - p.x) * r.y - (q.y - p.y) * r.x) / denominator;
515
+ if (!(along > 0 && along < 1))
516
+ return;
517
+ const t = ((q.x - p.x) * u.y - (q.y - p.y) * u.x) / denominator;
518
+ return { x: p.x + t * r.x, y: p.y + t * r.y };
519
+ }
520
+ /** Where two loose straight wall ends would meet if both ran on to their corner. */
521
+ function cornerOf(cluster, byId, reachOf) {
522
+ if (cluster.length !== 2)
523
+ return;
524
+ const [a, b] = cluster.map((group) => byId.get([...group.boundaryIds][0])?.boundary);
525
+ if (!(a && b) || isCurvedWall(a) || isCurvedWall(b))
526
+ return;
527
+ const r = { x: a.end[0] - a.start[0], y: a.end[1] - a.start[1] };
528
+ const u = { x: b.end[0] - b.start[0], y: b.end[1] - b.start[1] };
529
+ const denominator = r.x * u.y - r.y * u.x;
530
+ // Only a real corner: walls nearly in line meet where their ends already are.
531
+ if (Math.abs(denominator) < 0.5 * Math.hypot(r.x, r.y) * Math.hypot(u.x, u.y))
532
+ return;
533
+ const t = ((b.start[0] - a.start[0]) * u.y - (b.start[1] - a.start[1]) * u.x) / denominator;
534
+ const corner = { x: a.start[0] + t * r.x, y: a.start[1] + t * r.y };
535
+ const reach = reachOf(a, b);
536
+ return cluster.every(({ point }) => Math.hypot(point.x - corner.x, point.y - corner.y) <= reach)
537
+ ? corner
538
+ : undefined;
539
+ }
540
+ /** Distance from a wall end touching this wall's body within the tolerance of its end at `corner`. */
541
+ function bodyReach(point, corner, sampled, reach = WALL_JUNCTION_TOLERANCE) {
542
+ if (sampled.boundary.type !== 'wall')
543
+ return Number.POSITIVE_INFINITY;
544
+ const { points } = sampled;
545
+ const atStart = pointKey(points[0]) === pointKey(corner.point);
546
+ const [a, b] = atStart ? [points[0], points[1]] : [points.at(-1), points.at(-2)];
547
+ const length = Math.hypot(b.x - a.x, b.y - a.y);
548
+ // A stub is reached through its ends only.
549
+ if (!(length > 2 * reach))
550
+ return Number.POSITIVE_INFINITY;
551
+ const along = ((point.x - a.x) * (b.x - a.x) + (point.y - a.y) * (b.y - a.y)) / length;
552
+ if (along < 0 || along > reach)
553
+ return Number.POSITIVE_INFINITY;
554
+ return Math.abs((point.x - a.x) * (b.y - a.y) - (point.y - a.y) * (b.x - a.x)) / length;
555
+ }
556
+ /**
557
+ * Walls drawn a few centimetres short of a corner read as joined when their drawn
558
+ * bodies touch there. A wall end that meets no other boundary joins the nearest
559
+ * boundary end within the junction tolerance, or a wall body that close to its end,
560
+ * whose drawn body touches its own (a visible gap, however small the walls, stays
561
+ * open). Returns exact endpoint keys mapped to their junction point. A junction only
562
+ * involves walls that touch within the tolerance, so incremental topology rebuilds of
563
+ * one component elect the same point as full ones.
564
+ */
565
+ function nearMissJunctions(boundaries, bodyJoints, diagnostics) {
566
+ const reachOf = (a, b) => bodyJoints ? junctionReach(a, b) : WALL_JUNCTION_TOLERANCE;
567
+ const sampled = boundaries.map(sampleBoundary);
568
+ const byId = new Map(sampled.map((item) => [item.boundary.id, item]));
569
+ const near = spatialIndex(sampled, (item) => item.box);
570
+ const groups = new Map();
571
+ for (const boundary of boundaries)
572
+ for (const tuple of [boundary.start, boundary.end]) {
573
+ const point = pointFromTuple(tuple);
574
+ const key = pointKey(point);
575
+ const group = groups.get(key) ?? { key, point, boundaryIds: new Set(), state: 'joined' };
576
+ group.boundaryIds.add(boundary.id);
577
+ groups.set(key, group);
578
+ }
579
+ const ordered = [...groups.values()].sort((a, b) => (a.key < b.key ? -1 : a.key > b.key ? 1 : 0));
580
+ const nearGroups = spatialIndex(ordered, (group) => pointBox(group.point));
581
+ const crossing = new Map();
582
+ const looseEnd = (end) => groups.get(pointKey(end))?.state === 'loose';
583
+ // The graph is planar only at junctions; connecting a wall that crosses another
584
+ // would close faces through the crossing.
585
+ const crosses = (wall) => {
586
+ let value = crossing.get(wall.boundary.id);
587
+ if (value === undefined) {
588
+ value = false;
589
+ for (const other of near(wall.box, 0))
590
+ if (other !== wall &&
591
+ sampledCrossings(wall, other).length >
592
+ (bodyJoints ? overshootCrossings(wall, other, looseEnd).length : 0)) {
593
+ value = true;
594
+ break;
595
+ }
596
+ crossing.set(wall.boundary.id, value);
597
+ }
598
+ return value;
599
+ };
600
+ for (const group of ordered) {
601
+ const [only, ...rest] = group.boundaryIds;
602
+ const wall = byId.get(only);
603
+ if (rest.length || wall.boundary.type !== 'wall')
604
+ continue;
605
+ let joined = false;
606
+ for (const other of near(pointBox(group.point), WALL_JUNCTION_TOLERANCE))
607
+ if (other !== wall && joinsBoundaryInterior(group.point, other)) {
608
+ joined = true;
609
+ break;
610
+ }
611
+ if (!joined)
612
+ group.state = 'loose';
613
+ }
614
+ const blocked = (group) => group.state === 'loose' && crosses(byId.get([...group.boundaryIds][0]));
615
+ const parent = new Map();
616
+ const find = (key) => {
617
+ const next = parent.get(key);
618
+ if (!next || next === key)
619
+ return key;
620
+ const root = find(next);
621
+ parent.set(key, root);
622
+ return root;
623
+ };
624
+ const members = new Map();
625
+ const membersOf = (root) => members.get(root) ?? new Set([root]);
626
+ const ends = new Map(boundaries.map((boundary) => [
627
+ boundary.id,
628
+ [pointKey(pointFromTuple(boundary.start)), pointKey(pointFromTuple(boundary.end))],
629
+ ]));
630
+ // Joining must neither collapse a wall onto one junction nor lay a wall on top of
631
+ // another one between the same two junctions.
632
+ const neighbours = (keys, joined) => {
633
+ const roots = new Set();
634
+ for (const key of keys)
635
+ for (const id of groups.get(key).boundaryIds) {
636
+ const [start, end] = ends.get(id);
637
+ if (start === end)
638
+ continue;
639
+ if (joined.has(start) && joined.has(end))
640
+ return null;
641
+ roots.add(find(joined.has(start) ? end : start));
642
+ }
643
+ return roots;
644
+ };
645
+ for (const group of ordered) {
646
+ if (group.state !== 'loose')
647
+ continue;
648
+ const wall = byId.get([...group.boundaryIds][0]);
649
+ const candidates = [];
650
+ for (const candidate of nearGroups(pointBox(group.point), 2 * TEE_REACH)) {
651
+ if (candidate === group || candidate.boundaryIds.has(wall.boundary.id))
652
+ continue;
653
+ // Thick walls are reached as far as their drawn bodies can touch the end.
654
+ const reach = Math.max(...[...candidate.boundaryIds].map((id) => reachOf(wall.boundary, byId.get(id).boundary)));
655
+ const distance = Math.min(Math.hypot(candidate.point.x - group.point.x, candidate.point.y - group.point.y), ...[...candidate.boundaryIds].map((id) => bodyReach(group.point, candidate, byId.get(id), reach)));
656
+ if (distance <= reach)
657
+ candidates.push({ group: candidate, distance });
658
+ }
659
+ if (!candidates.length || blocked(group))
660
+ continue;
661
+ candidates.sort((a, b) => a.distance - b.distance || (a.group.key < b.group.key ? -1 : 1));
662
+ const best = candidates.find(({ group: candidate }) => !blocked(candidate) &&
663
+ [...candidate.boundaryIds].some((id) => bodiesTouch(wall, byId.get(id), group.point)))?.group;
664
+ if (!best)
665
+ continue;
666
+ const left = find(group.key);
667
+ const right = find(best.key);
668
+ if (left === right)
669
+ continue;
670
+ const joined = new Set([...membersOf(left), ...membersOf(right)]);
671
+ const leftRoots = neighbours(membersOf(left), joined);
672
+ const rightRoots = neighbours(membersOf(right), joined);
673
+ if (!(leftRoots && rightRoots) || [...leftRoots].some((root) => rightRoots.has(root)))
674
+ continue;
675
+ parent.set(left, right);
676
+ members.set(right, joined);
677
+ members.delete(left);
678
+ }
679
+ // A wall end standing inside another wall's drawn body, away from its ends, joins it
680
+ // at the foot of that body's reference line even when the lines are far apart.
681
+ const tees = new Map();
682
+ for (const group of bodyJoints ? ordered : []) {
683
+ if (group.state !== 'loose' || membersOf(find(group.key)).size > 1 || blocked(group))
684
+ continue;
685
+ const wall = byId.get([...group.boundaryIds][0]);
686
+ const approach = endDirection(wall, group.point);
687
+ let best;
688
+ for (const other of near(pointBox(group.point), TEE_REACH)) {
689
+ if (other === wall || other.boundary.type !== 'wall')
690
+ continue;
691
+ const foot = interiorFoot(group.point, other);
692
+ if (!foot || foot.distance > junctionReach(wall.boundary, other.boundary))
693
+ continue;
694
+ // Walls running alongside each other are stacked, not joined.
695
+ if (Math.abs(approach.x * foot.direction.y - approach.y * foot.direction.x) < 0.5)
696
+ continue;
697
+ // A stub drawn entirely inside the other wall's body shows nothing to join.
698
+ const start = wall.points[pointKey(wall.points[0]) === group.key ? wall.points.length - 1 : 0];
699
+ if ((interiorFoot(start, other)?.distance ?? Number.POSITIVE_INFINITY) <= halfBody(other))
700
+ continue;
701
+ if (best && foot.distance >= best.distance)
702
+ continue;
703
+ if (bodiesTouch(wall, other, group.point))
704
+ best = foot;
705
+ }
706
+ if (best)
707
+ tees.set(group.key, best.point);
708
+ }
709
+ const junctions = new Map(tees);
710
+ for (const keys of members.values()) {
711
+ const cluster = [...keys].map((key) => groups.get(key));
712
+ const junction = cluster.find((group) => group.state === 'joined')?.point ??
713
+ cornerOf(cluster, byId, reachOf) ??
714
+ cluster.sort((a, b) => (a.key < b.key ? -1 : 1))[0].point;
715
+ for (const group of cluster)
716
+ if (pointKey(group.point) !== pointKey(junction))
717
+ junctions.set(group.key, junction);
718
+ }
719
+ if (diagnostics)
720
+ for (const group of ordered) {
721
+ for (const id of group.boundaryIds) {
722
+ const wall = byId.get(id);
723
+ if (wall.boundary.type !== 'wall')
724
+ continue;
725
+ const approach = endDirection(wall, group.point);
726
+ let best;
727
+ let crossingTarget;
728
+ for (const other of near(pointBox(group.point), 0.35)) {
729
+ if (other === wall || other.boundary.type !== 'wall')
730
+ continue;
731
+ const consider = (point, kind, parallel) => {
732
+ const distance = Math.hypot(point.x - group.point.x, point.y - group.point.y);
733
+ if (distance > 0.35 || (best && distance >= best.distance))
734
+ return;
735
+ best = {
736
+ candidate: { wallId: other.boundary.id, point: pointToTuple(point), kind },
737
+ distance,
738
+ parallel,
739
+ gap: bodyGap(wall, other, group.point, 0.35),
740
+ };
741
+ };
742
+ for (const point of [other.points[0], other.points.at(-1)])
743
+ consider(point, 'endpoint', false);
744
+ const foot = interiorFoot(group.point, other);
745
+ if (foot) {
746
+ const parallel = Math.abs(approach.x * foot.direction.y - approach.y * foot.direction.x) < 0.5;
747
+ // A straight wall joins a straight body where its own line meets it, never tilting.
748
+ const meet = parallel ? undefined : ownAxisMeet(wall, other);
749
+ consider(meet ?? foot.point, 'body', parallel);
750
+ }
751
+ for (const crossing of sampledCrossings(wall, other)) {
752
+ const distance = Math.hypot(crossing.point.x - group.point.x, crossing.point.y - group.point.y);
753
+ if (distance <= 0.35 && (!crossingTarget || distance < crossingTarget.distance))
754
+ crossingTarget = {
755
+ candidate: {
756
+ wallId: other.boundary.id,
757
+ point: pointToTuple(crossing.point),
758
+ kind: 'body',
759
+ },
760
+ distance,
761
+ parallel: false,
762
+ gap: 0,
763
+ };
764
+ }
765
+ }
766
+ const target = crossingTarget ?? best;
767
+ const reason = crossingTarget || crosses(wall)
768
+ ? 'crosses'
769
+ : best?.parallel
770
+ ? 'parallel'
771
+ : best && best.gap > JOINT_GAP
772
+ ? 'gap'
773
+ : best
774
+ ? 'rejected'
775
+ : 'isolated';
776
+ diagnostics.push({
777
+ wallId: id,
778
+ end: pointKey(pointFromTuple(wall.boundary.start)) === group.key ? 'start' : 'end',
779
+ point: pointToTuple(group.point),
780
+ reason,
781
+ ...(reason === 'gap' && best && Number.isFinite(best.gap) ? { gap: best.gap } : {}),
782
+ ...(target ? { candidate: target.candidate } : {}),
783
+ });
784
+ }
785
+ }
786
+ // Free once joints are elected: a loose end no joint connected.
787
+ const freeEnd = (end) => {
788
+ const key = pointKey(end);
789
+ return looseEnd(end) && !tees.has(key) && membersOf(find(key)).size === 1;
790
+ };
791
+ return { junctions, freeEnd };
792
+ }
793
+ export function wallEndJoinCandidates(nodes, levelId) {
794
+ const ends = [];
795
+ nearMissJunctions(Object.values(nodes).filter((node) => (node.type === 'wall' || node.type === 'separator') && node.parentId === levelId), true, ends);
796
+ return ends;
797
+ }
798
+ /** Separator edges preserve intentional openings after wall deletion; only wall ends are reported. */
799
+ export function detectOpenWallEnds(nodes, levelId) {
800
+ const boundaries = Object.values(nodes).filter((node) => (node.type === 'wall' || node.type === 'separator') && node.parentId === levelId);
801
+ const joined = extractRoomGraph(boundaries, {}, true, true);
802
+ if (!joined.bodyJoints)
803
+ return joined.openEnds;
804
+ const plain = extractRoomGraph(boundaries, {}, false, true);
805
+ const selected = new Set(keepPlainRoomsWhereLost(plain.rooms, joined.rooms));
806
+ const rejected = new Set(plain.rooms
807
+ .filter((room) => selected.has(room) && !joined.rooms.includes(room))
808
+ .flatMap((room) => room.spans.map((span) => span.boundaryId)));
809
+ return [
810
+ ...joined.openEnds.filter((end) => !rejected.has(end.wallId)),
811
+ ...plain.openEnds
812
+ .filter((end) => rejected.has(end.wallId))
813
+ .map((end) => ({ ...end, reason: 'rejected' })),
814
+ ].sort((a, b) => a.wallId.localeCompare(b.wallId) || a.end.localeCompare(b.end));
815
+ }
816
+ /**
817
+ * Rooms enclosed by walls and separators. Joints where drawn wall bodies touch (thick
818
+ * walls, ends inside another wall's body) only ever add or split rooms: wherever they
819
+ * would lose room area the plain junction rules drew, that structure keeps the plain
820
+ * result, so no scene loses a room it had.
821
+ */
822
+ export function extractRooms(boundaries, options = {}) {
823
+ const joined = extractRoomGraph(boundaries, options, true);
824
+ if (!joined.bodyJoints)
825
+ return joined.rooms;
826
+ const plain = extractRoomGraph(boundaries, options, false).rooms;
827
+ return keepPlainRoomsWhereLost(plain, joined.rooms);
828
+ }
829
+ function roomArea(rooms) {
830
+ return rooms.map((room) => ({ outer: room.referencePolygon, holes: room.holes }));
831
+ }
832
+ /** Joints may split rooms or close new ones, never shrink or merge the plain ones. */
833
+ function losesRooms(group) {
834
+ try {
835
+ const plain = roomArea(group.plain);
836
+ const joined = roomArea(group.joined);
837
+ if (area(difference(union(plain), union(joined))) > 0.01)
838
+ return true;
839
+ return joined.some((room) => plain.filter((other) => area(intersection(room, other)) > 0.2).length > 1);
840
+ }
841
+ catch {
842
+ return true;
843
+ }
844
+ }
845
+ function keepPlainRoomsWhereLost(plain, joined) {
846
+ // Structures: rooms of either result that share a boundary.
847
+ const all = [...plain, ...joined];
848
+ const parent = all.map((_, i) => i);
849
+ const find = (i) => {
850
+ while (parent[i] !== i)
851
+ i = parent[i];
852
+ return i;
853
+ };
854
+ const owner = new Map();
855
+ all.forEach((room, i) => {
856
+ for (const span of room.spans) {
857
+ const other = owner.get(span.boundaryId);
858
+ if (other === undefined)
859
+ owner.set(span.boundaryId, i);
860
+ else
861
+ parent[find(i)] = find(other);
862
+ }
863
+ });
864
+ const groups = new Map();
865
+ all.forEach((room, i) => {
866
+ const group = groups.get(find(i)) ?? { plain: [], joined: [] };
867
+ (i < plain.length ? group.plain : group.joined).push(room);
868
+ groups.set(find(i), group);
869
+ });
870
+ const rooms = [];
871
+ for (const group of groups.values()) {
872
+ const same = group.plain.length === group.joined.length &&
873
+ group.plain.every((room, i) => room.id === group.joined[i].id);
874
+ rooms.push(...(!same && group.plain.length && losesRooms(group) ? group.plain : group.joined));
875
+ }
876
+ rooms.sort((a, b) => Math.abs(polygonArea(b.polygon)) - Math.abs(polygonArea(a.polygon)));
877
+ return rooms;
878
+ }
879
+ function extractRoomGraph(boundaries, { includeHoles = true }, bodyJoints, diagnostics = false) {
880
+ if (boundaries.length < 3 && !diagnostics)
881
+ return { rooms: [], bodyJoints: false, openEnds: [] };
882
+ // Snapped junctions must elect the same representative in migrations,
883
+ // full index rebuilds and incremental edits, independent of map insertion order.
884
+ const walls = [...boundaries].sort((a, b) => a.id.localeCompare(b.id));
885
+ const wallById = new Map(walls.map((wall) => [wall.id, wall]));
886
+ const graph = new Map();
887
+ const halfEdges = new Map();
888
+ const upsertNode = (point) => {
889
+ const key = pointKey(point);
890
+ if (!graph.has(key)) {
891
+ graph.set(key, { point: { ...point }, outgoing: [] });
892
+ }
893
+ return key;
894
+ };
895
+ // Planarize first: collect every wall endpoint as a candidate graph vertex so
896
+ // straight walls can be split at T-junctions where another wall ends mid-span.
897
+ // Without this the touching wall's endpoint is a dangling degree-1 node and the
898
+ // enclosed area (e.g. a room added against the middle of an existing wall)
899
+ // never forms a cycle.
900
+ const openEnds = [];
901
+ const { junctions, freeEnd } = nearMissJunctions(walls, bodyJoints, diagnostics ? openEnds : undefined);
902
+ // Whether the body joints change the graph at all: new junctions, or doubled spans
903
+ // dropped where joints connect walls.
904
+ let changed = false;
905
+ if (bodyJoints) {
906
+ const plain = nearMissJunctions(walls, false).junctions;
907
+ changed =
908
+ plain.size !== junctions.size ||
909
+ [...junctions].some(([key, point]) => {
910
+ const other = plain.get(key);
911
+ return !other || pointKey(other) !== pointKey(point);
912
+ });
913
+ }
914
+ const junction = (tuple) => {
915
+ const point = pointFromTuple(tuple);
916
+ return junctions.get(pointKey(point)) ?? point;
917
+ };
918
+ const vertexByKey = new Map();
919
+ for (const wall of walls) {
920
+ for (const tuple of [wall.start, wall.end]) {
921
+ const point = junction(tuple);
922
+ const key = pointKey(point);
923
+ const existing = vertexByKey.get(key);
924
+ if (!existing)
925
+ vertexByKey.set(key, { ...point, wallEndpoint: wall.type === 'wall' });
926
+ else if (wall.type === 'wall')
927
+ existing.wallEndpoint = true;
928
+ }
929
+ }
930
+ const vertices = [...vertexByKey.values()];
931
+ if (bodyJoints) {
932
+ const sampled = walls.map(sampleBoundary);
933
+ const near = spatialIndex(sampled, (item) => item.box);
934
+ for (const wall of sampled)
935
+ for (const other of near(wall.box, 0)) {
936
+ if (wall.boundary.id >= other.boundary.id)
937
+ continue;
938
+ // An end already joined (e.g. onto the crossed wall's body) gets no second vertex at
939
+ // the crossing, which would only double that joint with a sliver.
940
+ for (const { point } of overshootCrossings(wall, other, freeEnd)) {
941
+ vertices.push({ ...point, wallEndpoint: false });
942
+ changed = true;
943
+ }
944
+ }
945
+ }
946
+ const nearVertices = spatialIndex(vertices, (vertex) => pointBox(vertex));
947
+ const parts = [];
948
+ for (const wall of walls) {
949
+ const start = pointFromTuple(wall.start);
950
+ const end = pointFromTuple(wall.end);
951
+ if (samePointWithinTolerance(start, end))
952
+ continue;
953
+ const points = sampleWallPointsForRoomDetection(wall);
954
+ const localVertices = [...nearVertices(bboxOf(points), WALL_JUNCTION_TOLERANCE)];
955
+ const subPolylines = isCurvedWall(wall)
956
+ ? splitCurvedWallAtVertices(points, localVertices, wall)
957
+ : (() => {
958
+ const ordered = splitStraightWallAtVertices(start, end, localVertices, wall.type === 'separator');
959
+ const parts = [];
960
+ for (let index = 0; index < ordered.length - 1; index += 1) {
961
+ parts.push([ordered[index], ordered[index + 1]]);
962
+ }
963
+ return parts;
964
+ })();
965
+ // A near-miss end moves onto its junction only after the body is split, so every
966
+ // T-junction found along the wall as drawn stays connected.
967
+ const startJunction = junctions.get(pointKey(start));
968
+ const endJunction = junctions.get(pointKey(end));
969
+ const snapped = new Set();
970
+ if (startJunction && subPolylines.length) {
971
+ subPolylines[0] = [startJunction, ...subPolylines[0].slice(1)];
972
+ snapped.add(0);
973
+ }
974
+ if (endJunction && subPolylines.length) {
975
+ subPolylines[subPolylines.length - 1] = [...subPolylines.at(-1).slice(0, -1), endJunction];
976
+ snapped.add(subPolylines.length - 1);
977
+ }
978
+ for (const [subIndex, points] of subPolylines.entries())
979
+ parts.push({ wall, points, subIndex, snapped: snapped.has(subIndex) });
980
+ }
981
+ // A moved end never doubles a span another boundary already draws between the same
982
+ // two nodes (e.g. parallel walls a few centimetres apart).
983
+ const pairKey = (points) => {
984
+ const keys = points.map(pointKey);
985
+ const reversed = [...keys].reverse();
986
+ return (keys.join('|') < reversed.join('|') ? keys : reversed).join('|');
987
+ };
988
+ const drawnPairs = new Set(parts.filter((part) => !part.snapped).map((part) => pairKey(part.points)));
989
+ // Where joints connect walls, a span drawn twice (walls stacked on each other) would
990
+ // give two edges with the same angle at a node, and the face walk could cut through
991
+ // rooms: keep one per span there. Elsewhere the graph stays exactly as drawn.
992
+ const componentOf = new Map();
993
+ const root = (key) => {
994
+ const next = componentOf.get(key);
995
+ if (!next || next === key)
996
+ return key;
997
+ const found = root(next);
998
+ componentOf.set(key, found);
999
+ return found;
1000
+ };
1001
+ for (const { points } of parts) {
1002
+ const a = root(pointKey(points[0]));
1003
+ const b = root(pointKey(points.at(-1)));
1004
+ if (a !== b)
1005
+ componentOf.set(a, b);
1006
+ }
1007
+ const joined = new Set(bodyJoints ? [...junctions.values()].map((point) => root(pointKey(point))) : []);
1008
+ const seenPairs = new Set();
1009
+ for (const { wall, points, subIndex, snapped } of parts) {
1010
+ const pair = pairKey(points);
1011
+ if (snapped && drawnPairs.has(pair))
1012
+ continue;
1013
+ if (joined.has(root(pointKey(points[0])))) {
1014
+ if (seenPairs.has(pair)) {
1015
+ changed = true;
1016
+ continue;
1017
+ }
1018
+ seenPairs.add(pair);
1019
+ }
1020
+ const from = points[0];
1021
+ const to = points[points.length - 1];
1022
+ const fromKey = upsertNode(from);
1023
+ const toKey = upsertNode(to);
1024
+ if (fromKey === toKey)
1025
+ continue;
1026
+ const reversePoints = [...points].reverse();
1027
+ const forwardId = `${wall.id}#${subIndex}:f`;
1028
+ const reverseId = `${wall.id}#${subIndex}:r`;
1029
+ halfEdges.set(forwardId, {
1030
+ id: forwardId,
1031
+ reverseId,
1032
+ fromKey,
1033
+ toKey,
1034
+ angle: Math.atan2(points[1].y - from.y, points[1].x - from.x),
1035
+ points,
1036
+ wallId: wall.id,
1037
+ face: 'front',
1038
+ });
1039
+ halfEdges.set(reverseId, {
1040
+ id: reverseId,
1041
+ reverseId: forwardId,
1042
+ fromKey: toKey,
1043
+ toKey: fromKey,
1044
+ angle: Math.atan2(reversePoints[1].y - to.y, reversePoints[1].x - to.x),
1045
+ points: reversePoints,
1046
+ wallId: wall.id,
1047
+ face: 'back',
1048
+ });
1049
+ graph.get(fromKey)?.outgoing.push(forwardId);
1050
+ graph.get(toKey)?.outgoing.push(reverseId);
1051
+ }
1052
+ const sortedOutgoing = new Map();
1053
+ for (const [key, node] of graph.entries()) {
1054
+ const outgoing = [...node.outgoing];
1055
+ outgoing.sort((a, b) => (halfEdges.get(a)?.angle ?? 0) - (halfEdges.get(b)?.angle ?? 0));
1056
+ sortedOutgoing.set(key, outgoing);
1057
+ }
1058
+ const nextEdge = (edgeId) => {
1059
+ const edge = halfEdges.get(edgeId);
1060
+ if (!edge)
1061
+ return null;
1062
+ const outgoing = sortedOutgoing.get(edge.toKey);
1063
+ if (!outgoing || outgoing.length === 0)
1064
+ return null;
1065
+ const idx = outgoing.indexOf(edge.reverseId);
1066
+ if (idx === -1)
1067
+ return null;
1068
+ const nextIdx = (idx - 1 + outgoing.length) % outgoing.length;
1069
+ return outgoing[nextIdx] ?? null;
1070
+ };
1071
+ const splitIntoSimpleCycles = (walkEdgeIds) => {
1072
+ const cycles = [];
1073
+ const firstEdge = halfEdges.get(walkEdgeIds[0] ?? '');
1074
+ if (!firstEdge)
1075
+ return cycles;
1076
+ const pathEdges = [];
1077
+ const pathVertices = [firstEdge.fromKey];
1078
+ const vertexIndex = new Map([[firstEdge.fromKey, 0]]);
1079
+ for (const edgeId of walkEdgeIds) {
1080
+ const edge = halfEdges.get(edgeId);
1081
+ if (!edge || edge.fromKey !== pathVertices[pathVertices.length - 1])
1082
+ return [];
1083
+ pathEdges.push(edgeId);
1084
+ const repeatedIndex = vertexIndex.get(edge.toKey);
1085
+ if (repeatedIndex === undefined) {
1086
+ pathVertices.push(edge.toKey);
1087
+ vertexIndex.set(edge.toKey, pathVertices.length - 1);
1088
+ continue;
1089
+ }
1090
+ const cycle = pathEdges.slice(repeatedIndex);
1091
+ if (cycle.length >= 3)
1092
+ cycles.push(cycle);
1093
+ for (let index = repeatedIndex + 1; index < pathVertices.length; index += 1) {
1094
+ vertexIndex.delete(pathVertices[index]);
1095
+ }
1096
+ pathVertices.length = repeatedIndex + 1;
1097
+ pathEdges.length = repeatedIndex;
1098
+ }
1099
+ return pathEdges.length === 0 && pathVertices.length === 1 ? cycles : [];
1100
+ };
1101
+ const visitedDirected = new Set();
1102
+ const rooms = [];
1103
+ const innerCycles = [];
1104
+ // A face walk cannot revisit a half-edge, so the half-edge count bounds its
1105
+ // length. It can revisit a vertex when dangling walls or other graph bridges
1106
+ // are traced out and back; those excursions are removed below.
1107
+ const maxSteps = Math.min(2000, halfEdges.size + 10);
1108
+ for (const edgeId of halfEdges.keys()) {
1109
+ if (visitedDirected.has(edgeId))
1110
+ continue;
1111
+ const cycleEdgeIds = [];
1112
+ let currentEdgeId = edgeId;
1113
+ let valid = true;
1114
+ let closed = false;
1115
+ for (let step = 0; step < maxSteps; step += 1) {
1116
+ const currentEdge = halfEdges.get(currentEdgeId);
1117
+ if (!currentEdge) {
1118
+ valid = false;
1119
+ break;
1120
+ }
1121
+ visitedDirected.add(currentEdgeId);
1122
+ cycleEdgeIds.push(currentEdgeId);
1123
+ const next = nextEdge(currentEdgeId);
1124
+ if (!next) {
1125
+ valid = false;
1126
+ break;
1127
+ }
1128
+ currentEdgeId = next;
1129
+ if (currentEdgeId === edgeId) {
1130
+ closed = true;
1131
+ break;
1132
+ }
1133
+ }
1134
+ if (!(valid && closed) || cycleEdgeIds.length < 3)
1135
+ continue;
1136
+ for (const simpleCycleEdgeIds of splitIntoSimpleCycles(cycleEdgeIds)) {
1137
+ const bodyEdges = simpleCycleEdgeIds.map((id) => {
1138
+ const edge = halfEdges.get(id);
1139
+ return { wall: wallById.get(edge.wallId), points: edge.points };
1140
+ });
1141
+ const polygon = bodyEdges.some(({ wall }) => wall.type === 'wall' && wall.justification !== undefined)
1142
+ ? roomBodyPolygon(bodyEdges)
1143
+ : dedupeSequentialPoints(simpleCycleEdgeIds.flatMap((id, index) => {
1144
+ const points = halfEdges.get(id)?.points ?? [];
1145
+ return index === simpleCycleEdgeIds.length - 1 ? points : points.slice(0, -1);
1146
+ }));
1147
+ if (polygon.length < 3)
1148
+ continue;
1149
+ const referencePoints = dedupeSequentialPoints(simpleCycleEdgeIds.flatMap((id) => halfEdges.get(id).points.slice(0, -1))).map(pointToTuple);
1150
+ // Room identity must not change when wall thickness or justification changes.
1151
+ const signedArea = polygonArea(referencePoints.map(pointFromTuple));
1152
+ if (signedArea <= 0 && !includeHoles)
1153
+ continue;
1154
+ const minArea = bodyEdges.every(({ wall }) => wall.type === 'separator') ? 0.25 : 0.5;
1155
+ if (Math.abs(signedArea) < minArea - 1e-9 || Math.abs(signedArea) > 10_000)
1156
+ continue;
1157
+ const cycles = signedArea > 0 ? rooms : innerCycles;
1158
+ const signature = polygonSignature(polygon);
1159
+ if (cycles.some((room) => polygonSignature(room.polygon) === signature))
1160
+ continue;
1161
+ let first = 0;
1162
+ for (let i = 1; i < referencePoints.length; i++) {
1163
+ const p = referencePoints[i], q = referencePoints[first];
1164
+ if (p[0] < q[0] || (p[0] === q[0] && p[1] < q[1]))
1165
+ first = i;
1166
+ }
1167
+ const referencePolygon = [...referencePoints.slice(first), ...referencePoints.slice(0, first)];
1168
+ const roomId = `room-${polygonSignature(referencePolygon.map(pointFromTuple))}`;
1169
+ const spans = simpleCycleEdgeIds.map((id) => {
1170
+ const edge = halfEdges.get(id);
1171
+ const boundary = wallById.get(edge.wallId);
1172
+ const start = pointFromTuple(boundary.start);
1173
+ const end = pointFromTuple(boundary.end);
1174
+ const from = segmentProjection(edge.points[0], start, end).t;
1175
+ const to = segmentProjection(edge.points.at(-1), start, end).t;
1176
+ return {
1177
+ roomId,
1178
+ boundaryId: boundary.id,
1179
+ kind: boundary.type,
1180
+ face: edge.face === 'front' ? 'a' : 'b',
1181
+ t0: Math.max(0, Math.min(1, Math.min(from, to))),
1182
+ t1: Math.max(0, Math.min(1, Math.max(from, to))),
1183
+ };
1184
+ });
1185
+ spans.sort((a, b) => a.boundaryId.localeCompare(b.boundaryId) || a.face.localeCompare(b.face) || a.t0 - b.t0);
1186
+ cycles.push({
1187
+ id: roomId,
1188
+ referencePolygon,
1189
+ holes: [],
1190
+ spans,
1191
+ polygon,
1192
+ boundaryFaces: simpleCycleEdgeIds.flatMap((id) => {
1193
+ const edge = halfEdges.get(id);
1194
+ if (!edge || wallById.get(edge.wallId)?.type !== 'wall')
1195
+ return [];
1196
+ return [
1197
+ {
1198
+ wallId: edge.wallId,
1199
+ face: edge.face,
1200
+ points: edge.points.map(pointToTuple),
1201
+ },
1202
+ ];
1203
+ }),
1204
+ });
1205
+ }
1206
+ }
1207
+ const shells = rooms
1208
+ .map((room) => ({
1209
+ room,
1210
+ area: Math.abs(polygonArea(room.referencePolygon.map(pointFromTuple))),
1211
+ bbox: bboxOf(room.referencePolygon.map(pointFromTuple)),
1212
+ }))
1213
+ .sort((a, b) => a.area - b.area || a.room.id.localeCompare(b.room.id));
1214
+ for (const cycle of innerCycles) {
1215
+ const ring = cycle.referencePolygon;
1216
+ const cycleArea = Math.abs(polygonArea(ring.map(pointFromTuple)));
1217
+ const bounds = bboxOf(ring.map(pointFromTuple));
1218
+ const containing = shells.find((shell) => shell.area > cycleArea + 1e-6 &&
1219
+ // The reverse walk of the same boundary is the exterior, even when
1220
+ // snapped endpoints give it a slightly smaller numerical area.
1221
+ !shell.room.spans.some((outer) => cycle.spans.some((inner) => outer.boundaryId === inner.boundaryId &&
1222
+ Math.min(outer.t1, inner.t1) - Math.max(outer.t0, inner.t0) > 1e-8)) &&
1223
+ shell.bbox.minX <= bounds.minX &&
1224
+ shell.bbox.minY <= bounds.minY &&
1225
+ shell.bbox.maxX >= bounds.maxX &&
1226
+ shell.bbox.maxY >= bounds.maxY &&
1227
+ area(difference(ring, shell.room.referencePolygon)) < 1e-6)?.room;
1228
+ if (!containing)
1229
+ continue;
1230
+ containing.holes.push(ring);
1231
+ containing.boundaryFaces.push(...cycle.boundaryFaces);
1232
+ containing.spans.push(...cycle.spans.map((span) => ({ ...span, roomId: containing.id })));
1233
+ }
1234
+ for (const room of rooms) {
1235
+ room.holes.sort((a, b) => polygonSignature(a.map(pointFromTuple)).localeCompare(polygonSignature(b.map(pointFromTuple))));
1236
+ room.spans.sort((a, b) => a.boundaryId.localeCompare(b.boundaryId) || a.face.localeCompare(b.face) || a.t0 - b.t0);
1237
+ }
1238
+ rooms.sort((a, b) => Math.abs(polygonArea(b.polygon)) - Math.abs(polygonArea(a.polygon)));
1239
+ return {
1240
+ rooms,
1241
+ bodyJoints: changed,
1242
+ openEnds: openEnds.filter((end) => {
1243
+ const point = junctions.get(pointKey(pointFromTuple(end.point))) ?? pointFromTuple(end.point);
1244
+ const node = graph.get(pointKey(point));
1245
+ return !node || new Set(node.outgoing.map((id) => halfEdges.get(id).wallId)).size < 2;
1246
+ }),
1247
+ };
1248
+ }
1249
+ export function detectRoomFaces(levelWalls, levelSeparators = []) {
1250
+ return extractRooms([...levelWalls, ...levelSeparators].sort((a, b) => a.id.localeCompare(b.id))).map((room) => ({
1251
+ key: room.id,
1252
+ polygon: room.referencePolygon,
1253
+ holes: room.holes,
1254
+ boundaryWallIds: [
1255
+ ...new Set(room.spans
1256
+ .filter((span) => span.kind === 'wall')
1257
+ .map((span) => span.boundaryId)),
1258
+ ].sort(),
1259
+ boundarySeparatorIds: [
1260
+ ...new Set(room.spans
1261
+ .filter((span) => span.kind === 'separator')
1262
+ .map((span) => span.boundaryId)),
1263
+ ].sort(),
1264
+ }));
1265
+ }