@pascal-app/core 0.9.2 → 1.0.0-beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (339) hide show
  1. package/README.md +17 -10
  2. package/dist/events/bus.d.ts +21 -2
  3. package/dist/events/bus.d.ts.map +1 -1
  4. package/dist/hooks/spatial-grid/floor-placed-elevation.d.ts +17 -1
  5. package/dist/hooks/spatial-grid/floor-placed-elevation.d.ts.map +1 -1
  6. package/dist/hooks/spatial-grid/floor-placed-elevation.js +61 -8
  7. package/dist/hooks/spatial-grid/spatial-grid-manager.d.ts +116 -66
  8. package/dist/hooks/spatial-grid/spatial-grid-manager.d.ts.map +1 -1
  9. package/dist/hooks/spatial-grid/spatial-grid-manager.js +319 -441
  10. package/dist/hooks/spatial-grid/spatial-grid-sync.d.ts +46 -1
  11. package/dist/hooks/spatial-grid/spatial-grid-sync.d.ts.map +1 -1
  12. package/dist/hooks/spatial-grid/spatial-grid-sync.js +204 -12
  13. package/dist/hooks/spatial-grid/support-host-id.d.ts +3 -0
  14. package/dist/hooks/spatial-grid/support-host-id.d.ts.map +1 -0
  15. package/dist/hooks/spatial-grid/support-host-id.js +2 -0
  16. package/dist/hooks/spatial-grid/support-host-patch.d.ts +51 -0
  17. package/dist/hooks/spatial-grid/support-host-patch.d.ts.map +1 -0
  18. package/dist/hooks/spatial-grid/support-host-patch.js +164 -0
  19. package/dist/index.d.ts +23 -11
  20. package/dist/index.d.ts.map +1 -1
  21. package/dist/index.js +22 -10
  22. package/dist/lib/measurement-geometry.d.ts +4 -0
  23. package/dist/lib/measurement-geometry.d.ts.map +1 -1
  24. package/dist/lib/measurement-geometry.js +27 -10
  25. package/dist/lib/slab-polygon.d.ts.map +1 -1
  26. package/dist/lib/slab-polygon.js +33 -1
  27. package/dist/lib/space-detection.d.ts +15 -4
  28. package/dist/lib/space-detection.d.ts.map +1 -1
  29. package/dist/lib/space-detection.js +232 -91
  30. package/dist/lib/terrain-brush.d.ts +163 -0
  31. package/dist/lib/terrain-brush.d.ts.map +1 -0
  32. package/dist/lib/terrain-brush.js +359 -0
  33. package/dist/lib/terrain-codec.d.ts +51 -0
  34. package/dist/lib/terrain-codec.d.ts.map +1 -0
  35. package/dist/lib/terrain-codec.js +167 -0
  36. package/dist/lib/terrain-field.d.ts +150 -0
  37. package/dist/lib/terrain-field.d.ts.map +1 -0
  38. package/dist/lib/terrain-field.js +248 -0
  39. package/dist/lib/terrain-raycast.d.ts +44 -0
  40. package/dist/lib/terrain-raycast.d.ts.map +1 -0
  41. package/dist/lib/terrain-raycast.js +188 -0
  42. package/dist/lib/terrain-source.d.ts +60 -0
  43. package/dist/lib/terrain-source.d.ts.map +1 -0
  44. package/dist/lib/terrain-source.js +90 -0
  45. package/dist/lib/terrain-support.d.ts +85 -0
  46. package/dist/lib/terrain-support.d.ts.map +1 -0
  47. package/dist/lib/terrain-support.js +218 -0
  48. package/dist/lib/zone-quantities.d.ts +1 -1
  49. package/dist/lib/zone-quantities.d.ts.map +1 -1
  50. package/dist/lib/zone-quantities.js +311 -66
  51. package/dist/material-library.d.ts +9 -1
  52. package/dist/material-library.d.ts.map +1 -1
  53. package/dist/material-library.js +56 -4
  54. package/dist/registry/handles.d.ts +16 -1
  55. package/dist/registry/handles.d.ts.map +1 -1
  56. package/dist/registry/index.d.ts +1 -1
  57. package/dist/registry/index.d.ts.map +1 -1
  58. package/dist/registry/subtree.d.ts.map +1 -1
  59. package/dist/registry/subtree.js +5 -2
  60. package/dist/registry/types.d.ts +83 -1
  61. package/dist/registry/types.d.ts.map +1 -1
  62. package/dist/schema/index.d.ts +6 -3
  63. package/dist/schema/index.d.ts.map +1 -1
  64. package/dist/schema/index.js +6 -3
  65. package/dist/schema/nodes/cabinet.d.ts +2 -0
  66. package/dist/schema/nodes/cabinet.d.ts.map +1 -1
  67. package/dist/schema/nodes/cabinet.js +4 -2
  68. package/dist/schema/nodes/ceiling.d.ts +1 -1
  69. package/dist/schema/nodes/ceiling.d.ts.map +1 -1
  70. package/dist/schema/nodes/ceiling.js +7 -1
  71. package/dist/schema/nodes/column.d.ts +1 -0
  72. package/dist/schema/nodes/column.d.ts.map +1 -1
  73. package/dist/schema/nodes/column.js +2 -0
  74. package/dist/schema/nodes/construction-dimension.d.ts +195 -0
  75. package/dist/schema/nodes/construction-dimension.d.ts.map +1 -0
  76. package/dist/schema/nodes/construction-dimension.js +151 -0
  77. package/dist/schema/nodes/door.d.ts +29 -0
  78. package/dist/schema/nodes/door.d.ts.map +1 -1
  79. package/dist/schema/nodes/door.js +20 -0
  80. package/dist/schema/nodes/duct-terminal.d.ts +1 -0
  81. package/dist/schema/nodes/duct-terminal.d.ts.map +1 -1
  82. package/dist/schema/nodes/duct-terminal.js +2 -0
  83. package/dist/schema/nodes/fence.d.ts +2 -0
  84. package/dist/schema/nodes/fence.d.ts.map +1 -1
  85. package/dist/schema/nodes/fence.js +8 -0
  86. package/dist/schema/nodes/hvac-equipment.d.ts +1 -0
  87. package/dist/schema/nodes/hvac-equipment.d.ts.map +1 -1
  88. package/dist/schema/nodes/hvac-equipment.js +2 -0
  89. package/dist/schema/nodes/item.d.ts +1 -0
  90. package/dist/schema/nodes/item.d.ts.map +1 -1
  91. package/dist/schema/nodes/item.js +13 -0
  92. package/dist/schema/nodes/level.d.ts +2 -1
  93. package/dist/schema/nodes/level.d.ts.map +1 -1
  94. package/dist/schema/nodes/level.js +12 -33
  95. package/dist/schema/nodes/shelf.d.ts +1 -0
  96. package/dist/schema/nodes/shelf.d.ts.map +1 -1
  97. package/dist/schema/nodes/shelf.js +2 -0
  98. package/dist/schema/nodes/site.d.ts +9 -0
  99. package/dist/schema/nodes/site.d.ts.map +1 -1
  100. package/dist/schema/nodes/site.js +8 -6
  101. package/dist/schema/nodes/slab.d.ts +5 -0
  102. package/dist/schema/nodes/slab.d.ts.map +1 -1
  103. package/dist/schema/nodes/slab.js +14 -2
  104. package/dist/schema/nodes/spawn.d.ts +1 -0
  105. package/dist/schema/nodes/spawn.d.ts.map +1 -1
  106. package/dist/schema/nodes/spawn.js +2 -0
  107. package/dist/schema/nodes/stair.d.ts +3 -1
  108. package/dist/schema/nodes/stair.d.ts.map +1 -1
  109. package/dist/schema/nodes/stair.js +8 -1
  110. package/dist/schema/nodes/structural-grid.d.ts +27 -0
  111. package/dist/schema/nodes/structural-grid.d.ts.map +1 -0
  112. package/dist/schema/nodes/structural-grid.js +17 -0
  113. package/dist/schema/nodes/wall.d.ts +5 -2
  114. package/dist/schema/nodes/wall.d.ts.map +1 -1
  115. package/dist/schema/nodes/wall.js +13 -4
  116. package/dist/schema/nodes/window.d.ts +29 -0
  117. package/dist/schema/nodes/window.d.ts.map +1 -1
  118. package/dist/schema/nodes/window.js +18 -0
  119. package/dist/schema/nodes/zone.d.ts +20 -0
  120. package/dist/schema/nodes/zone.d.ts.map +1 -1
  121. package/dist/schema/nodes/zone.js +15 -0
  122. package/dist/schema/terrain.d.ts +28 -0
  123. package/dist/schema/terrain.d.ts.map +1 -0
  124. package/dist/schema/terrain.js +30 -0
  125. package/dist/schema/types.d.ts +211 -3
  126. package/dist/schema/types.d.ts.map +1 -1
  127. package/dist/schema/types.js +4 -0
  128. package/dist/services/__fixtures__/wall-plane-top-boundary-repro.d.ts +80 -0
  129. package/dist/services/__fixtures__/wall-plane-top-boundary-repro.d.ts.map +1 -0
  130. package/dist/services/__fixtures__/wall-plane-top-boundary-repro.js +89 -0
  131. package/dist/services/index.d.ts +2 -1
  132. package/dist/services/index.d.ts.map +1 -1
  133. package/dist/services/index.js +2 -1
  134. package/dist/services/level-height.d.ts +8 -9
  135. package/dist/services/level-height.d.ts.map +1 -1
  136. package/dist/services/level-height.js +48 -16
  137. package/dist/services/storey.d.ts +103 -0
  138. package/dist/services/storey.d.ts.map +1 -0
  139. package/dist/services/storey.js +296 -0
  140. package/dist/store/actions/node-actions.d.ts.map +1 -1
  141. package/dist/store/actions/node-actions.js +47 -3
  142. package/dist/store/history-control.d.ts +20 -0
  143. package/dist/store/history-control.d.ts.map +1 -1
  144. package/dist/store/history-control.js +110 -13
  145. package/dist/store/use-live-terrain.d.ts +65 -0
  146. package/dist/store/use-live-terrain.d.ts.map +1 -0
  147. package/dist/store/use-live-terrain.js +31 -0
  148. package/dist/store/use-live-transforms.d.ts +8 -0
  149. package/dist/store/use-live-transforms.d.ts.map +1 -1
  150. package/dist/store/use-scene.d.ts +31 -2
  151. package/dist/store/use-scene.d.ts.map +1 -1
  152. package/dist/store/use-scene.js +638 -8
  153. package/dist/systems/elevator/elevator-opening-system.d.ts +1 -0
  154. package/dist/systems/elevator/elevator-opening-system.d.ts.map +1 -1
  155. package/dist/systems/elevator/elevator-opening-system.js +27 -21
  156. package/dist/systems/elevator/elevator-service.d.ts +0 -2
  157. package/dist/systems/elevator/elevator-service.d.ts.map +1 -1
  158. package/dist/systems/elevator/elevator-service.js +2 -24
  159. package/dist/systems/slab/slab-placement.d.ts +11 -0
  160. package/dist/systems/slab/slab-placement.d.ts.map +1 -0
  161. package/dist/systems/slab/slab-placement.js +14 -0
  162. package/dist/systems/slab/slab-support.d.ts +150 -0
  163. package/dist/systems/slab/slab-support.d.ts.map +1 -0
  164. package/dist/systems/slab/slab-support.js +575 -0
  165. package/dist/systems/stair/stair-opening-preview.d.ts +1060 -935
  166. package/dist/systems/stair/stair-opening-preview.d.ts.map +1 -1
  167. package/dist/systems/stair/stair-opening-sync.d.ts.map +1 -1
  168. package/dist/systems/stair/stair-opening-sync.js +18 -15
  169. package/dist/systems/stair/stair-opening-system.d.ts.map +1 -1
  170. package/dist/systems/stair/stair-opening-system.js +32 -4
  171. package/dist/systems/stair/stair-rise.d.ts +22 -0
  172. package/dist/systems/stair/stair-rise.d.ts.map +1 -0
  173. package/dist/systems/stair/stair-rise.js +79 -0
  174. package/dist/systems/wall/wall-curve.d.ts +10 -0
  175. package/dist/systems/wall/wall-curve.d.ts.map +1 -1
  176. package/dist/systems/wall/wall-curve.js +1 -1
  177. package/dist/systems/wall/wall-mitering.js +6 -6
  178. package/dist/systems/wall/wall-top.d.ts +40 -0
  179. package/dist/systems/wall/wall-top.d.ts.map +1 -0
  180. package/dist/systems/wall/wall-top.js +46 -0
  181. package/dist/utils/clone-scene-graph.d.ts.map +1 -1
  182. package/dist/utils/clone-scene-graph.js +34 -3
  183. package/dist/utils/heal-scene-graph.d.ts +1 -1
  184. package/dist/utils/heal-scene-graph.d.ts.map +1 -1
  185. package/dist/utils/heal-scene-graph.js +25 -9
  186. package/dist/validation/validate-build-json.d.ts +2 -0
  187. package/dist/validation/validate-build-json.d.ts.map +1 -1
  188. package/dist/validation/validate-build-json.js +59 -3
  189. package/package.json +2 -2
  190. package/dist/hooks/scene-registry/scene-registry.test.d.ts +0 -2
  191. package/dist/hooks/scene-registry/scene-registry.test.d.ts.map +0 -1
  192. package/dist/hooks/scene-registry/scene-registry.test.js +0 -26
  193. package/dist/hooks/spatial-grid/floor-placed-elevation.test.d.ts +0 -2
  194. package/dist/hooks/spatial-grid/floor-placed-elevation.test.d.ts.map +0 -1
  195. package/dist/hooks/spatial-grid/floor-placed-elevation.test.js +0 -366
  196. package/dist/hooks/spatial-grid/wall-slab-overlap.test.d.ts +0 -2
  197. package/dist/hooks/spatial-grid/wall-slab-overlap.test.d.ts.map +0 -1
  198. package/dist/hooks/spatial-grid/wall-slab-overlap.test.js +0 -363
  199. package/dist/lib/measurement-geometry.test.d.ts +0 -2
  200. package/dist/lib/measurement-geometry.test.d.ts.map +0 -1
  201. package/dist/lib/measurement-geometry.test.js +0 -102
  202. package/dist/lib/slab-polygon.test.d.ts +0 -2
  203. package/dist/lib/slab-polygon.test.d.ts.map +0 -1
  204. package/dist/lib/slab-polygon.test.js +0 -635
  205. package/dist/lib/space-detection-pause.test.d.ts +0 -2
  206. package/dist/lib/space-detection-pause.test.d.ts.map +0 -1
  207. package/dist/lib/space-detection-pause.test.js +0 -42
  208. package/dist/lib/space-detection.test.d.ts +0 -2
  209. package/dist/lib/space-detection.test.d.ts.map +0 -1
  210. package/dist/lib/space-detection.test.js +0 -376
  211. package/dist/lib/zone-quantities.test.d.ts +0 -2
  212. package/dist/lib/zone-quantities.test.d.ts.map +0 -1
  213. package/dist/lib/zone-quantities.test.js +0 -82
  214. package/dist/registry/registry.test.d.ts +0 -2
  215. package/dist/registry/registry.test.d.ts.map +0 -1
  216. package/dist/registry/registry.test.js +0 -196
  217. package/dist/registry/relations-resolver.test.d.ts +0 -2
  218. package/dist/registry/relations-resolver.test.d.ts.map +0 -1
  219. package/dist/registry/relations-resolver.test.js +0 -183
  220. package/dist/registry/scene-api.test.d.ts +0 -2
  221. package/dist/registry/scene-api.test.d.ts.map +0 -1
  222. package/dist/registry/scene-api.test.js +0 -183
  223. package/dist/registry/subtree.test.d.ts +0 -2
  224. package/dist/registry/subtree.test.d.ts.map +0 -1
  225. package/dist/registry/subtree.test.js +0 -163
  226. package/dist/schema/asset-url.test.d.ts +0 -2
  227. package/dist/schema/asset-url.test.d.ts.map +0 -1
  228. package/dist/schema/asset-url.test.js +0 -134
  229. package/dist/schema/material.test.d.ts +0 -2
  230. package/dist/schema/material.test.d.ts.map +0 -1
  231. package/dist/schema/material.test.js +0 -43
  232. package/dist/schema/nodes/measurement.test.d.ts +0 -2
  233. package/dist/schema/nodes/measurement.test.d.ts.map +0 -1
  234. package/dist/schema/nodes/measurement.test.js +0 -139
  235. package/dist/schema/nodes/ridge-vent-defaults.test.d.ts +0 -2
  236. package/dist/schema/nodes/ridge-vent-defaults.test.d.ts.map +0 -1
  237. package/dist/schema/nodes/ridge-vent-defaults.test.js +0 -205
  238. package/dist/schema/nodes/roof-segment-shape.test.d.ts +0 -2
  239. package/dist/schema/nodes/roof-segment-shape.test.d.ts.map +0 -1
  240. package/dist/schema/nodes/roof-segment-shape.test.js +0 -175
  241. package/dist/schema/nodes/roof-segment-surface.test.d.ts +0 -2
  242. package/dist/schema/nodes/roof-segment-surface.test.d.ts.map +0 -1
  243. package/dist/schema/nodes/roof-segment-surface.test.js +0 -48
  244. package/dist/schema/nodes/roof-segment-trim.test.d.ts +0 -2
  245. package/dist/schema/nodes/roof-segment-trim.test.d.ts.map +0 -1
  246. package/dist/schema/nodes/roof-segment-trim.test.js +0 -107
  247. package/dist/schema/nodes/roof-segment-walls.test.d.ts +0 -2
  248. package/dist/schema/nodes/roof-segment-walls.test.d.ts.map +0 -1
  249. package/dist/schema/nodes/roof-segment-walls.test.js +0 -92
  250. package/dist/schema/nodes/wall.test.d.ts +0 -2
  251. package/dist/schema/nodes/wall.test.d.ts.map +0 -1
  252. package/dist/schema/nodes/wall.test.js +0 -208
  253. package/dist/services/alignment-anchors.test.d.ts +0 -2
  254. package/dist/services/alignment-anchors.test.d.ts.map +0 -1
  255. package/dist/services/alignment-anchors.test.js +0 -383
  256. package/dist/services/alignment.test.d.ts +0 -2
  257. package/dist/services/alignment.test.d.ts.map +0 -1
  258. package/dist/services/alignment.test.js +0 -92
  259. package/dist/services/drag-session.test.d.ts +0 -2
  260. package/dist/services/drag-session.test.d.ts.map +0 -1
  261. package/dist/services/drag-session.test.js +0 -219
  262. package/dist/services/hosting.test.d.ts +0 -2
  263. package/dist/services/hosting.test.d.ts.map +0 -1
  264. package/dist/services/hosting.test.js +0 -230
  265. package/dist/services/movement.test.d.ts +0 -2
  266. package/dist/services/movement.test.d.ts.map +0 -1
  267. package/dist/services/movement.test.js +0 -133
  268. package/dist/services/opening-guides.test.d.ts +0 -2
  269. package/dist/services/opening-guides.test.d.ts.map +0 -1
  270. package/dist/services/opening-guides.test.js +0 -208
  271. package/dist/services/port-connectivity.test.d.ts +0 -2
  272. package/dist/services/port-connectivity.test.d.ts.map +0 -1
  273. package/dist/services/port-connectivity.test.js +0 -297
  274. package/dist/services/riser-diagram.test.d.ts +0 -2
  275. package/dist/services/riser-diagram.test.d.ts.map +0 -1
  276. package/dist/services/riser-diagram.test.js +0 -66
  277. package/dist/services/single-undo-dance.test.d.ts +0 -2
  278. package/dist/services/single-undo-dance.test.d.ts.map +0 -1
  279. package/dist/services/single-undo-dance.test.js +0 -210
  280. package/dist/services/snap.test.d.ts +0 -2
  281. package/dist/services/snap.test.d.ts.map +0 -1
  282. package/dist/services/snap.test.js +0 -137
  283. package/dist/services/system-graph.test.d.ts +0 -2
  284. package/dist/services/system-graph.test.d.ts.map +0 -1
  285. package/dist/services/system-graph.test.js +0 -138
  286. package/dist/services/validate-dwv.test.d.ts +0 -2
  287. package/dist/services/validate-dwv.test.d.ts.map +0 -1
  288. package/dist/services/validate-dwv.test.js +0 -109
  289. package/dist/store/actions/node-mutation-sanitize.test.d.ts +0 -2
  290. package/dist/store/actions/node-mutation-sanitize.test.d.ts.map +0 -1
  291. package/dist/store/actions/node-mutation-sanitize.test.js +0 -147
  292. package/dist/store/actions/reparent.test.d.ts +0 -2
  293. package/dist/store/actions/reparent.test.d.ts.map +0 -1
  294. package/dist/store/actions/reparent.test.js +0 -212
  295. package/dist/store/actions/ridge-vent-update.test.d.ts +0 -2
  296. package/dist/store/actions/ridge-vent-update.test.d.ts.map +0 -1
  297. package/dist/store/actions/ridge-vent-update.test.js +0 -264
  298. package/dist/store/use-scene-dirty-tracking.test.d.ts +0 -2
  299. package/dist/store/use-scene-dirty-tracking.test.d.ts.map +0 -1
  300. package/dist/store/use-scene-dirty-tracking.test.js +0 -68
  301. package/dist/store/use-scene-elevator-migration.test.d.ts +0 -2
  302. package/dist/store/use-scene-elevator-migration.test.d.ts.map +0 -1
  303. package/dist/store/use-scene-elevator-migration.test.js +0 -109
  304. package/dist/store/use-scene-measurement-roundtrip.test.d.ts +0 -2
  305. package/dist/store/use-scene-measurement-roundtrip.test.d.ts.map +0 -1
  306. package/dist/store/use-scene-measurement-roundtrip.test.js +0 -97
  307. package/dist/store/use-scene-plugins.test.d.ts +0 -2
  308. package/dist/store/use-scene-plugins.test.d.ts.map +0 -1
  309. package/dist/store/use-scene-plugins.test.js +0 -51
  310. package/dist/store/use-scene-wall-slot-migration.test.d.ts +0 -2
  311. package/dist/store/use-scene-wall-slot-migration.test.d.ts.map +0 -1
  312. package/dist/store/use-scene-wall-slot-migration.test.js +0 -210
  313. package/dist/store/use-scene-window-migration.test.d.ts +0 -2
  314. package/dist/store/use-scene-window-migration.test.d.ts.map +0 -1
  315. package/dist/store/use-scene-window-migration.test.js +0 -85
  316. package/dist/systems/elevator/elevator-opening-sync.test.d.ts +0 -2
  317. package/dist/systems/elevator/elevator-opening-sync.test.d.ts.map +0 -1
  318. package/dist/systems/elevator/elevator-opening-sync.test.js +0 -146
  319. package/dist/systems/elevator/elevator-runtime.test.d.ts +0 -2
  320. package/dist/systems/elevator/elevator-runtime.test.d.ts.map +0 -1
  321. package/dist/systems/elevator/elevator-runtime.test.js +0 -64
  322. package/dist/systems/fence/fence-spline.test.d.ts +0 -2
  323. package/dist/systems/fence/fence-spline.test.d.ts.map +0 -1
  324. package/dist/systems/fence/fence-spline.test.js +0 -136
  325. package/dist/systems/stair/stair-opening-preview.test.d.ts +0 -2
  326. package/dist/systems/stair/stair-opening-preview.test.d.ts.map +0 -1
  327. package/dist/systems/stair/stair-opening-preview.test.js +0 -80
  328. package/dist/systems/stair/stair-opening-sync.test.d.ts +0 -2
  329. package/dist/systems/stair/stair-opening-sync.test.d.ts.map +0 -1
  330. package/dist/systems/stair/stair-opening-sync.test.js +0 -485
  331. package/dist/systems/wall/wall-mitering.test.d.ts +0 -2
  332. package/dist/systems/wall/wall-mitering.test.d.ts.map +0 -1
  333. package/dist/systems/wall/wall-mitering.test.js +0 -63
  334. package/dist/utils/clone-scene-graph.test.d.ts +0 -2
  335. package/dist/utils/clone-scene-graph.test.d.ts.map +0 -1
  336. package/dist/utils/clone-scene-graph.test.js +0 -62
  337. package/dist/utils/heal-scene-graph.test.d.ts +0 -2
  338. package/dist/utils/heal-scene-graph.test.d.ts.map +0 -1
  339. package/dist/utils/heal-scene-graph.test.js +0 -88
@@ -1,363 +0,0 @@
1
- import { describe, expect, it } from 'bun:test';
2
- import { SlabNode, WallNode } from '../../schema';
3
- import { computeWallSlabElevation, computeWallSlabSupport, wallOverlapsPolygon, } from './spatial-grid-manager';
4
- // 4×4 square slab, like an auto-slab derived from a room's wall centerlines.
5
- const SLAB = [
6
- [0, 0],
7
- [4, 0],
8
- [4, 4],
9
- [0, 4],
10
- ];
11
- const wall = (start, end, curveOffset = 0) => ({
12
- start,
13
- end,
14
- curveOffset,
15
- thickness: 0.1,
16
- });
17
- describe('wallOverlapsPolygon', () => {
18
- it('excludes perpendicular walls butting into the slab, on every side', () => {
19
- // Regression: side-dependent ray-cast tie-breaking used to push some of
20
- // these walls (depending on which slab edge they touched) but not others.
21
- expect(wallOverlapsPolygon(wall([2, 4], [2, 7]), SLAB)).toBe(false); // top
22
- expect(wallOverlapsPolygon(wall([2, 0], [2, -3]), SLAB)).toBe(false); // bottom
23
- expect(wallOverlapsPolygon(wall([0, 2], [-3, 2]), SLAB)).toBe(false); // left
24
- expect(wallOverlapsPolygon(wall([4, 2], [7, 2]), SLAB)).toBe(false); // right
25
- // Reversed direction (endpoint order must not matter)
26
- expect(wallOverlapsPolygon(wall([2, 7], [2, 4]), SLAB)).toBe(false);
27
- expect(wallOverlapsPolygon(wall([-3, 2], [0, 2]), SLAB)).toBe(false);
28
- });
29
- it('includes walls lying on the slab boundary, on every side', () => {
30
- expect(wallOverlapsPolygon(wall([0, 0], [4, 0]), SLAB)).toBe(true); // bottom
31
- expect(wallOverlapsPolygon(wall([4, 0], [4, 4]), SLAB)).toBe(true); // right
32
- expect(wallOverlapsPolygon(wall([4, 4], [0, 4]), SLAB)).toBe(true); // top
33
- expect(wallOverlapsPolygon(wall([0, 4], [0, 0]), SLAB)).toBe(true); // left
34
- // Partial edge coverage still counts
35
- expect(wallOverlapsPolygon(wall([1, 0], [3, 0]), SLAB)).toBe(true);
36
- });
37
- it('includes a wall running past the slab if enough of it lies on the edge', () => {
38
- // 4m on the edge + 6m beyond: whole wall follows the slab.
39
- expect(wallOverlapsPolygon(wall([0, 0], [10, 0]), SLAB)).toBe(true);
40
- });
41
- it('excludes corner-only contact', () => {
42
- expect(wallOverlapsPolygon(wall([4, 4], [6, 6]), SLAB)).toBe(false);
43
- expect(wallOverlapsPolygon(wall([0, 0], [-2, -2]), SLAB)).toBe(false);
44
- });
45
- it('includes walls inside or crossing through the slab', () => {
46
- expect(wallOverlapsPolygon(wall([1, 1], [3, 3]), SLAB)).toBe(true); // fully inside
47
- expect(wallOverlapsPolygon(wall([-1, 2], [5, 2]), SLAB)).toBe(true); // crossing
48
- });
49
- it('uses wall thickness: a face grazing the slab counts, clear separation does not', () => {
50
- // Centerline 4cm outside, body (half thickness 5cm) reaches the slab.
51
- expect(wallOverlapsPolygon(wall([0, -0.04], [4, -0.04]), SLAB)).toBe(true);
52
- // Centerline 1m outside: no contact.
53
- expect(wallOverlapsPolygon(wall([0, -1], [4, -1]), SLAB)).toBe(false);
54
- });
55
- it('handles curved walls by their sampled body', () => {
56
- // Chord below the slab, bowing into the slab interior (negative offset
57
- // bows toward +z here).
58
- expect(wallOverlapsPolygon(wall([0, -0.5], [4, -0.5], -1), SLAB)).toBe(true);
59
- // Same chord bowing away from the slab: never touches it.
60
- expect(wallOverlapsPolygon(wall([0, -0.5], [4, -0.5], 1), SLAB)).toBe(false);
61
- });
62
- it('supports the legacy (start, end, polygon) call shape', () => {
63
- expect(wallOverlapsPolygon([1, 1], [3, 3], SLAB)).toBe(true);
64
- expect(wallOverlapsPolygon([2, 4], [2, 7], SLAB)).toBe(false);
65
- });
66
- });
67
- describe('computeWallSlabElevation', () => {
68
- const parseWall = (start, end, thickness = 0.1) => WallNode.parse({ start, end, thickness });
69
- it('lifts a wall standing on an auto slab stored at the centerlines', () => {
70
- const walls = [
71
- parseWall([0, 0], [4, 0]),
72
- parseWall([4, 0], [4, 4]),
73
- parseWall([4, 4], [0, 4]),
74
- parseWall([0, 4], [0, 0]),
75
- ];
76
- const slab = SlabNode.parse({ polygon: SLAB, elevation: 0.1 });
77
- const bottom = walls[0];
78
- expect(computeWallSlabElevation({ start: bottom.start, end: bottom.end, thickness: bottom.thickness }, [slab], walls)).toBeCloseTo(0.1);
79
- });
80
- it('lifts a wall whose body a legacy stored polygon falls short of', () => {
81
- // Legacy hand-adjusted slab: edges 6cm inside the wall centerlines —
82
- // 1cm short of even the inner faces, so the STORED polygon never
83
- // touches the wall body and the old stored-polygon test returned 0.
84
- // The rendered footprint band-adopts the edges out to the outer
85
- // faces, so the wall stands on the slab.
86
- const walls = [
87
- parseWall([0, 0], [4, 0]),
88
- parseWall([4, 0], [4, 4]),
89
- parseWall([4, 4], [0, 4]),
90
- parseWall([0, 4], [0, 0]),
91
- ];
92
- const slab = SlabNode.parse({
93
- polygon: [
94
- [0.06, 0.06],
95
- [3.94, 0.06],
96
- [3.94, 3.94],
97
- [0.06, 3.94],
98
- ],
99
- elevation: 0.1,
100
- });
101
- const bottom = walls[0];
102
- expect(computeWallSlabElevation({ start: bottom.start, end: bottom.end, thickness: bottom.thickness }, [slab], walls)).toBeCloseTo(0.1);
103
- });
104
- it('does not lift a wall clearly off the slab', () => {
105
- const walls = [parseWall([0, 0], [4, 0])];
106
- const slab = SlabNode.parse({ polygon: SLAB, elevation: 0.1 });
107
- expect(computeWallSlabElevation({ start: [0, -1], end: [4, -1], thickness: 0.1 }, [slab], walls)).toBe(0);
108
- });
109
- it('ignores a slab when the wall runs entirely inside a hole', () => {
110
- const walls = [parseWall([1, 2], [3, 2])];
111
- const slab = SlabNode.parse({
112
- polygon: SLAB,
113
- elevation: 0.1,
114
- holes: [
115
- [
116
- [0.5, 0.5],
117
- [3.5, 0.5],
118
- [3.5, 3.5],
119
- [0.5, 3.5],
120
- ],
121
- ],
122
- });
123
- expect(computeWallSlabElevation({ start: [1, 2], end: [3, 2], thickness: 0.1 }, [slab], walls)).toBe(0);
124
- });
125
- it('keeps a wall on the lower slab when a higher slab only reaches one endpoint', () => {
126
- // The floating-wall bug: a wall standing on the low room whose far
127
- // endpoint pokes 0.2m onto a raised platform must NOT lift wholesale.
128
- const low = SlabNode.parse({ polygon: SLAB, elevation: 0.05 });
129
- const high = SlabNode.parse({
130
- polygon: [
131
- [4, 0],
132
- [8, 0],
133
- [8, 4],
134
- [4, 4],
135
- ],
136
- elevation: 0.6,
137
- });
138
- expect(computeWallSlabElevation({ start: [0.5, 2], end: [4.2, 2], thickness: 0.1 }, [low, high], [])).toBeCloseTo(0.05);
139
- });
140
- it('keeps a curved wall on the lower slab when a higher slab only reaches its end', () => {
141
- const low = SlabNode.parse({ polygon: SLAB, elevation: 0.05 });
142
- const high = SlabNode.parse({
143
- polygon: [
144
- [4, 0],
145
- [8, 0],
146
- [8, 4],
147
- [4, 4],
148
- ],
149
- elevation: 0.6,
150
- });
151
- expect(computeWallSlabElevation({ start: [0.5, 2], end: [4.2, 2], curveOffset: 0.5, thickness: 0.1 }, [low, high], [])).toBeCloseTo(0.05);
152
- });
153
- it('lifts a wall standing fully on a raised platform', () => {
154
- const platform = SlabNode.parse({ polygon: SLAB, elevation: 0.6 });
155
- expect(computeWallSlabElevation({ start: [1, 2], end: [3, 2], thickness: 0.1 }, [platform], [])).toBeCloseTo(0.6);
156
- });
157
- it('lifts a wall half on a raised platform, half in the air, onto the platform', () => {
158
- // No elevation reaches majority (only 39% supported), so the
159
- // best-covered slab wins — the only alternative would bury the
160
- // supported half inside the platform.
161
- const platform = SlabNode.parse({ polygon: SLAB, elevation: 0.6 });
162
- expect(computeWallSlabElevation({ start: [0.1, 2], end: [10.1, 2], thickness: 0.1 }, [platform], [])).toBeCloseTo(0.6);
163
- });
164
- it('pools same-elevation slabs so a shared wall follows their common level', () => {
165
- // Rooms A and B at the same elevation each cover exactly half the
166
- // wall (interior edges seam at the x=2 midline); a raised slab covers
167
- // just under half. Pooled, the common level covers 100% and must
168
- // win — without pooling the raised slab's 0.4975 would beat either
169
- // half alone.
170
- const roomA = SlabNode.parse({
171
- polygon: [
172
- [0, 0],
173
- [2, 0],
174
- [2, 4],
175
- [0, 4],
176
- ],
177
- elevation: 0.1,
178
- });
179
- const roomB = SlabNode.parse({
180
- polygon: [
181
- [2, 0],
182
- [4, 0],
183
- [4, 4],
184
- [2, 4],
185
- ],
186
- elevation: 0.1,
187
- });
188
- const raised = SlabNode.parse({
189
- polygon: [
190
- [1.0, 1],
191
- [2.99, 1],
192
- [2.99, 3],
193
- [1.0, 3],
194
- ],
195
- elevation: 0.6,
196
- });
197
- expect(computeWallSlabElevation({ start: [0, 2], end: [4, 2], thickness: 0.1 }, [roomA, roomB, raised], [])).toBeCloseTo(0.1);
198
- });
199
- it('prefers the higher of two majority-supporting slabs (platform stacked on a floor)', () => {
200
- const floor = SlabNode.parse({
201
- polygon: [
202
- [0, 0],
203
- [8, 0],
204
- [8, 4],
205
- [0, 4],
206
- ],
207
- elevation: 0.05,
208
- });
209
- const platform = SlabNode.parse({
210
- polygon: [
211
- [0, 0],
212
- [5, 0],
213
- [5, 4],
214
- [0, 4],
215
- ],
216
- elevation: 0.6,
217
- });
218
- // Wall 6m long: floor covers all of it, platform covers ~2/3 — both
219
- // majorities, and the wall physically rests on the platform.
220
- expect(computeWallSlabElevation({ start: [1, 2], end: [7, 2], thickness: 0.1 }, [floor, platform], [])).toBeCloseTo(0.6);
221
- });
222
- it('keeps a wall pushed up on a raised platform above a coincident floor', () => {
223
- const floor = SlabNode.parse({ polygon: SLAB, elevation: 0.05 });
224
- const platform = SlabNode.parse({ polygon: SLAB, elevation: 0.6 });
225
- expect(computeWallSlabSupport({ start: [1, 2], end: [3, 2], thickness: 0.1 }, [floor, platform], [])).toEqual({
226
- elevation: 0.6,
227
- baseElevation: 0.6,
228
- baseSegments: [{ start: 0, end: 1, elevation: 0.6 }],
229
- });
230
- });
231
- it('fills down only when a lower support is exposed beyond a partial platform', () => {
232
- const floor = SlabNode.parse({ polygon: SLAB, elevation: 0.05 });
233
- const platform = SlabNode.parse({
234
- polygon: [
235
- [0, 0],
236
- [2.5, 0],
237
- [2.5, 4],
238
- [0, 4],
239
- ],
240
- elevation: 0.6,
241
- });
242
- expect(computeWallSlabSupport({ start: [0.5, 2], end: [3.5, 2], thickness: 0.1 }, [floor, platform], [])).toEqual({
243
- elevation: 0.6,
244
- baseElevation: 0.05,
245
- baseSegments: [
246
- { start: 0, end: 2 / 3, elevation: 0.6 },
247
- { start: 2 / 3, end: 1, elevation: 0.05 },
248
- ],
249
- });
250
- });
251
- it('keeps a shared wall on the higher slab that carries the full wall band', () => {
252
- const sharedWall = parseWall([4, 0], [4, 4]);
253
- const low = SlabNode.parse({ polygon: SLAB, elevation: 0.05 });
254
- const high = SlabNode.parse({
255
- polygon: [
256
- [4, 0],
257
- [8, 0],
258
- [8, 4],
259
- [4, 4],
260
- ],
261
- elevation: 0.6,
262
- });
263
- expect(computeWallSlabSupport({ start: sharedWall.start, end: sharedWall.end, thickness: sharedWall.thickness }, [low, high], [sharedWall])).toEqual({
264
- elevation: 0.6,
265
- baseElevation: 0.6,
266
- baseSegments: [{ start: 0, end: 1, elevation: 0.6 }],
267
- });
268
- });
269
- it('profiles an offset-room wall as high-only, shared, then low-only', () => {
270
- const sharedWall = parseWall([4, 0], [4, 4.5]);
271
- const walls = [
272
- parseWall([0, 0], [4, 0]),
273
- parseWall([0, 3], [0, 0]),
274
- parseWall([0, 3], [4, 3]),
275
- sharedWall,
276
- parseWall([4, 1.5], [8, 1.5]),
277
- parseWall([8, 1.5], [8, 4.5]),
278
- parseWall([8, 4.5], [4, 4.5]),
279
- ];
280
- const high = SlabNode.parse({
281
- polygon: [
282
- [0, 0],
283
- [4, 0],
284
- [4, 3],
285
- [0, 3],
286
- ],
287
- elevation: 0.6,
288
- });
289
- const low = SlabNode.parse({
290
- polygon: [
291
- [4, 1.5],
292
- [8, 1.5],
293
- [8, 4.5],
294
- [4, 4.5],
295
- ],
296
- elevation: 0.05,
297
- });
298
- expect(computeWallSlabSupport({ start: sharedWall.start, end: sharedWall.end, thickness: sharedWall.thickness }, [high, low], walls)).toEqual({
299
- elevation: 0.6,
300
- baseElevation: 0.05,
301
- baseSegments: [
302
- { start: 0, end: 3.05 / 4.5, elevation: 0.6 },
303
- { start: 3.05 / 4.5, end: 1, elevation: 0.05 },
304
- ],
305
- });
306
- });
307
- it('lifts a tiny stub wall standing fully on a slab', () => {
308
- const slab = SlabNode.parse({ polygon: SLAB, elevation: 0.3 });
309
- expect(computeWallSlabElevation({ start: [2, 2], end: [2.08, 2], thickness: 0.1 }, [slab], [])).toBeCloseTo(0.3);
310
- });
311
- it('does not lift a wall whose run over a higher slab is mostly inside a hole', () => {
312
- const low = SlabNode.parse({
313
- polygon: [
314
- [0, 0],
315
- [8, 0],
316
- [8, 4],
317
- [0, 4],
318
- ],
319
- elevation: 0.05,
320
- });
321
- const high = SlabNode.parse({
322
- polygon: [
323
- [0, 0],
324
- [8, 0],
325
- [8, 4],
326
- [0, 4],
327
- ],
328
- elevation: 0.6,
329
- holes: [
330
- [
331
- [0.5, 0],
332
- [8, 0],
333
- [8, 4],
334
- [0.5, 4],
335
- ],
336
- ],
337
- });
338
- // Net high support is only x ∈ [0, 0.5]; the low slab carries the wall.
339
- expect(computeWallSlabElevation({ start: [0, 2], end: [8, 2], thickness: 0.1 }, [low, high], [])).toBeCloseTo(0.05);
340
- });
341
- it('keeps support for a wall running along a hole rim', () => {
342
- // Hole boundaries count as solid: the wall ringing a stairwell sits
343
- // on the rim, its outer face on solid slab.
344
- const slab = SlabNode.parse({
345
- polygon: [
346
- [0, 0],
347
- [6, 0],
348
- [6, 6],
349
- [0, 6],
350
- ],
351
- elevation: 0.4,
352
- holes: [
353
- [
354
- [2, 2],
355
- [4, 2],
356
- [4, 4],
357
- [2, 4],
358
- ],
359
- ],
360
- });
361
- expect(computeWallSlabElevation({ start: [2, 2], end: [4, 2], thickness: 0.1 }, [slab], [])).toBeCloseTo(0.4);
362
- });
363
- });
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=measurement-geometry.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"measurement-geometry.test.d.ts","sourceRoot":"","sources":["../../src/lib/measurement-geometry.test.ts"],"names":[],"mappings":""}
@@ -1,102 +0,0 @@
1
- import { describe, expect, test } from 'bun:test';
2
- import { areMeasurementPointsCoplanar, closestMeasurementFeatureBinding, measurementAngle, measurementArea, measurementAreaVector, measurementCentroid, measurementDistance, measurementNormal, measurementPerimeter, measurementPrismVolume, } from './measurement-geometry';
3
- const expectPointCloseTo = (actual, expected) => {
4
- expect(actual).not.toBeNull();
5
- for (let index = 0; index < 3; index++) {
6
- expect(actual[index]).toBeCloseTo(expected[index]);
7
- }
8
- };
9
- describe('measurement geometry', () => {
10
- test('measures full 3D distance', () => {
11
- expect(measurementDistance([1, 2, 3], [4, 6, 15])).toBe(13);
12
- });
13
- test('measures the smaller 3D angle and a closed perimeter', () => {
14
- expect(measurementAngle([1, 0, 0], [0, 0, 0], [0, 1, 0])).toBeCloseTo(Math.PI / 2);
15
- expect(measurementAngle([0, 0, 0], [0, 0, 0], [1, 0, 0])).toBe(0);
16
- expect(measurementPerimeter([
17
- [0, 0, 0],
18
- [3, 0, 0],
19
- [3, 0, 4],
20
- ])).toBe(12);
21
- });
22
- test('matches the closest semantic feature with a normalized path position', () => {
23
- const features = [
24
- {
25
- id: 'boundary',
26
- label: 'Boundary',
27
- snapKind: 'edge',
28
- geometry: {
29
- kind: 'polygon',
30
- points: [
31
- [0, 0, 0],
32
- [2, 0, 0],
33
- [2, 0, 2],
34
- [0, 0, 2],
35
- ],
36
- },
37
- },
38
- ];
39
- const match = closestMeasurementFeatureBinding(features, [1.9, 0, 1], 0.2);
40
- expect(match?.featureId).toBe('boundary');
41
- expect(match?.point).toEqual([2, 0, 1]);
42
- expect(match?.parameters?.t).toBeCloseTo(0.375);
43
- expect(match?.distance).toBeCloseTo(0.1);
44
- });
45
- test('computes a Newell area vector, area, and winding-aware normal', () => {
46
- const base = [
47
- [0, 0, 0],
48
- [2, 0, 0],
49
- [2, 1, 1],
50
- [0, 1, 1],
51
- ];
52
- expectPointCloseTo(measurementAreaVector(base), [0, -2, 2]);
53
- expect(measurementArea(base)).toBeCloseTo(2 * Math.sqrt(2));
54
- expectPointCloseTo(measurementNormal(base), [0, -Math.SQRT1_2, Math.SQRT1_2]);
55
- expectPointCloseTo(measurementNormal([...base].reverse()), [0, Math.SQRT1_2, -Math.SQRT1_2]);
56
- });
57
- test('checks coplanarity against the Newell normal', () => {
58
- const base = [
59
- [0, 0, 0],
60
- [2, 0, 0],
61
- [2, 1, 1],
62
- [0, 1, 1],
63
- ];
64
- expect(areMeasurementPointsCoplanar(base)).toBe(true);
65
- expect(areMeasurementPointsCoplanar([...base, [1, 0.5, 0.51]])).toBe(false);
66
- expect(areMeasurementPointsCoplanar([
67
- [0, 0, 0],
68
- [1, 0, 0],
69
- [2, 0, 0],
70
- ])).toBe(false);
71
- });
72
- test('computes the area-weighted centroid of a planar 3D polygon', () => {
73
- expectPointCloseTo(measurementCentroid([
74
- [0, 0, 0],
75
- [2, 0, 0],
76
- [2, 1, 1],
77
- [0, 1, 1],
78
- ]), [1, 0.5, 0.5]);
79
- });
80
- test('computes area and centroid for a concave polygon', () => {
81
- const base = [
82
- [0, 0, 0],
83
- [2, 0, 0],
84
- [2, 0, 1],
85
- [1, 0, 1],
86
- [1, 0, 2],
87
- [0, 0, 2],
88
- ];
89
- expect(measurementArea(base)).toBeCloseTo(3);
90
- expectPointCloseTo(measurementCentroid(base), [5 / 6, 0, 5 / 6]);
91
- });
92
- test('computes prism volume from normal extrusion and ignores tangential extrusion', () => {
93
- const base = [
94
- [0, 0, 0],
95
- [3, 0, 0],
96
- [3, 2, 0],
97
- [0, 2, 0],
98
- ];
99
- expect(measurementPrismVolume(base, [5, 7, 4])).toBeCloseTo(24);
100
- expect(measurementPrismVolume([...base].reverse(), [5, 7, 4])).toBeCloseTo(24);
101
- });
102
- });
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=slab-polygon.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"slab-polygon.test.d.ts","sourceRoot":"","sources":["../../src/lib/slab-polygon.test.ts"],"names":[],"mappings":""}