@pascal-app/core 1.0.4 → 1.0.5

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 (866) hide show
  1. package/dist/agent-operations/__fixtures__/add-object-cases.d.ts +102 -90
  2. package/dist/agent-operations/__fixtures__/add-object-cases.d.ts.map +1 -1
  3. package/dist/agent-operations/__fixtures__/add-object-cases.js +301 -1
  4. package/dist/agent-operations/__fixtures__/add-stair-cases.d.ts +3 -0
  5. package/dist/agent-operations/__fixtures__/add-stair-cases.d.ts.map +1 -0
  6. package/dist/agent-operations/__fixtures__/add-stair-cases.js +176 -0
  7. package/dist/agent-operations/__fixtures__/build-room-cases.d.ts.map +1 -1
  8. package/dist/agent-operations/__fixtures__/build-room-cases.js +410 -40
  9. package/dist/agent-operations/__fixtures__/cases.d.ts +18 -3
  10. package/dist/agent-operations/__fixtures__/cases.d.ts.map +1 -1
  11. package/dist/agent-operations/__fixtures__/cases.js +183 -4
  12. package/dist/agent-operations/__fixtures__/corner-window-cases.d.ts +3 -0
  13. package/dist/agent-operations/__fixtures__/corner-window-cases.d.ts.map +1 -0
  14. package/dist/agent-operations/__fixtures__/corner-window-cases.js +155 -0
  15. package/dist/agent-operations/__fixtures__/design-brief-cases.d.ts +14 -0
  16. package/dist/agent-operations/__fixtures__/design-brief-cases.d.ts.map +1 -0
  17. package/dist/agent-operations/__fixtures__/design-brief-cases.js +709 -0
  18. package/dist/agent-operations/__fixtures__/finish-cases.d.ts +7 -0
  19. package/dist/agent-operations/__fixtures__/finish-cases.d.ts.map +1 -0
  20. package/dist/agent-operations/__fixtures__/finish-cases.js +758 -0
  21. package/dist/agent-operations/__fixtures__/lot-info-cases.d.ts +3 -0
  22. package/dist/agent-operations/__fixtures__/lot-info-cases.d.ts.map +1 -0
  23. package/dist/agent-operations/__fixtures__/lot-info-cases.js +370 -0
  24. package/dist/agent-operations/__fixtures__/merge-windows-cases.d.ts +3 -0
  25. package/dist/agent-operations/__fixtures__/merge-windows-cases.d.ts.map +1 -0
  26. package/dist/agent-operations/__fixtures__/merge-windows-cases.js +321 -0
  27. package/dist/agent-operations/__fixtures__/native-materials.d.ts +2237 -0
  28. package/dist/agent-operations/__fixtures__/native-materials.d.ts.map +1 -0
  29. package/dist/agent-operations/__fixtures__/native-materials.js +82 -0
  30. package/dist/agent-operations/__fixtures__/node-read-cases.d.ts +4 -0
  31. package/dist/agent-operations/__fixtures__/node-read-cases.d.ts.map +1 -0
  32. package/dist/agent-operations/__fixtures__/node-read-cases.js +639 -0
  33. package/dist/agent-operations/__fixtures__/notation-cases.d.ts +24 -0
  34. package/dist/agent-operations/__fixtures__/notation-cases.d.ts.map +1 -0
  35. package/dist/agent-operations/__fixtures__/notation-cases.js +356 -0
  36. package/dist/agent-operations/__fixtures__/place-items-cases.d.ts.map +1 -1
  37. package/dist/agent-operations/__fixtures__/place-items-cases.js +80 -2
  38. package/dist/agent-operations/__fixtures__/roof-bearing-cases.d.ts +19726 -0
  39. package/dist/agent-operations/__fixtures__/roof-bearing-cases.d.ts.map +1 -0
  40. package/dist/agent-operations/__fixtures__/roof-bearing-cases.js +106 -0
  41. package/dist/agent-operations/__fixtures__/roof-cases.d.ts +9 -0
  42. package/dist/agent-operations/__fixtures__/roof-cases.d.ts.map +1 -0
  43. package/dist/agent-operations/__fixtures__/roof-cases.js +382 -0
  44. package/dist/agent-operations/__fixtures__/room-cases.d.ts +2 -1
  45. package/dist/agent-operations/__fixtures__/room-cases.d.ts.map +1 -1
  46. package/dist/agent-operations/__fixtures__/room-cases.js +136 -1
  47. package/dist/agent-operations/__fixtures__/scene-check-cases.d.ts +4 -0
  48. package/dist/agent-operations/__fixtures__/scene-check-cases.d.ts.map +1 -0
  49. package/dist/agent-operations/__fixtures__/scene-check-cases.js +417 -0
  50. package/dist/agent-operations/__fixtures__/search-assets-cases.d.ts.map +1 -1
  51. package/dist/agent-operations/__fixtures__/search-assets-cases.js +15 -3
  52. package/dist/agent-operations/__fixtures__/site-cases.d.ts +290 -0
  53. package/dist/agent-operations/__fixtures__/site-cases.d.ts.map +1 -0
  54. package/dist/agent-operations/__fixtures__/site-cases.js +780 -0
  55. package/dist/agent-operations/__fixtures__/structure-cases.d.ts +1 -0
  56. package/dist/agent-operations/__fixtures__/structure-cases.d.ts.map +1 -1
  57. package/dist/agent-operations/__fixtures__/structure-cases.js +630 -3
  58. package/dist/agent-operations/__fixtures__/verify-scene-cases.d.ts +311 -1
  59. package/dist/agent-operations/__fixtures__/verify-scene-cases.d.ts.map +1 -1
  60. package/dist/agent-operations/__fixtures__/verify-scene-cases.js +59 -11
  61. package/dist/agent-operations/__fixtures__/view-assets-cases.d.ts +3 -0
  62. package/dist/agent-operations/__fixtures__/view-assets-cases.d.ts.map +1 -0
  63. package/dist/agent-operations/__fixtures__/view-assets-cases.js +155 -0
  64. package/dist/agent-operations/__fixtures__/view-scene-cases.d.ts +50 -0
  65. package/dist/agent-operations/__fixtures__/view-scene-cases.d.ts.map +1 -0
  66. package/dist/agent-operations/__fixtures__/view-scene-cases.js +425 -0
  67. package/dist/agent-operations/achieved.d.ts +5 -0
  68. package/dist/agent-operations/achieved.d.ts.map +1 -1
  69. package/dist/agent-operations/achieved.js +21 -1
  70. package/dist/agent-operations/add-column.d.ts.map +1 -1
  71. package/dist/agent-operations/add-column.js +3 -1
  72. package/dist/agent-operations/add-fence.d.ts +18 -0
  73. package/dist/agent-operations/add-fence.d.ts.map +1 -0
  74. package/dist/agent-operations/add-fence.js +48 -0
  75. package/dist/agent-operations/add-level.d.ts +4 -1
  76. package/dist/agent-operations/add-level.d.ts.map +1 -1
  77. package/dist/agent-operations/add-level.js +48 -12
  78. package/dist/agent-operations/add-object.d.ts +38 -9
  79. package/dist/agent-operations/add-object.d.ts.map +1 -1
  80. package/dist/agent-operations/add-object.js +172 -11
  81. package/dist/agent-operations/add-wall.d.ts +1 -3
  82. package/dist/agent-operations/add-wall.d.ts.map +1 -1
  83. package/dist/agent-operations/add-wall.js +35 -9
  84. package/dist/agent-operations/apply-changes.d.ts +7 -1
  85. package/dist/agent-operations/apply-changes.d.ts.map +1 -1
  86. package/dist/agent-operations/apply-changes.js +54 -22
  87. package/dist/agent-operations/apply-outcome.d.ts +6 -0
  88. package/dist/agent-operations/apply-outcome.d.ts.map +1 -1
  89. package/dist/agent-operations/apply-outcome.js +23 -8
  90. package/dist/agent-operations/asset-views.d.ts +75 -0
  91. package/dist/agent-operations/asset-views.d.ts.map +1 -0
  92. package/dist/agent-operations/asset-views.js +234 -0
  93. package/dist/agent-operations/author-scene.d.ts +157 -0
  94. package/dist/agent-operations/author-scene.d.ts.map +1 -0
  95. package/dist/agent-operations/author-scene.js +1076 -0
  96. package/dist/agent-operations/authored-scene-merge.d.ts +4 -0
  97. package/dist/agent-operations/authored-scene-merge.d.ts.map +1 -0
  98. package/dist/agent-operations/authored-scene-merge.js +96 -0
  99. package/dist/agent-operations/batch.d.ts +22 -0
  100. package/dist/agent-operations/batch.d.ts.map +1 -0
  101. package/dist/agent-operations/batch.js +104 -0
  102. package/dist/agent-operations/ceiling-object-observations.d.ts +31 -0
  103. package/dist/agent-operations/ceiling-object-observations.d.ts.map +1 -0
  104. package/dist/agent-operations/ceiling-object-observations.js +111 -0
  105. package/dist/agent-operations/corner-window.d.ts +19 -0
  106. package/dist/agent-operations/corner-window.d.ts.map +1 -0
  107. package/dist/agent-operations/corner-window.js +84 -0
  108. package/dist/agent-operations/create-roof.d.ts +32 -0
  109. package/dist/agent-operations/create-roof.d.ts.map +1 -0
  110. package/dist/agent-operations/create-roof.js +304 -0
  111. package/dist/agent-operations/create-room.d.ts +2 -0
  112. package/dist/agent-operations/create-room.d.ts.map +1 -1
  113. package/dist/agent-operations/create-room.js +73 -5
  114. package/dist/agent-operations/create-stair.d.ts +6 -28
  115. package/dist/agent-operations/create-stair.d.ts.map +1 -1
  116. package/dist/agent-operations/create-stair.js +187 -104
  117. package/dist/agent-operations/design-brief.d.ts +38 -0
  118. package/dist/agent-operations/design-brief.d.ts.map +1 -0
  119. package/dist/agent-operations/design-brief.js +300 -0
  120. package/dist/agent-operations/designs.d.ts +24 -0
  121. package/dist/agent-operations/designs.d.ts.map +1 -0
  122. package/dist/agent-operations/designs.js +48 -0
  123. package/dist/agent-operations/door-clearance.d.ts +16 -1
  124. package/dist/agent-operations/door-clearance.d.ts.map +1 -1
  125. package/dist/agent-operations/door-clearance.js +61 -4
  126. package/dist/agent-operations/duplicate-level.d.ts.map +1 -1
  127. package/dist/agent-operations/duplicate-level.js +2 -1
  128. package/dist/agent-operations/find-by-type.d.ts +14 -7
  129. package/dist/agent-operations/find-by-type.d.ts.map +1 -1
  130. package/dist/agent-operations/find-by-type.js +266 -43
  131. package/dist/agent-operations/furnish-room.d.ts +22 -1
  132. package/dist/agent-operations/furnish-room.d.ts.map +1 -1
  133. package/dist/agent-operations/furnish-room.js +66 -19
  134. package/dist/agent-operations/furniture-kind.d.ts +22 -0
  135. package/dist/agent-operations/furniture-kind.d.ts.map +1 -0
  136. package/dist/agent-operations/furniture-kind.js +69 -0
  137. package/dist/agent-operations/get-node.d.ts +5 -2
  138. package/dist/agent-operations/get-node.d.ts.map +1 -1
  139. package/dist/agent-operations/get-node.js +82 -10
  140. package/dist/agent-operations/hosted-services.d.ts +2 -1
  141. package/dist/agent-operations/hosted-services.d.ts.map +1 -1
  142. package/dist/agent-operations/index.d.ts +281 -69
  143. package/dist/agent-operations/index.d.ts.map +1 -1
  144. package/dist/agent-operations/index.js +66 -5
  145. package/dist/agent-operations/item-space.d.ts +22 -0
  146. package/dist/agent-operations/item-space.d.ts.map +1 -0
  147. package/dist/agent-operations/item-space.js +69 -0
  148. package/dist/agent-operations/layout-clearance.d.ts +52 -3
  149. package/dist/agent-operations/layout-clearance.d.ts.map +1 -1
  150. package/dist/agent-operations/layout-clearance.js +340 -30
  151. package/dist/agent-operations/level-height-fill.d.ts +12 -0
  152. package/dist/agent-operations/level-height-fill.d.ts.map +1 -0
  153. package/dist/agent-operations/level-height-fill.js +59 -0
  154. package/dist/agent-operations/level-reads.d.ts +5 -1
  155. package/dist/agent-operations/level-reads.d.ts.map +1 -1
  156. package/dist/agent-operations/level-reads.js +10 -3
  157. package/dist/agent-operations/list-levels.d.ts.map +1 -1
  158. package/dist/agent-operations/list-levels.js +23 -0
  159. package/dist/agent-operations/material-preset.d.ts.map +1 -1
  160. package/dist/agent-operations/material-preset.js +3 -9
  161. package/dist/agent-operations/material-refs.d.ts +7 -1
  162. package/dist/agent-operations/material-refs.d.ts.map +1 -1
  163. package/dist/agent-operations/material-refs.js +10 -5
  164. package/dist/agent-operations/merge-windows.d.ts +6 -0
  165. package/dist/agent-operations/merge-windows.d.ts.map +1 -0
  166. package/dist/agent-operations/merge-windows.js +27 -0
  167. package/dist/agent-operations/move-roofs.d.ts +9 -0
  168. package/dist/agent-operations/move-roofs.d.ts.map +1 -0
  169. package/dist/agent-operations/move-roofs.js +29 -0
  170. package/dist/agent-operations/paint.d.ts +2 -1
  171. package/dist/agent-operations/paint.d.ts.map +1 -1
  172. package/dist/agent-operations/paint.js +163 -53
  173. package/dist/agent-operations/photo-elevation.d.ts +155 -0
  174. package/dist/agent-operations/photo-elevation.d.ts.map +1 -0
  175. package/dist/agent-operations/photo-elevation.js +761 -0
  176. package/dist/agent-operations/place-in-room.d.ts +29 -0
  177. package/dist/agent-operations/place-in-room.d.ts.map +1 -0
  178. package/dist/agent-operations/place-in-room.js +403 -0
  179. package/dist/agent-operations/place-items.d.ts.map +1 -1
  180. package/dist/agent-operations/place-items.js +15 -2
  181. package/dist/agent-operations/plan-geometry.d.ts.map +1 -1
  182. package/dist/agent-operations/plan-geometry.js +3 -0
  183. package/dist/agent-operations/point-context.d.ts +139 -0
  184. package/dist/agent-operations/point-context.d.ts.map +1 -0
  185. package/dist/agent-operations/point-context.js +1 -0
  186. package/dist/agent-operations/project-files.d.ts +9 -0
  187. package/dist/agent-operations/project-files.d.ts.map +1 -0
  188. package/dist/agent-operations/project-files.js +25 -0
  189. package/dist/agent-operations/record-made.d.ts +18 -0
  190. package/dist/agent-operations/record-made.d.ts.map +1 -0
  191. package/dist/agent-operations/record-made.js +28 -0
  192. package/dist/agent-operations/roof-footprint.d.ts +24 -0
  193. package/dist/agent-operations/roof-footprint.d.ts.map +1 -0
  194. package/dist/agent-operations/roof-footprint.js +242 -0
  195. package/dist/agent-operations/roof-writes.d.ts +20 -0
  196. package/dist/agent-operations/roof-writes.d.ts.map +1 -0
  197. package/dist/agent-operations/roof-writes.js +165 -0
  198. package/dist/agent-operations/room-findings.d.ts +54 -0
  199. package/dist/agent-operations/room-findings.d.ts.map +1 -0
  200. package/dist/agent-operations/room-findings.js +143 -0
  201. package/dist/agent-operations/room-floor-script.d.ts +23 -0
  202. package/dist/agent-operations/room-floor-script.d.ts.map +1 -0
  203. package/dist/agent-operations/room-floor-script.js +54 -0
  204. package/dist/agent-operations/room-structure.d.ts +2 -2
  205. package/dist/agent-operations/room-structure.d.ts.map +1 -1
  206. package/dist/agent-operations/scene-checkpoint.d.ts +94 -0
  207. package/dist/agent-operations/scene-checkpoint.d.ts.map +1 -0
  208. package/dist/agent-operations/scene-checkpoint.js +176 -0
  209. package/dist/agent-operations/scene-queries.d.ts +3750 -3319
  210. package/dist/agent-operations/scene-queries.d.ts.map +1 -1
  211. package/dist/agent-operations/scene-queries.js +13 -23
  212. package/dist/agent-operations/scene-review.d.ts +52 -0
  213. package/dist/agent-operations/scene-review.d.ts.map +1 -0
  214. package/dist/agent-operations/scene-review.js +106 -0
  215. package/dist/agent-operations/scene-view.d.ts +82 -15
  216. package/dist/agent-operations/scene-view.d.ts.map +1 -1
  217. package/dist/agent-operations/scene-view.js +408 -51
  218. package/dist/agent-operations/search-assets.d.ts +2 -2
  219. package/dist/agent-operations/search-assets.d.ts.map +1 -1
  220. package/dist/agent-operations/search-assets.js +4 -3
  221. package/dist/agent-operations/search-materials.d.ts +9 -3
  222. package/dist/agent-operations/search-materials.d.ts.map +1 -1
  223. package/dist/agent-operations/search-materials.js +83 -29
  224. package/dist/agent-operations/set-checkpoint.d.ts +9 -0
  225. package/dist/agent-operations/set-checkpoint.d.ts.map +1 -0
  226. package/dist/agent-operations/set-checkpoint.js +31 -0
  227. package/dist/agent-operations/set-ground-level.d.ts +12 -0
  228. package/dist/agent-operations/set-ground-level.d.ts.map +1 -0
  229. package/dist/agent-operations/set-ground-level.js +61 -0
  230. package/dist/agent-operations/site.d.ts +21 -0
  231. package/dist/agent-operations/site.d.ts.map +1 -0
  232. package/dist/agent-operations/site.js +123 -0
  233. package/dist/agent-operations/types.d.ts +66 -7
  234. package/dist/agent-operations/types.d.ts.map +1 -1
  235. package/dist/agent-operations/verify-scene.d.ts +39 -5
  236. package/dist/agent-operations/verify-scene.d.ts.map +1 -1
  237. package/dist/agent-operations/verify-scene.js +223 -44
  238. package/dist/agent-operations/wall-face-script.d.ts +28 -0
  239. package/dist/agent-operations/wall-face-script.d.ts.map +1 -0
  240. package/dist/agent-operations/wall-face-script.js +62 -0
  241. package/dist/agent-operations/wall-object-observations.d.ts +41 -0
  242. package/dist/agent-operations/wall-object-observations.d.ts.map +1 -0
  243. package/dist/agent-operations/wall-object-observations.js +249 -0
  244. package/dist/agent-operations/wall-opening.d.ts +23 -23
  245. package/dist/agent-operations/wall-opening.d.ts.map +1 -1
  246. package/dist/agent-operations/wall-skirting.d.ts +24 -0
  247. package/dist/agent-operations/wall-skirting.d.ts.map +1 -0
  248. package/dist/agent-operations/wall-skirting.js +85 -0
  249. package/dist/agent-tools/add-object.d.ts +11 -7
  250. package/dist/agent-tools/add-object.d.ts.map +1 -1
  251. package/dist/agent-tools/add-object.js +17 -11
  252. package/dist/agent-tools/assets.d.ts +8 -0
  253. package/dist/agent-tools/assets.d.ts.map +1 -1
  254. package/dist/agent-tools/assets.js +13 -1
  255. package/dist/agent-tools/author-scene.d.ts +651 -0
  256. package/dist/agent-tools/author-scene.d.ts.map +1 -0
  257. package/dist/agent-tools/author-scene.js +252 -0
  258. package/dist/agent-tools/batch.d.ts +25 -0
  259. package/dist/agent-tools/batch.d.ts.map +1 -0
  260. package/dist/agent-tools/batch.js +61 -0
  261. package/dist/agent-tools/checkpoints.d.ts +13 -0
  262. package/dist/agent-tools/checkpoints.d.ts.map +1 -0
  263. package/dist/agent-tools/checkpoints.js +16 -0
  264. package/dist/agent-tools/clear-scene.d.ts.map +1 -1
  265. package/dist/agent-tools/collections.d.ts +6 -6
  266. package/dist/agent-tools/collections.d.ts.map +1 -1
  267. package/dist/agent-tools/columns.d.ts +18 -18
  268. package/dist/agent-tools/columns.js +2 -2
  269. package/dist/agent-tools/corner-window.d.ts +46 -0
  270. package/dist/agent-tools/corner-window.d.ts.map +1 -0
  271. package/dist/agent-tools/corner-window.js +47 -0
  272. package/dist/agent-tools/create-room.d.ts +26 -25
  273. package/dist/agent-tools/create-room.d.ts.map +1 -1
  274. package/dist/agent-tools/create-room.js +11 -4
  275. package/dist/agent-tools/design-brief.d.ts +408 -0
  276. package/dist/agent-tools/design-brief.d.ts.map +1 -0
  277. package/dist/agent-tools/design-brief.js +149 -0
  278. package/dist/agent-tools/designs.d.ts +34 -0
  279. package/dist/agent-tools/designs.d.ts.map +1 -0
  280. package/dist/agent-tools/designs.js +50 -0
  281. package/dist/agent-tools/fences.d.ts +28 -0
  282. package/dist/agent-tools/fences.d.ts.map +1 -0
  283. package/dist/agent-tools/fences.js +31 -0
  284. package/dist/agent-tools/find-by-type.d.ts +8 -1
  285. package/dist/agent-tools/find-by-type.d.ts.map +1 -1
  286. package/dist/agent-tools/find-by-type.js +23 -2
  287. package/dist/agent-tools/furnish-room.d.ts +10 -8
  288. package/dist/agent-tools/furnish-room.d.ts.map +1 -1
  289. package/dist/agent-tools/furnish-room.js +3 -1
  290. package/dist/agent-tools/hosted-services.d.ts +177 -141
  291. package/dist/agent-tools/hosted-services.d.ts.map +1 -1
  292. package/dist/agent-tools/hosted-services.js +47 -14
  293. package/dist/agent-tools/index.d.ts +894 -215
  294. package/dist/agent-tools/index.d.ts.map +1 -1
  295. package/dist/agent-tools/index.js +47 -3
  296. package/dist/agent-tools/levels.d.ts +11 -3
  297. package/dist/agent-tools/levels.d.ts.map +1 -1
  298. package/dist/agent-tools/levels.js +16 -5
  299. package/dist/agent-tools/measurement.d.ts +38 -20
  300. package/dist/agent-tools/measurement.d.ts.map +1 -1
  301. package/dist/agent-tools/measurement.js +117 -67
  302. package/dist/agent-tools/merge-windows.d.ts +10 -0
  303. package/dist/agent-tools/merge-windows.d.ts.map +1 -0
  304. package/dist/agent-tools/merge-windows.js +12 -0
  305. package/dist/agent-tools/nodes.d.ts.map +1 -1
  306. package/dist/agent-tools/nodes.js +1 -1
  307. package/dist/agent-tools/notation-inventory.d.ts +16 -0
  308. package/dist/agent-tools/notation-inventory.d.ts.map +1 -0
  309. package/dist/agent-tools/notation-inventory.js +105 -0
  310. package/dist/agent-tools/paint.d.ts +5 -5
  311. package/dist/agent-tools/paint.d.ts.map +1 -1
  312. package/dist/agent-tools/paint.js +1 -1
  313. package/dist/agent-tools/photo-elevation.d.ts +32 -0
  314. package/dist/agent-tools/photo-elevation.d.ts.map +1 -0
  315. package/dist/agent-tools/photo-elevation.js +73 -0
  316. package/dist/agent-tools/place-in-room.d.ts +35 -0
  317. package/dist/agent-tools/place-in-room.d.ts.map +1 -0
  318. package/dist/agent-tools/place-in-room.js +61 -0
  319. package/dist/agent-tools/place-items.d.ts +1 -1
  320. package/dist/agent-tools/place-items.js +2 -2
  321. package/dist/agent-tools/project-files.d.ts +189 -0
  322. package/dist/agent-tools/project-files.d.ts.map +1 -0
  323. package/dist/agent-tools/project-files.js +99 -0
  324. package/dist/agent-tools/refusal.d.ts.map +1 -1
  325. package/dist/agent-tools/retired.d.ts +21 -0
  326. package/dist/agent-tools/retired.d.ts.map +1 -0
  327. package/dist/agent-tools/retired.js +29 -0
  328. package/dist/agent-tools/roofs.d.ts +100 -0
  329. package/dist/agent-tools/roofs.d.ts.map +1 -0
  330. package/dist/agent-tools/roofs.js +96 -0
  331. package/dist/agent-tools/room-structure.d.ts +46 -38
  332. package/dist/agent-tools/room-structure.d.ts.map +1 -1
  333. package/dist/agent-tools/room-structure.js +30 -27
  334. package/dist/agent-tools/search-materials.d.ts +22 -3
  335. package/dist/agent-tools/search-materials.d.ts.map +1 -1
  336. package/dist/agent-tools/search-materials.js +13 -14
  337. package/dist/agent-tools/site.d.ts +27 -0
  338. package/dist/agent-tools/site.d.ts.map +1 -0
  339. package/dist/agent-tools/site.js +40 -0
  340. package/dist/agent-tools/sources.d.ts +12 -0
  341. package/dist/agent-tools/sources.d.ts.map +1 -0
  342. package/dist/agent-tools/sources.js +11 -0
  343. package/dist/agent-tools/stairs.d.ts +48 -28
  344. package/dist/agent-tools/stairs.d.ts.map +1 -1
  345. package/dist/agent-tools/stairs.js +65 -22
  346. package/dist/agent-tools/verify-scene.d.ts.map +1 -1
  347. package/dist/agent-tools/verify-scene.js +1 -1
  348. package/dist/agent-tools/view-scene.d.ts +50 -12
  349. package/dist/agent-tools/view-scene.d.ts.map +1 -1
  350. package/dist/agent-tools/view-scene.js +74 -31
  351. package/dist/agent-tools/wall-openings.d.ts +77 -73
  352. package/dist/agent-tools/wall-openings.d.ts.map +1 -1
  353. package/dist/agent-tools/wall-openings.js +9 -5
  354. package/dist/agent-tools/walls.d.ts +4 -4
  355. package/dist/agent-tools/walls.d.ts.map +1 -1
  356. package/dist/agent-tools/walls.js +7 -2
  357. package/dist/building/__fixtures__/wall-opening-cases.d.ts +454 -250
  358. package/dist/building/__fixtures__/wall-opening-cases.d.ts.map +1 -1
  359. package/dist/building/__fixtures__/wall-opening-cases.js +62 -2
  360. package/dist/building/corner-window.d.ts +56 -0
  361. package/dist/building/corner-window.d.ts.map +1 -0
  362. package/dist/building/corner-window.js +179 -0
  363. package/dist/building/ground-level.d.ts +26 -0
  364. package/dist/building/ground-level.d.ts.map +1 -0
  365. package/dist/building/ground-level.js +58 -0
  366. package/dist/building/index.d.ts +5 -0
  367. package/dist/building/index.d.ts.map +1 -1
  368. package/dist/building/index.js +5 -0
  369. package/dist/building/level-duplication.d.ts +7472 -6613
  370. package/dist/building/level-duplication.d.ts.map +1 -1
  371. package/dist/building/level-duplication.js +18 -4
  372. package/dist/building/level-insertion.d.ts +55 -0
  373. package/dist/building/level-insertion.d.ts.map +1 -0
  374. package/dist/building/level-insertion.js +35 -0
  375. package/dist/building/merge-windows.d.ts +58 -0
  376. package/dist/building/merge-windows.d.ts.map +1 -0
  377. package/dist/building/merge-windows.js +189 -0
  378. package/dist/building/opening-style-presets.d.ts +2 -2
  379. package/dist/building/opening-style-presets.d.ts.map +1 -1
  380. package/dist/building/photo-elevation.d.ts +125 -0
  381. package/dist/building/photo-elevation.d.ts.map +1 -0
  382. package/dist/building/photo-elevation.js +404 -0
  383. package/dist/building/wall-gaps.d.ts +13 -0
  384. package/dist/building/wall-gaps.d.ts.map +1 -0
  385. package/dist/building/wall-gaps.js +158 -0
  386. package/dist/building/wall-openings.d.ts +154 -119
  387. package/dist/building/wall-openings.d.ts.map +1 -1
  388. package/dist/building/wall-openings.js +37 -9
  389. package/dist/capture/schema.d.ts +22 -22
  390. package/dist/capture/source.d.ts.map +1 -1
  391. package/dist/capture/source.js +1 -1
  392. package/dist/commands/structure/create-zone.d.ts +12 -1
  393. package/dist/commands/structure/create-zone.d.ts.map +1 -1
  394. package/dist/commands/structure/create-zone.js +49 -0
  395. package/dist/commands/structure/divide-zone.d.ts +3 -3
  396. package/dist/commands/structure/index.d.ts +1 -1
  397. package/dist/commands/structure/index.d.ts.map +1 -1
  398. package/dist/commands/structure/index.js +1 -1
  399. package/dist/commands/structure/set-floor-foundation.d.ts +6 -6
  400. package/dist/commands/structure/set-zone-intent.d.ts +4 -0
  401. package/dist/commands/structure/set-zone-intent.d.ts.map +1 -1
  402. package/dist/commands/structure/set-zone-intent.js +19 -0
  403. package/dist/commands/structure/shared.d.ts +3642 -3213
  404. package/dist/commands/structure/shared.d.ts.map +1 -1
  405. package/dist/commands/structure/zone-wall-merge.d.ts +4149 -3334
  406. package/dist/commands/structure/zone-wall-merge.d.ts.map +1 -1
  407. package/dist/contracts/reference-inventory.d.ts.map +1 -1
  408. package/dist/contracts/reference-inventory.js +106 -26
  409. package/dist/events/bus.d.ts +22 -3
  410. package/dist/events/bus.d.ts.map +1 -1
  411. package/dist/events/capture-sessions.d.ts +5 -0
  412. package/dist/events/capture-sessions.d.ts.map +1 -0
  413. package/dist/events/capture-sessions.js +31 -0
  414. package/dist/hooks/scene-registry/scene-registry.d.ts.map +1 -1
  415. package/dist/hooks/spatial-grid/spatial-grid-manager.d.ts +1 -2
  416. package/dist/hooks/spatial-grid/spatial-grid-manager.d.ts.map +1 -1
  417. package/dist/hooks/spatial-grid/spatial-grid-manager.js +4 -6
  418. package/dist/hooks/spatial-grid/spatial-grid-sync.d.ts +3608 -3179
  419. package/dist/hooks/spatial-grid/spatial-grid-sync.d.ts.map +1 -1
  420. package/dist/hooks/spatial-grid/spatial-grid.d.ts.map +1 -1
  421. package/dist/hooks/spatial-grid/support-host-patch.d.ts.map +1 -1
  422. package/dist/hooks/spatial-grid/support-host-patch.js +11 -2
  423. package/dist/hooks/spatial-grid/use-spatial-query.d.ts +3 -3
  424. package/dist/hooks/spatial-grid/wall-spatial-grid.d.ts.map +1 -1
  425. package/dist/index.d.ts +37 -9
  426. package/dist/index.d.ts.map +1 -1
  427. package/dist/index.js +36 -9
  428. package/dist/lib/__fixtures__/mezzanine.d.ts +11800 -10132
  429. package/dist/lib/__fixtures__/mezzanine.d.ts.map +1 -1
  430. package/dist/lib/absorb-wall-separators.d.ts +3642 -3213
  431. package/dist/lib/absorb-wall-separators.d.ts.map +1 -1
  432. package/dist/lib/angle-accumulator.d.ts.map +1 -1
  433. package/dist/lib/artifact-store.d.ts.map +1 -1
  434. package/dist/lib/below-grade-footprints.d.ts +65 -0
  435. package/dist/lib/below-grade-footprints.d.ts.map +1 -0
  436. package/dist/lib/below-grade-footprints.js +181 -0
  437. package/dist/lib/building-footprint.d.ts +33 -0
  438. package/dist/lib/building-footprint.d.ts.map +1 -0
  439. package/dist/lib/building-footprint.js +89 -0
  440. package/dist/lib/corner-pair.d.ts +1129 -0
  441. package/dist/lib/corner-pair.d.ts.map +1 -0
  442. package/dist/lib/corner-pair.js +130 -0
  443. package/dist/lib/corner-snap.d.ts +54 -0
  444. package/dist/lib/corner-snap.d.ts.map +1 -0
  445. package/dist/lib/corner-snap.js +125 -0
  446. package/dist/lib/critically-damped.d.ts +11 -0
  447. package/dist/lib/critically-damped.d.ts.map +1 -0
  448. package/dist/lib/critically-damped.js +14 -0
  449. package/dist/lib/deepest-drawn.d.ts +18 -0
  450. package/dist/lib/deepest-drawn.d.ts.map +1 -0
  451. package/dist/lib/deepest-drawn.js +65 -0
  452. package/dist/lib/door-operation.d.ts +1 -1
  453. package/dist/lib/exterior-wall-loops.d.ts +17 -0
  454. package/dist/lib/exterior-wall-loops.d.ts.map +1 -0
  455. package/dist/lib/exterior-wall-loops.js +334 -0
  456. package/dist/lib/finish-script.d.ts +61 -0
  457. package/dist/lib/finish-script.d.ts.map +1 -0
  458. package/dist/lib/finish-script.js +86 -0
  459. package/dist/lib/floor-intent-changes.d.ts.map +1 -1
  460. package/dist/lib/floor-intent-changes.js +4 -4
  461. package/dist/lib/floor-plate-paint.d.ts +3 -1
  462. package/dist/lib/floor-plate-paint.d.ts.map +1 -1
  463. package/dist/lib/floor-plate-paint.js +24 -4
  464. package/dist/lib/floor-plates.d.ts +50 -50
  465. package/dist/lib/floor-script.d.ts +24 -0
  466. package/dist/lib/floor-script.d.ts.map +1 -0
  467. package/dist/lib/floor-script.js +51 -0
  468. package/dist/lib/foundation-construction.d.ts +73 -0
  469. package/dist/lib/foundation-construction.d.ts.map +1 -0
  470. package/dist/lib/foundation-construction.js +242 -0
  471. package/dist/lib/foundation-standard.d.ts +30 -0
  472. package/dist/lib/foundation-standard.d.ts.map +1 -0
  473. package/dist/lib/foundation-standard.js +30 -0
  474. package/dist/lib/foundation-wall.d.ts +36 -0
  475. package/dist/lib/foundation-wall.d.ts.map +1 -0
  476. package/dist/lib/foundation-wall.js +66 -0
  477. package/dist/lib/generic-foundation.d.ts +40 -0
  478. package/dist/lib/generic-foundation.d.ts.map +1 -0
  479. package/dist/lib/generic-foundation.js +200 -0
  480. package/dist/lib/geometry-script-node.d.ts +32 -3
  481. package/dist/lib/geometry-script-node.d.ts.map +1 -1
  482. package/dist/lib/geometry-script-node.js +26 -0
  483. package/dist/lib/grade-standing.d.ts +38 -0
  484. package/dist/lib/grade-standing.d.ts.map +1 -0
  485. package/dist/lib/grade-standing.js +137 -0
  486. package/dist/lib/ground-level.d.ts +20 -0
  487. package/dist/lib/ground-level.d.ts.map +1 -0
  488. package/dist/lib/ground-level.js +49 -0
  489. package/dist/lib/ground-over-part.d.ts +13 -0
  490. package/dist/lib/ground-over-part.d.ts.map +1 -0
  491. package/dist/lib/ground-over-part.js +94 -0
  492. package/dist/lib/ground-seat.d.ts +47 -0
  493. package/dist/lib/ground-seat.d.ts.map +1 -0
  494. package/dist/lib/ground-seat.js +61 -0
  495. package/dist/lib/ground-window.d.ts +39 -0
  496. package/dist/lib/ground-window.d.ts.map +1 -0
  497. package/dist/lib/ground-window.js +147 -0
  498. package/dist/lib/opening-floor-datum.d.ts.map +1 -1
  499. package/dist/lib/opening-floor-datum.js +2 -3
  500. package/dist/lib/own-floor-intent.d.ts.map +1 -1
  501. package/dist/lib/own-floor-intent.js +4 -4
  502. package/dist/lib/plate-surface.d.ts.map +1 -1
  503. package/dist/lib/plate-surface.js +3 -1
  504. package/dist/lib/point-ask.d.ts +9 -0
  505. package/dist/lib/point-ask.d.ts.map +1 -0
  506. package/dist/lib/point-ask.js +36 -0
  507. package/dist/lib/room-drawn-floor.d.ts +1 -1
  508. package/dist/lib/room-drawn-floor.d.ts.map +1 -1
  509. package/dist/lib/room-floor-feasibility.d.ts.map +1 -1
  510. package/dist/lib/room-floor-feasibility.js +3 -3
  511. package/dist/lib/room-graph.d.ts.map +1 -1
  512. package/dist/lib/room-graph.js +2 -0
  513. package/dist/lib/room-name.d.ts +2 -0
  514. package/dist/lib/room-name.d.ts.map +1 -1
  515. package/dist/lib/room-name.js +2 -0
  516. package/dist/lib/room-topology-index.d.ts.map +1 -1
  517. package/dist/lib/room-topology-index.js +1 -1
  518. package/dist/lib/room-zone-adoption.d.ts.map +1 -1
  519. package/dist/lib/script-inputs-key.d.ts +3 -0
  520. package/dist/lib/script-inputs-key.d.ts.map +1 -0
  521. package/dist/lib/script-inputs-key.js +13 -0
  522. package/dist/lib/setback-envelope.d.ts +95 -5
  523. package/dist/lib/setback-envelope.d.ts.map +1 -1
  524. package/dist/lib/setback-envelope.js +351 -35
  525. package/dist/lib/site-flatwork.d.ts +11 -0
  526. package/dist/lib/site-flatwork.d.ts.map +1 -0
  527. package/dist/lib/site-flatwork.js +11 -0
  528. package/dist/lib/site-ground-height.d.ts +13 -0
  529. package/dist/lib/site-ground-height.d.ts.map +1 -0
  530. package/dist/lib/site-ground-height.js +16 -0
  531. package/dist/lib/site-placement.d.ts +362 -0
  532. package/dist/lib/site-placement.d.ts.map +1 -0
  533. package/dist/lib/site-placement.js +942 -0
  534. package/dist/lib/snap-ease.d.ts +20 -0
  535. package/dist/lib/snap-ease.d.ts.map +1 -0
  536. package/dist/lib/snap-ease.js +50 -0
  537. package/dist/lib/structure-kernel.d.ts +1 -1
  538. package/dist/lib/structure-kernel.d.ts.map +1 -1
  539. package/dist/lib/structure-kernel.js +2 -0
  540. package/dist/lib/surface-support-references.d.ts +4 -0
  541. package/dist/lib/surface-support-references.d.ts.map +1 -0
  542. package/dist/lib/surface-support-references.js +19 -0
  543. package/dist/lib/terrain-support-query.d.ts +10 -0
  544. package/dist/lib/terrain-support-query.d.ts.map +1 -1
  545. package/dist/lib/terrain-support-query.js +1 -1
  546. package/dist/lib/wall-face-script.d.ts +66 -0
  547. package/dist/lib/wall-face-script.d.ts.map +1 -0
  548. package/dist/lib/wall-face-script.js +235 -0
  549. package/dist/lib/zone-colors.d.ts +1 -1
  550. package/dist/lib/zone-colors.d.ts.map +1 -1
  551. package/dist/lib/zone-quantities.d.ts.map +1 -1
  552. package/dist/lib/zone-quantities.js +4 -5
  553. package/dist/material-kinds.d.ts +9 -0
  554. package/dist/material-kinds.d.ts.map +1 -0
  555. package/dist/material-kinds.js +30 -0
  556. package/dist/material-library.d.ts +4 -4
  557. package/dist/material-library.d.ts.map +1 -1
  558. package/dist/material-library.js +72 -26
  559. package/dist/node-slots/index.d.ts +1 -0
  560. package/dist/node-slots/index.d.ts.map +1 -1
  561. package/dist/node-slots/index.js +7 -1
  562. package/dist/node-slots/roof.d.ts +5 -0
  563. package/dist/node-slots/roof.d.ts.map +1 -0
  564. package/dist/node-slots/roof.js +12 -0
  565. package/dist/node-slots/stair.d.ts +2 -0
  566. package/dist/node-slots/stair.d.ts.map +1 -1
  567. package/dist/node-slots/stair.js +6 -2
  568. package/dist/procedural-items/design-placement.d.ts.map +1 -1
  569. package/dist/procedural-items/design.d.ts +19 -19
  570. package/dist/procedural-items/fixtures.d.ts +297 -297
  571. package/dist/procedural-items/fixtures.d.ts.map +1 -1
  572. package/dist/procedural-items/integration.d.ts +106 -106
  573. package/dist/procedural-items/joints.d.ts +4 -4
  574. package/dist/procedural-items/library-colors.d.ts +22 -22
  575. package/dist/procedural-items/library-colors.d.ts.map +1 -1
  576. package/dist/procedural-items/motion-controller.d.ts.map +1 -1
  577. package/dist/procedural-items/node.d.ts +291 -291
  578. package/dist/procedural-items/query.d.ts +1 -1
  579. package/dist/procedural-items/query.d.ts.map +1 -1
  580. package/dist/procedural-items/recipe.d.ts +11 -11
  581. package/dist/procedural-items/recipe.d.ts.map +1 -1
  582. package/dist/procedural-items/section.d.ts.map +1 -1
  583. package/dist/registry/index.d.ts +1 -1
  584. package/dist/registry/index.d.ts.map +1 -1
  585. package/dist/registry/scene-api.d.ts +1 -0
  586. package/dist/registry/scene-api.d.ts.map +1 -1
  587. package/dist/registry/scene-api.js +3 -0
  588. package/dist/registry/subtree.d.ts.map +1 -1
  589. package/dist/registry/subtree.js +2 -0
  590. package/dist/registry/types.d.ts +120 -1
  591. package/dist/registry/types.d.ts.map +1 -1
  592. package/dist/schema/assembly.d.ts +41 -41
  593. package/dist/schema/asset-url.d.ts +1 -1
  594. package/dist/schema/asset-url.d.ts.map +1 -1
  595. package/dist/schema/base.d.ts +9 -9
  596. package/dist/schema/base.d.ts.map +1 -1
  597. package/dist/schema/camera.d.ts +1 -1
  598. package/dist/schema/collection-templates.d.ts +20 -20
  599. package/dist/schema/collection-templates.d.ts.map +1 -1
  600. package/dist/schema/geometry-metadata.d.ts +7 -7
  601. package/dist/schema/geometry-metadata.d.ts.map +1 -1
  602. package/dist/schema/geometry-source.d.ts +26 -16
  603. package/dist/schema/geometry-source.d.ts.map +1 -1
  604. package/dist/schema/geometry-source.js +14 -0
  605. package/dist/schema/index.d.ts +10 -7
  606. package/dist/schema/index.d.ts.map +1 -1
  607. package/dist/schema/index.js +10 -7
  608. package/dist/schema/material.d.ts +33 -33
  609. package/dist/schema/nodes/barrel-roof.d.ts +3 -0
  610. package/dist/schema/nodes/barrel-roof.d.ts.map +1 -0
  611. package/dist/schema/nodes/barrel-roof.js +11 -0
  612. package/dist/schema/nodes/block.d.ts +8 -8
  613. package/dist/schema/nodes/box-vent.d.ts +13 -13
  614. package/dist/schema/nodes/building.d.ts +9 -8
  615. package/dist/schema/nodes/building.d.ts.map +1 -1
  616. package/dist/schema/nodes/building.js +2 -0
  617. package/dist/schema/nodes/cabinet.d.ts +130 -129
  618. package/dist/schema/nodes/cabinet.d.ts.map +1 -1
  619. package/dist/schema/nodes/cabinet.js +1 -1
  620. package/dist/schema/nodes/ceiling.d.ts +15 -15
  621. package/dist/schema/nodes/chimney.d.ts +23 -23
  622. package/dist/schema/nodes/column.d.ts +207 -199
  623. package/dist/schema/nodes/column.d.ts.map +1 -1
  624. package/dist/schema/nodes/column.js +2 -0
  625. package/dist/schema/nodes/construction-dimension.d.ts +34 -34
  626. package/dist/schema/nodes/cupola.d.ts +15 -15
  627. package/dist/schema/nodes/curtain-wall.d.ts +21 -20
  628. package/dist/schema/nodes/curtain-wall.d.ts.map +1 -1
  629. package/dist/schema/nodes/curtain-wall.js +23 -0
  630. package/dist/schema/nodes/door.d.ts +50 -43
  631. package/dist/schema/nodes/door.d.ts.map +1 -1
  632. package/dist/schema/nodes/door.js +19 -0
  633. package/dist/schema/nodes/dormer.d.ts +37 -36
  634. package/dist/schema/nodes/dormer.d.ts.map +1 -1
  635. package/dist/schema/nodes/downspout.d.ts +17 -17
  636. package/dist/schema/nodes/duct-fitting.d.ts +24 -24
  637. package/dist/schema/nodes/duct-segment.d.ts +14 -14
  638. package/dist/schema/nodes/duct-terminal.d.ts +12 -12
  639. package/dist/schema/nodes/elevator.d.ts +15 -15
  640. package/dist/schema/nodes/eyebrow-vent.d.ts +13 -13
  641. package/dist/schema/nodes/fence-feature.d.ts +37 -37
  642. package/dist/schema/nodes/fence-types.d.ts +32 -0
  643. package/dist/schema/nodes/fence-types.d.ts.map +1 -0
  644. package/dist/schema/nodes/fence-types.js +22 -0
  645. package/dist/schema/nodes/fence.d.ts +43 -72
  646. package/dist/schema/nodes/fence.d.ts.map +1 -1
  647. package/dist/schema/nodes/fence.js +4 -20
  648. package/dist/schema/nodes/floor-opening.d.ts +8 -8
  649. package/dist/schema/nodes/guide.d.ts +8 -8
  650. package/dist/schema/nodes/gutter.d.ts +14 -14
  651. package/dist/schema/nodes/gutter.d.ts.map +1 -1
  652. package/dist/schema/nodes/gutter.js +6 -5
  653. package/dist/schema/nodes/hvac-equipment.d.ts +13 -13
  654. package/dist/schema/nodes/imported-mesh.d.ts +8 -8
  655. package/dist/schema/nodes/item.d.ts +30 -25
  656. package/dist/schema/nodes/item.d.ts.map +1 -1
  657. package/dist/schema/nodes/lean-to-extension.d.ts +36 -36
  658. package/dist/schema/nodes/level.d.ts +9 -9
  659. package/dist/schema/nodes/lineset.d.ts +8 -8
  660. package/dist/schema/nodes/liquid-line.d.ts +8 -8
  661. package/dist/schema/nodes/measurement.d.ts +8 -8
  662. package/dist/schema/nodes/opening-types.d.ts +13 -13
  663. package/dist/schema/nodes/opening-types.d.ts.map +1 -1
  664. package/dist/schema/nodes/pipe-fitting.d.ts +15 -15
  665. package/dist/schema/nodes/pipe-segment.d.ts +11 -11
  666. package/dist/schema/nodes/pipe-trap.d.ts +9 -9
  667. package/dist/schema/nodes/ridge-vent.d.ts +14 -14
  668. package/dist/schema/nodes/ridge-vent.d.ts.map +1 -1
  669. package/dist/schema/nodes/ridge-vent.js +3 -1
  670. package/dist/schema/nodes/roof-glazing-config.d.ts +90 -0
  671. package/dist/schema/nodes/roof-glazing-config.d.ts.map +1 -0
  672. package/dist/schema/nodes/roof-glazing-config.js +34 -0
  673. package/dist/schema/nodes/roof-glazing.d.ts +57 -0
  674. package/dist/schema/nodes/roof-glazing.d.ts.map +1 -0
  675. package/dist/schema/nodes/roof-glazing.js +514 -0
  676. package/dist/schema/nodes/roof-segment-resize.d.ts +4 -0
  677. package/dist/schema/nodes/roof-segment-resize.d.ts.map +1 -0
  678. package/dist/schema/nodes/roof-segment-resize.js +21 -0
  679. package/dist/schema/nodes/roof-segment-shape.d.ts +5 -0
  680. package/dist/schema/nodes/roof-segment-shape.d.ts.map +1 -1
  681. package/dist/schema/nodes/roof-segment-shape.js +44 -0
  682. package/dist/schema/nodes/roof-segment-walls.d.ts +1 -1
  683. package/dist/schema/nodes/roof-segment-walls.d.ts.map +1 -1
  684. package/dist/schema/nodes/roof-segment-walls.js +24 -0
  685. package/dist/schema/nodes/roof-segment.d.ts +153 -46
  686. package/dist/schema/nodes/roof-segment.d.ts.map +1 -1
  687. package/dist/schema/nodes/roof-segment.js +91 -20
  688. package/dist/schema/nodes/roof-types.d.ts +14 -0
  689. package/dist/schema/nodes/roof-types.d.ts.map +1 -0
  690. package/dist/schema/nodes/roof-types.js +14 -0
  691. package/dist/schema/nodes/roof.d.ts +49 -49
  692. package/dist/schema/nodes/scan.d.ts +8 -8
  693. package/dist/schema/nodes/separator.d.ts +8 -8
  694. package/dist/schema/nodes/shelf.d.ts +16 -16
  695. package/dist/schema/nodes/site-facts.d.ts +64 -0
  696. package/dist/schema/nodes/site-facts.d.ts.map +1 -0
  697. package/dist/schema/nodes/site-facts.js +73 -0
  698. package/dist/schema/nodes/site.d.ts +105 -63
  699. package/dist/schema/nodes/site.d.ts.map +1 -1
  700. package/dist/schema/nodes/site.js +7 -70
  701. package/dist/schema/nodes/skylight.d.ts +41 -41
  702. package/dist/schema/nodes/skylight.d.ts.map +1 -1
  703. package/dist/schema/nodes/slab.d.ts +21 -21
  704. package/dist/schema/nodes/solar-panel.d.ts +21 -21
  705. package/dist/schema/nodes/spawn.d.ts +8 -8
  706. package/dist/schema/nodes/stair-construction.d.ts +3 -3
  707. package/dist/schema/nodes/stair-defaults.d.ts +16 -0
  708. package/dist/schema/nodes/stair-defaults.d.ts.map +1 -0
  709. package/dist/schema/nodes/stair-defaults.js +15 -0
  710. package/dist/schema/nodes/stair-segment.d.ts +22 -22
  711. package/dist/schema/nodes/stair-types.d.ts +29 -0
  712. package/dist/schema/nodes/stair-types.d.ts.map +1 -0
  713. package/dist/schema/nodes/stair-types.js +23 -0
  714. package/dist/schema/nodes/stair.d.ts +51 -75
  715. package/dist/schema/nodes/stair.d.ts.map +1 -1
  716. package/dist/schema/nodes/stair.js +6 -20
  717. package/dist/schema/nodes/structural-grid.d.ts +8 -8
  718. package/dist/schema/nodes/surface-hole-metadata.d.ts +2 -2
  719. package/dist/schema/nodes/turbine-vent.d.ts +13 -13
  720. package/dist/schema/nodes/unit.d.ts +10 -10
  721. package/dist/schema/nodes/unit.d.ts.map +1 -1
  722. package/dist/schema/nodes/wall.d.ts +479 -146
  723. package/dist/schema/nodes/wall.d.ts.map +1 -1
  724. package/dist/schema/nodes/wall.js +19 -0
  725. package/dist/schema/nodes/window.d.ts +55 -39
  726. package/dist/schema/nodes/window.d.ts.map +1 -1
  727. package/dist/schema/nodes/window.js +10 -0
  728. package/dist/schema/nodes/zone.d.ts +231 -12
  729. package/dist/schema/nodes/zone.d.ts.map +1 -1
  730. package/dist/schema/nodes/zone.js +10 -0
  731. package/dist/schema/provenance.d.ts +21 -21
  732. package/dist/schema/scene-material.d.ts +5 -5
  733. package/dist/schema/site-presentation.d.ts +100 -0
  734. package/dist/schema/site-presentation.d.ts.map +1 -0
  735. package/dist/schema/site-presentation.js +83 -0
  736. package/dist/schema/types.d.ts +1954 -1414
  737. package/dist/schema/types.d.ts.map +1 -1
  738. package/dist/services/__fixtures__/wall-plane-top-boundary-repro.d.ts.map +1 -1
  739. package/dist/services/index.d.ts +5 -1
  740. package/dist/services/index.d.ts.map +1 -1
  741. package/dist/services/index.js +5 -1
  742. package/dist/services/level-height.d.ts.map +1 -1
  743. package/dist/services/level-height.js +7 -3
  744. package/dist/services/port-connectivity.d.ts +4 -0
  745. package/dist/services/port-connectivity.d.ts.map +1 -1
  746. package/dist/services/port-connectivity.js +35 -0
  747. package/dist/services/project-file-sink.d.ts +9 -0
  748. package/dist/services/project-file-sink.d.ts.map +1 -0
  749. package/dist/services/project-file-sink.js +13 -0
  750. package/dist/services/roof-bearing.d.ts +62 -0
  751. package/dist/services/roof-bearing.d.ts.map +1 -0
  752. package/dist/services/roof-bearing.js +234 -0
  753. package/dist/services/roof-level.d.ts +121 -0
  754. package/dist/services/roof-level.d.ts.map +1 -0
  755. package/dist/services/roof-level.js +280 -0
  756. package/dist/services/roof-move.d.ts +83 -0
  757. package/dist/services/roof-move.d.ts.map +1 -0
  758. package/dist/services/roof-move.js +316 -0
  759. package/dist/services/stair-surface-snap.d.ts +14 -0
  760. package/dist/services/stair-surface-snap.d.ts.map +1 -0
  761. package/dist/services/stair-surface-snap.js +116 -0
  762. package/dist/services/storey-datum.d.ts +12 -0
  763. package/dist/services/storey-datum.d.ts.map +1 -0
  764. package/dist/services/storey-datum.js +18 -0
  765. package/dist/services/storey.d.ts +51 -5
  766. package/dist/services/storey.d.ts.map +1 -1
  767. package/dist/services/storey.js +125 -8
  768. package/dist/solar-panel-presets.d.ts +2 -2
  769. package/dist/store/actions/node-actions.d.ts +3613 -3182
  770. package/dist/store/actions/node-actions.d.ts.map +1 -1
  771. package/dist/store/actions/node-actions.js +46 -1
  772. package/dist/store/derived-node-guard.d.ts.map +1 -1
  773. package/dist/store/history-control.d.ts +39 -0
  774. package/dist/store/history-control.d.ts.map +1 -1
  775. package/dist/store/history-control.js +84 -4
  776. package/dist/store/scene-annotations.d.ts +7267 -6409
  777. package/dist/store/scene-annotations.d.ts.map +1 -1
  778. package/dist/store/scene-preview.d.ts +16 -0
  779. package/dist/store/scene-preview.d.ts.map +1 -0
  780. package/dist/store/scene-preview.js +144 -0
  781. package/dist/store/use-live-node-overrides.d.ts.map +1 -1
  782. package/dist/store/use-live-terrain.d.ts.map +1 -1
  783. package/dist/store/use-live-transforms.d.ts.map +1 -1
  784. package/dist/store/use-scene.d.ts.map +1 -1
  785. package/dist/store/use-scene.js +37 -4
  786. package/dist/systems/elevator/elevator-dispatch.js +1 -1
  787. package/dist/systems/fence/fence-features.d.ts.map +1 -1
  788. package/dist/systems/owned-floor-openings.d.ts.map +1 -1
  789. package/dist/systems/owned-floor-openings.js +24 -3
  790. package/dist/systems/roof/roof-elevation-system.d.ts.map +1 -1
  791. package/dist/systems/roof/roof-elevation-system.js +9 -3
  792. package/dist/systems/roof/roof-elevation.d.ts +5 -0
  793. package/dist/systems/roof/roof-elevation.d.ts.map +1 -1
  794. package/dist/systems/roof/roof-elevation.js +91 -62
  795. package/dist/systems/slab/__fixtures__/floor-step.d.ts +4623 -3516
  796. package/dist/systems/slab/__fixtures__/floor-step.d.ts.map +1 -1
  797. package/dist/systems/slab/__fixtures__/raised-room.d.ts +5149 -4076
  798. package/dist/systems/slab/__fixtures__/raised-room.d.ts.map +1 -1
  799. package/dist/systems/slab/slab-support.d.ts +6 -3
  800. package/dist/systems/slab/slab-support.d.ts.map +1 -1
  801. package/dist/systems/slab/slab-support.js +78 -10
  802. package/dist/systems/stair/stair-detail-budget.d.ts +2 -2
  803. package/dist/systems/stair/stair-detail-budget.d.ts.map +1 -1
  804. package/dist/systems/stair/stair-footprint.d.ts +6 -0
  805. package/dist/systems/stair/stair-footprint.d.ts.map +1 -1
  806. package/dist/systems/stair/stair-footprint.js +27 -14
  807. package/dist/systems/stair/stair-layout.d.ts +2 -2
  808. package/dist/systems/stair/stair-opening-preview.d.ts +3643 -3214
  809. package/dist/systems/stair/stair-opening-preview.d.ts.map +1 -1
  810. package/dist/systems/stair/stair-presets.d.ts +73 -65
  811. package/dist/systems/stair/stair-presets.d.ts.map +1 -1
  812. package/dist/systems/stair/stair-presets.js +16 -9
  813. package/dist/systems/stair/stair-rail-path.d.ts +1 -1
  814. package/dist/systems/stair/stair-rise-query.d.ts +16 -0
  815. package/dist/systems/stair/stair-rise-query.d.ts.map +1 -1
  816. package/dist/systems/stair/stair-rise-query.js +57 -7
  817. package/dist/systems/stair/stair-sizing.d.ts +101 -99
  818. package/dist/systems/stair/stair-sizing.d.ts.map +1 -1
  819. package/dist/systems/wall/wall-assembly.d.ts +11 -0
  820. package/dist/systems/wall/wall-assembly.d.ts.map +1 -1
  821. package/dist/systems/wall/wall-assembly.js +21 -0
  822. package/dist/systems/wall/wall-curve.d.ts +5 -0
  823. package/dist/systems/wall/wall-curve.d.ts.map +1 -1
  824. package/dist/systems/wall/wall-curve.js +13 -0
  825. package/dist/systems/wall/wall-frame.d.ts.map +1 -1
  826. package/dist/systems/wall/wall-frame.js +8 -0
  827. package/dist/systems/wall/wall-room-sides.d.ts +8 -0
  828. package/dist/systems/wall/wall-room-sides.d.ts.map +1 -1
  829. package/dist/systems/wall/wall-room-sides.js +60 -7
  830. package/dist/systems/wall/wall-top.d.ts +7 -4
  831. package/dist/systems/wall/wall-top.d.ts.map +1 -1
  832. package/dist/systems/wall/wall-top.js +14 -6
  833. package/dist/systems/wall/wall-topology.d.ts +4 -0
  834. package/dist/systems/wall/wall-topology.d.ts.map +1 -1
  835. package/dist/systems/wall/wall-topology.js +4 -2
  836. package/dist/systems/wall/wall-trim.d.ts +7 -0
  837. package/dist/systems/wall/wall-trim.d.ts.map +1 -0
  838. package/dist/systems/wall/wall-trim.js +10 -0
  839. package/dist/utils/clone-scene-graph.d.ts.map +1 -1
  840. package/dist/utils/clone-scene-graph.js +8 -0
  841. package/dist/utils/ensure-scene-openings.d.ts +7420 -6562
  842. package/dist/utils/ensure-scene-openings.d.ts.map +1 -1
  843. package/dist/utils/floor-piece-adoption.d.ts +2 -2
  844. package/dist/utils/floor-plate-migration.d.ts +3746 -3317
  845. package/dist/utils/floor-plate-migration.d.ts.map +1 -1
  846. package/dist/utils/floor-plate-migration.js +2 -2
  847. package/dist/utils/heal-scene-graph.d.ts +12 -0
  848. package/dist/utils/heal-scene-graph.d.ts.map +1 -1
  849. package/dist/utils/heal-scene-graph.js +40 -23
  850. package/dist/utils/legacy-wall-datums.d.ts.map +1 -1
  851. package/dist/utils/legacy-wall-datums.js +2 -2
  852. package/dist/utils/owned-floor-opening-migration.d.ts +3642 -3213
  853. package/dist/utils/owned-floor-opening-migration.d.ts.map +1 -1
  854. package/dist/utils/reconcile-structure-on-load.d.ts +3730 -7777
  855. package/dist/utils/reconcile-structure-on-load.d.ts.map +1 -1
  856. package/dist/utils/scene-migrations.d.ts +1 -1
  857. package/dist/utils/scene-migrations.d.ts.map +1 -1
  858. package/dist/utils/scene-migrations.js +1 -1
  859. package/dist/utils/semantic-equal.d.ts +3 -0
  860. package/dist/utils/semantic-equal.d.ts.map +1 -0
  861. package/dist/utils/semantic-equal.js +26 -0
  862. package/dist/utils/structure-id.d.ts.map +1 -1
  863. package/dist/utils/types.d.ts.map +1 -1
  864. package/dist/utils/wall-face-migration.d.ts +1 -1
  865. package/dist/utils/wall-face-migration.d.ts.map +1 -1
  866. package/package.json +36 -10
@@ -0,0 +1,942 @@
1
+ import { migrateSiteMetadata } from '../schema/nodes/site-facts.js';
2
+ import { footprintOutline, levelFootprintLoops, levelFrame, siteFrame, turnPlanPoint, yawOf, } from './building-footprint.js';
3
+ import { area, containsPoint, difference, distanceToBoundary } from './polygon-boolean.js';
4
+ import { polygonInteriorPoint } from './polygon-label.js';
5
+ import { segmentsIntersect } from './polygon-relations.js';
6
+ import { edgeLength, envelopeFrontEdge, outwardNormal, polygonAreaAbs, rayToPolygon, resolveFrontEdge, setbackEnvelope, } from './setback-envelope.js';
7
+ import { heightAt } from './terrain-field.js';
8
+ import { persistedTerrainFieldOf } from './terrain-source-persisted.js';
9
+ const SIDES = { north: [0, -1], east: [1, 0], south: [0, 1], west: [-1, 0] };
10
+ const OPPOSITE = {
11
+ north: 'south',
12
+ south: 'north',
13
+ east: 'west',
14
+ west: 'east',
15
+ };
16
+ /** What a footprint may lose to a ring's edge and still count as inside it: rounding, not a wall. */
17
+ const FIT_AREA_M2 = 0.01;
18
+ const DEFAULT_SQUARE = 15;
19
+ const DEG = 180 / Math.PI;
20
+ const round = (n, step = 100) => Math.round(n * step) / step || 0;
21
+ const roundPt = (p) => [round(p[0]), round(p[1])];
22
+ function boundsOf(points) {
23
+ let minX = Number.POSITIVE_INFINITY;
24
+ let minZ = Number.POSITIVE_INFINITY;
25
+ let maxX = Number.NEGATIVE_INFINITY;
26
+ let maxZ = Number.NEGATIVE_INFINITY;
27
+ for (const [x, z] of points) {
28
+ minX = Math.min(minX, x);
29
+ maxX = Math.max(maxX, x);
30
+ minZ = Math.min(minZ, z);
31
+ maxZ = Math.max(maxZ, z);
32
+ }
33
+ return { minX, minZ, maxX, maxZ };
34
+ }
35
+ const boundsCentre = (b) => [(b.minX + b.maxX) / 2, (b.minZ + b.maxZ) / 2];
36
+ function sideOf(dx, dz) {
37
+ if (Math.abs(dx) > Math.abs(dz))
38
+ return dx > 0 ? 'east' : 'west';
39
+ return dz > 0 ? 'south' : 'north';
40
+ }
41
+ function selfIntersects(ring) {
42
+ const n = ring.length;
43
+ for (let i = 0; i < n; i++) {
44
+ for (let j = i + 2; j < n; j++) {
45
+ if (i === 0 && j === n - 1)
46
+ continue;
47
+ const a = ring[i];
48
+ const b = ring[(i + 1) % n];
49
+ const c = ring[j];
50
+ const d = ring[(j + 1) % n];
51
+ if (segmentsIntersect(a, b, c, d))
52
+ return true;
53
+ }
54
+ }
55
+ return false;
56
+ }
57
+ /** A ring's centroid when it lies inside the ring, else its most interior point. */
58
+ function ringCentre(ring) {
59
+ if (ring.length < 3 || polygonAreaAbs(ring) <= 0)
60
+ return null;
61
+ return polygonInteriorPoint({ polygon: ring.map((p) => [p[0], p[1]]) }, true);
62
+ }
63
+ function isPlaceholderSquare(points) {
64
+ if (points.length !== 4)
65
+ return false;
66
+ const corners = new Set(points.map(([x, z]) => `${Math.sign(x)},${Math.sign(z)}`));
67
+ return (corners.size === 4 &&
68
+ points.every(([x, z]) => Math.abs(Math.abs(x) - DEFAULT_SQUARE) < 1e-6 &&
69
+ Math.abs(Math.abs(z) - DEFAULT_SQUARE) < 1e-6));
70
+ }
71
+ /** The site with its legacy metadata lifted onto the real fields (read-side only). */
72
+ function readSiteNode(node) {
73
+ const patch = migrateSiteMetadata(node);
74
+ return Object.keys(patch).length > 0 ? { ...node, ...patch } : node;
75
+ }
76
+ /** The street edge the site records: its front edge, else its first street edge; never a guess. */
77
+ function recordedStreetEdge(site) {
78
+ const n = site.polygon?.points?.length ?? 0;
79
+ const valid = (i) => Number.isInteger(i) && i >= 0 && i < n;
80
+ return valid(site.frontEdge) ? site.frontEdge : site.streetEdges?.find(valid);
81
+ }
82
+ /**
83
+ * The lot's front edge, which the setbacks, the yards and the street are all measured from: the
84
+ * street edge the site records, else the edge facing most nearly north.
85
+ */
86
+ export function siteFrontEdge(site) {
87
+ return resolveFrontEdge((site.polygon?.points ?? []), recordedStreetEdge(site), site.northRotation ?? 0);
88
+ }
89
+ /**
90
+ * Which way a building's street is, from the house toward it: a unit vector in the site's plan
91
+ * (x east, z south). The street edge its site records (its frontEdge, else its first street edge);
92
+ * with none recorded, the house's own front, its −z turned by its yaw, the way a generated house
93
+ * faces. Every side named as seen from the street reads this one street: a view's street sides,
94
+ * Architect's street order, plan labels and the gables its auto_roof names from the street.
95
+ */
96
+ export function buildingStreet(nodes, buildingId) {
97
+ const node = buildingId ? nodes[buildingId] : undefined;
98
+ const building = node?.type === 'building' ? node : null;
99
+ const stored = siteOfBuilding(nodes, building);
100
+ const site = stored && readSiteNode(stored);
101
+ const lot = (site?.polygon?.points ?? []);
102
+ const edge = site ? recordedStreetEdge(site) : undefined;
103
+ if (edge !== undefined && lot.length >= 3)
104
+ return outwardNormal(lot, edge);
105
+ return turnPlanPoint(0, -1, yawOf(building?.rotation));
106
+ }
107
+ /**
108
+ * The lot's buildable envelope, in site metres, as the site plan and the 3D site draw it: every
109
+ * lot line pushed in by its setback from the front edge's roles, the corner sight triangles kept
110
+ * clear. Empty when the site records no setbacks, when none of them is more than zero, or when
111
+ * they leave nothing.
112
+ */
113
+ export function siteSetbackEnvelope(site) {
114
+ const points = (site.polygon?.points ?? []);
115
+ if (!site.setbacks || points.length < 3)
116
+ return [];
117
+ const sightTriangleM = typeof site.sightTriangleFt === 'number' && site.sightTriangleFt > 0
118
+ ? site.sightTriangleFt * 0.3048
119
+ : 0;
120
+ return setbackEnvelope(points, site.setbacks, siteFrontEdge(site), {
121
+ streetEdges: (site.streetEdges ?? []).filter((i) => Number.isFinite(i)),
122
+ sightTriangleM,
123
+ }).map((p) => [p[0], p[1]]);
124
+ }
125
+ /** The buildable area in SITE metres; `inset` when its ring is the setback envelope, not the lot. */
126
+ function buildableInSite(site) {
127
+ const lot = (site.polygon?.points ?? []);
128
+ if (!site.setbacks)
129
+ return { state: 'lot', ring: lot, inset: false };
130
+ const envelope = siteSetbackEnvelope(site);
131
+ if (envelope.length >= 3)
132
+ return {
133
+ state: selfIntersects(envelope) ? 'advisory' : 'setbacks',
134
+ ring: envelope,
135
+ inset: true,
136
+ };
137
+ // setbacks of zero exclude nothing (the envelope is empty because there is nothing to draw)
138
+ const excludes = Object.values(site.setbacks).some((m) => typeof m === 'number' && m > 0);
139
+ return excludes
140
+ ? { state: 'none', ring: [], inset: false }
141
+ : { state: 'setbacks', ring: lot, inset: false };
142
+ }
143
+ /**
144
+ * Each edge of a ring taken as a front: its length, and how far the ring reaches back from it,
145
+ * square to it (inward by the ring's winding, so an L or a U measures right).
146
+ */
147
+ export function edgeFronts(ring) {
148
+ return ring.map((p, edge) => {
149
+ const frontage = edgeLength(ring, edge);
150
+ if (frontage < 1e-9)
151
+ return { edge, frontage: 0, depth: 0 };
152
+ const [nx, nz] = outwardNormal(ring, edge);
153
+ let depth = 0;
154
+ for (const v of ring)
155
+ depth = Math.max(depth, -((v[0] - p[0]) * nx + (v[1] - p[1]) * nz));
156
+ return { edge, frontage, depth };
157
+ });
158
+ }
159
+ /**
160
+ * The fall of a terrain over a lot: its highest point on the lot less its lowest. The ground is
161
+ * a plane on each of the field's triangles (the cells split by the diagonal `heightAt` uses), so the
162
+ * extremes lie at the field's samples on the lot, at the lot's corners, or where a lot line
163
+ * crosses a triangle's edge: a grid line (u or v whole, in samples) or a diagonal (u + v whole).
164
+ * Past the field `heightAt` holds its edge, so only the lines of the field itself count.
165
+ */
166
+ function terrainFall(field, lot) {
167
+ // a field a single sample wide is its first sample everywhere, as heightAt reads it
168
+ if (field.cols < 2 || field.rows < 2)
169
+ return 0;
170
+ const [ox, oz] = field.origin;
171
+ const s = field.spacing;
172
+ let low = Number.POSITIVE_INFINITY;
173
+ let high = Number.NEGATIVE_INFINITY;
174
+ const take = (height) => {
175
+ low = Math.min(low, height);
176
+ high = Math.max(high, height);
177
+ };
178
+ lot.forEach((a, i) => {
179
+ const b = lot[(i + 1) % lot.length];
180
+ const [ua, va] = [(a[0] - ox) / s, (a[1] - oz) / s];
181
+ const [du, dv] = [(b[0] - a[0]) / s, (b[1] - a[1]) / s];
182
+ take(heightAt(field, a[0], a[1]));
183
+ // where this lot line crosses u = k, v = k and u + v = k, k on the field
184
+ for (const [from, along, lines] of [
185
+ [ua, du, field.cols - 1],
186
+ [va, dv, field.rows - 1],
187
+ [ua + va, du + dv, field.cols + field.rows - 2],
188
+ ]) {
189
+ if (Math.abs(along) < 1e-12)
190
+ continue;
191
+ const to = from + along;
192
+ const first = Math.max(0, Math.ceil(Math.min(from, to)));
193
+ const last = Math.min(lines, Math.floor(Math.max(from, to)));
194
+ for (let k = first; k <= last; k++) {
195
+ const t = (k - from) / along;
196
+ if (t > 0 && t < 1)
197
+ take(heightAt(field, a[0] + (b[0] - a[0]) * t, a[1] + (b[1] - a[1]) * t));
198
+ }
199
+ }
200
+ });
201
+ // the samples inside, row by row between the lot lines' crossings of that row
202
+ for (let row = 0; row < field.rows; row++) {
203
+ const z = oz + row * s;
204
+ const crossings = [];
205
+ lot.forEach((a, i) => {
206
+ const b = lot[(i + 1) % lot.length];
207
+ if (a[1] <= z !== b[1] <= z)
208
+ crossings.push(a[0] + ((z - a[1]) * (b[0] - a[0])) / (b[1] - a[1]));
209
+ });
210
+ crossings.sort((x0, x1) => x0 - x1);
211
+ for (let k = 0; k + 1 < crossings.length; k += 2) {
212
+ const first = Math.max(0, Math.ceil((crossings[k] - ox) / s));
213
+ const last = Math.min(field.cols - 1, Math.floor((crossings[k + 1] - ox) / s));
214
+ // as heightAt shows it at the sample's place: a spacing finer than the coordinates can
215
+ // hold puts some samples where no point of the lot is
216
+ for (let col = first; col <= last; col++)
217
+ take(heightAt(field, ox + col * s, z));
218
+ }
219
+ }
220
+ return high - low;
221
+ }
222
+ const METRES_PER_FOOT = 0.3048;
223
+ /**
224
+ * The ground under the lot: the fall of its terrain across the lot, as the scene holds it (the
225
+ * lot drop-in's read records its own figure over the grid it sampled, which reaches past the
226
+ * lot); with no terrain, what that read found (`metadata.terrainSample`: a lot it found flat
227
+ * gets none), else unread.
228
+ */
229
+ function groundOf(site, lot) {
230
+ const field = persistedTerrainFieldOf(site);
231
+ const sample = site.metadata
232
+ ?.terrainSample;
233
+ if (field)
234
+ return { state: 'sloped', reliefM: terrainFall(field, lot) };
235
+ if (sample?.flat === true)
236
+ return {
237
+ state: 'flat',
238
+ reliefM: typeof sample.reliefFt === 'number' ? sample.reliefFt * METRES_PER_FOOT : 0,
239
+ };
240
+ return { state: 'unread', reliefM: null };
241
+ }
242
+ /* ------------------------------------------------- what stands where */
243
+ function sitesOf(nodes) {
244
+ return Object.values(nodes).filter((node) => node.type === 'site');
245
+ }
246
+ function buildingsOf(nodes) {
247
+ return Object.values(nodes).filter((node) => node.type === 'building');
248
+ }
249
+ function buildingLevels(nodes, building) {
250
+ return (building.children ?? [])
251
+ .map((id) => nodes[id])
252
+ .filter((node) => node?.type === 'level');
253
+ }
254
+ /** The building a level belongs to. */
255
+ function levelBuilding(nodes, levelId) {
256
+ const level = nodes[levelId];
257
+ const parent = level?.parentId ? nodes[level.parentId] : undefined;
258
+ return parent?.type === 'building' ? parent : null;
259
+ }
260
+ function siteOfBuilding(nodes, building) {
261
+ const parent = building?.parentId ? nodes[building.parentId] : undefined;
262
+ if (parent?.type === 'site')
263
+ return parent;
264
+ return sitesOf(nodes)[0] ?? null;
265
+ }
266
+ /**
267
+ * The building a site read or a placement is about: the one named, else the named level's, else
268
+ * the scene's only building. `ambiguous` when there are several and nothing names one.
269
+ */
270
+ export function resolveSiteBuilding(nodes, target = {}) {
271
+ if (target.buildingId) {
272
+ const node = nodes[target.buildingId];
273
+ return { building: node?.type === 'building' ? node : null, ambiguous: false };
274
+ }
275
+ if (target.levelId) {
276
+ const building = levelBuilding(nodes, target.levelId);
277
+ if (building)
278
+ return { building, ambiguous: false };
279
+ }
280
+ const buildings = buildingsOf(nodes);
281
+ return {
282
+ building: buildings.length === 1 ? (buildings[0] ?? null) : null,
283
+ ambiguous: buildings.length > 1,
284
+ };
285
+ }
286
+ /**
287
+ * The building's footprint in its level frame: the union of every storey's wall bands, a
288
+ * storey's rooms where it has no walls.
289
+ */
290
+ export function buildingFootprintRings(nodes, building) {
291
+ const loops = [];
292
+ for (const level of buildingLevels(nodes, building)) {
293
+ const walls = levelFootprintLoops(nodes, level, null);
294
+ if (walls.length > 0) {
295
+ loops.push(...walls);
296
+ continue;
297
+ }
298
+ for (const id of level.children ?? []) {
299
+ const child = nodes[id];
300
+ if (child?.type === 'zone' && child.polygon.length >= 3)
301
+ loops.push(child.polygon);
302
+ }
303
+ }
304
+ if (loops.length === 0)
305
+ return [];
306
+ return footprintOutline(loops).map((ring) => ring.map((p) => [p[0], p[1]]));
307
+ }
308
+ /* ------------------------------------------------------- measuring */
309
+ /** The ring edge nearest `p`, or the two edges of the corner nearest it. */
310
+ function nearestEdges(ring, p) {
311
+ const n = ring.length;
312
+ let best = 0;
313
+ let bestD = Number.POSITIVE_INFINITY;
314
+ let bestT = 0;
315
+ for (let i = 0; i < n; i++) {
316
+ const a = ring[i];
317
+ const b = ring[(i + 1) % n];
318
+ const dx = b[0] - a[0];
319
+ const dz = b[1] - a[1];
320
+ const l2 = dx * dx + dz * dz;
321
+ const t = l2 ? Math.max(0, Math.min(1, ((p[0] - a[0]) * dx + (p[1] - a[1]) * dz) / l2)) : 0;
322
+ const d = Math.hypot(p[0] - a[0] - dx * t, p[1] - a[1] - dz * t);
323
+ if (d < bestD - 1e-9) {
324
+ bestD = d;
325
+ best = i;
326
+ bestT = t;
327
+ }
328
+ }
329
+ if (bestT <= 1e-6)
330
+ return [best, (best - 1 + n) % n];
331
+ if (bestT >= 1 - 1e-6)
332
+ return [best, (best + 1) % n];
333
+ return [best];
334
+ }
335
+ /**
336
+ * What of `rings` lies outside `ring`, by area (an edge across a notch counts, not only its
337
+ * corners), how far it reaches past the ring's edge, and toward which sides.
338
+ */
339
+ function spill(rings, ring) {
340
+ const shapes = rings.map((r) => ({ outer: r.map((p) => [p[0], p[1]]), holes: [] }));
341
+ if (ring.length < 3) {
342
+ const all = area(shapes);
343
+ return { areaM2: all, reachM: Number.POSITIVE_INFINITY, sides: [] };
344
+ }
345
+ const outside = difference(shapes, ring.map((p) => [p[0], p[1]]));
346
+ const areaM2 = area(outside);
347
+ if (areaM2 <= FIT_AREA_M2)
348
+ return { areaM2: 0, reachM: 0, sides: [] };
349
+ const boundary = [{ outer: ring.map((p) => [p[0], p[1]]), holes: [] }];
350
+ let reachM = 0;
351
+ const sides = new Set();
352
+ for (const piece of outside) {
353
+ // a piece's corners can all lie on the line it crosses (a house bridging a notch); its most
354
+ // interior point is at least as far past the line as it is from the piece's own edges
355
+ const pole = polygonInteriorPoint({ polygon: piece.outer, holes: piece.holes });
356
+ for (const p of [...[piece.outer, ...piece.holes].flat(), pole]) {
357
+ const d = distanceToBoundary(boundary, p);
358
+ if (d <= 0.005)
359
+ continue;
360
+ reachM = Math.max(reachM, d);
361
+ // past the edge nearest it, or past both edges of the corner nearest it
362
+ for (const edge of nearestEdges(ring, p)) {
363
+ const [nx, nz] = outwardNormal(ring, edge);
364
+ const a = ring[edge];
365
+ if ((p[0] - a[0]) * nx + (p[1] - a[1]) * nz > 0.005)
366
+ sides.add(sideOf(nx, nz));
367
+ }
368
+ }
369
+ }
370
+ return { areaM2, reachM, sides: [...sides] };
371
+ }
372
+ /** Signed metres from each face's midpoint, square to the house, to the lot line. */
373
+ function planYards(rings, lot) {
374
+ const b = boundsOf(rings.flat());
375
+ const [mx, mz] = boundsCentre(b);
376
+ const lotShape = [{ outer: lot.map((p) => [p[0], p[1]]), holes: [] }];
377
+ const from = {
378
+ north: [mx, b.minZ],
379
+ south: [mx, b.maxZ],
380
+ west: [b.minX, mz],
381
+ east: [b.maxX, mz],
382
+ };
383
+ const yards = {};
384
+ for (const side of Object.keys(SIDES)) {
385
+ const [dx, dz] = SIDES[side];
386
+ const origin = from[side];
387
+ if (distanceToBoundary(lotShape, origin) < 1e-6)
388
+ yards[side] = 0;
389
+ else if (containsPoint(lotShape, origin)) {
390
+ yards[side] = rayToPolygon(lot, origin, dx, dz)?.distance ?? null;
391
+ }
392
+ else {
393
+ const back = rayToPolygon(lot, origin, -dx, -dz);
394
+ yards[side] = back ? -back.distance : null;
395
+ }
396
+ }
397
+ return yards;
398
+ }
399
+ /** The plan side of each yard, seen from the street: standing in it, facing the house. */
400
+ function streetFaces(front) {
401
+ const [fx, fz] = SIDES[front];
402
+ // facing the house is −front; its right hand, with z pointing south, is (−dz, dx)
403
+ const right = sideOf(fz, -fx);
404
+ return { front, rear: OPPOSITE[front], left: OPPOSITE[right], right };
405
+ }
406
+ /**
407
+ * The recorded street edge seen from a building turned `yaw`: the plan side it lies on, and the
408
+ * yaw nearest `yaw` that squares the house to it, in radians.
409
+ */
410
+ function streetAt(site, yaw) {
411
+ const lot = (site.polygon?.points ?? []);
412
+ const n = lot.length;
413
+ const named = recordedStreetEdge(site);
414
+ if (named === undefined || n < 3)
415
+ return null;
416
+ const [nx, nz] = outwardNormal(lot, named);
417
+ const [lx, lz] = turnPlanPoint(nx, nz, -yaw);
418
+ const p = lot[named];
419
+ const q = lot[(named + 1) % n];
420
+ // the house's local x runs along site angle −yaw; square to the edge when −yaw ≡ α (mod 90°)
421
+ const alpha = Math.atan2(q[1] - p[1], q[0] - p[0]);
422
+ const quarter = Math.PI / 2;
423
+ return {
424
+ side: sideOf(lx, lz),
425
+ edge: named,
426
+ squareYaw: -alpha + Math.round((yaw + alpha) / quarter) * quarter,
427
+ };
428
+ }
429
+ function formatAddress(site) {
430
+ const a = site.address;
431
+ if (!a)
432
+ return null;
433
+ const tail = [a.city, [a.state, a.zip].filter(Boolean).join(' ')].filter(Boolean).join(', ');
434
+ const text = [a.street, tail].filter(Boolean).join(', ');
435
+ return text || null;
436
+ }
437
+ /**
438
+ * How a footprint (rings in the building's level frame) sits on the site the brief reads: its
439
+ * bounds and centre, how far it is off the buildable centre, its yards, and whether it stays in
440
+ * the buildable area, on the lot, or past the lot line.
441
+ */
442
+ export function measureFootprint(rings, site) {
443
+ const { lot, buildable, street } = site;
444
+ const bounds = boundsOf(rings.flat());
445
+ const centre = boundsCentre(bounds);
446
+ const aim = buildable.centre ?? ringCentre(lot.ring) ?? centre;
447
+ const past = spill(rings, lot.ring);
448
+ const inYards = buildable.state === 'lot' ? past : spill(rings, buildable.ring);
449
+ const plan = planYards(rings, lot.ring);
450
+ const faces = street ? streetFaces(street.side) : null;
451
+ const yards = faces
452
+ ? Object.fromEntries(Object.keys(faces).map((key) => [key, plan[faces[key]]]))
453
+ : plan;
454
+ return {
455
+ rings: rings.map((ring) => ring.map((p) => [p[0], p[1]])),
456
+ bounds,
457
+ centre,
458
+ offCentreM: Math.hypot(centre[0] - aim[0], centre[1] - aim[1]),
459
+ yards,
460
+ fit: past.areaM2 > 0 ? 'outside' : inYards.areaM2 > 0 ? 'lot' : 'buildable',
461
+ overhang: {
462
+ lotM: past.reachM,
463
+ setbacksM: Number.isFinite(inYards.reachM) ? inYards.reachM : 0,
464
+ sides: past.areaM2 > 0 ? past.sides : inYards.sides,
465
+ },
466
+ };
467
+ }
468
+ /**
469
+ * Where new geometry on a level (rings in its level coordinates) crosses its lot line: null
470
+ * while it stays on the lot, or when the level's building has no site. Only the lot is read, so
471
+ * a program drawing room by room pays for no footprint.
472
+ */
473
+ export function lotOverhang(nodes, levelId, rings) {
474
+ const building = resolveSiteBuilding(nodes, { levelId }).building;
475
+ const lot = (siteOfBuilding(nodes, building)?.polygon?.points ?? []);
476
+ if (lot.length < 3)
477
+ return null;
478
+ const toLevel = levelFrame(building);
479
+ const past = spill(rings, lot.map((p) => toLevel(p[0], p[1])));
480
+ if (past.areaM2 === 0)
481
+ return null;
482
+ return { fit: 'outside', overhangM: round(past.reachM), sides: past.sides };
483
+ }
484
+ /** The building a brief is read for, and the site it stands on (the scene's first site for none). */
485
+ function forBuilding(nodes, target) {
486
+ const resolved = resolveSiteBuilding(nodes, target);
487
+ let building = resolved.building;
488
+ if (!building && resolved.ambiguous) {
489
+ const site = sitesOf(nodes)[0];
490
+ const first = site?.children?.map((id) => nodes[id]).find((node) => node?.type === 'building');
491
+ building = first ?? buildingsOf(nodes)[0] ?? null;
492
+ }
493
+ return { building, stored: siteOfBuilding(nodes, building) };
494
+ }
495
+ /**
496
+ * A site named by its id, and the building read on it: the viewed level's when it stands there,
497
+ * else the first standing on it (none on a vacant lot).
498
+ */
499
+ function onSite(nodes, siteId, levelId) {
500
+ const site = nodes[siteId];
501
+ if (site?.type !== 'site')
502
+ return { building: null, stored: null };
503
+ const viewed = levelId ? levelBuilding(nodes, levelId) : null;
504
+ return {
505
+ building: viewed?.parentId === site.id
506
+ ? viewed
507
+ : (buildingsOf(nodes).find((building) => building.parentId === site.id) ?? null),
508
+ stored: site,
509
+ };
510
+ }
511
+ /**
512
+ * The site a building stands on, in that building's level coordinates. The building is the one
513
+ * named, else the named level's, else the scene's only one, else the site's first; or the site
514
+ * is named, and the building is the named level's when it stands there, else the first standing
515
+ * on it. In site coordinates when no building stands on it; null when the scene has no site with
516
+ * a lot.
517
+ */
518
+ export function siteBrief(nodes, target = {}) {
519
+ const { building, stored } = target.siteId
520
+ ? onSite(nodes, target.siteId, target.levelId)
521
+ : forBuilding(nodes, target);
522
+ if (!stored)
523
+ return null;
524
+ const site = readSiteNode(stored);
525
+ const siteRing = (site.polygon?.points ?? []).map((p) => [p[0], p[1]]);
526
+ if (siteRing.length < 3)
527
+ return null;
528
+ const yaw = building?.rotation?.[1] ?? 0;
529
+ const toLevel = levelFrame(building);
530
+ const inLevel = (ring) => ring.map((p) => toLevel(p[0], p[1]));
531
+ const ring = inLevel(siteRing);
532
+ const inSite = buildableInSite(site);
533
+ const buildableRing = inLevel(inSite.ring);
534
+ const facing = streetAt(site, yaw);
535
+ const lotFront = facing ? edgeFronts(siteRing)[facing.edge] : undefined;
536
+ const street = facing && lotFront
537
+ ? {
538
+ side: facing.side,
539
+ edge: facing.edge,
540
+ squareRotationDeg: round(facing.squareYaw * DEG, 10),
541
+ frontage: lotFront.frontage,
542
+ depth: lotFront.depth,
543
+ }
544
+ : null;
545
+ const buildable = {
546
+ state: inSite.state,
547
+ ring: buildableRing,
548
+ centre: inSite.state === 'none' ? null : ringCentre(buildableRing),
549
+ areaM2: polygonAreaAbs(inSite.ring),
550
+ edges: edgeFronts(inSite.ring),
551
+ frontEdge: inSite.state === 'none'
552
+ ? null
553
+ : inSite.inset
554
+ ? envelopeFrontEdge(siteRing, siteFrontEdge(site), inSite.ring)
555
+ : siteFrontEdge(site),
556
+ ...(site.setbacks ? { setbacks: site.setbacks } : {}),
557
+ ...(site.setbacksSource ? { source: site.setbacksSource } : {}),
558
+ };
559
+ const parcel = site.parcel;
560
+ const lotArea = polygonAreaAbs(siteRing);
561
+ const lot = {
562
+ ring,
563
+ siteRing,
564
+ bounds: boundsOf(ring),
565
+ areaM2: lotArea,
566
+ approximate: Boolean(parcel && ((parcel.notes ?? []).some((note) => /approximate/i.test(note)) || !parcel.apn)),
567
+ footprintRangeM2: [lotArea * 0.3, lotArea * 0.45],
568
+ };
569
+ const rings = building ? buildingFootprintRings(nodes, building) : [];
570
+ const footprint = rings.length > 0 ? measureFootprint(rings, { lot, buildable, street }) : null;
571
+ const others = [];
572
+ for (const other of buildingsOf(nodes)) {
573
+ if (other.id === building?.id || siteOfBuilding(nodes, other)?.id !== stored.id)
574
+ continue;
575
+ const toSite = siteFrame(other);
576
+ const ringsOther = buildingFootprintRings(nodes, other);
577
+ if (ringsOther.length === 0)
578
+ continue;
579
+ const points = ringsOther.flat().map((p) => {
580
+ const s = toSite(p[0], p[1]);
581
+ return toLevel(s[0], s[1]);
582
+ });
583
+ others.push({ buildingId: other.id, bounds: boundsOf(points) });
584
+ }
585
+ return {
586
+ siteId: stored.id,
587
+ buildingId: building?.id ?? null,
588
+ pose: {
589
+ position: [...(building?.position ?? [0, 0, 0])],
590
+ rotationDeg: yaw * DEG,
591
+ },
592
+ lot,
593
+ placeholder: !formatAddress(site) && !parcel && !site.setbacks && isPlaceholderSquare(siteRing),
594
+ buildable,
595
+ street,
596
+ ground: groundOf(stored, siteRing),
597
+ northDeg: (((((site.northRotation ?? 0) + yaw) * DEG) % 360) + 360) % 360,
598
+ address: formatAddress(site),
599
+ parcel: parcel
600
+ ? {
601
+ ...(parcel.apn ? { apn: parcel.apn } : {}),
602
+ ...(parcel.lotAreaSqFt ? { lotAreaSqFt: parcel.lotAreaSqFt } : {}),
603
+ ...(parcel.source ? { source: parcel.source } : {}),
604
+ ...(parcel.notes?.length ? { notes: parcel.notes } : {}),
605
+ }
606
+ : null,
607
+ zone: site.zone ?? null,
608
+ footprint,
609
+ others,
610
+ };
611
+ }
612
+ const refusal = (code, message) => ({
613
+ ok: false,
614
+ code,
615
+ message,
616
+ });
617
+ /**
618
+ * Where a building goes on its site: the building's position (and, when asked, its rotation)
619
+ * that puts its footprint's centre on the buildable centre, or at the yards a site plan or the
620
+ * person gives. The inputs are pose-independent (an outline in the drawing's own coordinates,
621
+ * yards from the lot lines), so a repeated call gives the same pose. The lot is never resized: a
622
+ * footprint too big for it is still centred, and the brief reports it outside.
623
+ */
624
+ export function placeBuildingPose(nodes, input) {
625
+ if (!sitesOf(nodes).some((site) => (site.polygon?.points?.length ?? 0) >= 3))
626
+ return refusal('no_site', 'The scene has no site with a lot to stand a building on.');
627
+ const resolved = resolveSiteBuilding(nodes, input);
628
+ if (input.buildingId && !resolved.building)
629
+ return refusal('not_a_building', `${input.buildingId} is not a building.`);
630
+ if (resolved.ambiguous)
631
+ return refusal('which_building', 'The site has several buildings: name the one to place (its id from list_levels, parentId).');
632
+ const building = resolved.building;
633
+ if (!building)
634
+ return refusal('no_building', 'The scene has no building to place.');
635
+ const site = readSiteNode(siteOfBuilding(nodes, building));
636
+ const standing = buildingFootprintRings(nodes, building);
637
+ const current = building.rotation?.[1] ?? 0;
638
+ // a standing house keeps its facing; one about to rise faces the street square
639
+ const yaw = input.rotationDeg !== undefined
640
+ ? input.rotationDeg / DEG
641
+ : standing.length === 0
642
+ ? (streetAt(site, current)?.squareYaw ?? current)
643
+ : current;
644
+ const rings = input.outline && input.outline.length >= 3
645
+ ? [input.outline.map((p) => [p[0], p[1]])]
646
+ : standing;
647
+ if (rings.length === 0)
648
+ return refusal('needs_footprint', 'The building has no walls or rooms yet: pass the outline of the plan you are about to draw, in the coordinates you will draw it.');
649
+ const yards = input.yards ?? {};
650
+ const given = Object.keys(yards).filter((key) => Number.isFinite(yards[key]));
651
+ if (given.includes('front') && given.includes('rear'))
652
+ return refusal('yards_conflict', 'Give the front yard or the rear one, not both: the house fills the rest.');
653
+ if (given.includes('left') && given.includes('right'))
654
+ return refusal('yards_conflict', 'Give the left yard or the right one, not both: the house fills the rest.');
655
+ const before = siteBrief(nodes, { buildingId: building.id });
656
+ if (given.length > 0 && !before.street)
657
+ return refusal('no_street', 'The site has no street edge, so front, rear, left and right mean nothing yet: set the site frontEdge first.');
658
+ if (given.length === 0 && before.others.length > 0)
659
+ return refusal('other_building_on_site', `Another building stands on this site (${before.others.map((o) => o.buildingId).join(', ')}): centring could put one on the other, so give yards.`);
660
+ const lotSite = before.lot.siteRing;
661
+ const inSite = buildableInSite(site);
662
+ const aimRing = inSite.state === 'none' ? lotSite : inSite.ring;
663
+ const [cx, cz] = boundsCentre(boundsOf(rings.flat()));
664
+ const poseAt = (target) => {
665
+ const [tx, tz] = turnPlanPoint(cx, cz, yaw);
666
+ return [target[0] - tx, target[1] - tz];
667
+ };
668
+ const siteRings = (at) => {
669
+ const toSite = siteFrame({ position: [at[0], 0, at[1]], rotation: [0, yaw, 0] });
670
+ return rings.map((ring) => ring.map((p) => toSite(p[0], p[1])));
671
+ };
672
+ const fits = (at) => spill(siteRings(at), aimRing).areaM2 === 0;
673
+ const centre = ringCentre(aimRing) ?? boundsCentre(boundsOf(lotSite));
674
+ let at = poseAt(centre);
675
+ if (!fits(at)) {
676
+ const pole = polygonInteriorPoint({ polygon: aimRing.map((p) => [p[0], p[1]]) });
677
+ const atPole = poseAt(pole);
678
+ if (fits(atPole))
679
+ at = atPole;
680
+ }
681
+ if (given.length > 0) {
682
+ // the street's side as the house will face it, not as it faces now
683
+ const faces = streetFaces(streetAt(site, yaw).side);
684
+ const yardsAt = (p) => {
685
+ const toLevel = levelFrame({ position: [p[0], 0, p[1]], rotation: [0, yaw, 0] });
686
+ return planYards(rings, lotSite.map((q) => toLevel(q[0], q[1])));
687
+ };
688
+ const misses = (p) => {
689
+ const now = yardsAt(p);
690
+ return given.map((key) => {
691
+ const yard = now[faces[key]];
692
+ return yard === null ? null : yard - yards[key];
693
+ });
694
+ };
695
+ // Each yard is moved along its own face's normal; on a turned lot moving one moves the other,
696
+ // so both are solved together. Straight lot lines make it exact in one step.
697
+ const along = given.map((key) => turnPlanPoint(...SIDES[faces[key]], yaw));
698
+ const step = 0.5;
699
+ for (let pass = 0; pass < 6; pass++) {
700
+ const miss = misses(at);
701
+ const blind = given.find((_, i) => miss[i] === null);
702
+ if (blind)
703
+ return refusal('yards_infeasible', `The ${blind} face does not look onto a lot line.`);
704
+ const [r0 = 0, r1 = 0] = miss;
705
+ if (Math.abs(r0) < 1e-3 && Math.abs(r1) < 1e-3)
706
+ break;
707
+ // how each miss changes per metre moved along each face's normal (one yard: a 1×1 system)
708
+ const slope = along.map(([dx, dz]) => misses([at[0] + dx * step, at[1] + dz * step]).map((m, i) => (m - miss[i]) / step));
709
+ const [[a = 0, c = 0] = [], [b = 0, d = 1] = []] = slope;
710
+ const det = a * d - b * c;
711
+ if (Math.abs(det) < 1e-6)
712
+ break;
713
+ const moves = [(r1 * b - r0 * d) / det, (r0 * c - r1 * a) / det];
714
+ at = along.reduce((p, [dx, dz], i) => [p[0] + dx * (moves[i] ?? 0), p[1] + dz * (moves[i] ?? 0)], [at[0], at[1]]);
715
+ }
716
+ const placed = yardsAt(at);
717
+ for (const key of given) {
718
+ const yard = placed[faces[key]];
719
+ if (yard === null || Math.abs(yard - yards[key]) > 0.01)
720
+ return refusal('yards_infeasible', `No place on this lot gives a ${yards[key]} m ${key} yard with the other yards asked: give one of them, or turn the house square to the street (rotationDeg).`);
721
+ }
722
+ for (const key of given) {
723
+ const across = placed[OPPOSITE[faces[key]]];
724
+ if (across === null || across < 0)
725
+ return refusal('yards_infeasible', `A ${yards[key]} m ${key} yard pushes the house ${across === null ? 'off' : `${round(-across)} m past`} the lot line opposite: the lot is too shallow for it on that side.`);
726
+ }
727
+ }
728
+ const position = [
729
+ round(at[0], 1e4),
730
+ building.position?.[1] ?? 0,
731
+ round(at[1], 1e4),
732
+ ];
733
+ const rotation = [
734
+ building.rotation?.[0] ?? 0,
735
+ round(yaw, 1e6),
736
+ building.rotation?.[2] ?? 0,
737
+ ];
738
+ const moved = Math.hypot(position[0] - (building.position?.[0] ?? 0), position[2] - (building.position?.[2] ?? 0)) > 1e-3 || Math.abs(rotation[1] - (building.rotation?.[1] ?? 0)) > 1e-5;
739
+ const placedNodes = { ...nodes, [building.id]: { ...building, position, rotation } };
740
+ const brief = siteBrief(placedNodes, { buildingId: building.id });
741
+ return {
742
+ ok: true,
743
+ buildingId: building.id,
744
+ position,
745
+ rotation,
746
+ moved,
747
+ brief,
748
+ footprint: measureFootprint(rings, brief),
749
+ };
750
+ }
751
+ /** A site brief's numbers rounded to the centimetre (angles to a tenth of a degree), as agents read them. */
752
+ export function roundedSiteBrief(brief) {
753
+ const bounds = (b) => ({
754
+ minX: round(b.minX),
755
+ minZ: round(b.minZ),
756
+ maxX: round(b.maxX),
757
+ maxZ: round(b.maxZ),
758
+ });
759
+ const front = (edge) => ({
760
+ ...edge,
761
+ frontage: round(edge.frontage),
762
+ depth: round(edge.depth),
763
+ });
764
+ const { footprint, street, ground } = brief;
765
+ const [fewest, most] = brief.lot.footprintRangeM2;
766
+ return {
767
+ ...brief,
768
+ pose: {
769
+ position: brief.pose.position.map((n) => round(n)),
770
+ rotationDeg: round(brief.pose.rotationDeg, 10),
771
+ },
772
+ lot: {
773
+ ...brief.lot,
774
+ ring: brief.lot.ring.map(roundPt),
775
+ siteRing: brief.lot.siteRing.map(roundPt),
776
+ bounds: bounds(brief.lot.bounds),
777
+ areaM2: round(brief.lot.areaM2, 10),
778
+ footprintRangeM2: [Math.round(fewest), Math.round(most)],
779
+ },
780
+ buildable: {
781
+ ...brief.buildable,
782
+ ring: brief.buildable.ring.map(roundPt),
783
+ centre: brief.buildable.centre ? roundPt(brief.buildable.centre) : null,
784
+ areaM2: round(brief.buildable.areaM2, 10),
785
+ edges: brief.buildable.edges.map(front),
786
+ },
787
+ street: street ? front(street) : null,
788
+ ground: { ...ground, reliefM: ground.reliefM === null ? null : round(ground.reliefM) },
789
+ northDeg: round(brief.northDeg, 10),
790
+ footprint: footprint
791
+ ? {
792
+ bounds: bounds(footprint.bounds),
793
+ centre: roundPt(footprint.centre),
794
+ offCentreM: round(footprint.offCentreM),
795
+ yards: Object.fromEntries(Object.entries(footprint.yards).map(([key, m]) => [
796
+ key,
797
+ m === null ? null : round(m ?? 0),
798
+ ])),
799
+ fit: footprint.fit,
800
+ overhang: {
801
+ lotM: round(footprint.overhang.lotM),
802
+ setbacksM: round(footprint.overhang.setbacksM),
803
+ sides: footprint.overhang.sides,
804
+ },
805
+ }
806
+ : null,
807
+ others: brief.others.map((other) => ({ ...other, bounds: bounds(other.bounds) })),
808
+ };
809
+ }
810
+ const num = (n) => {
811
+ const r = Math.round(n * 10) / 10 || 0;
812
+ return Number.isInteger(r) ? String(r) : r.toFixed(1);
813
+ };
814
+ const fmtPt = (p) => `[${num(p[0])}, ${num(p[1])}]`;
815
+ const span = (b) => `x ${num(b.minX)}..${num(b.maxX)}, z ${num(b.minZ)}..${num(b.maxZ)}`;
816
+ const size = (b) => `${num(b.maxX - b.minX)}×${num(b.maxZ - b.minZ)} m`;
817
+ /** `18×32 m` for a rectangular lot, whatever its turn; null for any other shape. */
818
+ function rectangleSize(ring) {
819
+ if (ring.length !== 4)
820
+ return null;
821
+ const side = (i) => {
822
+ const a = ring[i];
823
+ const b = ring[(i + 1) % 4];
824
+ return [b[0] - a[0], b[1] - a[1]];
825
+ };
826
+ for (let i = 0; i < 4; i++) {
827
+ const [ax, az] = side(i);
828
+ const [bx, bz] = side((i + 1) % 4);
829
+ if (Math.abs(ax * bx + az * bz) > 1e-3 * Math.hypot(ax, az) * Math.hypot(bx, bz))
830
+ return null;
831
+ }
832
+ return `${num(Math.hypot(...side(0)))}×${num(Math.hypot(...side(1)))} m`;
833
+ }
834
+ function describeSetbacks(setbacks) {
835
+ const parts = [`front ${num(setbacks.front)}`];
836
+ if (setbacks.left !== undefined || setbacks.right !== undefined)
837
+ parts.push(`left ${num(setbacks.left ?? setbacks.side)}`, `right ${num(setbacks.right ?? setbacks.side)}`);
838
+ else
839
+ parts.push(`sides ${num(setbacks.side)}`);
840
+ parts.push(`rear ${num(setbacks.rear)}`);
841
+ if (setbacks.streetSide !== undefined)
842
+ parts.push(`street side ${num(setbacks.streetSide)}`);
843
+ return `${parts.join(', ')} m`;
844
+ }
845
+ /**
846
+ * The site in a few lines, as the agent reads it before drawing: the lot (in the building's level
847
+ * coordinates), its facts, the buildable area and its centre, the street and north, and where the
848
+ * footprint stands, or where a new one goes.
849
+ */
850
+ export function describeSiteBrief(brief) {
851
+ const { lot, buildable, street, footprint } = brief;
852
+ const [px, py, pz] = brief.pose.position;
853
+ const posed = Math.hypot(px, pz) > 1e-3 || Math.abs(brief.pose.rotationDeg) > 0.05;
854
+ const lines = [
855
+ `lot, in ${brief.buildingId ? "this building's level" : 'site (no building stands on it yet)'} coordinates: [${lot.ring.map(fmtPt).join(', ')}]${posed
856
+ ? ` (stored in site coordinates; building at [${num(px)}, ${num(py)}, ${num(pz)}], ${num(brief.pose.rotationDeg)}°)`
857
+ : ''}`,
858
+ ];
859
+ const dims = rectangleSize(lot.ring);
860
+ const [fewest, most] = lot.footprintRangeM2;
861
+ // the placeholder is no real lot: a share of it says nothing of the house
862
+ const facts = [
863
+ `lot ${dims ? `${dims}, ` : ''}${Math.round(lot.areaM2)} m²${brief.placeholder ? '' : ` (a house usually covers 30–45%: ${Math.round(fewest)}–${Math.round(most)} m²)`}`,
864
+ ];
865
+ if (brief.placeholder)
866
+ facts.push('the new-project placeholder: no address or parcel, real property lines unknown');
867
+ if (brief.address)
868
+ facts.push(brief.address);
869
+ if (brief.parcel?.apn)
870
+ facts.push(`APN ${brief.parcel.apn}`);
871
+ if (brief.zone)
872
+ facts.push(`zone ${brief.zone}`);
873
+ if (lot.approximate)
874
+ facts.push('approximate rectangle: real property lines not found');
875
+ lines.push(facts.join(' · '));
876
+ const centre = buildable.centre;
877
+ if (buildable.state === 'none')
878
+ lines.push(`buildable: none — the setbacks (${describeSetbacks(buildable.setbacks)}) leave nothing on this lot`);
879
+ else if (buildable.state === 'lot')
880
+ lines.push(`buildable: the whole lot (no setbacks recorded) · centre ${centre ? fmtPt(centre) : 'none'}`);
881
+ else {
882
+ const front = buildable.edges.find((edge) => edge.edge === buildable.frontEdge);
883
+ const along = street
884
+ ? 'along the street'
885
+ : 'along its edge facing north (the setbacks take it as the front until the street is set)';
886
+ lines.push(`buildable${buildable.state === 'advisory' ? ' (advisory: the inset of this concave lot crosses itself)' : ''}: setbacks ${describeSetbacks(buildable.setbacks)}${buildable.source ? ` (${buildable.source})` : ''} · ${span(boundsOf(buildable.ring))} · centre ${centre ? fmtPt(centre) : 'none'} · ${Math.round(buildable.areaM2)} m² · ${front
887
+ ? `${num(front.frontage)} m ${along}, ${num(front.depth)} m deep (its edge ${front.edge})`
888
+ : `no edge of it faces ${street ? 'the street' : 'north'}, so no frontage to build along`}`);
889
+ }
890
+ const north = Math.abs(((brief.northDeg + 180) % 360) - 180) < 0.5
891
+ ? 'plan up'
892
+ : `${num(brief.northDeg)}° clockwise of plan up`;
893
+ const squared = !street || Math.abs(street.squareRotationDeg - brief.pose.rotationDeg) < 0.06;
894
+ const squaring = street ? `place_building rotationDeg ${num(street.squareRotationDeg)}` : '';
895
+ // a house yet to rise is squared by place_building itself: naming a rotation for it reads as
896
+ // one to draw the plan at
897
+ const facing = !footprint
898
+ ? 'a new house is stood square to it'
899
+ : squared
900
+ ? 'the house square to it'
901
+ : `${squaring} squares the house to it`;
902
+ lines.push(`${street ? `street: ${street.side} (lot edge ${street.edge}, ${num(street.frontage)} m of frontage, ${num(street.depth)} m deep; ${facing})` : 'street: not set'} · north: ${north}`);
903
+ const { ground } = brief;
904
+ lines.push(ground.state === 'sloped'
905
+ ? `ground: sloped, ${num(ground.reliefM ?? 0)} m of fall across the lot`
906
+ : ground.state === 'flat'
907
+ ? `ground: read flat (${num(ground.reliefM ?? 0)} m of fall over the grid read round the lot)`
908
+ : 'ground: not read, flat until it is');
909
+ if (!footprint) {
910
+ const aim = centre ?? boundsCentre(lot.bounds);
911
+ lines.push(`footprint: none yet — centre it on ${fmtPt(aim)} (a 12×10 m footprint spans ${span({ minX: aim[0] - 6, maxX: aim[0] + 6, minZ: aim[1] - 5, maxZ: aim[1] + 5 })})${squared
912
+ ? ''
913
+ : '; place_building with its outline first stands it there square to the street'}`);
914
+ return lines;
915
+ }
916
+ const measured = Object.entries(footprint.yards).filter((entry) => typeof entry[1] === 'number');
917
+ const yards = measured.length
918
+ ? ` · yards ${measured.map(([key, m]) => `${key} ${num(m)}`).join(', ')} m`
919
+ : '';
920
+ const room = buildable.ring.length >= 3 ? boundsOf(buildable.ring) : lot.bounds;
921
+ const tooBig = footprint.bounds.maxX - footprint.bounds.minX > room.maxX - room.minX ||
922
+ footprint.bounds.maxZ - footprint.bounds.minZ > room.maxZ - room.minZ;
923
+ const centred = footprint.offCentreM < 0.25;
924
+ const fix = centred
925
+ ? tooBig
926
+ ? `: it is bigger than the buildable area (${size(room)}) even centred, so say so`
927
+ : squared
928
+ ? ': even centred, the shape of the lot leaves it out: give yards or reshape the plan'
929
+ : `: even centred, it stands askew to the lot: ${squaring} squares it to the street`
930
+ : `: place_building centres it${tooBig ? `, but it is bigger than the buildable area (${size(room)}): say so` : ''}`;
931
+ const where = footprint.fit === 'outside'
932
+ ? `${num(footprint.overhang.lotM)} m past the lot line (${footprint.overhang.sides.join(', ')})${fix}`
933
+ : footprint.fit === 'lot'
934
+ ? buildable.state === 'none'
935
+ ? 'on the lot, with nothing buildable inside the setbacks'
936
+ : `on the lot but ${num(footprint.overhang.setbacksM)} m into the required yards (${footprint.overhang.sides.join(', ')})${fix}`
937
+ : centred
938
+ ? 'inside the buildable area, on its centre'
939
+ : `inside the buildable area, ${num(footprint.offCentreM)} m off its centre`;
940
+ lines.push(`footprint: ${size(footprint.bounds)} centred ${fmtPt(footprint.centre)}${yards} · ${where}`);
941
+ return lines;
942
+ }