@pascal-app/nodes 1.0.3 → 1.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (708) hide show
  1. package/dist/block/definition.d.ts.map +1 -1
  2. package/dist/block/definition.js +18 -3
  3. package/dist/block/floorplan.d.ts +11 -1
  4. package/dist/block/floorplan.d.ts.map +1 -1
  5. package/dist/block/floorplan.js +81 -13
  6. package/dist/block/geometry.d.ts +2 -2
  7. package/dist/block/geometry.d.ts.map +1 -1
  8. package/dist/block/geometry.js +39 -24
  9. package/dist/block/hosted-edit.d.ts.map +1 -1
  10. package/dist/block/hosted-edit.js +25 -0
  11. package/dist/block/material-slots.d.ts +1 -3
  12. package/dist/block/material-slots.d.ts.map +1 -1
  13. package/dist/block/material-slots.js +1 -11
  14. package/dist/block/paint.d.ts.map +1 -1
  15. package/dist/block/paint.js +4 -10
  16. package/dist/block/panel.d.ts.map +1 -1
  17. package/dist/block/panel.js +8 -3
  18. package/dist/block/selection.d.ts.map +1 -1
  19. package/dist/block/selection.js +2 -2
  20. package/dist/box-vent/definition.d.ts.map +1 -1
  21. package/dist/box-vent/definition.js +2 -5
  22. package/dist/box-vent/panel.d.ts.map +1 -1
  23. package/dist/box-vent/panel.js +5 -28
  24. package/dist/cabinet/countertop-layout.d.ts +13 -2
  25. package/dist/cabinet/countertop-layout.d.ts.map +1 -1
  26. package/dist/cabinet/definition.d.ts.map +1 -1
  27. package/dist/cabinet/definition.js +1 -2
  28. package/dist/cabinet/floorplan.d.ts.map +1 -1
  29. package/dist/cabinet/floorplan.js +125 -28
  30. package/dist/cabinet/geometry/shared.d.ts +1 -2
  31. package/dist/cabinet/geometry/shared.d.ts.map +1 -1
  32. package/dist/cabinet/geometry/shared.js +1 -2
  33. package/dist/cabinet/run-layout.d.ts.map +1 -1
  34. package/dist/cabinet/run-layout.js +8 -5
  35. package/dist/cabinet/run-ops.d.ts +13 -2
  36. package/dist/cabinet/run-ops.d.ts.map +1 -1
  37. package/dist/cabinet/tool.d.ts.map +1 -1
  38. package/dist/cabinet/tool.js +22 -24
  39. package/dist/cabinet/wall-snap.d.ts.map +1 -1
  40. package/dist/cabinet/wall-snap.js +8 -8
  41. package/dist/ceiling/boundary-editor.d.ts.map +1 -1
  42. package/dist/ceiling/boundary-editor.js +5 -3
  43. package/dist/ceiling/definition.d.ts +4 -4
  44. package/dist/ceiling/definition.d.ts.map +1 -1
  45. package/dist/ceiling/definition.js +15 -15
  46. package/dist/ceiling/floorplan-affordances.d.ts +84 -4
  47. package/dist/ceiling/floorplan-affordances.d.ts.map +1 -1
  48. package/dist/ceiling/floorplan-affordances.js +0 -1
  49. package/dist/ceiling/floorplan-move.d.ts.map +1 -1
  50. package/dist/ceiling/floorplan-move.js +0 -1
  51. package/dist/ceiling/floorplan.d.ts +1 -1
  52. package/dist/ceiling/floorplan.d.ts.map +1 -1
  53. package/dist/ceiling/floorplan.js +2 -1
  54. package/dist/ceiling/height-bounds.d.ts +19 -0
  55. package/dist/ceiling/height-bounds.d.ts.map +1 -0
  56. package/dist/ceiling/height-bounds.js +24 -0
  57. package/dist/ceiling/hole-editor.d.ts.map +1 -1
  58. package/dist/ceiling/hole-editor.js +3 -4
  59. package/dist/ceiling/materials.d.ts +1 -1
  60. package/dist/ceiling/materials.d.ts.map +1 -1
  61. package/dist/ceiling/materials.js +10 -3
  62. package/dist/ceiling/paint.d.ts +2 -8
  63. package/dist/ceiling/paint.d.ts.map +1 -1
  64. package/dist/ceiling/paint.js +121 -24
  65. package/dist/ceiling/panel.d.ts.map +1 -1
  66. package/dist/ceiling/panel.js +40 -23
  67. package/dist/ceiling/renderer.d.ts.map +1 -1
  68. package/dist/ceiling/renderer.js +41 -5
  69. package/dist/chimney/move-tool.d.ts.map +1 -1
  70. package/dist/chimney/move-tool.js +8 -2
  71. package/dist/chimney/paint.d.ts.map +1 -1
  72. package/dist/chimney/paint.js +3 -10
  73. package/dist/column/definition.d.ts.map +1 -1
  74. package/dist/column/definition.js +24 -2
  75. package/dist/column/floorplan-affordances.d.ts.map +1 -1
  76. package/dist/column/floorplan-affordances.js +5 -0
  77. package/dist/column/floorplan.d.ts +1 -1
  78. package/dist/column/floorplan.d.ts.map +1 -1
  79. package/dist/column/floorplan.js +47 -2
  80. package/dist/column/hosted-resize.d.ts +101 -2
  81. package/dist/column/hosted-resize.d.ts.map +1 -1
  82. package/dist/column/panel.d.ts.map +1 -1
  83. package/dist/column/panel.js +147 -146
  84. package/dist/column/renderer.d.ts.map +1 -1
  85. package/dist/column/renderer.js +6 -4
  86. package/dist/column/surface.d.ts.map +1 -1
  87. package/dist/column/surface.js +7 -0
  88. package/dist/construction-dimension/floorplan.js +7 -3
  89. package/dist/cupola/definition.d.ts.map +1 -1
  90. package/dist/cupola/definition.js +2 -8
  91. package/dist/cupola/panel.d.ts.map +1 -1
  92. package/dist/cupola/panel.js +5 -23
  93. package/dist/door/definition.d.ts.map +1 -1
  94. package/dist/door/definition.js +12 -3
  95. package/dist/door/door-math.d.ts +5 -10
  96. package/dist/door/door-math.d.ts.map +1 -1
  97. package/dist/door/door-math.js +14 -15
  98. package/dist/door/floorplan-move.d.ts.map +1 -1
  99. package/dist/door/floorplan-move.js +3 -1
  100. package/dist/door/floorplan.d.ts.map +1 -1
  101. package/dist/door/floorplan.js +55 -21
  102. package/dist/door/mechanism.d.ts +4 -0
  103. package/dist/door/mechanism.d.ts.map +1 -0
  104. package/dist/door/mechanism.js +24 -0
  105. package/dist/door/move-tool.d.ts.map +1 -1
  106. package/dist/door/move-tool.js +72 -48
  107. package/dist/door/paint.d.ts.map +1 -1
  108. package/dist/door/paint.js +3 -0
  109. package/dist/door/panel.d.ts.map +1 -1
  110. package/dist/door/panel.js +34 -259
  111. package/dist/door/placement.d.ts +45 -0
  112. package/dist/door/placement.d.ts.map +1 -0
  113. package/dist/door/placement.js +51 -0
  114. package/dist/door/preview.d.ts.map +1 -1
  115. package/dist/door/preview.js +2 -0
  116. package/dist/door/renderer.d.ts.map +1 -1
  117. package/dist/door/renderer.js +3 -2
  118. package/dist/door/tool.d.ts.map +1 -1
  119. package/dist/door/tool.js +92 -21
  120. package/dist/dormer/csg-geometry.d.ts.map +1 -1
  121. package/dist/dormer/csg-geometry.js +2 -0
  122. package/dist/dormer/paint.d.ts.map +1 -1
  123. package/dist/dormer/paint.js +2 -5
  124. package/dist/dormer/panel.d.ts.map +1 -1
  125. package/dist/dormer/panel.js +4 -14
  126. package/dist/downspout/definition.d.ts.map +1 -1
  127. package/dist/downspout/definition.js +2 -2
  128. package/dist/duct-fitting/definition.d.ts.map +1 -1
  129. package/dist/duct-fitting/definition.js +2 -1
  130. package/dist/duct-fitting/geometry.d.ts.map +1 -1
  131. package/dist/duct-fitting/geometry.js +1 -1
  132. package/dist/duct-fitting/move-tool.d.ts.map +1 -1
  133. package/dist/duct-fitting/move-tool.js +8 -2
  134. package/dist/duct-segment/definition.d.ts.map +1 -1
  135. package/dist/duct-segment/definition.js +2 -2
  136. package/dist/duct-segment/geometry.d.ts.map +1 -1
  137. package/dist/duct-segment/geometry.js +1 -1
  138. package/dist/duct-segment/move-tool.d.ts.map +1 -1
  139. package/dist/duct-segment/move-tool.js +8 -2
  140. package/dist/elevator/definition.d.ts.map +1 -1
  141. package/dist/elevator/definition.js +1 -2
  142. package/dist/elevator/panel.d.ts.map +1 -1
  143. package/dist/elevator/panel.js +5 -27
  144. package/dist/elevator/parametrics.js +1 -1
  145. package/dist/elevator/renderer.d.ts.map +1 -1
  146. package/dist/elevator/renderer.js +3 -4
  147. package/dist/eyebrow-vent/definition.d.ts.map +1 -1
  148. package/dist/eyebrow-vent/definition.js +2 -5
  149. package/dist/eyebrow-vent/paint.d.ts.map +1 -1
  150. package/dist/eyebrow-vent/paint.js +3 -6
  151. package/dist/eyebrow-vent/panel.d.ts.map +1 -1
  152. package/dist/eyebrow-vent/panel.js +5 -23
  153. package/dist/fence/actions/move-endpoint.d.ts +1 -1
  154. package/dist/fence/actions/move-endpoint.d.ts.map +1 -1
  155. package/dist/fence/actions/move-endpoint.js +2 -1
  156. package/dist/fence/definition.d.ts +2 -1
  157. package/dist/fence/definition.d.ts.map +1 -1
  158. package/dist/fence/definition.js +83 -28
  159. package/dist/fence/drafting.d.ts +36 -0
  160. package/dist/fence/drafting.d.ts.map +1 -0
  161. package/dist/fence/drafting.js +210 -0
  162. package/dist/fence/feature-tool.d.ts +4 -0
  163. package/dist/fence/feature-tool.d.ts.map +1 -0
  164. package/dist/fence/feature-tool.js +140 -0
  165. package/dist/fence/features.d.ts +2 -0
  166. package/dist/fence/features.d.ts.map +1 -0
  167. package/dist/fence/features.js +12 -0
  168. package/dist/fence/floorplan-affordances.d.ts.map +1 -1
  169. package/dist/fence/floorplan-affordances.js +2 -1
  170. package/dist/fence/floorplan.d.ts +2 -3
  171. package/dist/fence/floorplan.d.ts.map +1 -1
  172. package/dist/fence/floorplan.js +131 -71
  173. package/dist/fence/geometry-parts.d.ts +50 -0
  174. package/dist/fence/geometry-parts.d.ts.map +1 -0
  175. package/dist/fence/geometry-parts.js +1144 -0
  176. package/dist/fence/geometry.d.ts +2 -3
  177. package/dist/fence/geometry.d.ts.map +1 -1
  178. package/dist/fence/geometry.js +84 -7
  179. package/dist/fence/index.d.ts +1 -0
  180. package/dist/fence/index.d.ts.map +1 -1
  181. package/dist/fence/index.js +1 -0
  182. package/dist/fence/inspector-editors.d.ts +15 -0
  183. package/dist/fence/inspector-editors.d.ts.map +1 -1
  184. package/dist/fence/inspector-editors.js +128 -3
  185. package/dist/fence/lift.d.ts.map +1 -1
  186. package/dist/fence/lift.js +5 -2
  187. package/dist/fence/move-tool.js +2 -1
  188. package/dist/fence/panel-model.d.ts +4 -0
  189. package/dist/fence/panel-model.d.ts.map +1 -0
  190. package/dist/fence/panel-model.js +12 -0
  191. package/dist/fence/parametrics.d.ts +0 -12
  192. package/dist/fence/parametrics.d.ts.map +1 -1
  193. package/dist/fence/parametrics.js +185 -18
  194. package/dist/fence/system.d.ts.map +1 -1
  195. package/dist/fence/system.js +141 -31
  196. package/dist/fence/tool.d.ts.map +1 -1
  197. package/dist/fence/tool.js +256 -47
  198. package/dist/fence-feature/actions.d.ts +7 -0
  199. package/dist/fence-feature/actions.d.ts.map +1 -0
  200. package/dist/fence-feature/actions.js +26 -0
  201. package/dist/fence-feature/definition.d.ts +4 -0
  202. package/dist/fence-feature/definition.d.ts.map +1 -0
  203. package/dist/fence-feature/definition.js +112 -0
  204. package/dist/fence-feature/floorplan-affordances.d.ts +3 -0
  205. package/dist/fence-feature/floorplan-affordances.d.ts.map +1 -0
  206. package/dist/fence-feature/floorplan-affordances.js +37 -0
  207. package/dist/fence-feature/floorplan.d.ts +4 -0
  208. package/dist/fence-feature/floorplan.d.ts.map +1 -0
  209. package/dist/fence-feature/floorplan.js +120 -0
  210. package/dist/fence-feature/geometry.d.ts +5 -0
  211. package/dist/fence-feature/geometry.d.ts.map +1 -0
  212. package/dist/fence-feature/geometry.js +43 -0
  213. package/dist/fence-feature/handles.d.ts +5 -0
  214. package/dist/fence-feature/handles.d.ts.map +1 -0
  215. package/dist/fence-feature/handles.js +84 -0
  216. package/dist/fence-feature/inspector.d.ts +6 -0
  217. package/dist/fence-feature/inspector.d.ts.map +1 -0
  218. package/dist/fence-feature/inspector.js +214 -0
  219. package/dist/fence-feature/interaction.d.ts +3 -0
  220. package/dist/fence-feature/interaction.d.ts.map +1 -0
  221. package/dist/fence-feature/interaction.js +41 -0
  222. package/dist/fence-feature/move-session.d.ts +9 -0
  223. package/dist/fence-feature/move-session.d.ts.map +1 -0
  224. package/dist/fence-feature/move-session.js +48 -0
  225. package/dist/fence-feature/move-tool.d.ts +5 -0
  226. package/dist/fence-feature/move-tool.d.ts.map +1 -0
  227. package/dist/fence-feature/move-tool.js +58 -0
  228. package/dist/fence-feature/pick-target.d.ts +7 -0
  229. package/dist/fence-feature/pick-target.d.ts.map +1 -0
  230. package/dist/fence-feature/pick-target.js +52 -0
  231. package/dist/floor-opening/definition.d.ts +3 -0
  232. package/dist/floor-opening/definition.d.ts.map +1 -0
  233. package/dist/floor-opening/definition.js +41 -0
  234. package/dist/floor-opening/floorplan.d.ts +156 -0
  235. package/dist/floor-opening/floorplan.d.ts.map +1 -0
  236. package/dist/floor-opening/floorplan.js +63 -0
  237. package/dist/gutter/definition.d.ts.map +1 -1
  238. package/dist/gutter/definition.js +2 -2
  239. package/dist/imported-mesh/definition.d.ts.map +1 -1
  240. package/dist/imported-mesh/definition.js +2 -0
  241. package/dist/imported-mesh/geometry.d.ts +1 -1
  242. package/dist/imported-mesh/geometry.d.ts.map +1 -1
  243. package/dist/imported-mesh/geometry.js +40 -12
  244. package/dist/index.d.ts +13 -2
  245. package/dist/index.d.ts.map +1 -1
  246. package/dist/index.js +20 -2
  247. package/dist/item/authored-face-host.d.ts +10 -0
  248. package/dist/item/authored-face-host.d.ts.map +1 -0
  249. package/dist/item/authored-face-host.js +87 -0
  250. package/dist/item/authored-params.d.ts +15 -0
  251. package/dist/item/authored-params.d.ts.map +1 -0
  252. package/dist/item/authored-params.js +72 -0
  253. package/dist/item/definition.d.ts +2 -2
  254. package/dist/item/definition.d.ts.map +1 -1
  255. package/dist/item/definition.js +33 -4
  256. package/dist/item/floorplan.d.ts +1 -1
  257. package/dist/item/floorplan.d.ts.map +1 -1
  258. package/dist/item/floorplan.js +35 -5
  259. package/dist/item/index.d.ts +1 -0
  260. package/dist/item/index.d.ts.map +1 -1
  261. package/dist/item/index.js +1 -0
  262. package/dist/item/model-loader.d.ts +2 -0
  263. package/dist/item/model-loader.d.ts.map +1 -1
  264. package/dist/item/model-loader.js +55 -23
  265. package/dist/item/move-tool.js +4 -4
  266. package/dist/item/paint.d.ts.map +1 -1
  267. package/dist/item/paint.js +5 -24
  268. package/dist/item/panel.d.ts +1 -3
  269. package/dist/item/panel.d.ts.map +1 -1
  270. package/dist/item/panel.js +20 -24
  271. package/dist/item/placement-notice.d.ts +14 -0
  272. package/dist/item/placement-notice.d.ts.map +1 -0
  273. package/dist/item/placement-notice.js +38 -0
  274. package/dist/item/plan-symbols.d.ts +67 -0
  275. package/dist/item/plan-symbols.d.ts.map +1 -0
  276. package/dist/item/plan-symbols.js +407 -0
  277. package/dist/item/renderer.d.ts +10 -0
  278. package/dist/item/renderer.d.ts.map +1 -1
  279. package/dist/item/renderer.js +64 -38
  280. package/dist/item/script-param-defaults.d.ts +12 -0
  281. package/dist/item/script-param-defaults.d.ts.map +1 -0
  282. package/dist/item/script-param-defaults.js +34 -0
  283. package/dist/lean-to-extension/definition.d.ts.map +1 -1
  284. package/dist/lean-to-extension/definition.js +1 -2
  285. package/dist/lean-to-extension/geometry.d.ts.map +1 -1
  286. package/dist/lean-to-extension/geometry.js +1 -1
  287. package/dist/lean-to-extension/layout.d.ts.map +1 -1
  288. package/dist/lean-to-extension/layout.js +2 -3
  289. package/dist/lean-to-extension/placement-validation.d.ts.map +1 -1
  290. package/dist/lean-to-extension/placement-validation.js +5 -5
  291. package/dist/lean-to-extension/tool.d.ts.map +1 -1
  292. package/dist/lean-to-extension/tool.js +5 -5
  293. package/dist/lineset/move-tool.d.ts.map +1 -1
  294. package/dist/lineset/move-tool.js +8 -2
  295. package/dist/liquid-line/move-tool.d.ts.map +1 -1
  296. package/dist/liquid-line/move-tool.js +8 -2
  297. package/dist/measurement/definition.js +1 -1
  298. package/dist/pipe-fitting/move-tool.d.ts.map +1 -1
  299. package/dist/pipe-fitting/move-tool.js +8 -2
  300. package/dist/pipe-segment/move-tool.d.ts.map +1 -1
  301. package/dist/pipe-segment/move-tool.js +8 -2
  302. package/dist/procedural-item/animation.d.ts +8 -0
  303. package/dist/procedural-item/animation.d.ts.map +1 -0
  304. package/dist/procedural-item/animation.js +116 -0
  305. package/dist/procedural-item/definition.d.ts.map +1 -1
  306. package/dist/procedural-item/definition.js +74 -8
  307. package/dist/procedural-item/geometry.d.ts +5 -1
  308. package/dist/procedural-item/geometry.d.ts.map +1 -1
  309. package/dist/procedural-item/geometry.js +239 -15
  310. package/dist/procedural-item/renderer.d.ts.map +1 -1
  311. package/dist/procedural-item/renderer.js +272 -23
  312. package/dist/ridge-vent/panel.d.ts.map +1 -1
  313. package/dist/ridge-vent/panel.js +5 -23
  314. package/dist/ridge-vent/renderer.d.ts.map +1 -1
  315. package/dist/ridge-vent/renderer.js +9 -8
  316. package/dist/roof/definition.d.ts.map +1 -1
  317. package/dist/roof/definition.js +4 -1
  318. package/dist/roof/floorplan.d.ts +8 -0
  319. package/dist/roof/floorplan.d.ts.map +1 -1
  320. package/dist/roof/floorplan.js +194 -18
  321. package/dist/roof/panel-model.d.ts.map +1 -1
  322. package/dist/roof/panel-model.js +10 -6
  323. package/dist/roof/panel.d.ts.map +1 -1
  324. package/dist/roof/panel.js +3 -10
  325. package/dist/roof/renderer.d.ts.map +1 -1
  326. package/dist/roof/renderer.js +5 -2
  327. package/dist/roof-segment/panel.d.ts.map +1 -1
  328. package/dist/roof-segment/panel.js +5 -24
  329. package/dist/roof-segment/renderer.d.ts.map +1 -1
  330. package/dist/roof-segment/renderer.js +17 -8
  331. package/dist/separator/definition.d.ts +3 -0
  332. package/dist/separator/definition.d.ts.map +1 -0
  333. package/dist/separator/definition.js +39 -0
  334. package/dist/separator/renderer.d.ts +5 -0
  335. package/dist/separator/renderer.d.ts.map +1 -0
  336. package/dist/separator/renderer.js +36 -0
  337. package/dist/shared/duct-body-paint.d.ts +0 -4
  338. package/dist/shared/duct-body-paint.d.ts.map +1 -1
  339. package/dist/shared/duct-body-paint.js +1 -5
  340. package/dist/shared/item-interaction-actions.d.ts +6 -0
  341. package/dist/shared/item-interaction-actions.d.ts.map +1 -0
  342. package/dist/shared/item-interaction-actions.js +27 -0
  343. package/dist/shared/item-interactions.d.ts +9 -0
  344. package/dist/shared/item-interactions.d.ts.map +1 -0
  345. package/dist/shared/item-interactions.js +74 -0
  346. package/dist/shared/item-light-placement.d.ts +2 -0
  347. package/dist/shared/item-light-placement.d.ts.map +1 -0
  348. package/dist/shared/item-light-placement.js +3 -0
  349. package/dist/shared/move-roof-tool.js +2 -1
  350. package/dist/shared/node-batch/batchable.d.ts +12 -0
  351. package/dist/shared/node-batch/batchable.d.ts.map +1 -0
  352. package/dist/shared/node-batch/batchable.js +41 -0
  353. package/dist/shared/node-batch/candidates.d.ts +7 -5
  354. package/dist/shared/node-batch/candidates.d.ts.map +1 -1
  355. package/dist/shared/node-batch/candidates.js +43 -59
  356. package/dist/shared/node-batch/release.d.ts +8 -0
  357. package/dist/shared/node-batch/release.d.ts.map +1 -0
  358. package/dist/shared/node-batch/release.js +16 -0
  359. package/dist/shared/node-batch/system.d.ts.map +1 -1
  360. package/dist/shared/node-batch/system.js +17 -12
  361. package/dist/shared/node-batch/types.d.ts +4 -1
  362. package/dist/shared/node-batch/types.d.ts.map +1 -1
  363. package/dist/shared/opening-documentation.d.ts +13 -1
  364. package/dist/shared/opening-documentation.d.ts.map +1 -1
  365. package/dist/shared/opening-documentation.js +245 -59
  366. package/dist/shared/opening-guides-runtime.d.ts.map +1 -1
  367. package/dist/shared/opening-guides-runtime.js +17 -14
  368. package/dist/shared/opening-placement-dimensions.d.ts.map +1 -1
  369. package/dist/shared/opening-placement-dimensions.js +3 -3
  370. package/dist/shared/opening-plane-offset.d.ts +23 -0
  371. package/dist/shared/opening-plane-offset.d.ts.map +1 -0
  372. package/dist/shared/opening-plane-offset.js +24 -0
  373. package/dist/shared/polygon-centroid-move.d.ts.map +1 -1
  374. package/dist/shared/polygon-centroid-move.js +4 -1
  375. package/dist/shared/polygon-vertex-affordance.d.ts.map +1 -1
  376. package/dist/shared/polygon-vertex-affordance.js +19 -15
  377. package/dist/shared/run-hangers.d.ts.map +1 -1
  378. package/dist/shared/run-hangers.js +5 -4
  379. package/dist/shared/scripted-opening-handles.d.ts +18 -0
  380. package/dist/shared/scripted-opening-handles.d.ts.map +1 -0
  381. package/dist/shared/scripted-opening-handles.js +53 -0
  382. package/dist/shared/scripted-opening.d.ts +25 -0
  383. package/dist/shared/scripted-opening.d.ts.map +1 -0
  384. package/dist/shared/scripted-opening.js +72 -0
  385. package/dist/shared/slot-paint.d.ts +14 -2
  386. package/dist/shared/slot-paint.d.ts.map +1 -1
  387. package/dist/shared/slot-paint.js +29 -29
  388. package/dist/shared/surface-paint.d.ts.map +1 -1
  389. package/dist/shared/surface-paint.js +2 -5
  390. package/dist/shared/swap-preview-material.d.ts +11 -0
  391. package/dist/shared/swap-preview-material.d.ts.map +1 -0
  392. package/dist/shared/swap-preview-material.js +16 -0
  393. package/dist/shared/system-checks.d.ts.map +1 -1
  394. package/dist/shared/system-checks.js +5 -3
  395. package/dist/shared/wall-attach-target.d.ts +3 -10
  396. package/dist/shared/wall-attach-target.d.ts.map +1 -1
  397. package/dist/shared/wall-attach-target.js +3 -63
  398. package/dist/shared/wall-opening-ceiling.d.ts +5 -15
  399. package/dist/shared/wall-opening-ceiling.d.ts.map +1 -1
  400. package/dist/shared/wall-opening-ceiling.js +10 -18
  401. package/dist/shelf/definition.d.ts.map +1 -1
  402. package/dist/shelf/definition.js +1 -1
  403. package/dist/shelf/geometry.d.ts.map +1 -1
  404. package/dist/shelf/geometry.js +1 -2
  405. package/dist/shelf/paint.d.ts.map +1 -1
  406. package/dist/shelf/paint.js +4 -10
  407. package/dist/site/line-ribbon.d.ts +31 -0
  408. package/dist/site/line-ribbon.d.ts.map +1 -0
  409. package/dist/site/line-ribbon.js +117 -0
  410. package/dist/site/lot-mask.d.ts +18 -0
  411. package/dist/site/lot-mask.d.ts.map +1 -0
  412. package/dist/site/lot-mask.js +35 -0
  413. package/dist/site/panel.d.ts +10 -0
  414. package/dist/site/panel.d.ts.map +1 -0
  415. package/dist/site/panel.js +155 -0
  416. package/dist/site/parametrics.d.ts +7 -0
  417. package/dist/site/parametrics.d.ts.map +1 -1
  418. package/dist/site/parametrics.js +8 -0
  419. package/dist/site/recessed-slab-ground-holes.d.ts.map +1 -1
  420. package/dist/site/recessed-slab-ground-holes.js +5 -2
  421. package/dist/site/renderer.d.ts.map +1 -1
  422. package/dist/site/renderer.js +150 -19
  423. package/dist/site/setbacks.d.ts +33 -0
  424. package/dist/site/setbacks.d.ts.map +1 -0
  425. package/dist/site/setbacks.js +204 -0
  426. package/dist/site/terrain-geometry.d.ts +28 -1
  427. package/dist/site/terrain-geometry.d.ts.map +1 -1
  428. package/dist/site/terrain-geometry.js +78 -4
  429. package/dist/site/terrain-holes.d.ts +15 -0
  430. package/dist/site/terrain-holes.d.ts.map +1 -0
  431. package/dist/site/terrain-holes.js +74 -0
  432. package/dist/site/terrain-mesh.d.ts +9 -2
  433. package/dist/site/terrain-mesh.d.ts.map +1 -1
  434. package/dist/site/terrain-mesh.js +36 -9
  435. package/dist/site/terrain-renderer.d.ts +9 -2
  436. package/dist/site/terrain-renderer.d.ts.map +1 -1
  437. package/dist/site/terrain-renderer.js +14 -4
  438. package/dist/slab/boundary-editor.d.ts +1 -1
  439. package/dist/slab/boundary-editor.d.ts.map +1 -1
  440. package/dist/slab/boundary-editor.js +13 -13
  441. package/dist/slab/definition.d.ts.map +1 -1
  442. package/dist/slab/definition.js +19 -3
  443. package/dist/slab/dependency-tracker.d.ts.map +1 -1
  444. package/dist/slab/dependency-tracker.js +67 -7
  445. package/dist/slab/elevation-limit.d.ts.map +1 -1
  446. package/dist/slab/elevation-limit.js +2 -2
  447. package/dist/slab/floorplan-affordances.d.ts +176 -4
  448. package/dist/slab/floorplan-affordances.d.ts.map +1 -1
  449. package/dist/slab/floorplan-affordances.js +0 -1
  450. package/dist/slab/floorplan-move.d.ts.map +1 -1
  451. package/dist/slab/floorplan-move.js +3 -4
  452. package/dist/slab/floorplan.d.ts +7 -0
  453. package/dist/slab/floorplan.d.ts.map +1 -1
  454. package/dist/slab/floorplan.js +22 -5
  455. package/dist/slab/geometry.d.ts.map +1 -1
  456. package/dist/slab/geometry.js +186 -76
  457. package/dist/slab/move-tool.js +7 -6
  458. package/dist/slab/paint.d.ts +18 -5
  459. package/dist/slab/paint.d.ts.map +1 -1
  460. package/dist/slab/paint.js +458 -9
  461. package/dist/slab/panel.d.ts.map +1 -1
  462. package/dist/slab/panel.js +28 -9
  463. package/dist/slab/placement-ownership.d.ts +2 -1
  464. package/dist/slab/placement-ownership.d.ts.map +1 -1
  465. package/dist/slab/placement-ownership.js +2 -2
  466. package/dist/slab/surface-split.d.ts +24 -0
  467. package/dist/slab/surface-split.d.ts.map +1 -0
  468. package/dist/slab/surface-split.js +389 -0
  469. package/dist/slab/tool.d.ts.map +1 -1
  470. package/dist/slab/tool.js +3 -3
  471. package/dist/stair/baluster-geometry.d.ts +21 -0
  472. package/dist/stair/baluster-geometry.d.ts.map +1 -0
  473. package/dist/stair/baluster-geometry.js +74 -0
  474. package/dist/stair/baluster-guard.d.ts +50 -0
  475. package/dist/stair/baluster-guard.d.ts.map +1 -0
  476. package/dist/stair/baluster-guard.js +71 -0
  477. package/dist/stair/boards-guard.d.ts +37 -0
  478. package/dist/stair/boards-guard.d.ts.map +1 -0
  479. package/dist/stair/boards-guard.js +61 -0
  480. package/dist/stair/cable-guard.d.ts +39 -0
  481. package/dist/stair/cable-guard.d.ts.map +1 -0
  482. package/dist/stair/cable-guard.js +105 -0
  483. package/dist/stair/construction-controls.d.ts +15 -0
  484. package/dist/stair/construction-controls.d.ts.map +1 -0
  485. package/dist/stair/construction-controls.js +29 -0
  486. package/dist/stair/continuous-railings.d.ts +10 -0
  487. package/dist/stair/continuous-railings.d.ts.map +1 -0
  488. package/dist/stair/continuous-railings.js +159 -0
  489. package/dist/stair/definition.d.ts.map +1 -1
  490. package/dist/stair/definition.js +16 -37
  491. package/dist/stair/documentation.d.ts +1 -1
  492. package/dist/stair/documentation.d.ts.map +1 -1
  493. package/dist/stair/documentation.js +10 -17
  494. package/dist/stair/floorplan-affordances.d.ts.map +1 -1
  495. package/dist/stair/floorplan-affordances.js +9 -25
  496. package/dist/stair/floorplan.d.ts +1 -23
  497. package/dist/stair/floorplan.d.ts.map +1 -1
  498. package/dist/stair/floorplan.js +102 -86
  499. package/dist/stair/glass-guard.d.ts +72 -0
  500. package/dist/stair/glass-guard.d.ts.map +1 -0
  501. package/dist/stair/glass-guard.js +167 -0
  502. package/dist/stair/guard-path.d.ts +119 -0
  503. package/dist/stair/guard-path.d.ts.map +1 -0
  504. package/dist/stair/guard-path.js +208 -0
  505. package/dist/stair/materials.d.ts +11 -0
  506. package/dist/stair/materials.d.ts.map +1 -0
  507. package/dist/stair/materials.js +51 -0
  508. package/dist/stair/metal-guard.d.ts +38 -0
  509. package/dist/stair/metal-guard.d.ts.map +1 -0
  510. package/dist/stair/metal-guard.js +79 -0
  511. package/dist/stair/paint.d.ts +32 -0
  512. package/dist/stair/paint.d.ts.map +1 -1
  513. package/dist/stair/paint.js +75 -36
  514. package/dist/stair/panel.d.ts.map +1 -1
  515. package/dist/stair/panel.js +154 -17
  516. package/dist/stair/parametrics.d.ts +1 -1
  517. package/dist/stair/parametrics.d.ts.map +1 -1
  518. package/dist/stair/parametrics.js +32 -15
  519. package/dist/stair/plan-entry.d.ts +31 -0
  520. package/dist/stair/plan-entry.d.ts.map +1 -0
  521. package/dist/stair/plan-entry.js +325 -0
  522. package/dist/stair/post-and-rail-guard.d.ts +31 -0
  523. package/dist/stair/post-and-rail-guard.d.ts.map +1 -0
  524. package/dist/stair/post-and-rail-guard.js +63 -0
  525. package/dist/stair/railing-controls.d.ts +9 -0
  526. package/dist/stair/railing-controls.d.ts.map +1 -0
  527. package/dist/stair/railing-controls.js +49 -0
  528. package/dist/stair/renderer.d.ts.map +1 -1
  529. package/dist/stair/renderer.js +259 -259
  530. package/dist/stair/use-stair-render-data.d.ts +317 -0
  531. package/dist/stair/use-stair-render-data.d.ts.map +1 -0
  532. package/dist/stair/use-stair-render-data.js +73 -0
  533. package/dist/stair-segment/definition.d.ts.map +1 -1
  534. package/dist/stair-segment/definition.js +51 -10
  535. package/dist/stair-segment/panel.d.ts.map +1 -1
  536. package/dist/stair-segment/panel.js +36 -42
  537. package/dist/stair-segment/parametrics.d.ts +1 -1
  538. package/dist/stair-segment/parametrics.d.ts.map +1 -1
  539. package/dist/stair-segment/parametrics.js +21 -8
  540. package/dist/stair-segment/renderer.d.ts.map +1 -1
  541. package/dist/stair-segment/renderer.js +16 -28
  542. package/dist/turbine-vent/definition.d.ts.map +1 -1
  543. package/dist/turbine-vent/definition.js +2 -5
  544. package/dist/turbine-vent/paint.d.ts.map +1 -1
  545. package/dist/turbine-vent/paint.js +2 -5
  546. package/dist/turbine-vent/panel.d.ts.map +1 -1
  547. package/dist/turbine-vent/panel.js +5 -23
  548. package/dist/unit/unit-panel.d.ts.map +1 -1
  549. package/dist/unit/unit-panel.js +6 -1
  550. package/dist/wall/actions.d.ts.map +1 -1
  551. package/dist/wall/actions.js +7 -2
  552. package/dist/wall/construction-dimensions.js +8 -5
  553. package/dist/wall/contextual-dimensions.js +4 -4
  554. package/dist/wall/curtain-wall-materials.d.ts +1 -1
  555. package/dist/wall/curtain-wall-materials.d.ts.map +1 -1
  556. package/dist/wall/curtain-wall-materials.js +2 -2
  557. package/dist/wall/curve-tool.d.ts.map +1 -1
  558. package/dist/wall/curve-tool.js +4 -0
  559. package/dist/wall/definition.d.ts.map +1 -1
  560. package/dist/wall/definition.js +41 -17
  561. package/dist/wall/floorplan-move.d.ts +1 -1
  562. package/dist/wall/floorplan-move.d.ts.map +1 -1
  563. package/dist/wall/floorplan-move.js +20 -83
  564. package/dist/wall/floorplan-tool.d.ts.map +1 -1
  565. package/dist/wall/floorplan-tool.js +10 -11
  566. package/dist/wall/floorplan.d.ts +3 -1
  567. package/dist/wall/floorplan.d.ts.map +1 -1
  568. package/dist/wall/floorplan.js +184 -21
  569. package/dist/wall/measurement.d.ts.map +1 -1
  570. package/dist/wall/measurement.js +5 -5
  571. package/dist/wall/move-endpoint-tool.d.ts.map +1 -1
  572. package/dist/wall/move-endpoint-tool.js +20 -7
  573. package/dist/wall/move-shared.d.ts.map +1 -1
  574. package/dist/wall/move-shared.js +11 -7
  575. package/dist/wall/move-tool.d.ts.map +1 -1
  576. package/dist/wall/move-tool.js +118 -148
  577. package/dist/wall/paint.d.ts +26 -15
  578. package/dist/wall/paint.d.ts.map +1 -1
  579. package/dist/wall/paint.js +306 -117
  580. package/dist/wall/panel-model.d.ts +18 -0
  581. package/dist/wall/panel-model.d.ts.map +1 -1
  582. package/dist/wall/panel-model.js +77 -19
  583. package/dist/wall/panel.d.ts.map +1 -1
  584. package/dist/wall/panel.js +217 -41
  585. package/dist/wall/parametrics.d.ts.map +1 -1
  586. package/dist/wall/parametrics.js +3 -0
  587. package/dist/wall/rectangle-command.d.ts +111 -12
  588. package/dist/wall/rectangle-command.d.ts.map +1 -1
  589. package/dist/wall/rectangle-tool.d.ts.map +1 -1
  590. package/dist/wall/rectangle-tool.js +26 -8
  591. package/dist/wall/renderer.d.ts.map +1 -1
  592. package/dist/wall/renderer.js +4 -2
  593. package/dist/wall/split-floorplan-layer.d.ts.map +1 -1
  594. package/dist/wall/split-floorplan-layer.js +7 -7
  595. package/dist/wall/split-session.d.ts.map +1 -1
  596. package/dist/wall/split-session.js +7 -1
  597. package/dist/wall/system.d.ts.map +1 -1
  598. package/dist/wall/system.js +36 -4
  599. package/dist/wall/tool.d.ts.map +1 -1
  600. package/dist/wall/tool.js +105 -49
  601. package/dist/wall/treatment-level-data.d.ts +3 -2
  602. package/dist/wall/treatment-level-data.d.ts.map +1 -1
  603. package/dist/wall/treatment-level-data.js +17 -13
  604. package/dist/wall/treatments.d.ts +10 -10
  605. package/dist/wall/treatments.d.ts.map +1 -1
  606. package/dist/wall/treatments.js +67 -54
  607. package/dist/wall/wall-batch-system.d.ts +7 -0
  608. package/dist/wall/wall-batch-system.d.ts.map +1 -1
  609. package/dist/wall/wall-batch-system.js +35 -3
  610. package/dist/wall/wall-batch.d.ts +6 -0
  611. package/dist/wall/wall-batch.d.ts.map +1 -1
  612. package/dist/wall/wall-batch.js +7 -1
  613. package/dist/window/definition.d.ts.map +1 -1
  614. package/dist/window/definition.js +12 -4
  615. package/dist/window/floorplan-move.d.ts.map +1 -1
  616. package/dist/window/floorplan-move.js +3 -1
  617. package/dist/window/floorplan.d.ts.map +1 -1
  618. package/dist/window/floorplan.js +145 -60
  619. package/dist/window/mechanism.d.ts +4 -0
  620. package/dist/window/mechanism.d.ts.map +1 -0
  621. package/dist/window/mechanism.js +20 -0
  622. package/dist/window/move-tool.d.ts.map +1 -1
  623. package/dist/window/move-tool.js +79 -48
  624. package/dist/window/paint.d.ts.map +1 -1
  625. package/dist/window/paint.js +3 -0
  626. package/dist/window/panel.d.ts.map +1 -1
  627. package/dist/window/panel.js +32 -88
  628. package/dist/window/placement.d.ts +23 -0
  629. package/dist/window/placement.d.ts.map +1 -0
  630. package/dist/window/placement.js +66 -0
  631. package/dist/window/preview.d.ts.map +1 -1
  632. package/dist/window/preview.js +2 -0
  633. package/dist/window/renderer.d.ts.map +1 -1
  634. package/dist/window/renderer.js +3 -2
  635. package/dist/window/tool.d.ts.map +1 -1
  636. package/dist/window/tool.js +96 -24
  637. package/dist/window/window-math.d.ts +6 -14
  638. package/dist/window/window-math.d.ts.map +1 -1
  639. package/dist/window/window-math.js +14 -20
  640. package/dist/zone/contextual-dimensions.d.ts.map +1 -1
  641. package/dist/zone/contextual-dimensions.js +6 -28
  642. package/dist/zone/definition.d.ts.map +1 -1
  643. package/dist/zone/definition.js +3 -3
  644. package/dist/zone/floorplan-affordances.d.ts +200 -0
  645. package/dist/zone/floorplan-affordances.d.ts.map +1 -1
  646. package/dist/zone/floorplan.d.ts +1 -1
  647. package/dist/zone/floorplan.d.ts.map +1 -1
  648. package/dist/zone/floorplan.js +93 -53
  649. package/dist/zone/quantities-panel.d.ts.map +1 -1
  650. package/dist/zone/quantities-panel.js +3 -14
  651. package/dist/zone/quick-measurement.d.ts +2 -2
  652. package/dist/zone/quick-measurement.d.ts.map +1 -1
  653. package/dist/zone/quick-measurement.js +6 -5
  654. package/dist/zone/renderer.d.ts +1 -1
  655. package/dist/zone/renderer.d.ts.map +1 -1
  656. package/dist/zone/renderer.js +58 -146
  657. package/dist/zone/room-clear-dimensions.js +3 -3
  658. package/dist/zone/room-documentation.d.ts.map +1 -1
  659. package/dist/zone/room-documentation.js +2 -6
  660. package/package.json +11 -11
  661. package/dist/block/slots.d.ts +0 -4
  662. package/dist/block/slots.d.ts.map +0 -1
  663. package/dist/block/slots.js +0 -17
  664. package/dist/cabinet/slots.d.ts +0 -4
  665. package/dist/cabinet/slots.d.ts.map +0 -1
  666. package/dist/cabinet/slots.js +0 -24
  667. package/dist/ceiling/slots.d.ts +0 -6
  668. package/dist/ceiling/slots.d.ts.map +0 -1
  669. package/dist/ceiling/slots.js +0 -7
  670. package/dist/column/slots.d.ts +0 -9
  671. package/dist/column/slots.d.ts.map +0 -1
  672. package/dist/column/slots.js +0 -19
  673. package/dist/door/slots.d.ts +0 -9
  674. package/dist/door/slots.d.ts.map +0 -1
  675. package/dist/door/slots.js +0 -20
  676. package/dist/elevator/slots.d.ts +0 -8
  677. package/dist/elevator/slots.d.ts.map +0 -1
  678. package/dist/elevator/slots.js +0 -17
  679. package/dist/fence/slots.d.ts +0 -10
  680. package/dist/fence/slots.d.ts.map +0 -1
  681. package/dist/fence/slots.js +0 -23
  682. package/dist/item/__fixtures__/main-floorplan.d.ts +0 -26
  683. package/dist/item/__fixtures__/main-floorplan.d.ts.map +0 -1
  684. package/dist/item/__fixtures__/main-floorplan.js +0 -297
  685. package/dist/lean-to-extension/slots.d.ts +0 -5
  686. package/dist/lean-to-extension/slots.d.ts.map +0 -1
  687. package/dist/lean-to-extension/slots.js +0 -15
  688. package/dist/shelf/slots.d.ts +0 -9
  689. package/dist/shelf/slots.d.ts.map +0 -1
  690. package/dist/shelf/slots.js +0 -30
  691. package/dist/slab/slots.d.ts +0 -10
  692. package/dist/slab/slots.d.ts.map +0 -1
  693. package/dist/slab/slots.js +0 -20
  694. package/dist/stair/floor-stack.d.ts +0 -10
  695. package/dist/stair/floor-stack.d.ts.map +0 -1
  696. package/dist/stair/floor-stack.js +0 -115
  697. package/dist/stair/slots.d.ts +0 -7
  698. package/dist/stair/slots.d.ts.map +0 -1
  699. package/dist/stair/slots.js +0 -13
  700. package/dist/wall/drawing-mode.d.ts +0 -12
  701. package/dist/wall/drawing-mode.d.ts.map +0 -1
  702. package/dist/wall/drawing-mode.js +0 -38
  703. package/dist/wall/slots.d.ts +0 -10
  704. package/dist/wall/slots.d.ts.map +0 -1
  705. package/dist/wall/slots.js +0 -92
  706. package/dist/window/slots.d.ts +0 -5
  707. package/dist/window/slots.d.ts.map +0 -1
  708. package/dist/window/slots.js +0 -11
@@ -1,4 +1,4 @@
1
- import { heightAtSample, normalAt } from '@pascal-app/core';
1
+ import { heightAt, heightAtSample, normalAt, } from '@pascal-app/core';
2
2
  /**
3
3
  * Builds the terrain mesh buffers from a `TerrainField`.
4
4
  *
@@ -39,7 +39,7 @@ export const HORIZON_PLANE_Y = -0.07;
39
39
  * under the horizon disc. A metre reads as earth thickness from a grazing camera
40
40
  * without being tall enough to poke out of a neighbouring excavation.
41
41
  */
42
- const SKIRT_DROP = 1;
42
+ export const SKIRT_DROP = 1;
43
43
  /** Vertex index of sample [c,r]. */
44
44
  function vertexIndex(field, col, row) {
45
45
  return row * field.cols + col;
@@ -148,13 +148,58 @@ function boundarySample(field, i) {
148
148
  return { col: 2 * lastCol + lastRow - i, row: lastRow };
149
149
  return { col: 0, row: 2 * (lastCol + lastRow) - i };
150
150
  }
151
- export function buildTerrainSkirt(field) {
152
- const count = perimeterCount(field);
151
+ /**
152
+ * The base of the lot as a block: one flat level under the field's lowest
153
+ * point (and under the horizon plane), so the skirt along the property line
154
+ * reads as earth whose thickness follows the slope, and the horizon disc can
155
+ * sit just beneath it without cutting into the lot anywhere.
156
+ */
157
+ export function terrainBlockBase(field) {
158
+ let minH = 0;
159
+ for (let i = 0; i < field.heights.length; i++) {
160
+ const h = field.heights[i] ?? 0;
161
+ if (h < minH)
162
+ minH = h;
163
+ }
164
+ return Math.min(minH * field.step, HORIZON_PLANE_Y) - SKIRT_DROP;
165
+ }
166
+ /**
167
+ * The lot's property line as the skirt walks it: counter-clockwise in x, z (the
168
+ * field perimeter's own direction, so one winding and one normal formula serve
169
+ * both), a point at least every half grid cell so the top edge follows the
170
+ * ground between samples. Empty when the polygon is not a ring.
171
+ */
172
+ export function skirtRing(field, polygon) {
173
+ const points = polygon.filter(([x, z]) => Number.isFinite(x) && Number.isFinite(z));
174
+ if (points.length < 3 || field.cols < 2 || field.rows < 2)
175
+ return new Float32Array(0);
176
+ let area = 0;
177
+ for (let i = 0; i < points.length; i++) {
178
+ const [x0, z0] = points[i];
179
+ const [x1, z1] = points[(i + 1) % points.length];
180
+ area += x0 * z1 - x1 * z0;
181
+ }
182
+ const ordered = area > 0 ? points : [...points].reverse();
183
+ const step = field.spacing / 2;
184
+ const out = [];
185
+ for (let i = 0; i < ordered.length; i++) {
186
+ const [ax, az] = ordered[i];
187
+ const [bx, bz] = ordered[(i + 1) % ordered.length];
188
+ const n = Math.max(1, Math.ceil(Math.hypot(bx - ax, bz - az) / step));
189
+ for (let k = 0; k < n; k++)
190
+ out.push(ax + ((bx - ax) * k) / n, az + ((bz - az) * k) / n);
191
+ }
192
+ return Float32Array.from(out);
193
+ }
194
+ export function buildTerrainSkirt(field, ring) {
195
+ const onRing = !!ring && ring.length >= 6;
196
+ const count = onRing ? ring.length / 2 : perimeterCount(field);
153
197
  const vertices = count === 0 ? 0 : (count + 1) * 2;
154
198
  const buffers = {
155
199
  positions: new Float32Array(vertices * 3),
156
200
  normals: new Float32Array(vertices * 3),
157
201
  indices: new Uint32Array(count * 6),
202
+ ...(onRing ? { ring: ring } : {}),
158
203
  };
159
204
  for (let i = 0; i < count; i++) {
160
205
  const base = i * 6;
@@ -181,6 +226,10 @@ export function buildTerrainSkirt(field) {
181
226
  * complexity because it saves 400 KB a dab; here there is nothing to save.
182
227
  */
183
228
  export function updateTerrainSkirt(field, buffers) {
229
+ if (buffers.ring) {
230
+ updateRingSkirt(field, buffers, buffers.ring);
231
+ return;
232
+ }
184
233
  const count = perimeterCount(field);
185
234
  if (count === 0)
186
235
  return;
@@ -204,6 +253,31 @@ export function updateTerrainSkirt(field, buffers) {
204
253
  writeSkirtVertex(buffers, bottomIndex, x, Math.min(h, HORIZON_PLANE_Y) - SKIRT_DROP, z, nx, nz);
205
254
  }
206
255
  }
256
+ /**
257
+ * The property-line skirt: its top on the rendered ground (`heightAt`, the
258
+ * surface's own triangles), its bottom on the block's flat base — never above
259
+ * the ground it closes, so nothing stands proud of the lot from any side.
260
+ */
261
+ function updateRingSkirt(field, buffers, ring) {
262
+ const count = ring.length / 2;
263
+ if (count < 3)
264
+ return;
265
+ const base = terrainBlockBase(field);
266
+ for (let i = 0; i <= count; i++) {
267
+ const at = i % count;
268
+ const x = ring[at * 2] ?? 0;
269
+ const z = ring[at * 2 + 1] ?? 0;
270
+ const prev = (at - 1 + count) % count;
271
+ const next = (at + 1) % count;
272
+ const tx = (ring[next * 2] ?? 0) - (ring[prev * 2] ?? 0);
273
+ const tz = (ring[next * 2 + 1] ?? 0) - (ring[prev * 2 + 1] ?? 0);
274
+ const tLength = Math.hypot(tx, tz) || 1;
275
+ const nx = tz / tLength;
276
+ const nz = -tx / tLength;
277
+ writeSkirtVertex(buffers, i * 2, x, heightAt(field, x, z), z, nx, nz);
278
+ writeSkirtVertex(buffers, i * 2 + 1, x, base, z, nx, nz);
279
+ }
280
+ }
207
281
  function writeSkirtVertex(buffers, index, x, y, z, nx, nz) {
208
282
  buffers.positions[index * 3] = x;
209
283
  buffers.positions[index * 3 + 1] = y;
@@ -0,0 +1,15 @@
1
+ import { type Ring } from '@pascal-app/core';
2
+ import { BufferGeometry } from 'three';
3
+ import type { TerrainMeshBuffers } from './terrain-geometry';
4
+ type Sample = {
5
+ indices: number[];
6
+ weights: number[];
7
+ };
8
+ export type TerrainHoleBoundary = {
9
+ geometry: BufferGeometry;
10
+ samples: Sample[];
11
+ };
12
+ export declare function cutTerrainHoles(buffers: TerrainMeshBuffers, holes: Ring[]): TerrainHoleBoundary | null;
13
+ export declare function updateTerrainHoleBoundary(boundary: TerrainHoleBoundary, buffers: TerrainMeshBuffers): void;
14
+ export {};
15
+ //# sourceMappingURL=terrain-holes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"terrain-holes.d.ts","sourceRoot":"","sources":["../../src/site/terrain-holes.ts"],"names":[],"mappings":"AAAA,OAAO,EAAc,KAAK,IAAI,EAAS,MAAM,kBAAkB,CAAA;AAC/D,OAAO,EAAmB,cAAc,EAAyC,MAAM,OAAO,CAAA;AAC9F,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAA;AAE5D,KAAK,MAAM,GAAG;IAAE,OAAO,EAAE,MAAM,EAAE,CAAC;IAAC,OAAO,EAAE,MAAM,EAAE,CAAA;CAAE,CAAA;AACtD,MAAM,MAAM,mBAAmB,GAAG;IAAE,QAAQ,EAAE,cAAc,CAAC;IAAC,OAAO,EAAE,MAAM,EAAE,CAAA;CAAE,CAAA;AAIjF,wBAAgB,eAAe,CAC7B,OAAO,EAAE,kBAAkB,EAC3B,KAAK,EAAE,IAAI,EAAE,GACZ,mBAAmB,GAAG,IAAI,CAkE5B;AAED,wBAAgB,yBAAyB,CACvC,QAAQ,EAAE,mBAAmB,EAC7B,OAAO,EAAE,kBAAkB,GAC1B,IAAI,CAkBN"}
@@ -0,0 +1,74 @@
1
+ import { difference, union } from '@pascal-app/core';
2
+ import { BufferAttribute, BufferGeometry, DynamicDrawUsage, ShapeUtils, Vector2 } from 'three';
3
+ // Keep the regular grid's vertex layout for partial brush uploads. Only triangles
4
+ // crossing an excavation rim need additional vertices, interpolated on that grid.
5
+ export function cutTerrainHoles(buffers, holes) {
6
+ if (!holes.length)
7
+ return null;
8
+ const cutouts = union(holes);
9
+ const bounds = cutouts.map(({ outer }) => ({
10
+ minX: Math.min(...outer.map(([x]) => x)),
11
+ maxX: Math.max(...outer.map(([x]) => x)),
12
+ minZ: Math.min(...outer.map(([, z]) => z)),
13
+ maxZ: Math.max(...outer.map(([, z]) => z)),
14
+ }));
15
+ const kept = [], indices = [], samples = [];
16
+ for (let i = 0; i < buffers.indices.length; i += 3) {
17
+ const source = Array.from(buffers.indices.subarray(i, i + 3));
18
+ const triangle = source.map((id) => [
19
+ buffers.positions[id * 3],
20
+ buffers.positions[id * 3 + 2],
21
+ ]);
22
+ const xs = triangle.map(([x]) => x), zs = triangle.map(([, z]) => z);
23
+ if (!bounds.some((box) => box.maxX > Math.min(...xs) &&
24
+ box.minX < Math.max(...xs) &&
25
+ box.maxZ > Math.min(...zs) &&
26
+ box.minZ < Math.max(...zs))) {
27
+ kept.push(...source);
28
+ continue;
29
+ }
30
+ const [a, b, c] = triangle;
31
+ const determinant = (b[1] - c[1]) * (a[0] - c[0]) + (c[0] - b[0]) * (a[1] - c[1]);
32
+ for (const polygon of difference(triangle, cutouts)) {
33
+ const contour = polygon.outer.map(([x, z]) => new Vector2(x, z));
34
+ const voids = polygon.holes.map((ring) => ring.map(([x, z]) => new Vector2(x, z)));
35
+ const offset = samples.length;
36
+ for (const { x, y: z } of [contour, ...voids].flat()) {
37
+ const wa = ((b[1] - c[1]) * (x - c[0]) + (c[0] - b[0]) * (z - c[1])) / determinant;
38
+ const wb = ((c[1] - a[1]) * (x - c[0]) + (a[0] - c[0]) * (z - c[1])) / determinant;
39
+ samples.push({ indices: source, weights: [wa, wb, 1 - wa - wb] });
40
+ }
41
+ for (const [a, b, c] of ShapeUtils.triangulateShape(contour, voids))
42
+ indices.push(offset + c, offset + b, offset + a);
43
+ }
44
+ }
45
+ buffers.indices = new Uint32Array(kept);
46
+ const geometry = new BufferGeometry();
47
+ for (const name of ['position', 'normal'])
48
+ geometry.setAttribute(name, new BufferAttribute(new Float32Array(samples.length * 3), 3).setUsage(DynamicDrawUsage));
49
+ const uv = new Float32Array(samples.length * 2);
50
+ for (let i = 0; i < samples.length; i++)
51
+ for (let axis = 0; axis < 2; axis++)
52
+ uv[i * 2 + axis] = samples[i].indices.reduce((sum, id, j) => sum + buffers.uvs[id * 2 + axis] * samples[i].weights[j], 0);
53
+ geometry.setAttribute('uv', new BufferAttribute(uv, 2));
54
+ geometry.setIndex(indices);
55
+ const boundary = { geometry, samples };
56
+ updateTerrainHoleBoundary(boundary, buffers);
57
+ return boundary;
58
+ }
59
+ export function updateTerrainHoleBoundary(boundary, buffers) {
60
+ for (const [name, source] of [
61
+ ['position', buffers.positions],
62
+ ['normal', buffers.normals],
63
+ ]) {
64
+ const attribute = boundary.geometry.getAttribute(name);
65
+ for (let i = 0; i < boundary.samples.length; i++) {
66
+ const sample = boundary.samples[i];
67
+ for (let axis = 0; axis < 3; axis++)
68
+ attribute.array[i * 3 + axis] = sample.indices.reduce((sum, id, j) => sum + source[id * 3 + axis] * sample.weights[j], 0);
69
+ }
70
+ attribute.needsUpdate = true;
71
+ }
72
+ boundary.geometry.normalizeNormals();
73
+ boundary.geometry.computeBoundingSphere();
74
+ }
@@ -1,6 +1,7 @@
1
- import type { HeightPatch, TerrainField } from '@pascal-app/core';
1
+ import type { HeightPatch, Ring, TerrainField } from '@pascal-app/core';
2
2
  import { BufferGeometry } from 'three';
3
3
  import { type TerrainMeshBuffers, type TerrainSkirtBuffers } from './terrain-geometry';
4
+ import { type TerrainHoleBoundary } from './terrain-holes';
4
5
  /**
5
6
  * The Three.js side of the terrain heightfield: owns the `BufferGeometry` and the
6
7
  * dirty-rect upload.
@@ -20,6 +21,7 @@ import { type TerrainMeshBuffers, type TerrainSkirtBuffers } from './terrain-geo
20
21
  /** A terrain geometry plus the CPU buffers backing it. */
21
22
  export type TerrainGeometry = {
22
23
  readonly geometry: BufferGeometry;
24
+ readonly holeBoundary: TerrainHoleBoundary | null;
23
25
  readonly buffers: TerrainMeshBuffers;
24
26
  /** Expands during live edits; a committed-field rebuild tightens it again. */
25
27
  readonly heightBounds: {
@@ -32,7 +34,12 @@ export type TerrainGeometry = {
32
34
  readonly buffers: TerrainSkirtBuffers;
33
35
  };
34
36
  };
35
- export declare function createTerrainGeometry(field: TerrainField): TerrainGeometry;
37
+ /**
38
+ * `ring` (from `skirtRing`) runs the skirt along the lot's property line instead
39
+ * of the field's rectangle: the surface is cut to the lot by its material (see
40
+ * `lotMaskedMaterial`), and the skirt closes it as a block with a flat base.
41
+ */
42
+ export declare function createTerrainGeometry(field: TerrainField, holes?: Ring[], ring?: Float32Array | null): TerrainGeometry;
36
43
  /**
37
44
  * Push one patch to the GPU, touching only the affected rows.
38
45
  *
@@ -1 +1 @@
1
- {"version":3,"file":"terrain-mesh.d.ts","sourceRoot":"","sources":["../../src/site/terrain-mesh.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAA;AACjE,OAAO,EAAmB,cAAc,EAA4B,MAAM,OAAO,CAAA;AACjF,OAAO,EAKL,KAAK,kBAAkB,EACvB,KAAK,mBAAmB,EAGzB,MAAM,oBAAoB,CAAA;AAE3B;;;;;;;;;;;;;;;GAeG;AAEH,0DAA0D;AAC1D,MAAM,MAAM,eAAe,GAAG;IAC5B,QAAQ,CAAC,QAAQ,EAAE,cAAc,CAAA;IACjC,QAAQ,CAAC,OAAO,EAAE,kBAAkB,CAAA;IACpC,8EAA8E;IAC9E,QAAQ,CAAC,YAAY,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAA;IACrD,uEAAuE;IACvE,QAAQ,CAAC,KAAK,EAAE;QAAE,QAAQ,CAAC,QAAQ,EAAE,cAAc,CAAC;QAAC,QAAQ,CAAC,OAAO,EAAE,mBAAmB,CAAA;KAAE,CAAA;CAC7F,CAAA;AAED,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,YAAY,GAAG,eAAe,CAsC1E;AAED;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,eAAe,EACvB,KAAK,EAAE,YAAY,EACnB,KAAK,EAAE,WAAW,GACjB,IAAI,CA6CN;AAuED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,eAAe,EAAE,KAAK,EAAE,YAAY,GAAG,OAAO,CAElF;AAED,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,eAAe,GAAG,IAAI,CAGpE"}
1
+ {"version":3,"file":"terrain-mesh.d.ts","sourceRoot":"","sources":["../../src/site/terrain-mesh.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,IAAI,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAA;AACvE,OAAO,EAAmB,cAAc,EAA4B,MAAM,OAAO,CAAA;AACjF,OAAO,EAML,KAAK,kBAAkB,EACvB,KAAK,mBAAmB,EAGzB,MAAM,oBAAoB,CAAA;AAE3B,OAAO,EAEL,KAAK,mBAAmB,EAEzB,MAAM,iBAAiB,CAAA;AAExB;;;;;;;;;;;;;;;GAeG;AAEH,0DAA0D;AAC1D,MAAM,MAAM,eAAe,GAAG;IAC5B,QAAQ,CAAC,QAAQ,EAAE,cAAc,CAAA;IACjC,QAAQ,CAAC,YAAY,EAAE,mBAAmB,GAAG,IAAI,CAAA;IACjD,QAAQ,CAAC,OAAO,EAAE,kBAAkB,CAAA;IACpC,8EAA8E;IAC9E,QAAQ,CAAC,YAAY,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAA;IACrD,uEAAuE;IACvE,QAAQ,CAAC,KAAK,EAAE;QAAE,QAAQ,CAAC,QAAQ,EAAE,cAAc,CAAC;QAAC,QAAQ,CAAC,OAAO,EAAE,mBAAmB,CAAA;KAAE,CAAA;CAC7F,CAAA;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,YAAY,EACnB,KAAK,GAAE,IAAI,EAAO,EAClB,IAAI,GAAE,YAAY,GAAG,IAAW,GAC/B,eAAe,CAyCjB;AAED;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,eAAe,EACvB,KAAK,EAAE,YAAY,EACnB,KAAK,EAAE,WAAW,GACjB,IAAI,CA+CN;AAoFD;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,eAAe,EAAE,KAAK,EAAE,YAAY,GAAG,OAAO,CAElF;AAED,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,eAAe,GAAG,IAAI,CAIpE"}
@@ -1,7 +1,14 @@
1
1
  import { BufferAttribute, BufferGeometry, DynamicDrawUsage, Sphere } from 'three';
2
- import { buildTerrainMesh, buildTerrainSkirt, HORIZON_PLANE_Y, patchUpdateRange, updateTerrainMesh, updateTerrainSkirt, } from './terrain-geometry';
3
- export function createTerrainGeometry(field) {
2
+ import { buildTerrainMesh, buildTerrainSkirt, HORIZON_PLANE_Y, patchUpdateRange, SKIRT_DROP, updateTerrainMesh, updateTerrainSkirt, } from './terrain-geometry';
3
+ import { cutTerrainHoles, updateTerrainHoleBoundary, } from './terrain-holes';
4
+ /**
5
+ * `ring` (from `skirtRing`) runs the skirt along the lot's property line instead
6
+ * of the field's rectangle: the surface is cut to the lot by its material (see
7
+ * `lotMaskedMaterial`), and the skirt closes it as a block with a flat base.
8
+ */
9
+ export function createTerrainGeometry(field, holes = [], ring = null) {
4
10
  const buffers = buildTerrainMesh(field);
11
+ const holeBoundary = cutTerrainHoles(buffers, holes);
5
12
  const geometry = new BufferGeometry();
6
13
  geometry.setAttribute('position', new BufferAttribute(buffers.positions, 3).setUsage(DynamicDrawUsage));
7
14
  geometry.setAttribute('normal', new BufferAttribute(buffers.normals, 3).setUsage(DynamicDrawUsage));
@@ -12,14 +19,17 @@ export function createTerrainGeometry(field) {
12
19
  // A separate geometry, not extra vertices on the surface: the surface's dirty
13
20
  // range is a row span over a `cols * rows` layout, and appending a perimeter ring
14
21
  // to it would break that indexing for a saving of one draw call.
15
- const skirtBuffers = buildTerrainSkirt(field);
22
+ const skirtBuffers = buildTerrainSkirt(field, ring);
16
23
  const skirtGeometry = new BufferGeometry();
17
24
  skirtGeometry.setAttribute('position', new BufferAttribute(skirtBuffers.positions, 3).setUsage(DynamicDrawUsage));
18
25
  skirtGeometry.setAttribute('normal', new BufferAttribute(skirtBuffers.normals, 3).setUsage(DynamicDrawUsage));
19
26
  skirtGeometry.setIndex(new BufferAttribute(skirtBuffers.indices, 1));
27
+ if (skirtBuffers.ring)
28
+ skirtGeometry.userData.ring = skirtBuffers.ring;
20
29
  setSkirtBounds(skirtGeometry, field, span);
21
30
  return {
22
31
  geometry,
32
+ holeBoundary,
23
33
  buffers,
24
34
  heightBounds: span,
25
35
  skirt: { geometry: skirtGeometry, buffers: skirtBuffers },
@@ -38,7 +48,10 @@ export function applyTerrainPatch(target, field, patch) {
38
48
  if (!range)
39
49
  return;
40
50
  updateTerrainMesh(field, target.buffers, patch);
41
- if (patch.col0 <= 0 ||
51
+ if (target.holeBoundary)
52
+ updateTerrainHoleBoundary(target.holeBoundary, target.buffers);
53
+ if (target.skirt.buffers.ring ||
54
+ patch.col0 <= 0 ||
42
55
  patch.row0 <= 0 ||
43
56
  patch.col0 + patch.cols >= field.cols ||
44
57
  patch.row0 + patch.rows >= field.rows) {
@@ -111,12 +124,25 @@ function setTerrainBounds(geometry, field, { minY, maxY }) {
111
124
  * same reason the geometry does.
112
125
  */
113
126
  function setSkirtBounds(geometry, field, { minY, maxY }) {
114
- const low = Math.min(minY, HORIZON_PLANE_Y) - 1;
127
+ const low = Math.min(minY, HORIZON_PLANE_Y) - SKIRT_DROP;
115
128
  const high = Math.max(maxY, HORIZON_PLANE_Y);
116
- const minX = field.origin[0];
117
- const minZ = field.origin[1];
118
- const maxX = minX + (field.cols - 1) * field.spacing;
119
- const maxZ = minZ + (field.rows - 1) * field.spacing;
129
+ let minX = field.origin[0];
130
+ let minZ = field.origin[1];
131
+ let maxX = minX + (field.cols - 1) * field.spacing;
132
+ let maxZ = minZ + (field.rows - 1) * field.spacing;
133
+ const ring = geometry.userData.ring;
134
+ if (ring && ring.length >= 6) {
135
+ minX = maxX = ring[0] ?? 0;
136
+ minZ = maxZ = ring[1] ?? 0;
137
+ for (let i = 2; i < ring.length; i += 2) {
138
+ const x = ring[i] ?? 0;
139
+ const z = ring[i + 1] ?? 0;
140
+ minX = Math.min(minX, x);
141
+ maxX = Math.max(maxX, x);
142
+ minZ = Math.min(minZ, z);
143
+ maxZ = Math.max(maxZ, z);
144
+ }
145
+ }
120
146
  geometry.boundingSphere ??= new Sphere();
121
147
  const sphere = geometry.boundingSphere;
122
148
  sphere.center.set((minX + maxX) / 2, (low + high) / 2, (minZ + maxZ) / 2);
@@ -147,5 +173,6 @@ export function needsRebuild(target, field) {
147
173
  }
148
174
  export function disposeTerrainGeometry(target) {
149
175
  target.geometry.dispose();
176
+ target.holeBoundary?.geometry.dispose();
150
177
  target.skirt.geometry.dispose();
151
178
  }
@@ -1,4 +1,4 @@
1
- import { type SiteNode } from '@pascal-app/core';
1
+ import { type Ring, type SiteNode } from '@pascal-app/core';
2
2
  import type { Material } from 'three';
3
3
  /**
4
4
  * Renders the site's sculpted ground.
@@ -19,10 +19,17 @@ import type { Material } from 'three';
19
19
  * the editor layer, but moving actual scene geometry there would exclude it from
20
20
  * the MRT depth/normal pass and break the screen-space ink against it.
21
21
  */
22
- export declare const TerrainRenderer: ({ material, site, }: {
22
+ export declare const TerrainRenderer: ({ material, site, holes, polygon, }: {
23
23
  /** Owned by `SiteRenderer` so the ground material stays defined in one place. */
24
24
  material: Material;
25
25
  site: SiteNode;
26
+ holes: Ring[];
27
+ /**
28
+ * The lot's property line (live while it is being edited). With one, the
29
+ * ground is the lot alone — cut to the line, closed by a skirt down to a flat
30
+ * base — rather than the field's padded box.
31
+ */
32
+ polygon?: ReadonlyArray<readonly [number, number]> | null;
26
33
  }) => import("react").JSX.Element | null;
27
34
  export default TerrainRenderer;
28
35
  //# sourceMappingURL=terrain-renderer.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"terrain-renderer.d.ts","sourceRoot":"","sources":["../../src/site/terrain-renderer.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,QAAQ,EAAkC,MAAM,kBAAkB,CAAA;AAEhF,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAA;AASrC;;;;;;;;;;;;;;;;;;GAkBG;AACH,eAAO,MAAM,eAAe,GAAI,qBAG7B;IACD,iFAAiF;IACjF,QAAQ,EAAE,QAAQ,CAAA;IAClB,IAAI,EAAE,QAAQ,CAAA;CACf,uCA6DA,CAAA;AAED,eAAe,eAAe,CAAA"}
1
+ {"version":3,"file":"terrain-renderer.d.ts","sourceRoot":"","sources":["../../src/site/terrain-renderer.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,IAAI,EAAE,KAAK,QAAQ,EAAkC,MAAM,kBAAkB,CAAA;AAE3F,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAA;AAWrC;;;;;;;;;;;;;;;;;;GAkBG;AACH,eAAO,MAAM,eAAe,GAAI,qCAK7B;IACD,iFAAiF;IACjF,QAAQ,EAAE,QAAQ,CAAA;IAClB,IAAI,EAAE,QAAQ,CAAA;IACd,KAAK,EAAE,IAAI,EAAE,CAAA;IACb;;;;OAIG;IACH,OAAO,CAAC,EAAE,aAAa,CAAC,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,GAAG,IAAI,CAAA;CAC1D,uCAoFA,CAAA;AAED,eAAe,eAAe,CAAA"}
@@ -2,6 +2,8 @@
2
2
  import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { terrainFieldOf, useLiveTerrain } from '@pascal-app/core';
4
4
  import { useEffect, useMemo, useRef } from 'react';
5
+ import { lotMaskedMaterial } from './lot-mask';
6
+ import { skirtRing } from './terrain-geometry';
5
7
  import { applyTerrainPatch, createTerrainGeometry, disposeTerrainGeometry, needsRebuild, } from './terrain-mesh';
6
8
  /**
7
9
  * Renders the site's sculpted ground.
@@ -22,7 +24,7 @@ import { applyTerrainPatch, createTerrainGeometry, disposeTerrainGeometry, needs
22
24
  * the editor layer, but moving actual scene geometry there would exclude it from
23
25
  * the MRT depth/normal pass and break the screen-space ink against it.
24
26
  */
25
- export const TerrainRenderer = ({ material, site, }) => {
27
+ export const TerrainRenderer = ({ material, site, holes, polygon, }) => {
26
28
  const targetRef = useRef(null);
27
29
  // Persisted terrain only — the live stroke is applied imperatively below, so a
28
30
  // dab never triggers a React render.
@@ -31,8 +33,16 @@ export const TerrainRenderer = ({ material, site, }) => {
31
33
  const field = useLiveTerrain.getState().fieldOf(site.id) ?? persistedField;
32
34
  if (!field)
33
35
  return null;
34
- return createTerrainGeometry(field);
35
- }, [persistedField, site.id]);
36
+ const ring = polygon && polygon.length >= 3 ? skirtRing(field, polygon) : null;
37
+ return createTerrainGeometry(field, holes, ring && ring.length >= 6 ? ring : null);
38
+ }, [persistedField, site.id, holes, polygon]);
39
+ // The surface (and the cut edges round recessed slabs) stop at the property
40
+ // line; the skirt keeps the plain material — it *is* the line.
41
+ const surfaceMaterial = useMemo(() => (polygon && polygon.length >= 3 ? lotMaskedMaterial(material, polygon) : material), [material, polygon]);
42
+ useEffect(() => () => {
43
+ if (surfaceMaterial !== material)
44
+ surfaceMaterial.dispose();
45
+ }, [surfaceMaterial, material]);
36
46
  targetRef.current = target;
37
47
  useEffect(() => () => {
38
48
  if (target)
@@ -64,6 +74,6 @@ export const TerrainRenderer = ({ material, site, }) => {
64
74
  }, [site.id]);
65
75
  if (!target)
66
76
  return null;
67
- return (_jsxs(_Fragment, { children: [_jsx("mesh", { castShadow: true, geometry: target.geometry, material: material, receiveShadow: true }), _jsx("mesh", { geometry: target.skirt.geometry, material: material, receiveShadow: true })] }));
77
+ return (_jsxs(_Fragment, { children: [_jsx("mesh", { castShadow: true, geometry: target.geometry, material: surfaceMaterial, receiveShadow: true }), target.holeBoundary && (_jsx("mesh", { castShadow: true, geometry: target.holeBoundary.geometry, material: surfaceMaterial, receiveShadow: true })), _jsx("mesh", { geometry: target.skirt.geometry, material: material, receiveShadow: true })] }));
68
78
  };
69
79
  export default TerrainRenderer;
@@ -3,7 +3,7 @@ import { type SlabNode } from '@pascal-app/core';
3
3
  * Phase 5 Stage D — slab boundary editor (registry-driven).
4
4
  *
5
5
  * Thin wrapper around the shared `PolygonEditor`. Activates when a
6
- * slab is selected in structure/select mode (not currently editing a
6
+ * slab is selected in select mode (not currently editing a
7
7
  * hole). The heavy lifting — vertex drag, edge slide, snap, history
8
8
  * bracketing — lives in `PolygonEditor` itself.
9
9
  *
@@ -1 +1 @@
1
- {"version":3,"file":"boundary-editor.d.ts","sourceRoot":"","sources":["../../src/slab/boundary-editor.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAkB,KAAK,QAAQ,EAAkC,MAAM,kBAAkB,CAAA;AAehG;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,kBAAkB,EAAE,KAAK,CAAC,EAAE,CAAC;IAAE,MAAM,EAAE,QAAQ,CAAC,IAAI,CAAC,CAAA;CAAE,CAqInE,CAAA;AAED,eAAe,kBAAkB,CAAA"}
1
+ {"version":3,"file":"boundary-editor.d.ts","sourceRoot":"","sources":["../../src/slab/boundary-editor.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAkB,KAAK,QAAQ,EAAkC,MAAM,kBAAkB,CAAA;AAehG;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,kBAAkB,EAAE,KAAK,CAAC,EAAE,CAAC;IAAE,MAAM,EAAE,QAAQ,CAAC,IAAI,CAAC,CAAA;CAAE,CAwInE,CAAA;AAED,eAAe,kBAAkB,CAAA"}
@@ -8,7 +8,7 @@ import { useCallback, useEffect } from 'react';
8
8
  * Phase 5 Stage D — slab boundary editor (registry-driven).
9
9
  *
10
10
  * Thin wrapper around the shared `PolygonEditor`. Activates when a
11
- * slab is selected in structure/select mode (not currently editing a
11
+ * slab is selected in select mode (not currently editing a
12
12
  * hole). The heavy lifting — vertex drag, edge slide, snap, history
13
13
  * bracketing — lives in `PolygonEditor` itself.
14
14
  *
@@ -24,16 +24,18 @@ import { useCallback, useEffect } from 'react';
24
24
  */
25
25
  export const SlabBoundaryEditor = ({ slabId }) => {
26
26
  const slabNode = useScene((s) => s.nodes[slabId]);
27
- const updateNode = useScene((s) => s.updateNode);
27
+ const detachDerivedNode = useScene((s) => s.detachDerivedNode);
28
28
  const markDirty = useScene((s) => s.markDirty);
29
29
  const setSelection = useViewer((s) => s.setSelection);
30
30
  const slab = slabNode?.type === 'slab' ? slabNode : null;
31
31
  const slabLevelId = slab ? resolveLevelId(slab, useScene.getState().nodes) : null;
32
32
  const handlePolygonChange = useCallback((newPolygon) => {
33
33
  clearSlabSnapFeedback();
34
- updateNode(slabId, { polygon: newPolygon, autoFromWalls: false });
34
+ // Reshaping the boundary is the sanctioned conversion of a derived floor
35
+ // plate into an authored slab — the reconciler stops owning it here.
36
+ detachDerivedNode(slabId, { polygon: newPolygon });
35
37
  setSelection({ selectedIds: [slabId] });
36
- }, [slabId, updateNode, setSelection]);
38
+ }, [slabId, detachDerivedNode, setSelection]);
37
39
  const handlePolygonPreview = useCallback((preview) => {
38
40
  if (preview) {
39
41
  useLiveNodeOverrides.getState().set(slabId, {
@@ -110,15 +112,13 @@ export const SlabBoundaryEditor = ({ slabId }) => {
110
112
  // Guarantee the override clears if the editor unmounts mid-drag
111
113
  // (selection change, mode switch) so the slab mesh doesn't get stuck
112
114
  // on a stale polygon.
113
- useEffect(() => {
114
- return () => {
115
- clearSlabSnapFeedback();
116
- useLiveNodeOverrides.getState().clear(slabId);
117
- useScene.getState().markDirty(slabId);
118
- useInteractionScope
119
- .getState()
120
- .endIf((s) => s.kind === 'reshaping' && s.reshape === 'boundary');
121
- };
115
+ useEffect(() => () => {
116
+ clearSlabSnapFeedback();
117
+ useLiveNodeOverrides.getState().clear(slabId);
118
+ useScene.getState().markDirty(slabId);
119
+ useInteractionScope
120
+ .getState()
121
+ .endIf((s) => s.kind === 'reshaping' && s.reshape === 'boundary');
122
122
  }, [slabId]);
123
123
  if (!slab?.polygon || slab.polygon.length < 3)
124
124
  return null;
@@ -1 +1 @@
1
- {"version":3,"file":"definition.d.ts","sourceRoot":"","sources":["../../src/slab/definition.ts"],"names":[],"mappings":"AAAA,OAAO,EAML,KAAK,cAAc,EAKpB,MAAM,kBAAkB,CAAA;AA8BzB,OAAO,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAA;AAsNnC;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,cAAc,EAAE,cAAc,CAAC,OAAO,QAAQ,CAyH1D,CAAA"}
1
+ {"version":3,"file":"definition.d.ts","sourceRoot":"","sources":["../../src/slab/definition.ts"],"names":[],"mappings":"AAAA,OAAO,EAOL,KAAK,cAAc,EAMpB,MAAM,kBAAkB,CAAA;AA+BzB,OAAO,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAA;AAyNnC;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,cAAc,EAAE,cAAc,CAAC,OAAO,QAAQ,CAyI1D,CAAA"}
@@ -1,5 +1,6 @@
1
- import { MIN_SLAB_THICKNESS, markSlabChangeDependents, pointInPolygon2D, syncStairRises, } from '@pascal-app/core';
1
+ import { liftedManualSlab, MIN_SLAB_THICKNESS, markSlabChangeDependents, pointInPolygon2D, slabSlots, syncStairRises, } from '@pascal-app/core';
2
2
  import { clearStructuralElevationGuide, DRAFTING_SURFACE_EXTENSION_KEY, publishStructuralElevationGuide, resolveStructuralElevationSnap, } from '@pascal-app/editor';
3
+ import { surfaceBatchable } from '../shared/node-batch/batchable';
3
4
  import { polygonMeasurementFeatures } from '../shared/polygon-measurement';
4
5
  import { sameOutlineSurfaceCounterparts } from '../shared/surface-counterparts';
5
6
  import { applySlabBaseElevationChange, applySlabThicknessChange, applySlabTopChange, getSlabBaseElevation, slabElevationUpperBound, } from './elevation-limit';
@@ -11,7 +12,6 @@ import { slabPaint } from './paint';
11
12
  import { slabParametrics } from './parametrics';
12
13
  import { slabQuickMeasurement } from './quick-measurement';
13
14
  import { SlabNode } from './schema';
14
- import { slabSlots } from './slots';
15
15
  const HEIGHT_HANDLE_OFFSET = 0.22;
16
16
  const MIN_SLAB_ELEVATION = -1;
17
17
  function polygonVertexAverage(polygon) {
@@ -171,6 +171,11 @@ function slabBaseElevationHandle() {
171
171
  };
172
172
  }
173
173
  function slabHandles(node) {
174
+ // A footprint's floor (base plate) has one control, its height above the
175
+ // ground, drawn by the editor's footprint height handle; room plates are
176
+ // reached through their room. Only user-drawn slabs keep these handles.
177
+ if (node.plateRole)
178
+ return [];
174
179
  return node.recessed
175
180
  ? [slabRecessedDepthHandle()]
176
181
  : [slabThicknessHandle(), slabBaseElevationHandle()];
@@ -220,9 +225,20 @@ export const slabDefinition = {
220
225
  autoFromWalls: false,
221
226
  }),
222
227
  capabilities: {
228
+ batchable: surfaceBatchable,
223
229
  selectable: { hitVolume: 'bbox' },
224
230
  surfaces: {
225
- top: { height: (n) => n.elevation },
231
+ top: {
232
+ height: (n) => n.elevation,
233
+ supportHeight: (node, x, z, context) => {
234
+ const slab = node;
235
+ if (slab.polygon.length < 3 ||
236
+ !pointInPolygon2D([x, z], slab.polygon, { includeBoundary: true }) ||
237
+ slab.holes.some((hole) => hole.length >= 3 && pointInPolygon2D([x, z], hole, { includeBoundary: false })))
238
+ return null;
239
+ return liftedManualSlab(context.nodes, slab).elevation;
240
+ },
241
+ },
226
242
  },
227
243
  duplicable: true,
228
244
  deletable: true,
@@ -1 +1 @@
1
- {"version":3,"file":"dependency-tracker.d.ts","sourceRoot":"","sources":["../../src/slab/dependency-tracker.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,OAAO,EACZ,KAAK,SAAS,EAQf,MAAM,kBAAkB,CAAA;AAmBzB,wBAAgB,2BAA2B,CAAC,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,WAwBxD,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAG,SAAS,EAAE,CAwF7D"}
1
+ {"version":3,"file":"dependency-tracker.d.ts","sourceRoot":"","sources":["../../src/slab/dependency-tracker.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,OAAO,EACZ,KAAK,SAAS,EAYf,MAAM,kBAAkB,CAAA;AAsBzB,wBAAgB,2BAA2B,CAAC,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,WAwDxD,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAG,SAAS,EAAE,CAoH7D"}