@pascal-app/nodes 0.1.1 → 1.0.0-beta.1

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 (408) hide show
  1. package/README.md +34 -0
  2. package/dist/building/definition.js +1 -1
  3. package/dist/cabinet/definition.d.ts.map +1 -1
  4. package/dist/cabinet/definition.js +809 -72
  5. package/dist/cabinet/geometry.d.ts.map +1 -1
  6. package/dist/cabinet/geometry.js +4 -0
  7. package/dist/cabinet/move-frame.js +3 -3
  8. package/dist/cabinet/panel.d.ts.map +1 -1
  9. package/dist/cabinet/panel.js +1 -0
  10. package/dist/cabinet/placement-snap.d.ts +8 -0
  11. package/dist/cabinet/placement-snap.d.ts.map +1 -0
  12. package/dist/cabinet/placement-snap.js +19 -0
  13. package/dist/cabinet/presets.js +8 -8
  14. package/dist/cabinet/quick-actions.d.ts.map +1 -1
  15. package/dist/cabinet/quick-actions.js +9 -3
  16. package/dist/cabinet/resize-limits.d.ts +11 -0
  17. package/dist/cabinet/resize-limits.d.ts.map +1 -0
  18. package/dist/cabinet/resize-limits.js +22 -0
  19. package/dist/cabinet/run-layout.d.ts +8 -2
  20. package/dist/cabinet/run-layout.d.ts.map +1 -1
  21. package/dist/cabinet/run-layout.js +59 -7
  22. package/dist/cabinet/run-ops.d.ts +44 -3
  23. package/dist/cabinet/run-ops.d.ts.map +1 -1
  24. package/dist/cabinet/run-ops.js +646 -110
  25. package/dist/cabinet/run-panel.d.ts +2 -1
  26. package/dist/cabinet/run-panel.d.ts.map +1 -1
  27. package/dist/cabinet/run-panel.js +38 -4
  28. package/dist/cabinet/stack-transitions.js +4 -4
  29. package/dist/cabinet/tool.d.ts.map +1 -1
  30. package/dist/cabinet/tool.js +95 -17
  31. package/dist/cabinet/wall-snap.d.ts.map +1 -1
  32. package/dist/cabinet/wall-snap.js +2 -6
  33. package/dist/ceiling/boundary-editor.d.ts.map +1 -1
  34. package/dist/ceiling/boundary-editor.js +2 -2
  35. package/dist/ceiling/definition.d.ts +1 -1
  36. package/dist/ceiling/definition.d.ts.map +1 -1
  37. package/dist/ceiling/definition.js +36 -5
  38. package/dist/ceiling/floorplan-affordances.d.ts +4 -4
  39. package/dist/ceiling/floorplan-move.d.ts +4 -4
  40. package/dist/ceiling/floorplan-move.d.ts.map +1 -1
  41. package/dist/ceiling/floorplan-move.js +5 -4
  42. package/dist/ceiling/hole-editor.d.ts.map +1 -1
  43. package/dist/ceiling/hole-editor.js +2 -2
  44. package/dist/ceiling/move-tool.d.ts.map +1 -1
  45. package/dist/ceiling/move-tool.js +4 -3
  46. package/dist/ceiling/panel.d.ts.map +1 -1
  47. package/dist/ceiling/panel.js +65 -3
  48. package/dist/ceiling/renderer.d.ts.map +1 -1
  49. package/dist/ceiling/renderer.js +6 -2
  50. package/dist/ceiling/tool.d.ts.map +1 -1
  51. package/dist/ceiling/tool.js +12 -1
  52. package/dist/chimney/definition.d.ts.map +1 -1
  53. package/dist/chimney/definition.js +1 -0
  54. package/dist/chimney/tool.d.ts.map +1 -1
  55. package/dist/chimney/tool.js +16 -1
  56. package/dist/column/definition.d.ts.map +1 -1
  57. package/dist/column/definition.js +14 -2
  58. package/dist/column/floorplan-affordances.d.ts.map +1 -1
  59. package/dist/column/floorplan-affordances.js +19 -14
  60. package/dist/column/floorplan-move.d.ts.map +1 -1
  61. package/dist/column/floorplan-move.js +7 -2
  62. package/dist/column/floorplan.d.ts +9 -1
  63. package/dist/column/floorplan.d.ts.map +1 -1
  64. package/dist/column/floorplan.js +59 -4
  65. package/dist/column/tool.d.ts.map +1 -1
  66. package/dist/column/tool.js +33 -7
  67. package/dist/construction-dimension/definition.d.ts +4 -0
  68. package/dist/construction-dimension/definition.d.ts.map +1 -0
  69. package/dist/construction-dimension/definition.js +83 -0
  70. package/dist/construction-dimension/drawing-coordination.d.ts +7 -0
  71. package/dist/construction-dimension/drawing-coordination.d.ts.map +1 -0
  72. package/dist/construction-dimension/drawing-coordination.js +54 -0
  73. package/dist/construction-dimension/floorplan-affordances.d.ts +4 -0
  74. package/dist/construction-dimension/floorplan-affordances.d.ts.map +1 -0
  75. package/dist/construction-dimension/floorplan-affordances.js +114 -0
  76. package/dist/construction-dimension/floorplan-tool.d.ts +21 -0
  77. package/dist/construction-dimension/floorplan-tool.d.ts.map +1 -0
  78. package/dist/construction-dimension/floorplan-tool.js +557 -0
  79. package/dist/construction-dimension/floorplan.d.ts +3 -0
  80. package/dist/construction-dimension/floorplan.d.ts.map +1 -0
  81. package/dist/construction-dimension/floorplan.js +457 -0
  82. package/dist/construction-dimension/geometry.d.ts +31 -0
  83. package/dist/construction-dimension/geometry.d.ts.map +1 -0
  84. package/dist/construction-dimension/geometry.js +144 -0
  85. package/dist/construction-dimension/index.d.ts +4 -0
  86. package/dist/construction-dimension/index.d.ts.map +1 -0
  87. package/dist/construction-dimension/index.js +3 -0
  88. package/dist/construction-dimension/panel.d.ts +2 -0
  89. package/dist/construction-dimension/panel.d.ts.map +1 -0
  90. package/dist/construction-dimension/panel.js +128 -0
  91. package/dist/construction-dimension/parametrics.d.ts +3 -0
  92. package/dist/construction-dimension/parametrics.d.ts.map +1 -0
  93. package/dist/construction-dimension/parametrics.js +4 -0
  94. package/dist/construction-dimension/schema.d.ts +2 -0
  95. package/dist/construction-dimension/schema.d.ts.map +1 -0
  96. package/dist/construction-dimension/schema.js +1 -0
  97. package/dist/door/contextual-dimensions.d.ts +3 -0
  98. package/dist/door/contextual-dimensions.d.ts.map +1 -0
  99. package/dist/door/contextual-dimensions.js +7 -0
  100. package/dist/door/definition.d.ts.map +1 -1
  101. package/dist/door/definition.js +13 -8
  102. package/dist/door/floorplan-affordances.d.ts +2 -5
  103. package/dist/door/floorplan-affordances.d.ts.map +1 -1
  104. package/dist/door/floorplan-affordances.js +9 -18
  105. package/dist/door/floorplan.d.ts +3 -4
  106. package/dist/door/floorplan.d.ts.map +1 -1
  107. package/dist/door/floorplan.js +88 -6
  108. package/dist/door/move-tool.d.ts.map +1 -1
  109. package/dist/door/move-tool.js +2 -2
  110. package/dist/door/panel.d.ts.map +1 -1
  111. package/dist/door/panel.js +3 -1
  112. package/dist/door/schema.d.ts +1 -1
  113. package/dist/door/schema.d.ts.map +1 -1
  114. package/dist/door/schema.js +1 -1
  115. package/dist/door/tool.d.ts.map +1 -1
  116. package/dist/door/tool.js +63 -6
  117. package/dist/dormer/definition.d.ts.map +1 -1
  118. package/dist/dormer/definition.js +1 -0
  119. package/dist/dormer/tool.d.ts.map +1 -1
  120. package/dist/dormer/tool.js +23 -1
  121. package/dist/duct-segment/tool.d.ts.map +1 -1
  122. package/dist/duct-segment/tool.js +20 -9
  123. package/dist/duct-terminal/tool.d.ts.map +1 -1
  124. package/dist/duct-terminal/tool.js +9 -6
  125. package/dist/elevator/floorplan-affordances.d.ts +2 -6
  126. package/dist/elevator/floorplan-affordances.d.ts.map +1 -1
  127. package/dist/elevator/floorplan-affordances.js +13 -12
  128. package/dist/fence/actions/move-endpoint.d.ts.map +1 -1
  129. package/dist/fence/actions/move-endpoint.js +29 -1
  130. package/dist/fence/definition.d.ts.map +1 -1
  131. package/dist/fence/definition.js +67 -14
  132. package/dist/fence/floorplan-affordances.d.ts.map +1 -1
  133. package/dist/fence/floorplan-affordances.js +48 -11
  134. package/dist/fence/floorplan-move.d.ts.map +1 -1
  135. package/dist/fence/floorplan-move.js +38 -3
  136. package/dist/fence/geometry.d.ts.map +1 -1
  137. package/dist/fence/geometry.js +9 -1
  138. package/dist/fence/lift.d.ts +15 -0
  139. package/dist/fence/lift.d.ts.map +1 -0
  140. package/dist/fence/lift.js +23 -0
  141. package/dist/fence/move-tool.d.ts.map +1 -1
  142. package/dist/fence/move-tool.js +25 -5
  143. package/dist/fence/system.d.ts +3 -0
  144. package/dist/fence/system.d.ts.map +1 -0
  145. package/dist/fence/system.js +41 -0
  146. package/dist/fence/tool.d.ts.map +1 -1
  147. package/dist/fence/tool.js +103 -32
  148. package/dist/hvac-equipment/tool.d.ts.map +1 -1
  149. package/dist/hvac-equipment/tool.js +8 -3
  150. package/dist/index.d.ts +2 -0
  151. package/dist/index.d.ts.map +1 -1
  152. package/dist/index.js +6 -0
  153. package/dist/item/definition.d.ts.map +1 -1
  154. package/dist/item/definition.js +7 -1
  155. package/dist/item/floorplan-move.d.ts.map +1 -1
  156. package/dist/item/floorplan-move.js +50 -43
  157. package/dist/item/floorplan.d.ts +1 -0
  158. package/dist/item/floorplan.d.ts.map +1 -1
  159. package/dist/item/floorplan.js +49 -0
  160. package/dist/item/renderer.d.ts +3 -0
  161. package/dist/item/renderer.d.ts.map +1 -1
  162. package/dist/item/renderer.js +96 -8
  163. package/dist/level/definition.d.ts.map +1 -1
  164. package/dist/level/definition.js +7 -3
  165. package/dist/lineset/tool.d.ts.map +1 -1
  166. package/dist/lineset/tool.js +5 -1
  167. package/dist/liquid-line/tool.d.ts.map +1 -1
  168. package/dist/liquid-line/tool.js +7 -1
  169. package/dist/measurement/definition.d.ts.map +1 -1
  170. package/dist/measurement/definition.js +5 -0
  171. package/dist/measurement/floorplan.d.ts.map +1 -1
  172. package/dist/measurement/floorplan.js +11 -10
  173. package/dist/measurement/index.d.ts +1 -1
  174. package/dist/measurement/index.d.ts.map +1 -1
  175. package/dist/measurement/index.js +1 -1
  176. package/dist/measurement/resolve.d.ts +5 -0
  177. package/dist/measurement/resolve.d.ts.map +1 -1
  178. package/dist/measurement/resolve.js +2 -2
  179. package/dist/measurement/surface-query.js +5 -5
  180. package/dist/measurement/tool.d.ts +6 -1
  181. package/dist/measurement/tool.d.ts.map +1 -1
  182. package/dist/measurement/tool.js +7 -11
  183. package/dist/pipe-segment/tool.d.ts.map +1 -1
  184. package/dist/pipe-segment/tool.js +22 -19
  185. package/dist/roof-segment/floorplan-affordances.d.ts.map +1 -1
  186. package/dist/roof-segment/floorplan-affordances.js +14 -8
  187. package/dist/shared/construction-dimension-standards.d.ts +34 -0
  188. package/dist/shared/construction-dimension-standards.d.ts.map +1 -0
  189. package/dist/shared/construction-dimension-standards.js +18 -0
  190. package/dist/shared/construction-length.d.ts +10 -0
  191. package/dist/shared/construction-length.d.ts.map +1 -0
  192. package/dist/shared/construction-length.js +57 -0
  193. package/dist/shared/dimension-string.d.ts +20 -0
  194. package/dist/shared/dimension-string.d.ts.map +1 -0
  195. package/dist/shared/dimension-string.js +19 -0
  196. package/dist/shared/draft-axis-guides.d.ts +36 -0
  197. package/dist/shared/draft-axis-guides.d.ts.map +1 -0
  198. package/dist/shared/draft-axis-guides.js +107 -0
  199. package/dist/shared/move-roof-tool.d.ts.map +1 -1
  200. package/dist/shared/move-roof-tool.js +17 -3
  201. package/dist/shared/opening-documentation-fields.d.ts +16 -0
  202. package/dist/shared/opening-documentation-fields.d.ts.map +1 -0
  203. package/dist/shared/opening-documentation-fields.js +54 -0
  204. package/dist/shared/opening-documentation.d.ts +47 -0
  205. package/dist/shared/opening-documentation.d.ts.map +1 -0
  206. package/dist/shared/opening-documentation.js +300 -0
  207. package/dist/shared/opening-guides-runtime.d.ts.map +1 -1
  208. package/dist/shared/opening-guides-runtime.js +3 -2
  209. package/dist/shared/opening-placement-dimensions.d.ts.map +1 -1
  210. package/dist/shared/opening-placement-dimensions.js +14 -5
  211. package/dist/shared/wall-opening-ceiling.d.ts +30 -0
  212. package/dist/shared/wall-opening-ceiling.d.ts.map +1 -0
  213. package/dist/shared/wall-opening-ceiling.js +29 -0
  214. package/dist/shelf/floorplan-affordances.d.ts.map +1 -1
  215. package/dist/shelf/floorplan-affordances.js +10 -5
  216. package/dist/shelf/floorplan-move.d.ts +2 -16
  217. package/dist/shelf/floorplan-move.d.ts.map +1 -1
  218. package/dist/shelf/floorplan-move.js +19 -40
  219. package/dist/shelf/tool.d.ts.map +1 -1
  220. package/dist/shelf/tool.js +8 -3
  221. package/dist/site/recessed-slab-ground-holes.d.ts.map +1 -1
  222. package/dist/site/recessed-slab-ground-holes.js +1 -4
  223. package/dist/site/renderer.d.ts.map +1 -1
  224. package/dist/site/renderer.js +118 -28
  225. package/dist/site/terrain-drape.d.ts +91 -0
  226. package/dist/site/terrain-drape.d.ts.map +1 -0
  227. package/dist/site/terrain-drape.js +205 -0
  228. package/dist/site/terrain-geometry.d.ts +131 -0
  229. package/dist/site/terrain-geometry.d.ts.map +1 -0
  230. package/dist/site/terrain-geometry.js +259 -0
  231. package/dist/site/terrain-mesh.d.ts +49 -0
  232. package/dist/site/terrain-mesh.d.ts.map +1 -0
  233. package/dist/site/terrain-mesh.js +122 -0
  234. package/dist/site/terrain-renderer.d.ts +28 -0
  235. package/dist/site/terrain-renderer.d.ts.map +1 -0
  236. package/dist/site/terrain-renderer.js +69 -0
  237. package/dist/skylight/definition.d.ts.map +1 -1
  238. package/dist/skylight/definition.js +1 -0
  239. package/dist/skylight/tool.d.ts.map +1 -1
  240. package/dist/skylight/tool.js +16 -1
  241. package/dist/slab/definition.d.ts.map +1 -1
  242. package/dist/slab/definition.js +87 -10
  243. package/dist/slab/elevation-limit.d.ts +43 -0
  244. package/dist/slab/elevation-limit.d.ts.map +1 -0
  245. package/dist/slab/elevation-limit.js +124 -0
  246. package/dist/slab/floorplan-affordances.d.ts +16 -0
  247. package/dist/slab/floorplan-affordances.d.ts.map +1 -1
  248. package/dist/slab/geometry.d.ts.map +1 -1
  249. package/dist/slab/geometry.js +98 -5
  250. package/dist/slab/panel.d.ts.map +1 -1
  251. package/dist/slab/panel.js +82 -4
  252. package/dist/slab/parametrics.d.ts +1 -1
  253. package/dist/slab/parametrics.d.ts.map +1 -1
  254. package/dist/slab/parametrics.js +13 -1
  255. package/dist/slab/placement-ownership.d.ts +3 -0
  256. package/dist/slab/placement-ownership.d.ts.map +1 -0
  257. package/dist/slab/placement-ownership.js +3 -0
  258. package/dist/slab/quick-measurement.d.ts.map +1 -1
  259. package/dist/slab/quick-measurement.js +3 -2
  260. package/dist/slab/system.d.ts.map +1 -1
  261. package/dist/slab/system.js +14 -4
  262. package/dist/slab/tool.d.ts.map +1 -1
  263. package/dist/slab/tool.js +81 -23
  264. package/dist/solar-panel/definition.d.ts.map +1 -1
  265. package/dist/solar-panel/definition.js +1 -0
  266. package/dist/solar-panel/tool.d.ts.map +1 -1
  267. package/dist/solar-panel/tool.js +17 -1
  268. package/dist/spawn/definition.d.ts.map +1 -1
  269. package/dist/spawn/definition.js +1 -0
  270. package/dist/spawn/floorplan-affordances.d.ts.map +1 -1
  271. package/dist/spawn/floorplan-affordances.js +7 -4
  272. package/dist/spawn/floorplan-move.d.ts.map +1 -1
  273. package/dist/spawn/floorplan-move.js +8 -6
  274. package/dist/spawn/renderer.d.ts +4 -0
  275. package/dist/spawn/renderer.d.ts.map +1 -1
  276. package/dist/spawn/renderer.js +32 -18
  277. package/dist/spawn/tool.d.ts +2 -2
  278. package/dist/spawn/tool.d.ts.map +1 -1
  279. package/dist/spawn/tool.js +78 -11
  280. package/dist/stair/definition.d.ts.map +1 -1
  281. package/dist/stair/definition.js +15 -7
  282. package/dist/stair/destination.d.ts +16 -0
  283. package/dist/stair/destination.d.ts.map +1 -0
  284. package/dist/stair/destination.js +24 -0
  285. package/dist/stair/documentation.d.ts +8 -0
  286. package/dist/stair/documentation.d.ts.map +1 -0
  287. package/dist/stair/documentation.js +245 -0
  288. package/dist/stair/floor-stack.d.ts.map +1 -1
  289. package/dist/stair/floor-stack.js +38 -0
  290. package/dist/stair/floorplan-affordances.d.ts.map +1 -1
  291. package/dist/stair/floorplan-affordances.js +28 -9
  292. package/dist/stair/floorplan-move.d.ts +3 -5
  293. package/dist/stair/floorplan-move.d.ts.map +1 -1
  294. package/dist/stair/floorplan-move.js +14 -16
  295. package/dist/stair/floorplan.d.ts.map +1 -1
  296. package/dist/stair/floorplan.js +27 -14
  297. package/dist/stair/panel.d.ts.map +1 -1
  298. package/dist/stair/panel.js +35 -2
  299. package/dist/stair/renderer.d.ts.map +1 -1
  300. package/dist/stair/renderer.js +4 -3
  301. package/dist/structural-grid/coordination.d.ts +16 -0
  302. package/dist/structural-grid/coordination.d.ts.map +1 -0
  303. package/dist/structural-grid/coordination.js +105 -0
  304. package/dist/structural-grid/definition.d.ts +4 -0
  305. package/dist/structural-grid/definition.d.ts.map +1 -0
  306. package/dist/structural-grid/definition.js +51 -0
  307. package/dist/structural-grid/floorplan-tool.d.ts +16 -0
  308. package/dist/structural-grid/floorplan-tool.d.ts.map +1 -0
  309. package/dist/structural-grid/floorplan-tool.js +183 -0
  310. package/dist/structural-grid/floorplan.d.ts +3 -0
  311. package/dist/structural-grid/floorplan.d.ts.map +1 -0
  312. package/dist/structural-grid/floorplan.js +61 -0
  313. package/dist/structural-grid/index.d.ts +2 -0
  314. package/dist/structural-grid/index.d.ts.map +1 -0
  315. package/dist/structural-grid/index.js +1 -0
  316. package/dist/structural-grid/schema.d.ts +2 -0
  317. package/dist/structural-grid/schema.d.ts.map +1 -0
  318. package/dist/structural-grid/schema.js +1 -0
  319. package/dist/wall/construction-dimensions.d.ts +32 -0
  320. package/dist/wall/construction-dimensions.d.ts.map +1 -0
  321. package/dist/wall/construction-dimensions.js +1031 -0
  322. package/dist/wall/contextual-dimensions.d.ts +13 -0
  323. package/dist/wall/contextual-dimensions.d.ts.map +1 -0
  324. package/dist/wall/contextual-dimensions.js +221 -0
  325. package/dist/wall/definition.d.ts.map +1 -1
  326. package/dist/wall/definition.js +20 -1
  327. package/dist/wall/floorplan-affordances.d.ts.map +1 -1
  328. package/dist/wall/floorplan-affordances.js +23 -8
  329. package/dist/wall/floorplan-overrides.d.ts +9 -6
  330. package/dist/wall/floorplan-overrides.d.ts.map +1 -1
  331. package/dist/wall/floorplan-overrides.js +20 -11
  332. package/dist/wall/floorplan.d.ts +12 -3
  333. package/dist/wall/floorplan.d.ts.map +1 -1
  334. package/dist/wall/floorplan.js +121 -79
  335. package/dist/wall/measurement.d.ts.map +1 -1
  336. package/dist/wall/measurement.js +17 -4
  337. package/dist/wall/move-endpoint-tool.d.ts.map +1 -1
  338. package/dist/wall/move-endpoint-tool.js +74 -27
  339. package/dist/wall/move-shared.d.ts.map +1 -1
  340. package/dist/wall/move-shared.js +3 -2
  341. package/dist/wall/move-tool.d.ts.map +1 -1
  342. package/dist/wall/move-tool.js +15 -3
  343. package/dist/wall/paint.d.ts.map +1 -1
  344. package/dist/wall/paint.js +10 -6
  345. package/dist/wall/panel.d.ts.map +1 -1
  346. package/dist/wall/panel.js +32 -5
  347. package/dist/wall/parametrics.d.ts.map +1 -1
  348. package/dist/wall/parametrics.js +2 -0
  349. package/dist/wall/preview.d.ts +8 -0
  350. package/dist/wall/preview.d.ts.map +1 -0
  351. package/dist/wall/preview.js +39 -0
  352. package/dist/wall/quick-measurement.d.ts.map +1 -1
  353. package/dist/wall/quick-measurement.js +3 -2
  354. package/dist/wall/renderer.d.ts.map +1 -1
  355. package/dist/wall/renderer.js +7 -5
  356. package/dist/wall/system.d.ts +1 -1
  357. package/dist/wall/system.d.ts.map +1 -1
  358. package/dist/wall/system.js +37 -2
  359. package/dist/wall/tool.d.ts.map +1 -1
  360. package/dist/wall/tool.js +148 -96
  361. package/dist/wall/treatment-level-data.d.ts +14 -0
  362. package/dist/wall/treatment-level-data.d.ts.map +1 -0
  363. package/dist/wall/treatment-level-data.js +31 -0
  364. package/dist/wall/treatments.d.ts +8 -2
  365. package/dist/wall/treatments.d.ts.map +1 -1
  366. package/dist/wall/treatments.js +58 -15
  367. package/dist/window/contextual-dimensions.d.ts +3 -0
  368. package/dist/window/contextual-dimensions.d.ts.map +1 -0
  369. package/dist/window/contextual-dimensions.js +7 -0
  370. package/dist/window/definition.d.ts.map +1 -1
  371. package/dist/window/definition.js +15 -10
  372. package/dist/window/floorplan-affordances.d.ts +2 -5
  373. package/dist/window/floorplan-affordances.d.ts.map +1 -1
  374. package/dist/window/floorplan-affordances.js +9 -15
  375. package/dist/window/floorplan-move.d.ts.map +1 -1
  376. package/dist/window/floorplan-move.js +1 -1
  377. package/dist/window/floorplan.d.ts.map +1 -1
  378. package/dist/window/floorplan.js +7 -1
  379. package/dist/window/move-tool.d.ts.map +1 -1
  380. package/dist/window/move-tool.js +3 -3
  381. package/dist/window/panel.d.ts.map +1 -1
  382. package/dist/window/panel.js +4 -1
  383. package/dist/window/schema.d.ts +1 -1
  384. package/dist/window/schema.d.ts.map +1 -1
  385. package/dist/window/schema.js +1 -1
  386. package/dist/window/tool.d.ts.map +1 -1
  387. package/dist/window/tool.js +64 -7
  388. package/dist/window/window-math.d.ts +7 -3
  389. package/dist/window/window-math.d.ts.map +1 -1
  390. package/dist/window/window-math.js +8 -3
  391. package/dist/zone/contextual-dimensions.d.ts +3 -0
  392. package/dist/zone/contextual-dimensions.d.ts.map +1 -0
  393. package/dist/zone/contextual-dimensions.js +43 -0
  394. package/dist/zone/definition.d.ts.map +1 -1
  395. package/dist/zone/definition.js +9 -1
  396. package/dist/zone/floorplan-affordances.d.ts +36 -0
  397. package/dist/zone/floorplan-affordances.d.ts.map +1 -1
  398. package/dist/zone/floorplan.d.ts.map +1 -1
  399. package/dist/zone/floorplan.js +59 -3
  400. package/dist/zone/quantities-panel.d.ts.map +1 -1
  401. package/dist/zone/quantities-panel.js +48 -4
  402. package/dist/zone/room-clear-dimensions.d.ts +3 -0
  403. package/dist/zone/room-clear-dimensions.d.ts.map +1 -0
  404. package/dist/zone/room-clear-dimensions.js +406 -0
  405. package/dist/zone/room-documentation.d.ts +11 -0
  406. package/dist/zone/room-documentation.d.ts.map +1 -0
  407. package/dist/zone/room-documentation.js +97 -0
  408. package/package.json +7 -7
@@ -8,6 +8,15 @@ export declare const zoneMoveVertexAffordance: import("@pascal-app/core").Floorp
8
8
  polygon: [number, number][];
9
9
  autoFromWalls: boolean;
10
10
  boundaryWallIds: `wall_${string}`[];
11
+ spaceRole: "generic" | "room";
12
+ roomNumber: string;
13
+ enclosureStatus: "auto" | "enclosed" | "open";
14
+ floorFinish: string;
15
+ wallFinish: string;
16
+ ceilingFinish: string;
17
+ ceilingHeight: number;
18
+ occupancy: string;
19
+ clearDimensionPolicy: "none" | "inside-faces" | "finish-faces";
11
20
  color: string;
12
21
  metadata: import("zod").JSONType;
13
22
  camera?: {
@@ -28,6 +37,15 @@ export declare const zoneAddVertexAffordance: import("@pascal-app/core").Floorpl
28
37
  polygon: [number, number][];
29
38
  autoFromWalls: boolean;
30
39
  boundaryWallIds: `wall_${string}`[];
40
+ spaceRole: "generic" | "room";
41
+ roomNumber: string;
42
+ enclosureStatus: "auto" | "enclosed" | "open";
43
+ floorFinish: string;
44
+ wallFinish: string;
45
+ ceilingFinish: string;
46
+ ceilingHeight: number;
47
+ occupancy: string;
48
+ clearDimensionPolicy: "none" | "inside-faces" | "finish-faces";
31
49
  color: string;
32
50
  metadata: import("zod").JSONType;
33
51
  camera?: {
@@ -48,6 +66,15 @@ export declare const zoneMoveEdgeAffordance: import("@pascal-app/core").Floorpla
48
66
  polygon: [number, number][];
49
67
  autoFromWalls: boolean;
50
68
  boundaryWallIds: `wall_${string}`[];
69
+ spaceRole: "generic" | "room";
70
+ roomNumber: string;
71
+ enclosureStatus: "auto" | "enclosed" | "open";
72
+ floorFinish: string;
73
+ wallFinish: string;
74
+ ceilingFinish: string;
75
+ ceilingHeight: number;
76
+ occupancy: string;
77
+ clearDimensionPolicy: "none" | "inside-faces" | "finish-faces";
51
78
  color: string;
52
79
  metadata: import("zod").JSONType;
53
80
  camera?: {
@@ -68,6 +95,15 @@ export declare const zoneDeleteVertexAffordance: import("@pascal-app/core").Floo
68
95
  polygon: [number, number][];
69
96
  autoFromWalls: boolean;
70
97
  boundaryWallIds: `wall_${string}`[];
98
+ spaceRole: "generic" | "room";
99
+ roomNumber: string;
100
+ enclosureStatus: "auto" | "enclosed" | "open";
101
+ floorFinish: string;
102
+ wallFinish: string;
103
+ ceilingFinish: string;
104
+ ceilingHeight: number;
105
+ occupancy: string;
106
+ clearDimensionPolicy: "none" | "inside-faces" | "finish-faces";
71
107
  color: string;
72
108
  metadata: import("zod").JSONType;
73
109
  camera?: {
@@ -1 +1 @@
1
- {"version":3,"file":"floorplan-affordances.d.ts","sourceRoot":"","sources":["../../src/zone/floorplan-affordances.ts"],"names":[],"mappings":"AAuBA,eAAO,MAAM,wBAAwB;;;;;;;;;;;;;;;;;;;EAGpC,CAAA;AACD,eAAO,MAAM,uBAAuB;;;;;;;;;;;;;;;;;;;EAGnC,CAAA;AACD,eAAO,MAAM,sBAAsB;;;;;;;;;;;;;;;;;;;EAGlC,CAAA;AACD,eAAO,MAAM,0BAA0B;;;;;;;;;;;;;;;;;;;EAGtC,CAAA"}
1
+ {"version":3,"file":"floorplan-affordances.d.ts","sourceRoot":"","sources":["../../src/zone/floorplan-affordances.ts"],"names":[],"mappings":"AAuBA,eAAO,MAAM,wBAAwB;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAGpC,CAAA;AACD,eAAO,MAAM,uBAAuB;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAGnC,CAAA;AACD,eAAO,MAAM,sBAAsB;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAGlC,CAAA;AACD,eAAO,MAAM,0BAA0B;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAGtC,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"floorplan.d.ts","sourceRoot":"","sources":["../../src/zone/floorplan.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,iBAAiB,EAEtB,KAAK,eAAe,EAEpB,KAAK,QAAQ,EACd,MAAM,kBAAkB,CAAA;AAEzB;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,QAAQ,EAAE,GAAG,EAAE,eAAe,GAAG,iBAAiB,GAAG,IAAI,CAoGjG"}
1
+ {"version":3,"file":"floorplan.d.ts","sourceRoot":"","sources":["../../src/zone/floorplan.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,iBAAiB,EAEtB,KAAK,eAAe,EAEpB,KAAK,QAAQ,EACd,MAAM,kBAAkB,CAAA;AAQzB;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,QAAQ,EAAE,GAAG,EAAE,eAAe,GAAG,iBAAiB,GAAG,IAAI,CAqHjG"}
@@ -1,4 +1,7 @@
1
1
  import { resolveAutoZonePolygon, } from '@pascal-app/core';
2
+ import { floorplanGeometryMetadata, readFloorplanContext } from '@pascal-app/editor';
3
+ import { formatConstructionLength, } from '../shared/construction-length';
4
+ import { buildRoomClearDimensions } from './room-clear-dimensions';
2
5
  /**
3
6
  * Stage C floor-plan builder for zone. Zones are colored polygons —
4
7
  * fill + outline both come from `zone.color`. Selection adds an
@@ -14,13 +17,15 @@ export function buildZoneFloorplan(node, ctx) {
14
17
  if (!ring || ring.length < 3)
15
18
  return null;
16
19
  const view = ctx.viewState;
20
+ const floorplanContext = readFloorplanContext(ctx);
17
21
  const palette = view?.palette;
18
22
  const isSelected = view?.selected ?? false;
19
23
  const isHighlighted = view?.highlighted ?? false;
20
24
  const showSelectedChrome = isSelected || isHighlighted;
21
25
  const points = ring.map(([x, z]) => [x, z]);
22
26
  const stroke = showSelectedChrome && palette ? palette.selectedStroke : node.color;
23
- const fillOpacity = isSelected ? 0.28 : 0.16;
27
+ const isRoom = node.spaceRole === 'room';
28
+ const fillOpacity = isRoom ? (isSelected ? 0.12 : 0.04) : isSelected ? 0.28 : 0.16;
24
29
  const children = [
25
30
  {
26
31
  kind: 'polygon',
@@ -80,9 +85,15 @@ export function buildZoneFloorplan(node, ctx) {
80
85
  // it). Mirrors the legacy `FloorplanZoneLabel` so the look is
81
86
  // consistent. Centered on the polygon's area-weighted centroid; the
82
87
  // bbox-center fallback handles degenerate rings without throwing.
88
+ const [cx, cy] = polygonCentroid(ring);
83
89
  const name = node.name?.trim();
84
- if (name) {
85
- const [cx, cy] = polygonCentroid(ring);
90
+ if (isRoom) {
91
+ children.push(...buildRoomLabels(node, cx, cy, view?.unit ?? 'metric', floorplanContext.purpose === 'document' ? 'document' : 'editor', floorplanContext.metricNotation, stroke));
92
+ if (floorplanContext.automaticDimensions) {
93
+ children.push(...buildRoomClearDimensions(node, ctx));
94
+ }
95
+ }
96
+ else if (name) {
86
97
  children.push({
87
98
  kind: 'text',
88
99
  x: cx,
@@ -106,6 +117,51 @@ export function buildZoneFloorplan(node, ctx) {
106
117
  return { kind: 'group', children };
107
118
  }
108
119
  const ZONE_LABEL_FONT_SIZE = 0.2;
120
+ const ROOM_NAME_FONT_SIZE = 0.2;
121
+ const ROOM_NUMBER_FONT_SIZE = 0.16;
122
+ const ROOM_DETAIL_FONT_SIZE = 0.11;
123
+ const ROOM_LABEL_LINE_SPACING = 0.18;
124
+ function buildRoomLabels(node, x, y, unit, profile, metricNotation, color) {
125
+ const lines = [];
126
+ const name = node.name.trim();
127
+ if (name)
128
+ lines.push({ text: name, fontSize: ROOM_NAME_FONT_SIZE, fontWeight: 700 });
129
+ if (node.roomNumber) {
130
+ lines.push({ text: node.roomNumber, fontSize: ROOM_NUMBER_FONT_SIZE, fontWeight: 600 });
131
+ }
132
+ const finishes = [
133
+ node.floorFinish ? `FL: ${node.floorFinish}` : '',
134
+ node.wallFinish ? `WL: ${node.wallFinish}` : '',
135
+ node.ceilingFinish ? `CL: ${node.ceilingFinish}` : '',
136
+ ].filter(Boolean);
137
+ if (finishes.length > 0) {
138
+ lines.push({ text: finishes.join(' · '), fontSize: ROOM_DETAIL_FONT_SIZE, fontWeight: 500 });
139
+ }
140
+ const roomDetails = [
141
+ `CH: ${formatConstructionLength(node.ceilingHeight, unit, profile, { metricNotation })}`,
142
+ ];
143
+ if (node.occupancy)
144
+ roomDetails.push(node.occupancy);
145
+ lines.push({ text: roomDetails.join(' · '), fontSize: ROOM_DETAIL_FONT_SIZE, fontWeight: 500 });
146
+ const startY = y - ((lines.length - 1) * ROOM_LABEL_LINE_SPACING) / 2;
147
+ return lines.map((line, index) => ({
148
+ kind: 'text',
149
+ x,
150
+ y: startY + index * ROOM_LABEL_LINE_SPACING,
151
+ text: line.text,
152
+ fontSize: line.fontSize,
153
+ fill: color,
154
+ stroke: '#ffffff',
155
+ strokeWidth: line.fontSize * 0.18,
156
+ paintOrder: 'stroke',
157
+ fontFamily: 'system-ui, -apple-system, sans-serif',
158
+ fontWeight: line.fontWeight,
159
+ textAnchor: 'middle',
160
+ dominantBaseline: 'central',
161
+ upright: true,
162
+ metadata: floorplanGeometryMetadata({ annotationRole: 'room-label' }),
163
+ }));
164
+ }
109
165
  /**
110
166
  * Area-weighted centroid of a simple polygon (Shoelace formula). Falls
111
167
  * back to the bounding-box center when the signed area is degenerate
@@ -1 +1 @@
1
- {"version":3,"file":"quantities-panel.d.ts","sourceRoot":"","sources":["../../src/zone/quantities-panel.tsx"],"names":[],"mappings":"AAyJA,MAAM,CAAC,OAAO,UAAU,mBAAmB,uCAsF1C"}
1
+ {"version":3,"file":"quantities-panel.d.ts","sourceRoot":"","sources":["../../src/zone/quantities-panel.tsx"],"names":[],"mappings":"AA4TA,MAAM,CAAC,OAAO,UAAU,mBAAmB,uCA2F1C"}
@@ -1,9 +1,9 @@
1
1
  'use client';
2
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
3
  import { deriveZoneQuantityReport, resolveAutoZonePolygon, useLiveNodeOverrides, useScene, } from '@pascal-app/core';
4
- import { formatAreaLabel, formatLinearMeasurement, formatVolumeLabel, PanelSection, } from '@pascal-app/editor';
4
+ import { formatAreaLabel, formatLinearMeasurement, formatVolumeLabel, MetricControl, PanelSection, ToggleControl, } from '@pascal-app/editor';
5
5
  import { useViewer } from '@pascal-app/viewer';
6
- import { useMemo } from 'react';
6
+ import { useEffect, useMemo, useRef, useState } from 'react';
7
7
  import { useShallow } from 'zustand/react/shallow';
8
8
  function ZonePlanSketch({ edgeLengths, polygon, unit, }) {
9
9
  if (polygon.length < 3) {
@@ -44,6 +44,50 @@ function ZonePlanSketch({ edgeLengths, polygon, unit, }) {
44
44
  function QuantityRow({ abbreviation, format, label, quantity, }) {
45
45
  return (_jsxs("div", { className: "rounded-md border border-border/50 bg-background/35 px-2.5 py-2", children: [_jsxs("div", { className: "flex items-baseline gap-2", children: [_jsx("span", { className: "font-mono font-semibold text-cyan-600 text-[10px]", children: abbreviation }), _jsx("span", { className: "text-muted-foreground text-xs", children: label }), _jsx("span", { className: "ml-auto font-mono font-medium text-foreground text-xs tabular-nums", children: quantity.status === 'available' ? format(quantity.value) : 'Not proven' })] }), _jsx("div", { className: "mt-1 text-[10px] text-muted-foreground leading-snug", children: quantity.status === 'available' ? quantity.note : quantity.reason })] }));
46
46
  }
47
+ function RoomTextField({ label, onCommit, value, }) {
48
+ const [draft, setDraft] = useState(value);
49
+ const cancelRef = useRef(false);
50
+ useEffect(() => setDraft(value), [value]);
51
+ const commit = () => {
52
+ if (cancelRef.current) {
53
+ cancelRef.current = false;
54
+ setDraft(value);
55
+ return;
56
+ }
57
+ const next = draft.trim();
58
+ if (next !== value)
59
+ onCommit(next);
60
+ else
61
+ setDraft(value);
62
+ };
63
+ return (_jsxs("label", { className: "flex h-10 items-center gap-3 rounded-lg border border-border/50 bg-[#2C2C2E] px-3 text-sm", children: [_jsx("span", { className: "shrink-0 text-muted-foreground", children: label }), _jsx("input", { className: "min-w-0 flex-1 bg-transparent text-right text-foreground outline-none selection:bg-primary/30", onBlur: commit, onChange: (event) => setDraft(event.target.value), onKeyDown: (event) => {
64
+ if (event.key === 'Enter')
65
+ event.currentTarget.blur();
66
+ if (event.key === 'Escape') {
67
+ cancelRef.current = true;
68
+ event.currentTarget.blur();
69
+ }
70
+ }, type: "text", value: draft })] }));
71
+ }
72
+ function RoomSelect({ label, onChange, options, value, }) {
73
+ return (_jsxs("label", { className: "flex h-10 items-center justify-between gap-3 rounded-lg border border-border/50 bg-[#2C2C2E] px-3 text-sm", children: [_jsx("span", { className: "text-muted-foreground", children: label }), _jsx("select", { className: "min-w-0 rounded-md border border-border/50 bg-[#232325] px-2 py-1 text-foreground text-xs outline-none", onChange: (event) => onChange(event.target.value), value: value, children: options.map((option) => (_jsx("option", { value: option.value, children: option.label }, option.value))) })] }));
74
+ }
75
+ function RoomDocumentationPanel({ zone }) {
76
+ const updateNode = useScene((state) => state.updateNode);
77
+ const update = (patch) => updateNode(zone.id, patch);
78
+ const isRoom = zone.spaceRole === 'room';
79
+ return (_jsxs(PanelSection, { title: "Room documentation", children: [_jsx(ToggleControl, { checked: isRoom, label: "Architectural room", onChange: (checked) => update({ spaceRole: checked ? 'room' : 'generic' }) }), isRoom ? (_jsxs(_Fragment, { children: [_jsx(RoomTextField, { label: "Room name", onCommit: (name) => update({ name }), value: zone.name }), _jsx(RoomTextField, { label: "Room number", onCommit: (roomNumber) => update({ roomNumber }), value: zone.roomNumber }), _jsx(RoomSelect, { label: "Enclosure", onChange: (enclosureStatus) => update({ enclosureStatus: enclosureStatus }), options: [
80
+ { label: 'Auto-detect', value: 'auto' },
81
+ { label: 'Enclosed', value: 'enclosed' },
82
+ { label: 'Open', value: 'open' },
83
+ ], value: zone.enclosureStatus }), _jsx(RoomTextField, { label: "Occupancy / use", onCommit: (occupancy) => update({ occupancy }), value: zone.occupancy }), _jsx(RoomTextField, { label: "Floor finish", onCommit: (floorFinish) => update({ floorFinish }), value: zone.floorFinish }), _jsx(RoomTextField, { label: "Wall finish", onCommit: (wallFinish) => update({ wallFinish }), value: zone.wallFinish }), _jsx(RoomTextField, { label: "Ceiling finish", onCommit: (ceilingFinish) => update({ ceilingFinish }), value: zone.ceilingFinish }), _jsx(MetricControl, { label: "Ceiling height", max: 20, min: 0.1, onChange: (ceilingHeight) => update({ ceilingHeight }), precision: 2, step: 0.05, unit: "m", value: zone.ceilingHeight }), _jsx(RoomSelect, { label: "Clear dimensions", onChange: (clearDimensionPolicy) => update({
84
+ clearDimensionPolicy: clearDimensionPolicy,
85
+ }), options: [
86
+ { label: 'None', value: 'none' },
87
+ { label: 'Inside faces', value: 'inside-faces' },
88
+ { label: 'Finish faces', value: 'finish-faces' },
89
+ ], value: zone.clearDimensionPolicy })] })) : null] }));
90
+ }
47
91
  export default function ZoneQuantitiesPanel() {
48
92
  const selectedZoneId = useViewer((state) => state.selection.zoneId);
49
93
  const unit = useViewer((state) => state.unit);
@@ -79,5 +123,5 @@ export default function ZoneQuantitiesPanel() {
79
123
  const report = useMemo(() => (effectiveZone ? deriveZoneQuantityReport(effectiveZone, effectiveNodes) : null), [effectiveNodes, effectiveZone]);
80
124
  if (!effectiveZone || !report)
81
125
  return null;
82
- return (_jsxs(PanelSection, { title: "Zone quantities", children: [_jsxs("div", { className: "overflow-hidden rounded-md border border-cyan-950/20 bg-[#f8faf7] text-slate-950", children: [_jsxs("div", { className: "flex items-center border-cyan-950/15 border-b px-2.5 py-2", children: [_jsx("span", { className: "font-semibold text-[11px]", children: effectiveZone.name }), _jsx("span", { className: "ml-auto rounded-full border border-cyan-800/25 bg-cyan-50 px-2 py-0.5 text-cyan-900 text-[9px]", children: report.classification === 'enclosed-room' ? 'Enclosed room' : 'Footprint only' })] }), _jsxs("div", { className: "flex items-baseline gap-2 px-2.5 py-2 font-mono text-[10px]", children: [_jsx("span", { className: "text-cyan-800", children: "A" }), _jsx("span", { children: formatAreaLabel(report.footprintArea, unit, 2) }), _jsx("span", { className: "ml-auto text-slate-600", children: "P" }), _jsx("span", { children: formatLinearMeasurement(report.perimeter, unit) })] })] }), _jsx(ZonePlanSketch, { edgeLengths: report.edgeLengths, polygon: effectiveZone.polygon, unit: unit }), _jsxs("div", { className: "flex flex-col gap-1.5", children: [_jsx(QuantityRow, { abbreviation: "Aw", format: (value) => formatAreaLabel(value, unit, 2), label: "Wall surface", quantity: report.wallSurface }), _jsx(QuantityRow, { abbreviation: "Af", format: (value) => formatAreaLabel(value, unit, 2), label: "Floor surface", quantity: report.floorSurface }), _jsx(QuantityRow, { abbreviation: "V", format: (value) => formatVolumeLabel(value, unit, 2), label: "Volume", quantity: report.volume })] })] }));
126
+ return (_jsxs(_Fragment, { children: [_jsx(RoomDocumentationPanel, { zone: effectiveZone }), _jsxs(PanelSection, { title: effectiveZone.spaceRole === 'room' ? 'Room quantities' : 'Zone quantities', children: [_jsxs("div", { className: "overflow-hidden rounded-md border border-cyan-950/20 bg-[#f8faf7] text-slate-950", children: [_jsxs("div", { className: "flex items-center border-cyan-950/15 border-b px-2.5 py-2", children: [_jsx("span", { className: "font-semibold text-[11px]", children: effectiveZone.name }), _jsx("span", { className: "ml-auto rounded-full border border-cyan-800/25 bg-cyan-50 px-2 py-0.5 text-cyan-900 text-[9px]", children: report.classification === 'enclosed-room' ? 'Enclosed room' : 'Footprint only' })] }), _jsxs("div", { className: "flex items-baseline gap-2 px-2.5 py-2 font-mono text-[10px]", children: [_jsx("span", { className: "text-cyan-800", children: "A" }), _jsx("span", { children: formatAreaLabel(report.footprintArea, unit, 2) }), _jsx("span", { className: "ml-auto text-slate-600", children: "P" }), _jsx("span", { children: formatLinearMeasurement(report.perimeter, unit) })] })] }), _jsx(ZonePlanSketch, { edgeLengths: report.edgeLengths, polygon: effectiveZone.polygon, unit: unit }), _jsxs("div", { className: "flex flex-col gap-1.5", children: [_jsx(QuantityRow, { abbreviation: "Aw", format: (value) => formatAreaLabel(value, unit, 2), label: "Wall surface", quantity: report.wallSurface }), _jsx(QuantityRow, { abbreviation: "Af", format: (value) => formatAreaLabel(value, unit, 2), label: "Floor surface", quantity: report.floorSurface }), _jsx(QuantityRow, { abbreviation: "V", format: (value) => formatVolumeLabel(value, unit, 2), label: "Volume", quantity: report.volume })] })] })] }));
83
127
  }
@@ -0,0 +1,3 @@
1
+ import { type FloorplanGeometry, type GeometryContext, type ZoneNode } from '@pascal-app/core';
2
+ export declare function buildRoomClearDimensions(node: ZoneNode, ctx: GeometryContext): FloorplanGeometry[];
3
+ //# sourceMappingURL=room-clear-dimensions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"room-clear-dimensions.d.ts","sourceRoot":"","sources":["../../src/zone/room-clear-dimensions.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,iBAAiB,EAEtB,KAAK,eAAe,EAIpB,KAAK,QAAQ,EACd,MAAM,kBAAkB,CAAA;AAuBzB,wBAAgB,wBAAwB,CACtC,IAAI,EAAE,QAAQ,EACd,GAAG,EAAE,eAAe,GACnB,iBAAiB,EAAE,CA4DrB"}
@@ -0,0 +1,406 @@
1
+ import { detectSpacesForLevel, getWallThickness, } from '@pascal-app/core';
2
+ import { readFloorplanContext } from '@pascal-app/editor';
3
+ import { formatConstructionLength, } from '../shared/construction-length';
4
+ const LINE_TOLERANCE = 1e-4;
5
+ const ANGLE_TOLERANCE = 1e-3;
6
+ const MIN_CLEAR_SPAN = 0.3;
7
+ const MIN_ROOM_TO_ROOM_SPAN = 0.03;
8
+ const FIRST_DIMENSION_POSITION = 0.32;
9
+ const SECOND_DIMENSION_POSITION = 0.68;
10
+ const EXTENSION_OVERSHOOT = 0.08;
11
+ export function buildRoomClearDimensions(node, ctx) {
12
+ if (node.spaceRole !== 'room' ||
13
+ (node.clearDimensionPolicy !== 'inside-faces' &&
14
+ node.clearDimensionPolicy !== 'finish-faces') ||
15
+ node.enclosureStatus === 'open' ||
16
+ !node.autoFromWalls ||
17
+ !node.parentId ||
18
+ node.boundaryWallIds.length < 3) {
19
+ return [];
20
+ }
21
+ const walls = node.boundaryWallIds.flatMap((id) => {
22
+ const resolved = ctx.resolve(id);
23
+ return resolved &&
24
+ typeof resolved === 'object' &&
25
+ 'type' in resolved &&
26
+ resolved.type === 'wall'
27
+ ? [resolved]
28
+ : [];
29
+ });
30
+ if (walls.length !== node.boundaryWallIds.length)
31
+ return [];
32
+ const boundaryIds = new Set(node.boundaryWallIds);
33
+ const space = detectSpacesForLevel(node.parentId, walls).spaces.find((candidate) => candidate.wallIds.length === boundaryIds.size &&
34
+ candidate.wallIds.every((id) => boundaryIds.has(id)));
35
+ if (!space)
36
+ return [];
37
+ const wallsById = new Map(walls.map((wall) => [wall.id, wall]));
38
+ const faceLines = resolveClearFaceLines(space.boundaryFaces, wallsById);
39
+ if (!faceLines)
40
+ return [];
41
+ const unit = ctx.viewState?.unit ?? 'metric';
42
+ const floorplanContext = readFloorplanContext(ctx);
43
+ const profile = floorplanContext.purpose === 'document' ? 'document' : 'editor';
44
+ const metricNotation = floorplanContext.metricNotation;
45
+ const stroke = ctx.viewState?.palette.measurementStroke ?? '#475569';
46
+ const rectangle = resolveClearFaceRectangle(faceLines);
47
+ const dimensions = rectangle
48
+ ? buildRectangleClearDimensions(rectangle, unit, profile, metricNotation, stroke)
49
+ : buildRectilinearClearDimensions(faceLines, unit, profile, metricNotation, stroke);
50
+ if (dimensions.length === 0)
51
+ return [];
52
+ return [
53
+ ...dimensions,
54
+ ...buildRoomToRoomClearDimensions(node, ctx, space.boundaryFaces, wallsById, unit, profile, metricNotation, stroke),
55
+ ];
56
+ }
57
+ function resolveClearFaceLines(boundaryFaces, wallsById) {
58
+ const faceLines = [];
59
+ for (const boundary of boundaryFaces) {
60
+ const wall = wallsById.get(boundary.wallId);
61
+ if (!wall || Math.abs(wall.curveOffset ?? 0) > LINE_TOLERANCE)
62
+ return null;
63
+ const line = offsetBoundaryFace(boundary, wall);
64
+ if (!line)
65
+ return null;
66
+ faceLines.push(line);
67
+ }
68
+ const merged = mergeCollinearFaces(faceLines);
69
+ return merged.length >= 4 ? merged : null;
70
+ }
71
+ function resolveClearFaceRectangle(merged) {
72
+ if (merged.length !== 4)
73
+ return null;
74
+ const vertices = merged.map((line, index) => {
75
+ const previous = merged[(index + merged.length - 1) % merged.length];
76
+ return intersectLines(previous, line);
77
+ });
78
+ if (vertices.some((vertex) => vertex === null))
79
+ return null;
80
+ const rectangle = vertices;
81
+ const directions = rectangle.map((start, index) => normalizedDirection(start, rectangle[(index + 1) % rectangle.length]));
82
+ if (directions.some((direction) => direction === null))
83
+ return null;
84
+ const [first, second, third, fourth] = directions;
85
+ if (Math.abs(dot(first, second)) > ANGLE_TOLERANCE ||
86
+ Math.abs(dot(second, third)) > ANGLE_TOLERANCE ||
87
+ Math.abs(dot(third, fourth)) > ANGLE_TOLERANCE ||
88
+ Math.abs(dot(fourth, first)) > ANGLE_TOLERANCE ||
89
+ dot(first, third) > -1 + ANGLE_TOLERANCE ||
90
+ dot(second, fourth) > -1 + ANGLE_TOLERANCE) {
91
+ return null;
92
+ }
93
+ return rectangle;
94
+ }
95
+ function buildRectangleClearDimensions(rectangle, unit, profile, metricNotation, stroke) {
96
+ const first = dimensionAcrossOppositeFaces(rectangle[0], rectangle[1], rectangle[3], rectangle[2], FIRST_DIMENSION_POSITION, unit, profile, metricNotation, stroke);
97
+ const second = dimensionAcrossOppositeFaces(rectangle[1], rectangle[2], rectangle[0], rectangle[3], SECOND_DIMENSION_POSITION, unit, profile, metricNotation, stroke);
98
+ return first && second ? [first, second] : [];
99
+ }
100
+ function buildRectilinearClearDimensions(faceLines, unit, profile, metricNotation, stroke) {
101
+ const vertices = clearFacePolygon(faceLines);
102
+ if (!vertices || !isRectilinearPolygon(vertices))
103
+ return [];
104
+ const dimensions = [];
105
+ const seen = new Set();
106
+ for (let firstIndex = 0; firstIndex < faceLines.length; firstIndex++) {
107
+ const first = faceLines[firstIndex];
108
+ const firstDirection = normalizedDirection(first.start, first.end);
109
+ if (!firstDirection)
110
+ return [];
111
+ for (let secondIndex = firstIndex + 1; secondIndex < faceLines.length; secondIndex++) {
112
+ const second = faceLines[secondIndex];
113
+ const secondDirection = normalizedDirection(second.start, second.end);
114
+ if (!secondDirection)
115
+ return [];
116
+ if (Math.abs(dot(firstDirection, secondDirection)) < 1 - ANGLE_TOLERANCE)
117
+ continue;
118
+ const dimension = dimensionBetweenOverlappingParallelFaces(first, second, firstDirection, vertices, unit, profile, metricNotation, stroke);
119
+ if (!dimension)
120
+ continue;
121
+ const key = dimensionKey(dimension);
122
+ if (seen.has(key))
123
+ continue;
124
+ seen.add(key);
125
+ dimensions.push(dimension);
126
+ }
127
+ }
128
+ return dimensions;
129
+ }
130
+ function offsetBoundaryFace(boundary, wall) {
131
+ const first = boundary.points[0];
132
+ const last = boundary.points[boundary.points.length - 1];
133
+ if (!(first && last))
134
+ return null;
135
+ const wallDirection = normalizedDirection(wall.start, wall.end);
136
+ if (!wallDirection)
137
+ return null;
138
+ const normal = [-wallDirection[1], wallDirection[0]];
139
+ const side = boundary.face === 'front' ? 1 : -1;
140
+ const offset = (getWallThickness(wall) / 2) * side;
141
+ return {
142
+ start: [first[0] + normal[0] * offset, first[1] + normal[1] * offset],
143
+ end: [last[0] + normal[0] * offset, last[1] + normal[1] * offset],
144
+ };
145
+ }
146
+ function clearFacePolygon(faceLines) {
147
+ const vertices = faceLines.map((line, index) => {
148
+ const previous = faceLines[(index + faceLines.length - 1) % faceLines.length];
149
+ return intersectLines(previous, line);
150
+ });
151
+ return vertices.some((vertex) => vertex === null) ? null : vertices;
152
+ }
153
+ function isRectilinearPolygon(vertices) {
154
+ if (vertices.length < 4)
155
+ return false;
156
+ const directions = vertices.map((start, index) => normalizedDirection(start, vertices[(index + 1) % vertices.length]));
157
+ if (directions.some((direction) => direction === null))
158
+ return false;
159
+ for (let index = 0; index < directions.length; index++) {
160
+ const current = directions[index];
161
+ const next = directions[(index + 1) % directions.length];
162
+ if (Math.abs(dot(current, next)) > ANGLE_TOLERANCE)
163
+ return false;
164
+ }
165
+ return true;
166
+ }
167
+ function dimensionBetweenOverlappingParallelFaces(first, second, direction, polygon, unit, profile, metricNotation, stroke) {
168
+ const firstStart = dot(first.start, direction);
169
+ const firstEnd = dot(first.end, direction);
170
+ const secondStart = dot(second.start, direction);
171
+ const secondEnd = dot(second.end, direction);
172
+ const overlapStart = Math.max(Math.min(firstStart, firstEnd), Math.min(secondStart, secondEnd));
173
+ const overlapEnd = Math.min(Math.max(firstStart, firstEnd), Math.max(secondStart, secondEnd));
174
+ if (overlapEnd - overlapStart < MIN_CLEAR_SPAN)
175
+ return null;
176
+ const projection = (overlapStart + overlapEnd) / 2;
177
+ const start = projectPointToLineProjection(first, direction, projection);
178
+ const end = projectPointToLineProjection(second, direction, projection);
179
+ const midpoint = [(start[0] + end[0]) / 2, (start[1] + end[1]) / 2];
180
+ if (!pointInPolygon(midpoint, polygon))
181
+ return null;
182
+ const axis = normalizedDirection(start, end);
183
+ if (!axis)
184
+ return null;
185
+ const length = distance(start, end);
186
+ if (length < MIN_CLEAR_SPAN)
187
+ return null;
188
+ return {
189
+ kind: 'dimension',
190
+ start,
191
+ end,
192
+ offsetNormal: [-axis[1], axis[0]],
193
+ offsetDistance: 0,
194
+ extensionOvershoot: EXTENSION_OVERSHOOT,
195
+ text: formatConstructionLength(length, unit, profile, { metricNotation }),
196
+ stroke,
197
+ };
198
+ }
199
+ function pointInPolygon(point, polygon) {
200
+ let inside = false;
201
+ for (let index = 0, previousIndex = polygon.length - 1; index < polygon.length; previousIndex = index++) {
202
+ const current = polygon[index];
203
+ const previous = polygon[previousIndex];
204
+ const intersects = current[1] > point[1] !== previous[1] > point[1] &&
205
+ point[0] <
206
+ ((previous[0] - current[0]) * (point[1] - current[1])) / (previous[1] - current[1]) +
207
+ current[0];
208
+ if (intersects)
209
+ inside = !inside;
210
+ }
211
+ return inside;
212
+ }
213
+ function dimensionKey(dimension) {
214
+ const first = `${roundKey(dimension.start[0])},${roundKey(dimension.start[1])}`;
215
+ const second = `${roundKey(dimension.end[0])},${roundKey(dimension.end[1])}`;
216
+ return first < second ? `${first}|${second}` : `${second}|${first}`;
217
+ }
218
+ function roundKey(value) {
219
+ return Math.round(value / LINE_TOLERANCE);
220
+ }
221
+ function buildRoomToRoomClearDimensions(node, ctx, boundaryFaces, wallsById, unit, profile, metricNotation, stroke) {
222
+ if (node.clearDimensionPolicy !== 'finish-faces')
223
+ return [];
224
+ const neighboringRooms = ctx.siblings.filter((sibling) => sibling.type === 'zone' &&
225
+ sibling.id !== node.id &&
226
+ String(node.id) < String(sibling.id) &&
227
+ sibling.spaceRole === 'room' &&
228
+ sibling.clearDimensionPolicy === 'finish-faces' &&
229
+ sibling.enclosureStatus !== 'open' &&
230
+ sibling.autoFromWalls &&
231
+ sibling.parentId === node.parentId);
232
+ if (neighboringRooms.length === 0)
233
+ return [];
234
+ const dimensions = [];
235
+ const currentBoundaryByWallId = new Map(boundaryFaces.map((boundary) => [boundary.wallId, boundary]));
236
+ for (const neighbor of neighboringRooms) {
237
+ const sharedWallIds = neighbor.boundaryWallIds.filter((wallId) => currentBoundaryByWallId.has(wallId));
238
+ if (sharedWallIds.length === 0)
239
+ continue;
240
+ const neighborWalls = neighbor.boundaryWallIds.flatMap((id) => {
241
+ const resolved = ctx.resolve(id);
242
+ return resolved &&
243
+ typeof resolved === 'object' &&
244
+ 'type' in resolved &&
245
+ resolved.type === 'wall'
246
+ ? [resolved]
247
+ : [];
248
+ });
249
+ if (neighborWalls.length !== neighbor.boundaryWallIds.length)
250
+ continue;
251
+ const neighborWallIds = new Set(neighbor.boundaryWallIds);
252
+ const neighborSpace = detectSpacesForLevel(neighbor.parentId ?? '', neighborWalls).spaces.find((candidate) => candidate.wallIds.length === neighborWallIds.size &&
253
+ candidate.wallIds.every((id) => neighborWallIds.has(id)));
254
+ if (!neighborSpace)
255
+ continue;
256
+ const neighborBoundaryByWallId = new Map(neighborSpace.boundaryFaces.map((boundary) => [boundary.wallId, boundary]));
257
+ for (const wallId of sharedWallIds) {
258
+ const wall = wallsById.get(wallId);
259
+ const currentBoundary = currentBoundaryByWallId.get(wallId);
260
+ const neighborBoundary = neighborBoundaryByWallId.get(wallId);
261
+ if (!(wall && currentBoundary && neighborBoundary))
262
+ continue;
263
+ const currentLine = offsetBoundaryFace(currentBoundary, wall);
264
+ const neighborLine = offsetBoundaryFace(neighborBoundary, wall);
265
+ if (!(currentLine && neighborLine))
266
+ continue;
267
+ const dimension = dimensionAcrossSharedRoomWall(currentLine, neighborLine, unit, profile, metricNotation, stroke);
268
+ if (dimension)
269
+ dimensions.push(dimension);
270
+ }
271
+ }
272
+ return dimensions;
273
+ }
274
+ function dimensionAcrossSharedRoomWall(currentLine, neighborLine, unit, profile, metricNotation, stroke) {
275
+ const direction = normalizedDirection(currentLine.start, currentLine.end);
276
+ if (!direction)
277
+ return null;
278
+ const neighborDirection = normalizedDirection(neighborLine.start, neighborLine.end);
279
+ if (!neighborDirection || Math.abs(dot(direction, neighborDirection)) < 1 - ANGLE_TOLERANCE) {
280
+ return null;
281
+ }
282
+ const currentStart = dot(currentLine.start, direction);
283
+ const currentEnd = dot(currentLine.end, direction);
284
+ const neighborStart = dot(neighborLine.start, direction);
285
+ const neighborEnd = dot(neighborLine.end, direction);
286
+ const overlapStart = Math.max(Math.min(currentStart, currentEnd), Math.min(neighborStart, neighborEnd));
287
+ const overlapEnd = Math.min(Math.max(currentStart, currentEnd), Math.max(neighborStart, neighborEnd));
288
+ if (overlapEnd - overlapStart < MIN_CLEAR_SPAN)
289
+ return null;
290
+ const projection = (overlapStart + overlapEnd) / 2;
291
+ const start = projectPointToLineProjection(currentLine, direction, projection);
292
+ const end = projectPointToLineProjection(neighborLine, direction, projection);
293
+ const clear = distance(start, end);
294
+ if (clear < MIN_ROOM_TO_ROOM_SPAN)
295
+ return null;
296
+ const axis = normalizedDirection(start, end);
297
+ if (!axis)
298
+ return null;
299
+ return {
300
+ kind: 'dimension',
301
+ start,
302
+ end,
303
+ offsetNormal: [-axis[1], axis[0]],
304
+ offsetDistance: 0,
305
+ extensionOvershoot: EXTENSION_OVERSHOOT,
306
+ text: `R-R ${formatConstructionLength(clear, unit, profile, { metricNotation })}`,
307
+ stroke,
308
+ };
309
+ }
310
+ function projectPointToLineProjection(line, direction, projection) {
311
+ const originProjection = dot(line.start, direction);
312
+ return [
313
+ line.start[0] + direction[0] * (projection - originProjection),
314
+ line.start[1] + direction[1] * (projection - originProjection),
315
+ ];
316
+ }
317
+ function mergeCollinearFaces(lines) {
318
+ const merged = [];
319
+ for (const line of lines) {
320
+ const previous = merged[merged.length - 1];
321
+ if (previous && canMerge(previous, line))
322
+ previous.end = line.end;
323
+ else
324
+ merged.push({ ...line });
325
+ }
326
+ while (merged.length > 1) {
327
+ const first = merged[0];
328
+ const last = merged[merged.length - 1];
329
+ if (!canMerge(last, first))
330
+ break;
331
+ first.start = last.start;
332
+ merged.pop();
333
+ }
334
+ return merged;
335
+ }
336
+ function canMerge(first, second) {
337
+ const firstDirection = normalizedDirection(first.start, first.end);
338
+ const secondDirection = normalizedDirection(second.start, second.end);
339
+ if (!(firstDirection && secondDirection))
340
+ return false;
341
+ return (dot(firstDirection, secondDirection) > 1 - ANGLE_TOLERANCE &&
342
+ pointLineDistance(second.start, first) <= LINE_TOLERANCE);
343
+ }
344
+ function intersectLines(first, second) {
345
+ const firstDirection = [
346
+ first.end[0] - first.start[0],
347
+ first.end[1] - first.start[1],
348
+ ];
349
+ const secondDirection = [
350
+ second.end[0] - second.start[0],
351
+ second.end[1] - second.start[1],
352
+ ];
353
+ const denominator = cross(firstDirection, secondDirection);
354
+ if (Math.abs(denominator) <= LINE_TOLERANCE)
355
+ return null;
356
+ const delta = [second.start[0] - first.start[0], second.start[1] - first.start[1]];
357
+ const parameter = cross(delta, secondDirection) / denominator;
358
+ return [
359
+ first.start[0] + firstDirection[0] * parameter,
360
+ first.start[1] + firstDirection[1] * parameter,
361
+ ];
362
+ }
363
+ function dimensionAcrossOppositeFaces(firstStart, firstEnd, oppositeStart, oppositeEnd, position, unit, profile, metricNotation, stroke) {
364
+ const start = interpolate(firstStart, firstEnd, position);
365
+ const end = interpolate(oppositeStart, oppositeEnd, position);
366
+ const direction = normalizedDirection(start, end);
367
+ if (!direction)
368
+ return null;
369
+ const length = distance(start, end);
370
+ if (length < MIN_CLEAR_SPAN)
371
+ return null;
372
+ return {
373
+ kind: 'dimension',
374
+ start,
375
+ end,
376
+ offsetNormal: [-direction[1], direction[0]],
377
+ offsetDistance: 0,
378
+ extensionOvershoot: EXTENSION_OVERSHOOT,
379
+ text: formatConstructionLength(length, unit, profile, { metricNotation }),
380
+ stroke,
381
+ };
382
+ }
383
+ function normalizedDirection(start, end) {
384
+ const dx = end[0] - start[0];
385
+ const dy = end[1] - start[1];
386
+ const length = Math.hypot(dx, dy);
387
+ return length <= LINE_TOLERANCE ? null : [dx / length, dy / length];
388
+ }
389
+ function pointLineDistance(point, line) {
390
+ const direction = normalizedDirection(line.start, line.end);
391
+ if (!direction)
392
+ return Number.POSITIVE_INFINITY;
393
+ return Math.abs(cross(direction, [point[0] - line.start[0], point[1] - line.start[1]]));
394
+ }
395
+ function interpolate(start, end, t) {
396
+ return [start[0] + (end[0] - start[0]) * t, start[1] + (end[1] - start[1]) * t];
397
+ }
398
+ function distance(first, second) {
399
+ return Math.hypot(second[0] - first[0], second[1] - first[1]);
400
+ }
401
+ function dot(first, second) {
402
+ return first[0] * second[0] + first[1] * second[1];
403
+ }
404
+ function cross(first, second) {
405
+ return first[0] * second[1] - first[1] * second[0];
406
+ }