@pascal-app/core 0.8.0 → 0.9.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (471) hide show
  1. package/dist/events/bus.d.ts +67 -13
  2. package/dist/events/bus.d.ts.map +1 -1
  3. package/dist/hooks/scene-registry/item-clip-registry.d.ts +18 -0
  4. package/dist/hooks/scene-registry/item-clip-registry.d.ts.map +1 -0
  5. package/dist/hooks/scene-registry/item-clip-registry.js +10 -0
  6. package/dist/hooks/scene-registry/scene-registry.d.ts +14 -23
  7. package/dist/hooks/scene-registry/scene-registry.d.ts.map +1 -1
  8. package/dist/hooks/scene-registry/scene-registry.js +59 -26
  9. package/dist/hooks/scene-registry/scene-registry.test.d.ts +2 -0
  10. package/dist/hooks/scene-registry/scene-registry.test.d.ts.map +1 -0
  11. package/dist/hooks/scene-registry/scene-registry.test.js +26 -0
  12. package/dist/hooks/spatial-grid/floor-placed-elevation.d.ts +14 -0
  13. package/dist/hooks/spatial-grid/floor-placed-elevation.d.ts.map +1 -0
  14. package/dist/hooks/spatial-grid/floor-placed-elevation.js +51 -0
  15. package/dist/hooks/spatial-grid/floor-placed-elevation.test.d.ts +2 -0
  16. package/dist/hooks/spatial-grid/floor-placed-elevation.test.d.ts.map +1 -0
  17. package/dist/hooks/spatial-grid/floor-placed-elevation.test.js +366 -0
  18. package/dist/hooks/spatial-grid/spatial-grid-manager.d.ts +79 -11
  19. package/dist/hooks/spatial-grid/spatial-grid-manager.d.ts.map +1 -1
  20. package/dist/hooks/spatial-grid/spatial-grid-manager.js +508 -141
  21. package/dist/hooks/spatial-grid/spatial-grid-sync.d.ts +28 -1
  22. package/dist/hooks/spatial-grid/spatial-grid-sync.d.ts.map +1 -1
  23. package/dist/hooks/spatial-grid/spatial-grid-sync.js +109 -18
  24. package/dist/hooks/spatial-grid/wall-slab-overlap.test.d.ts +2 -0
  25. package/dist/hooks/spatial-grid/wall-slab-overlap.test.d.ts.map +1 -0
  26. package/dist/hooks/spatial-grid/wall-slab-overlap.test.js +363 -0
  27. package/dist/index.d.ts +36 -8
  28. package/dist/index.d.ts.map +1 -1
  29. package/dist/index.js +33 -6
  30. package/dist/lib/level-name.d.ts +4 -0
  31. package/dist/lib/level-name.d.ts.map +1 -0
  32. package/dist/lib/level-name.js +10 -0
  33. package/dist/lib/measurement-geometry.d.ts +19 -0
  34. package/dist/lib/measurement-geometry.d.ts.map +1 -0
  35. package/dist/lib/measurement-geometry.js +232 -0
  36. package/dist/lib/measurement-geometry.test.d.ts +2 -0
  37. package/dist/lib/measurement-geometry.test.d.ts.map +1 -0
  38. package/dist/lib/measurement-geometry.test.js +102 -0
  39. package/dist/lib/polygon-geometry.d.ts +0 -1
  40. package/dist/lib/polygon-geometry.d.ts.map +1 -1
  41. package/dist/lib/polygon-geometry.js +0 -18
  42. package/dist/lib/polygon-relations.d.ts +10 -0
  43. package/dist/lib/polygon-relations.d.ts.map +1 -0
  44. package/dist/lib/polygon-relations.js +73 -0
  45. package/dist/lib/selection-proxy.d.ts +4 -0
  46. package/dist/lib/selection-proxy.d.ts.map +1 -0
  47. package/dist/lib/selection-proxy.js +12 -0
  48. package/dist/lib/slab-polygon.d.ts +31 -2
  49. package/dist/lib/slab-polygon.d.ts.map +1 -1
  50. package/dist/lib/slab-polygon.js +525 -31
  51. package/dist/lib/slab-polygon.test.d.ts +2 -0
  52. package/dist/lib/slab-polygon.test.d.ts.map +1 -0
  53. package/dist/lib/slab-polygon.test.js +635 -0
  54. package/dist/lib/slots.d.ts +14 -0
  55. package/dist/lib/slots.d.ts.map +1 -0
  56. package/dist/lib/slots.js +26 -0
  57. package/dist/lib/space-detection-pause.test.d.ts +2 -0
  58. package/dist/lib/space-detection-pause.test.d.ts.map +1 -0
  59. package/dist/lib/space-detection-pause.test.js +42 -0
  60. package/dist/lib/space-detection.d.ts +54 -2
  61. package/dist/lib/space-detection.d.ts.map +1 -1
  62. package/dist/lib/space-detection.js +599 -124
  63. package/dist/lib/space-detection.test.d.ts +2 -0
  64. package/dist/lib/space-detection.test.d.ts.map +1 -0
  65. package/dist/lib/space-detection.test.js +376 -0
  66. package/dist/lib/wall-distance.d.ts +60 -0
  67. package/dist/lib/wall-distance.d.ts.map +1 -0
  68. package/dist/lib/wall-distance.js +85 -0
  69. package/dist/lib/zone-quantities.d.ts +21 -0
  70. package/dist/lib/zone-quantities.d.ts.map +1 -0
  71. package/dist/lib/zone-quantities.js +183 -0
  72. package/dist/lib/zone-quantities.test.d.ts +2 -0
  73. package/dist/lib/zone-quantities.test.d.ts.map +1 -0
  74. package/dist/lib/zone-quantities.test.js +82 -0
  75. package/dist/material-library.d.ts +20 -1
  76. package/dist/material-library.d.ts.map +1 -1
  77. package/dist/material-library.js +3737 -200
  78. package/dist/registry/__bench__/relations-resolver.bench.d.ts +15 -0
  79. package/dist/registry/__bench__/relations-resolver.bench.d.ts.map +1 -0
  80. package/dist/registry/__bench__/relations-resolver.bench.js +170 -0
  81. package/dist/registry/handles.d.ts +394 -0
  82. package/dist/registry/handles.d.ts.map +1 -0
  83. package/dist/registry/handles.js +24 -0
  84. package/dist/registry/index.d.ts +7 -0
  85. package/dist/registry/index.d.ts.map +1 -0
  86. package/dist/registry/index.js +4 -0
  87. package/dist/registry/registry.d.ts +136 -0
  88. package/dist/registry/registry.d.ts.map +1 -0
  89. package/dist/registry/registry.js +282 -0
  90. package/dist/registry/registry.test.d.ts +2 -0
  91. package/dist/registry/registry.test.d.ts.map +1 -0
  92. package/dist/registry/registry.test.js +196 -0
  93. package/dist/registry/relations-resolver.d.ts +42 -0
  94. package/dist/registry/relations-resolver.d.ts.map +1 -0
  95. package/dist/registry/relations-resolver.js +77 -0
  96. package/dist/registry/relations-resolver.test.d.ts +2 -0
  97. package/dist/registry/relations-resolver.test.d.ts.map +1 -0
  98. package/dist/registry/relations-resolver.test.js +183 -0
  99. package/dist/registry/scene-api.d.ts +44 -0
  100. package/dist/registry/scene-api.d.ts.map +1 -0
  101. package/dist/registry/scene-api.js +111 -0
  102. package/dist/registry/scene-api.test.d.ts +2 -0
  103. package/dist/registry/scene-api.test.d.ts.map +1 -0
  104. package/dist/registry/scene-api.test.js +183 -0
  105. package/dist/registry/subtree.d.ts +67 -0
  106. package/dist/registry/subtree.d.ts.map +1 -0
  107. package/dist/registry/subtree.js +123 -0
  108. package/dist/registry/subtree.test.d.ts +2 -0
  109. package/dist/registry/subtree.test.d.ts.map +1 -0
  110. package/dist/registry/subtree.test.js +163 -0
  111. package/dist/registry/types.d.ts +2099 -0
  112. package/dist/registry/types.d.ts.map +1 -0
  113. package/dist/registry/types.js +1 -0
  114. package/dist/schema/index.d.ts +35 -4
  115. package/dist/schema/index.d.ts.map +1 -1
  116. package/dist/schema/index.js +32 -4
  117. package/dist/schema/material.d.ts +13 -2
  118. package/dist/schema/material.d.ts.map +1 -1
  119. package/dist/schema/material.js +17 -5
  120. package/dist/schema/material.test.d.ts +2 -0
  121. package/dist/schema/material.test.d.ts.map +1 -0
  122. package/dist/schema/material.test.js +43 -0
  123. package/dist/schema/nodes/box-vent.d.ts +74 -0
  124. package/dist/schema/nodes/box-vent.d.ts.map +1 -0
  125. package/dist/schema/nodes/box-vent.js +63 -0
  126. package/dist/schema/nodes/building.d.ts +1 -1
  127. package/dist/schema/nodes/building.d.ts.map +1 -1
  128. package/dist/schema/nodes/building.js +3 -2
  129. package/dist/schema/nodes/cabinet.d.ts +534 -0
  130. package/dist/schema/nodes/cabinet.d.ts.map +1 -0
  131. package/dist/schema/nodes/cabinet.js +137 -0
  132. package/dist/schema/nodes/ceiling.d.ts +5 -2
  133. package/dist/schema/nodes/ceiling.d.ts.map +1 -1
  134. package/dist/schema/nodes/ceiling.js +5 -1
  135. package/dist/schema/nodes/chimney.d.ts +158 -0
  136. package/dist/schema/nodes/chimney.d.ts.map +1 -0
  137. package/dist/schema/nodes/chimney.js +67 -0
  138. package/dist/schema/nodes/column.d.ts +600 -7
  139. package/dist/schema/nodes/column.d.ts.map +1 -1
  140. package/dist/schema/nodes/column.js +589 -6
  141. package/dist/schema/nodes/cupola.d.ts +66 -0
  142. package/dist/schema/nodes/cupola.d.ts.map +1 -0
  143. package/dist/schema/nodes/cupola.js +28 -0
  144. package/dist/schema/nodes/door.d.ts +13 -5
  145. package/dist/schema/nodes/door.d.ts.map +1 -1
  146. package/dist/schema/nodes/door.js +12 -0
  147. package/dist/schema/nodes/dormer.d.ts +228 -0
  148. package/dist/schema/nodes/dormer.d.ts.map +1 -0
  149. package/dist/schema/nodes/dormer.js +119 -0
  150. package/dist/schema/nodes/downspout.d.ts +75 -0
  151. package/dist/schema/nodes/downspout.d.ts.map +1 -0
  152. package/dist/schema/nodes/downspout.js +63 -0
  153. package/dist/schema/nodes/duct-fitting.d.ts +91 -0
  154. package/dist/schema/nodes/duct-fitting.d.ts.map +1 -0
  155. package/dist/schema/nodes/duct-fitting.js +92 -0
  156. package/dist/schema/nodes/duct-segment.d.ts +61 -0
  157. package/dist/schema/nodes/duct-segment.d.ts.map +1 -0
  158. package/dist/schema/nodes/duct-segment.js +73 -0
  159. package/dist/schema/nodes/duct-terminal.d.ts +57 -0
  160. package/dist/schema/nodes/duct-terminal.d.ts.map +1 -0
  161. package/dist/schema/nodes/duct-terminal.js +51 -0
  162. package/dist/schema/nodes/elevator.d.ts +106 -0
  163. package/dist/schema/nodes/elevator.d.ts.map +1 -0
  164. package/dist/schema/nodes/elevator.js +57 -0
  165. package/dist/schema/nodes/eyebrow-vent.d.ts +68 -0
  166. package/dist/schema/nodes/eyebrow-vent.d.ts.map +1 -0
  167. package/dist/schema/nodes/eyebrow-vent.js +40 -0
  168. package/dist/schema/nodes/fence.d.ts +19 -2
  169. package/dist/schema/nodes/fence.d.ts.map +1 -1
  170. package/dist/schema/nodes/fence.js +27 -2
  171. package/dist/schema/nodes/gutter.d.ts +84 -0
  172. package/dist/schema/nodes/gutter.d.ts.map +1 -0
  173. package/dist/schema/nodes/gutter.js +76 -0
  174. package/dist/schema/nodes/hvac-equipment.d.ts +63 -0
  175. package/dist/schema/nodes/hvac-equipment.d.ts.map +1 -0
  176. package/dist/schema/nodes/hvac-equipment.js +55 -0
  177. package/dist/schema/nodes/item.d.ts +12 -0
  178. package/dist/schema/nodes/item.d.ts.map +1 -1
  179. package/dist/schema/nodes/item.js +20 -0
  180. package/dist/schema/nodes/level.d.ts +1 -1
  181. package/dist/schema/nodes/level.d.ts.map +1 -1
  182. package/dist/schema/nodes/level.js +4 -0
  183. package/dist/schema/nodes/lineset.d.ts +42 -0
  184. package/dist/schema/nodes/lineset.d.ts.map +1 -0
  185. package/dist/schema/nodes/lineset.js +38 -0
  186. package/dist/schema/nodes/liquid-line.d.ts +34 -0
  187. package/dist/schema/nodes/liquid-line.d.ts.map +1 -0
  188. package/dist/schema/nodes/liquid-line.js +24 -0
  189. package/dist/schema/nodes/measurement.d.ts +306 -0
  190. package/dist/schema/nodes/measurement.d.ts.map +1 -0
  191. package/dist/schema/nodes/measurement.js +87 -0
  192. package/dist/schema/nodes/measurement.test.d.ts +2 -0
  193. package/dist/schema/nodes/measurement.test.d.ts.map +1 -0
  194. package/dist/schema/nodes/measurement.test.js +139 -0
  195. package/dist/schema/nodes/pipe-fitting.d.ts +56 -0
  196. package/dist/schema/nodes/pipe-fitting.d.ts.map +1 -0
  197. package/dist/schema/nodes/pipe-fitting.js +45 -0
  198. package/dist/schema/nodes/pipe-segment.d.ts +48 -0
  199. package/dist/schema/nodes/pipe-segment.d.ts.map +1 -0
  200. package/dist/schema/nodes/pipe-segment.js +36 -0
  201. package/dist/schema/nodes/pipe-trap.d.ts +43 -0
  202. package/dist/schema/nodes/pipe-trap.d.ts.map +1 -0
  203. package/dist/schema/nodes/pipe-trap.js +36 -0
  204. package/dist/schema/nodes/ridge-vent-defaults.test.d.ts +2 -0
  205. package/dist/schema/nodes/ridge-vent-defaults.test.d.ts.map +1 -0
  206. package/dist/schema/nodes/ridge-vent-defaults.test.js +205 -0
  207. package/dist/schema/nodes/ridge-vent.d.ts +82 -0
  208. package/dist/schema/nodes/ridge-vent.d.ts.map +1 -0
  209. package/dist/schema/nodes/ridge-vent.js +248 -0
  210. package/dist/schema/nodes/roof-segment-shape.d.ts +90 -0
  211. package/dist/schema/nodes/roof-segment-shape.d.ts.map +1 -0
  212. package/dist/schema/nodes/roof-segment-shape.js +318 -0
  213. package/dist/schema/nodes/roof-segment-shape.test.d.ts +2 -0
  214. package/dist/schema/nodes/roof-segment-shape.test.d.ts.map +1 -0
  215. package/dist/schema/nodes/roof-segment-shape.test.js +175 -0
  216. package/dist/schema/nodes/roof-segment-surface.test.d.ts +2 -0
  217. package/dist/schema/nodes/roof-segment-surface.test.d.ts.map +1 -0
  218. package/dist/schema/nodes/roof-segment-surface.test.js +48 -0
  219. package/dist/schema/nodes/roof-segment-trim.test.d.ts +2 -0
  220. package/dist/schema/nodes/roof-segment-trim.test.d.ts.map +1 -0
  221. package/dist/schema/nodes/roof-segment-trim.test.js +107 -0
  222. package/dist/schema/nodes/roof-segment-walls.d.ts +101 -0
  223. package/dist/schema/nodes/roof-segment-walls.d.ts.map +1 -0
  224. package/dist/schema/nodes/roof-segment-walls.js +330 -0
  225. package/dist/schema/nodes/roof-segment-walls.test.d.ts +2 -0
  226. package/dist/schema/nodes/roof-segment-walls.test.d.ts.map +1 -0
  227. package/dist/schema/nodes/roof-segment-walls.test.js +92 -0
  228. package/dist/schema/nodes/roof-segment.d.ts +273 -3
  229. package/dist/schema/nodes/roof-segment.d.ts.map +1 -1
  230. package/dist/schema/nodes/roof-segment.js +539 -3
  231. package/dist/schema/nodes/roof.d.ts +8 -8
  232. package/dist/schema/nodes/roof.d.ts.map +1 -1
  233. package/dist/schema/nodes/roof.js +4 -16
  234. package/dist/schema/nodes/shelf.d.ts +106 -0
  235. package/dist/schema/nodes/shelf.d.ts.map +1 -0
  236. package/dist/schema/nodes/shelf.js +90 -0
  237. package/dist/schema/nodes/site.d.ts +1 -122
  238. package/dist/schema/nodes/site.d.ts.map +1 -1
  239. package/dist/schema/nodes/site.js +2 -6
  240. package/dist/schema/nodes/skylight.d.ts +279 -0
  241. package/dist/schema/nodes/skylight.d.ts.map +1 -0
  242. package/dist/schema/nodes/skylight.js +152 -0
  243. package/dist/schema/nodes/slab.d.ts +5 -2
  244. package/dist/schema/nodes/slab.d.ts.map +1 -1
  245. package/dist/schema/nodes/slab.js +5 -1
  246. package/dist/schema/nodes/solar-panel.d.ts +117 -0
  247. package/dist/schema/nodes/solar-panel.d.ts.map +1 -0
  248. package/dist/schema/nodes/solar-panel.js +47 -0
  249. package/dist/schema/nodes/stair-segment.d.ts +4 -4
  250. package/dist/schema/nodes/stair.d.ts +13 -12
  251. package/dist/schema/nodes/stair.d.ts.map +1 -1
  252. package/dist/schema/nodes/stair.js +3 -0
  253. package/dist/schema/nodes/surface-hole-metadata.d.ts +2 -0
  254. package/dist/schema/nodes/surface-hole-metadata.d.ts.map +1 -1
  255. package/dist/schema/nodes/surface-hole-metadata.js +3 -1
  256. package/dist/schema/nodes/turbine-vent.d.ts +68 -0
  257. package/dist/schema/nodes/turbine-vent.d.ts.map +1 -0
  258. package/dist/schema/nodes/turbine-vent.js +41 -0
  259. package/dist/schema/nodes/wall.d.ts +245 -6
  260. package/dist/schema/nodes/wall.d.ts.map +1 -1
  261. package/dist/schema/nodes/wall.js +257 -0
  262. package/dist/schema/nodes/wall.test.d.ts +2 -0
  263. package/dist/schema/nodes/wall.test.d.ts.map +1 -0
  264. package/dist/schema/nodes/wall.test.js +208 -0
  265. package/dist/schema/nodes/window.d.ts +11 -3
  266. package/dist/schema/nodes/window.d.ts.map +1 -1
  267. package/dist/schema/nodes/window.js +12 -0
  268. package/dist/schema/nodes/zone.d.ts +2 -0
  269. package/dist/schema/nodes/zone.d.ts.map +1 -1
  270. package/dist/schema/nodes/zone.js +6 -0
  271. package/dist/schema/scene-material.d.ts +41 -0
  272. package/dist/schema/scene-material.d.ts.map +1 -0
  273. package/dist/schema/scene-material.js +9 -0
  274. package/dist/schema/types.d.ts +2850 -655
  275. package/dist/schema/types.d.ts.map +1 -1
  276. package/dist/schema/types.js +49 -0
  277. package/dist/services/alignment-anchors.d.ts +100 -0
  278. package/dist/services/alignment-anchors.d.ts.map +1 -0
  279. package/dist/services/alignment-anchors.js +312 -0
  280. package/dist/services/alignment-anchors.test.d.ts +2 -0
  281. package/dist/services/alignment-anchors.test.d.ts.map +1 -0
  282. package/dist/services/alignment-anchors.test.js +383 -0
  283. package/dist/services/alignment.d.ts +131 -0
  284. package/dist/services/alignment.d.ts.map +1 -0
  285. package/dist/services/alignment.js +171 -0
  286. package/dist/services/alignment.test.d.ts +2 -0
  287. package/dist/services/alignment.test.d.ts.map +1 -0
  288. package/dist/services/alignment.test.js +92 -0
  289. package/dist/services/drag-session.d.ts +47 -0
  290. package/dist/services/drag-session.d.ts.map +1 -0
  291. package/dist/services/drag-session.js +100 -0
  292. package/dist/services/drag-session.test.d.ts +2 -0
  293. package/dist/services/drag-session.test.d.ts.map +1 -0
  294. package/dist/services/drag-session.test.js +219 -0
  295. package/dist/services/hosting.d.ts +88 -0
  296. package/dist/services/hosting.d.ts.map +1 -0
  297. package/dist/services/hosting.js +131 -0
  298. package/dist/services/hosting.test.d.ts +2 -0
  299. package/dist/services/hosting.test.d.ts.map +1 -0
  300. package/dist/services/hosting.test.js +230 -0
  301. package/dist/services/index.d.ts +13 -0
  302. package/dist/services/index.d.ts.map +1 -0
  303. package/dist/services/index.js +12 -0
  304. package/dist/services/level-height.d.ts +28 -0
  305. package/dist/services/level-height.d.ts.map +1 -0
  306. package/dist/services/level-height.js +62 -0
  307. package/dist/services/movement.d.ts +48 -0
  308. package/dist/services/movement.d.ts.map +1 -0
  309. package/dist/services/movement.js +65 -0
  310. package/dist/services/movement.test.d.ts +2 -0
  311. package/dist/services/movement.test.d.ts.map +1 -0
  312. package/dist/services/movement.test.js +133 -0
  313. package/dist/services/opening-guides.d.ts +141 -0
  314. package/dist/services/opening-guides.d.ts.map +1 -0
  315. package/dist/services/opening-guides.js +267 -0
  316. package/dist/services/opening-guides.test.d.ts +2 -0
  317. package/dist/services/opening-guides.test.d.ts.map +1 -0
  318. package/dist/services/opening-guides.test.js +208 -0
  319. package/dist/services/port-connectivity.d.ts +115 -0
  320. package/dist/services/port-connectivity.d.ts.map +1 -0
  321. package/dist/services/port-connectivity.js +300 -0
  322. package/dist/services/port-connectivity.test.d.ts +2 -0
  323. package/dist/services/port-connectivity.test.d.ts.map +1 -0
  324. package/dist/services/port-connectivity.test.js +297 -0
  325. package/dist/services/riser-diagram.d.ts +40 -0
  326. package/dist/services/riser-diagram.d.ts.map +1 -0
  327. package/dist/services/riser-diagram.js +110 -0
  328. package/dist/services/riser-diagram.test.d.ts +2 -0
  329. package/dist/services/riser-diagram.test.d.ts.map +1 -0
  330. package/dist/services/riser-diagram.test.js +66 -0
  331. package/dist/services/single-undo-dance.test.d.ts +2 -0
  332. package/dist/services/single-undo-dance.test.d.ts.map +1 -0
  333. package/dist/services/single-undo-dance.test.js +210 -0
  334. package/dist/services/snap.d.ts +80 -0
  335. package/dist/services/snap.d.ts.map +1 -0
  336. package/dist/services/snap.js +140 -0
  337. package/dist/services/snap.test.d.ts +2 -0
  338. package/dist/services/snap.test.d.ts.map +1 -0
  339. package/dist/services/snap.test.js +137 -0
  340. package/dist/services/system-graph.d.ts +30 -0
  341. package/dist/services/system-graph.d.ts.map +1 -0
  342. package/dist/services/system-graph.js +164 -0
  343. package/dist/services/system-graph.test.d.ts +2 -0
  344. package/dist/services/system-graph.test.d.ts.map +1 -0
  345. package/dist/services/system-graph.test.js +138 -0
  346. package/dist/services/validate-dwv.d.ts +32 -0
  347. package/dist/services/validate-dwv.d.ts.map +1 -0
  348. package/dist/services/validate-dwv.js +118 -0
  349. package/dist/services/validate-dwv.test.d.ts +2 -0
  350. package/dist/services/validate-dwv.test.d.ts.map +1 -0
  351. package/dist/services/validate-dwv.test.js +109 -0
  352. package/dist/solar-panel-presets.d.ts +17 -0
  353. package/dist/solar-panel-presets.d.ts.map +1 -0
  354. package/dist/solar-panel-presets.js +43 -0
  355. package/dist/store/actions/node-actions.d.ts +14 -2
  356. package/dist/store/actions/node-actions.d.ts.map +1 -1
  357. package/dist/store/actions/node-actions.js +585 -15
  358. package/dist/store/actions/node-mutation-sanitize.test.d.ts +2 -0
  359. package/dist/store/actions/node-mutation-sanitize.test.d.ts.map +1 -0
  360. package/dist/store/actions/node-mutation-sanitize.test.js +147 -0
  361. package/dist/store/actions/reparent.test.d.ts +2 -0
  362. package/dist/store/actions/reparent.test.d.ts.map +1 -0
  363. package/dist/store/actions/reparent.test.js +212 -0
  364. package/dist/store/actions/ridge-vent-update.test.d.ts +2 -0
  365. package/dist/store/actions/ridge-vent-update.test.d.ts.map +1 -0
  366. package/dist/store/actions/ridge-vent-update.test.js +264 -0
  367. package/dist/store/history-control.d.ts +11 -0
  368. package/dist/store/history-control.d.ts.map +1 -1
  369. package/dist/store/history-control.js +33 -0
  370. package/dist/store/use-interactive.d.ts +39 -0
  371. package/dist/store/use-interactive.d.ts.map +1 -1
  372. package/dist/store/use-interactive.js +75 -0
  373. package/dist/store/use-live-node-overrides.d.ts +22 -0
  374. package/dist/store/use-live-node-overrides.d.ts.map +1 -0
  375. package/dist/store/use-live-node-overrides.js +59 -0
  376. package/dist/store/use-scene-dirty-tracking.test.d.ts +2 -0
  377. package/dist/store/use-scene-dirty-tracking.test.d.ts.map +1 -0
  378. package/dist/store/use-scene-dirty-tracking.test.js +68 -0
  379. package/dist/store/use-scene-elevator-migration.test.d.ts +2 -0
  380. package/dist/store/use-scene-elevator-migration.test.d.ts.map +1 -0
  381. package/dist/store/use-scene-elevator-migration.test.js +109 -0
  382. package/dist/store/use-scene-measurement-roundtrip.test.d.ts +2 -0
  383. package/dist/store/use-scene-measurement-roundtrip.test.d.ts.map +1 -0
  384. package/dist/store/use-scene-measurement-roundtrip.test.js +97 -0
  385. package/dist/store/use-scene-plugins.test.d.ts +2 -0
  386. package/dist/store/use-scene-plugins.test.d.ts.map +1 -0
  387. package/dist/store/use-scene-plugins.test.js +51 -0
  388. package/dist/store/use-scene-wall-slot-migration.test.d.ts +2 -0
  389. package/dist/store/use-scene-wall-slot-migration.test.d.ts.map +1 -0
  390. package/dist/store/use-scene-wall-slot-migration.test.js +210 -0
  391. package/dist/store/use-scene-window-migration.test.d.ts +2 -0
  392. package/dist/store/use-scene-window-migration.test.d.ts.map +1 -0
  393. package/dist/store/use-scene-window-migration.test.js +85 -0
  394. package/dist/store/use-scene.d.ts +28 -2
  395. package/dist/store/use-scene.d.ts.map +1 -1
  396. package/dist/store/use-scene.js +546 -49
  397. package/dist/systems/elevator/elevator-dispatch.d.ts +12 -0
  398. package/dist/systems/elevator/elevator-dispatch.d.ts.map +1 -0
  399. package/dist/systems/elevator/elevator-dispatch.js +57 -0
  400. package/dist/systems/elevator/elevator-geometry.d.ts +15 -0
  401. package/dist/systems/elevator/elevator-geometry.d.ts.map +1 -0
  402. package/dist/systems/elevator/elevator-geometry.js +50 -0
  403. package/dist/systems/elevator/elevator-opening-sync.d.ts +6 -0
  404. package/dist/systems/elevator/elevator-opening-sync.d.ts.map +1 -0
  405. package/dist/systems/elevator/elevator-opening-sync.js +218 -0
  406. package/dist/systems/elevator/elevator-opening-sync.test.d.ts +2 -0
  407. package/dist/systems/elevator/elevator-opening-sync.test.d.ts.map +1 -0
  408. package/dist/systems/elevator/elevator-opening-sync.test.js +146 -0
  409. package/dist/systems/elevator/elevator-opening-system.d.ts +2 -0
  410. package/dist/systems/elevator/elevator-opening-system.d.ts.map +1 -0
  411. package/dist/systems/elevator/elevator-opening-system.js +48 -0
  412. package/dist/systems/elevator/elevator-runtime-system.d.ts +2 -0
  413. package/dist/systems/elevator/elevator-runtime-system.d.ts.map +1 -0
  414. package/dist/systems/elevator/elevator-runtime-system.js +8 -0
  415. package/dist/systems/elevator/elevator-runtime.d.ts +18 -0
  416. package/dist/systems/elevator/elevator-runtime.d.ts.map +1 -0
  417. package/dist/systems/elevator/elevator-runtime.js +225 -0
  418. package/dist/systems/elevator/elevator-runtime.test.d.ts +2 -0
  419. package/dist/systems/elevator/elevator-runtime.test.d.ts.map +1 -0
  420. package/dist/systems/elevator/elevator-runtime.test.js +64 -0
  421. package/dist/systems/elevator/elevator-service.d.ts +19 -0
  422. package/dist/systems/elevator/elevator-service.d.ts.map +1 -0
  423. package/dist/systems/elevator/elevator-service.js +111 -0
  424. package/dist/systems/fence/fence-centerline.d.ts +12 -0
  425. package/dist/systems/fence/fence-centerline.d.ts.map +1 -0
  426. package/dist/systems/fence/fence-centerline.js +37 -0
  427. package/dist/systems/fence/fence-spline.d.ts +39 -0
  428. package/dist/systems/fence/fence-spline.d.ts.map +1 -0
  429. package/dist/systems/fence/fence-spline.js +196 -0
  430. package/dist/systems/fence/fence-spline.test.d.ts +2 -0
  431. package/dist/systems/fence/fence-spline.test.d.ts.map +1 -0
  432. package/dist/systems/fence/fence-spline.test.js +136 -0
  433. package/dist/systems/stair/stair-footprint.d.ts +44 -0
  434. package/dist/systems/stair/stair-footprint.d.ts.map +1 -0
  435. package/dist/systems/stair/stair-footprint.js +178 -0
  436. package/dist/systems/stair/stair-opening-preview.d.ts +2447 -0
  437. package/dist/systems/stair/stair-opening-preview.d.ts.map +1 -0
  438. package/dist/systems/stair/stair-opening-preview.js +93 -0
  439. package/dist/systems/stair/stair-opening-preview.test.d.ts +2 -0
  440. package/dist/systems/stair/stair-opening-preview.test.d.ts.map +1 -0
  441. package/dist/systems/stair/stair-opening-preview.test.js +80 -0
  442. package/dist/systems/stair/stair-opening-sync.d.ts.map +1 -1
  443. package/dist/systems/stair/stair-opening-sync.js +155 -147
  444. package/dist/systems/stair/stair-opening-sync.test.js +424 -2
  445. package/dist/systems/stair/stair-opening-system.d.ts +2 -0
  446. package/dist/systems/stair/stair-opening-system.d.ts.map +1 -0
  447. package/dist/systems/stair/stair-opening-system.js +104 -0
  448. package/dist/systems/wall/wall-mitering.d.ts.map +1 -1
  449. package/dist/systems/wall/wall-mitering.js +38 -2
  450. package/dist/systems/wall/wall-mitering.test.d.ts +2 -0
  451. package/dist/systems/wall/wall-mitering.test.d.ts.map +1 -0
  452. package/dist/systems/wall/wall-mitering.test.js +63 -0
  453. package/dist/systems/wall/wall-move.d.ts +48 -0
  454. package/dist/systems/wall/wall-move.d.ts.map +1 -0
  455. package/dist/systems/wall/wall-move.js +193 -0
  456. package/dist/utils/clone-scene-graph.d.ts +7 -4
  457. package/dist/utils/clone-scene-graph.d.ts.map +1 -1
  458. package/dist/utils/clone-scene-graph.js +29 -7
  459. package/dist/utils/clone-scene-graph.test.d.ts +2 -0
  460. package/dist/utils/clone-scene-graph.test.d.ts.map +1 -0
  461. package/dist/utils/clone-scene-graph.test.js +62 -0
  462. package/dist/utils/heal-scene-graph.d.ts +18 -0
  463. package/dist/utils/heal-scene-graph.d.ts.map +1 -0
  464. package/dist/utils/heal-scene-graph.js +90 -0
  465. package/dist/utils/heal-scene-graph.test.d.ts +2 -0
  466. package/dist/utils/heal-scene-graph.test.d.ts.map +1 -0
  467. package/dist/utils/heal-scene-graph.test.js +88 -0
  468. package/dist/validation/validate-build-json.d.ts +44 -0
  469. package/dist/validation/validate-build-json.d.ts.map +1 -0
  470. package/dist/validation/validate-build-json.js +256 -0
  471. package/package.json +11 -4
@@ -0,0 +1,297 @@
1
+ import { describe, expect, test } from 'bun:test';
2
+ import { registerNode } from '../registry';
3
+ import { analyzePortConnectivity, resolveConnectivityUpdates } from './port-connectivity';
4
+ // Stub registrations mirroring the real kinds' port + role conventions
5
+ // without importing the nodes package (which pulls in CSG and can't load
6
+ // under the test runner). A run exposes start/end at its path tips; the
7
+ // fitting here is a simple two-collar elbow at ±X around its position.
8
+ function stubDef(kind, distributionRole, ports) {
9
+ registerNode({
10
+ kind,
11
+ schemaVersion: 1,
12
+ schema: {},
13
+ category: 'utility',
14
+ distributionRole,
15
+ defaults: () => ({}),
16
+ capabilities: {},
17
+ ports,
18
+ });
19
+ }
20
+ stubDef('duct-segment', 'run', (node) => {
21
+ const path = node.path;
22
+ const system = node.system;
23
+ return [
24
+ { id: 'start', position: path[0], direction: [-1, 0, 0], diameter: 6, system },
25
+ { id: 'end', position: path[path.length - 1], direction: [1, 0, 0], diameter: 6, system },
26
+ ];
27
+ });
28
+ stubDef('duct-fitting', 'fitting', (node) => {
29
+ const position = node.position;
30
+ const system = node.system;
31
+ return [
32
+ {
33
+ id: 'inlet',
34
+ position: [position[0] - 0.2, position[1], position[2]],
35
+ direction: [-1, 0, 0],
36
+ diameter: 6,
37
+ system,
38
+ },
39
+ {
40
+ id: 'outlet',
41
+ position: [position[0] + 0.2, position[1], position[2]],
42
+ direction: [1, 0, 0],
43
+ diameter: 6,
44
+ system,
45
+ },
46
+ ];
47
+ });
48
+ stubDef('duct-tee', 'fitting', (node) => {
49
+ const position = node.position;
50
+ const system = node.system;
51
+ return [
52
+ {
53
+ id: 'inlet',
54
+ position: [position[0] - 0.2, position[1], position[2]],
55
+ direction: [-1, 0, 0],
56
+ diameter: 6,
57
+ system,
58
+ },
59
+ {
60
+ id: 'outlet',
61
+ position: [position[0] + 0.2, position[1], position[2]],
62
+ direction: [1, 0, 0],
63
+ diameter: 6,
64
+ system,
65
+ },
66
+ {
67
+ id: 'branch',
68
+ position: [position[0], position[1], position[2] + 0.2],
69
+ direction: [0, 0, 1],
70
+ diameter: 6,
71
+ system,
72
+ },
73
+ ];
74
+ });
75
+ let nextId = 0;
76
+ function makeNode(type, fields) {
77
+ nextId += 1;
78
+ return { id: `${type}_${nextId}`, type, object: 'node', parentId: null, ...fields };
79
+ }
80
+ function sceneOf(...nodes) {
81
+ return Object.fromEntries(nodes.map((n) => [n.id, n]));
82
+ }
83
+ function expectPointClose(actual, expected) {
84
+ expect(actual[0]).toBeCloseTo(expected[0], 6);
85
+ expect(actual[1]).toBeCloseTo(expected[1], 6);
86
+ expect(actual[2]).toBeCloseTo(expected[2], 6);
87
+ }
88
+ describe('port connectivity — joint follow (stretch vs translate)', () => {
89
+ // Layout: duct A ends at the fitting's inlet (−0.2,0,0); duct B starts at the
90
+ // fitting's outlet (+0.2,0,0). Both runs lie on the X axis. Dragging A's
91
+ // mated endpoint carries the fitting and duct B; how B reacts depends on
92
+ // whether the drag is along its axis (stretch) or across it (translate).
93
+ function joint() {
94
+ const fitting = makeNode('duct-fitting', { position: [0, 0, 0], system: 'supply' });
95
+ const ductA = makeNode('duct-segment', {
96
+ path: [
97
+ [-3, 0, 0],
98
+ [-0.2, 0, 0],
99
+ ],
100
+ system: 'supply',
101
+ });
102
+ const ductB = makeNode('duct-segment', {
103
+ path: [
104
+ [0.2, 0, 0],
105
+ [3, 0, 0],
106
+ ],
107
+ system: 'supply',
108
+ });
109
+ return { fitting, ductA, ductB };
110
+ }
111
+ function movedA(end) {
112
+ const { ductA } = joint();
113
+ return { ...ductA, path: [[-3, 0, 0], end] };
114
+ }
115
+ test('the fitting and sibling run are picked up as carried connections', () => {
116
+ const { fitting, ductA, ductB } = joint();
117
+ const connectivity = analyzePortConnectivity(ductA, sceneOf(fitting, ductA, ductB));
118
+ expect(connectivity.connections.find((c) => c.kind === 'rigid-node' && c.nodeId === fitting.id)).toBeDefined();
119
+ expect(connectivity.connections.find((c) => c.kind === 'run' && c.nodeId === ductB.id)).toBeDefined();
120
+ });
121
+ test('perpendicular drag translates the WHOLE sibling run (no skew)', () => {
122
+ const { fitting, ductA, ductB } = joint();
123
+ const nodes = sceneOf(fitting, ductA, ductB);
124
+ const connectivity = analyzePortConnectivity(ductA, nodes);
125
+ // Move A's mated end +1 in Z — perpendicular to B's X axis.
126
+ const updates = resolveConnectivityUpdates(connectivity, movedA([-0.2, 0, 1]));
127
+ expect(updates.find((u) => u.id === fitting.id).data.position).toEqual([0, 0, 1]);
128
+ const bPath = updates.find((u) => u.id === ductB.id).data.path;
129
+ // Both ends ride +1 in Z: the run keeps its length and direction.
130
+ expect(bPath[0]).toEqual([0.2, 0, 1]);
131
+ expect(bPath[1]).toEqual([3, 0, 1]);
132
+ });
133
+ test('parallel drag stretches the sibling run (only the near end slides)', () => {
134
+ const { fitting, ductA, ductB } = joint();
135
+ const nodes = sceneOf(fitting, ductA, ductB);
136
+ const connectivity = analyzePortConnectivity(ductA, nodes);
137
+ // Move A's mated end +0.5 in X — along B's axis (the fitting slides toward B).
138
+ const updates = resolveConnectivityUpdates(connectivity, movedA([0.3, 0, 0]));
139
+ const bPath = updates.find((u) => u.id === ductB.id).data.path;
140
+ // Near end slid +0.5 in X; far end stayed put → the run shortened.
141
+ expect(bPath[0]).toEqual([0.7, 0, 0]);
142
+ expect(bPath[1]).toEqual([3, 0, 0]);
143
+ });
144
+ test('perpendicular slide propagates through the sibling run to its far joint', () => {
145
+ // Extend the chain: duct B's far end (3,0,0) meets a second elbow, and duct
146
+ // C hangs off that elbow. A perpendicular drag should carry the whole chain.
147
+ const { fitting, ductA, ductB } = joint();
148
+ const elbow2 = makeNode('duct-fitting', { position: [3.2, 0, 0], system: 'supply' });
149
+ // elbow ports are ±0.2 on X around its position → inlet at (3,0,0) meets B.
150
+ const ductC = makeNode('duct-segment', {
151
+ path: [
152
+ [3.4, 0, 0],
153
+ [6, 0, 0],
154
+ ],
155
+ system: 'supply',
156
+ });
157
+ const nodes = sceneOf(fitting, ductA, ductB, elbow2, ductC);
158
+ const connectivity = analyzePortConnectivity(ductA, nodes);
159
+ const updates = resolveConnectivityUpdates(connectivity, movedA([-0.2, 0, 1]));
160
+ // Whole chain rode +1 in Z.
161
+ const bPath = updates.find((u) => u.id === ductB.id).data.path;
162
+ expect(bPath[1]).toEqual([3, 0, 1]);
163
+ expect(updates.find((u) => u.id === elbow2.id).data.position).toEqual([3.2, 0, 1]);
164
+ const cPath = updates.find((u) => u.id === ductC.id).data.path;
165
+ expect(cPath[0]).toEqual([3.4, 0, 1]);
166
+ expect(cPath[1]).toEqual([6, 0, 1]);
167
+ });
168
+ test('a run reached from both ends applies both endpoint deltas', () => {
169
+ const moved = makeNode('duct-segment', {
170
+ path: [
171
+ [0, 0, 0],
172
+ [3, 0, 0],
173
+ ],
174
+ system: 'supply',
175
+ });
176
+ const follower = makeNode('duct-segment', {
177
+ path: [
178
+ [0, 0, 0],
179
+ [3, 0, 0],
180
+ ],
181
+ system: 'supply',
182
+ });
183
+ const nodes = sceneOf(moved, follower);
184
+ const connectivity = analyzePortConnectivity(moved, nodes);
185
+ const preview = {
186
+ ...moved,
187
+ path: [
188
+ [0, 0, 1],
189
+ [3, 0, 2],
190
+ ],
191
+ };
192
+ const updates = resolveConnectivityUpdates(connectivity, preview);
193
+ const path = updates.find((u) => u.id === follower.id).data.path;
194
+ expect(path[0]).toEqual([0, 0, 1]);
195
+ expect(path[1]).toEqual([3, 0, 2]);
196
+ });
197
+ test('a polyline run reached from both ends preserves interior bend shape', () => {
198
+ const moved = makeNode('duct-segment', {
199
+ path: [
200
+ [0, 0, 0],
201
+ [3, 0, 3],
202
+ ],
203
+ system: 'supply',
204
+ });
205
+ const follower = makeNode('duct-segment', {
206
+ path: [
207
+ [0, 0, 0],
208
+ [1, 0, 0],
209
+ [1, 0, 3],
210
+ [3, 0, 3],
211
+ ],
212
+ system: 'supply',
213
+ });
214
+ const nodes = sceneOf(moved, follower);
215
+ const connectivity = analyzePortConnectivity(moved, nodes);
216
+ const preview = {
217
+ ...moved,
218
+ path: [
219
+ [-0.5, 0, 0],
220
+ [3.5, 0, 3],
221
+ ],
222
+ };
223
+ const updates = resolveConnectivityUpdates(connectivity, preview);
224
+ const path = updates.find((u) => u.id === follower.id).data.path;
225
+ expect(path).toEqual([
226
+ [-0.5, 0, 0],
227
+ [1, 0, 0],
228
+ [1, 0, 3],
229
+ [3.5, 0, 3],
230
+ ]);
231
+ });
232
+ test('a fitting reached from both collars rebroadcasts its final compatible rigid delta', () => {
233
+ const moved = makeNode('duct-segment', {
234
+ path: [
235
+ [-0.2, 0, 0],
236
+ [0.2, 0, 0],
237
+ ],
238
+ system: 'supply',
239
+ });
240
+ const fitting = makeNode('duct-tee', { position: [0, 0, 0], system: 'supply' });
241
+ const downstream = makeNode('duct-segment', {
242
+ path: [
243
+ [0, 0, 0.2],
244
+ [3, 0, 0.2],
245
+ ],
246
+ system: 'supply',
247
+ });
248
+ const nodes = sceneOf(moved, fitting, downstream);
249
+ const connectivity = analyzePortConnectivity(moved, nodes);
250
+ const preview = {
251
+ ...moved,
252
+ path: [
253
+ [-0.2, 0, 1],
254
+ [0.2, 0, 1.00005],
255
+ ],
256
+ };
257
+ const updates = resolveConnectivityUpdates(connectivity, preview);
258
+ expectPointClose(updates.find((u) => u.id === fitting.id).data.position, [0, 0, 1.000025]);
259
+ const path = updates.find((u) => u.id === downstream.id).data.path;
260
+ expectPointClose(path[0], [0, 0, 1.200025]);
261
+ expectPointClose(path[1], [3, 0, 1.200025]);
262
+ });
263
+ test('a fitting reached from incompatible collars merges constraints deterministically', () => {
264
+ const moved = makeNode('duct-segment', {
265
+ path: [
266
+ [-0.2, 0, 0],
267
+ [0.2, 0, 0],
268
+ ],
269
+ system: 'supply',
270
+ });
271
+ const fitting = makeNode('duct-fitting', { position: [0, 0, 0], system: 'supply' });
272
+ const nodes = sceneOf(moved, fitting);
273
+ const connectivity = analyzePortConnectivity(moved, nodes);
274
+ const preview = {
275
+ ...moved,
276
+ path: [
277
+ [-0.2, 0, 1],
278
+ [0.2, 0, -1],
279
+ ],
280
+ };
281
+ const updates = resolveConnectivityUpdates(connectivity, preview);
282
+ expectPointClose(updates.find((u) => u.id === fitting.id).data.position, [0, 0, 0]);
283
+ });
284
+ test('an unrelated run not on the fitting is left alone', () => {
285
+ const { fitting, ductA, ductB } = joint();
286
+ const distant = makeNode('duct-segment', {
287
+ path: [
288
+ [10, 0, 0],
289
+ [13, 0, 0],
290
+ ],
291
+ system: 'supply',
292
+ });
293
+ const nodes = sceneOf(fitting, ductA, ductB, distant);
294
+ const connectivity = analyzePortConnectivity(ductA, nodes);
295
+ expect(connectivity.connections.find((c) => c.nodeId === distant.id)).toBeUndefined();
296
+ });
297
+ });
@@ -0,0 +1,40 @@
1
+ import type { AnyNode, AnyNodeId } from '../schema';
2
+ /** A 3D level-local point (meters) projected to 2D iso screen space.
3
+ * Screen Y grows DOWNWARD (SVG convention), so higher elevation → lower
4
+ * screen Y. */
5
+ export declare function projectIso(x: number, y: number, z: number): [number, number];
6
+ export type RiserLine = {
7
+ /** Projected endpoints in iso screen space. */
8
+ from: [number, number];
9
+ to: [number, number];
10
+ system: 'waste' | 'vent';
11
+ /** Nominal size in inches. */
12
+ diameter: number;
13
+ /** True for a (near-)vertical run — drawn solid/bold as a stack. */
14
+ vertical: boolean;
15
+ /** Source node, so the editor can link selection. */
16
+ nodeId: AnyNodeId;
17
+ };
18
+ export type RiserMarker = {
19
+ point: [number, number];
20
+ kind: 'trap' | 'vent-termination' | 'fitting';
21
+ label: string;
22
+ nodeId: AnyNodeId;
23
+ };
24
+ export type RiserDiagram = {
25
+ lines: RiserLine[];
26
+ markers: RiserMarker[];
27
+ /** Bounding box of all projected geometry, screen space. */
28
+ bounds: {
29
+ minX: number;
30
+ minY: number;
31
+ maxX: number;
32
+ maxY: number;
33
+ };
34
+ };
35
+ /**
36
+ * Build the riser diagram for the whole scene. Returns null when there's
37
+ * no DWV geometry to draw.
38
+ */
39
+ export declare function buildRiserDiagram(nodes: Readonly<Record<AnyNodeId, AnyNode>>): RiserDiagram | null;
40
+ //# sourceMappingURL=riser-diagram.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"riser-diagram.d.ts","sourceRoot":"","sources":["../../src/services/riser-diagram.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAA;AAiBnD;;gBAEgB;AAChB,wBAAgB,UAAU,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAI5E;AAED,MAAM,MAAM,SAAS,GAAG;IACtB,+CAA+C;IAC/C,IAAI,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACtB,EAAE,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACpB,MAAM,EAAE,OAAO,GAAG,MAAM,CAAA;IACxB,8BAA8B;IAC9B,QAAQ,EAAE,MAAM,CAAA;IAChB,oEAAoE;IACpE,QAAQ,EAAE,OAAO,CAAA;IACjB,qDAAqD;IACrD,MAAM,EAAE,SAAS,CAAA;CAClB,CAAA;AAED,MAAM,MAAM,WAAW,GAAG;IACxB,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACvB,IAAI,EAAE,MAAM,GAAG,kBAAkB,GAAG,SAAS,CAAA;IAC7C,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,SAAS,CAAA;CAClB,CAAA;AAED,MAAM,MAAM,YAAY,GAAG;IACzB,KAAK,EAAE,SAAS,EAAE,CAAA;IAClB,OAAO,EAAE,WAAW,EAAE,CAAA;IACtB,4DAA4D;IAC5D,MAAM,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAA;CACnE,CAAA;AAcD;;;GAGG;AACH,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC,GAC1C,YAAY,GAAG,IAAI,CAuErB"}
@@ -0,0 +1,110 @@
1
+ /**
2
+ * Riser diagram (plumbing isometric) — the conventional way DWV systems
3
+ * are drawn for permit: the drain/vent tree projected to a 30° iso so
4
+ * vertical stacks read as vertical and horizontal runs lean off at 30°,
5
+ * annotated with size + slope and vent terminations.
6
+ *
7
+ * This is a pure projector: it turns the scene's DWV nodes into 2D
8
+ * drawables (level-independent, no rendering). The editor draws the
9
+ * result as SVG. Air/refrigerant nodes are ignored — riser diagrams are
10
+ * a plumbing convention.
11
+ */
12
+ const COS30 = Math.cos(Math.PI / 6);
13
+ const SIN30 = Math.sin(Math.PI / 6);
14
+ /** A 3D level-local point (meters) projected to 2D iso screen space.
15
+ * Screen Y grows DOWNWARD (SVG convention), so higher elevation → lower
16
+ * screen Y. */
17
+ export function projectIso(x, y, z) {
18
+ const sx = (x - z) * COS30;
19
+ const sy = (x + z) * SIN30 - y;
20
+ return [sx, sy];
21
+ }
22
+ /** Elevation gain per horizontal meter under which a leg is "vertical". */
23
+ const VERTICAL_EPS = 4; // dy/dxz ratio: steeper than this reads as a stack
24
+ function legIsVertical(a, b) {
25
+ const horizontal = Math.hypot(b[0] - a[0], b[2] - a[2]);
26
+ const vertical = Math.abs(b[1] - a[1]);
27
+ if (horizontal < 1e-4)
28
+ return true;
29
+ return vertical / horizontal > VERTICAL_EPS;
30
+ }
31
+ /**
32
+ * Build the riser diagram for the whole scene. Returns null when there's
33
+ * no DWV geometry to draw.
34
+ */
35
+ export function buildRiserDiagram(nodes) {
36
+ const lines = [];
37
+ const markers = [];
38
+ let minX = Infinity;
39
+ let minY = Infinity;
40
+ let maxX = -Infinity;
41
+ let maxY = -Infinity;
42
+ const grow = (p) => {
43
+ if (p[0] < minX)
44
+ minX = p[0];
45
+ if (p[1] < minY)
46
+ minY = p[1];
47
+ if (p[0] > maxX)
48
+ maxX = p[0];
49
+ if (p[1] > maxY)
50
+ maxY = p[1];
51
+ };
52
+ for (const node of Object.values(nodes)) {
53
+ if (!node)
54
+ continue;
55
+ if (node.type === 'pipe-segment') {
56
+ const path = node.path;
57
+ for (let i = 0; i < path.length - 1; i++) {
58
+ const a = path[i];
59
+ const b = path[i + 1];
60
+ const from = projectIso(a[0], a[1], a[2]);
61
+ const to = projectIso(b[0], b[1], b[2]);
62
+ grow(from);
63
+ grow(to);
64
+ lines.push({
65
+ from,
66
+ to,
67
+ system: node.system,
68
+ diameter: node.diameter,
69
+ vertical: legIsVertical(a, b),
70
+ nodeId: node.id,
71
+ });
72
+ }
73
+ // Vent runs that end above everything are vent terminations
74
+ // (through-roof). Tag the highest endpoint of a vent run.
75
+ if (node.system === 'vent') {
76
+ const top = path.reduce((hi, p) => (p[1] > hi[1] ? p : hi), path[0]);
77
+ const pt = projectIso(top[0], top[1], top[2]);
78
+ markers.push({
79
+ point: pt,
80
+ kind: 'vent-termination',
81
+ label: `${node.diameter}" VTR`,
82
+ nodeId: node.id,
83
+ });
84
+ }
85
+ }
86
+ else if (node.type === 'pipe-trap') {
87
+ const pt = projectIso(node.position[0], node.position[1], node.position[2]);
88
+ grow(pt);
89
+ markers.push({
90
+ point: pt,
91
+ kind: 'trap',
92
+ label: `${node.diameter}" P-trap`,
93
+ nodeId: node.id,
94
+ });
95
+ }
96
+ else if (node.type === 'pipe-fitting') {
97
+ const pt = projectIso(node.position[0], node.position[1], node.position[2]);
98
+ grow(pt);
99
+ markers.push({
100
+ point: pt,
101
+ kind: 'fitting',
102
+ label: node.fittingType,
103
+ nodeId: node.id,
104
+ });
105
+ }
106
+ }
107
+ if (lines.length === 0 && markers.length === 0)
108
+ return null;
109
+ return { lines, markers, bounds: { minX, minY, maxX, maxY } };
110
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=riser-diagram.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"riser-diagram.test.d.ts","sourceRoot":"","sources":["../../src/services/riser-diagram.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,66 @@
1
+ import { describe, expect, test } from 'bun:test';
2
+ import { buildRiserDiagram, projectIso } from './riser-diagram';
3
+ let nextId = 0;
4
+ function makeNode(type, fields) {
5
+ nextId += 1;
6
+ return { id: `${type}_${nextId}`, type, object: 'node', parentId: null, ...fields };
7
+ }
8
+ function sceneOf(...nodes) {
9
+ return Object.fromEntries(nodes.map((n) => [n.id, n]));
10
+ }
11
+ describe('projectIso', () => {
12
+ test('higher elevation maps to smaller screen Y', () => {
13
+ const [, lowY] = projectIso(0, 0, 0);
14
+ const [, highY] = projectIso(0, 2, 0);
15
+ expect(highY).toBeLessThan(lowY);
16
+ });
17
+ });
18
+ describe('buildRiserDiagram', () => {
19
+ test('null when no DWV nodes', () => {
20
+ const wall = makeNode('wall', {});
21
+ expect(buildRiserDiagram(sceneOf(wall))).toBeNull();
22
+ });
23
+ test('classifies a vertical stack vs a sloped horizontal drain', () => {
24
+ const stack = makeNode('pipe-segment', {
25
+ path: [
26
+ [0, 0, 0],
27
+ [0, 3, 0],
28
+ ],
29
+ diameter: 3,
30
+ system: 'vent',
31
+ });
32
+ const drain = makeNode('pipe-segment', {
33
+ path: [
34
+ [0, 0, 0],
35
+ [3, -0.06, 0],
36
+ ],
37
+ diameter: 2,
38
+ system: 'waste',
39
+ });
40
+ const diagram = buildRiserDiagram(sceneOf(stack, drain));
41
+ const stackLine = diagram.lines.find((l) => l.nodeId === stack.id);
42
+ const drainLine = diagram.lines.find((l) => l.nodeId === drain.id);
43
+ expect(stackLine.vertical).toBe(true);
44
+ expect(drainLine.vertical).toBe(false);
45
+ });
46
+ test('emits a vent-termination marker for a vent run', () => {
47
+ const vent = makeNode('pipe-segment', {
48
+ path: [
49
+ [0, 0, 0],
50
+ [0, 3, 0],
51
+ ],
52
+ diameter: 2,
53
+ system: 'vent',
54
+ });
55
+ const diagram = buildRiserDiagram(sceneOf(vent));
56
+ expect(diagram.markers.some((m) => m.kind === 'vent-termination')).toBe(true);
57
+ });
58
+ test('labels traps', () => {
59
+ const trap = makeNode('pipe-trap', {
60
+ position: [1, 0, 0],
61
+ diameter: 1.5,
62
+ });
63
+ const diagram = buildRiserDiagram(sceneOf(trap));
64
+ expect(diagram.markers.some((m) => m.kind === 'trap')).toBe(true);
65
+ });
66
+ });
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=single-undo-dance.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"single-undo-dance.test.d.ts","sourceRoot":"","sources":["../../src/services/single-undo-dance.test.ts"],"names":[],"mappings":""}