@ifc-lite/create 4.0.0 → 5.1.0

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 (325) hide show
  1. package/README.md +34 -0
  2. package/dist/in-store/align-boxes.d.ts +38 -0
  3. package/dist/in-store/align-boxes.d.ts.map +1 -0
  4. package/dist/in-store/align-boxes.js +97 -0
  5. package/dist/in-store/align-boxes.js.map +1 -0
  6. package/dist/in-store/anchor.d.ts.map +1 -1
  7. package/dist/in-store/anchor.js +13 -2
  8. package/dist/in-store/anchor.js.map +1 -1
  9. package/dist/in-store/beam.d.ts.map +1 -1
  10. package/dist/in-store/beam.js +3 -10
  11. package/dist/in-store/beam.js.map +1 -1
  12. package/dist/in-store/copy-array.d.ts +17 -0
  13. package/dist/in-store/copy-array.d.ts.map +1 -0
  14. package/dist/in-store/copy-array.js +47 -0
  15. package/dist/in-store/copy-array.js.map +1 -0
  16. package/dist/in-store/copy-batch.d.ts +27 -0
  17. package/dist/in-store/copy-batch.d.ts.map +1 -0
  18. package/dist/in-store/copy-batch.js +101 -0
  19. package/dist/in-store/copy-batch.js.map +1 -0
  20. package/dist/in-store/copy-dependent-walk.d.ts +27 -0
  21. package/dist/in-store/copy-dependent-walk.d.ts.map +1 -0
  22. package/dist/in-store/copy-dependent-walk.js +61 -0
  23. package/dist/in-store/copy-dependent-walk.js.map +1 -0
  24. package/dist/in-store/copy-frame.d.ts +4 -3
  25. package/dist/in-store/copy-frame.d.ts.map +1 -1
  26. package/dist/in-store/copy-frame.js +14 -1
  27. package/dist/in-store/copy-frame.js.map +1 -1
  28. package/dist/in-store/copy-product.d.ts +0 -20
  29. package/dist/in-store/copy-product.d.ts.map +1 -1
  30. package/dist/in-store/copy-product.js +35 -35
  31. package/dist/in-store/copy-product.js.map +1 -1
  32. package/dist/in-store/edit/effective-mutation-view.d.ts +6 -0
  33. package/dist/in-store/edit/effective-mutation-view.d.ts.map +1 -0
  34. package/dist/in-store/edit/effective-mutation-view.js +45 -0
  35. package/dist/in-store/edit/effective-mutation-view.js.map +1 -0
  36. package/dist/in-store/edit/effective-storey.d.ts +13 -0
  37. package/dist/in-store/edit/effective-storey.d.ts.map +1 -0
  38. package/dist/in-store/edit/effective-storey.js +36 -0
  39. package/dist/in-store/edit/effective-storey.js.map +1 -0
  40. package/dist/in-store/edit/effective-storeys.d.ts +9 -0
  41. package/dist/in-store/edit/effective-storeys.d.ts.map +1 -0
  42. package/dist/in-store/edit/effective-storeys.js +16 -0
  43. package/dist/in-store/edit/effective-storeys.js.map +1 -0
  44. package/dist/in-store/edit/hosted-opening-refit.d.ts +29 -0
  45. package/dist/in-store/edit/hosted-opening-refit.d.ts.map +1 -0
  46. package/dist/in-store/edit/hosted-opening-refit.js +168 -0
  47. package/dist/in-store/edit/hosted-opening-refit.js.map +1 -0
  48. package/dist/in-store/edit/length-unit-scale.d.ts +24 -0
  49. package/dist/in-store/edit/length-unit-scale.d.ts.map +1 -0
  50. package/dist/in-store/edit/length-unit-scale.js +37 -0
  51. package/dist/in-store/edit/length-unit-scale.js.map +1 -0
  52. package/dist/in-store/edit/linear-element-edit.d.ts +131 -0
  53. package/dist/in-store/edit/linear-element-edit.d.ts.map +1 -0
  54. package/dist/in-store/edit/linear-element-edit.js +259 -0
  55. package/dist/in-store/edit/linear-element-edit.js.map +1 -0
  56. package/dist/in-store/edit/metadata-clone-effective.d.ts +5 -0
  57. package/dist/in-store/edit/metadata-clone-effective.d.ts.map +1 -0
  58. package/dist/in-store/edit/metadata-clone-effective.js +47 -0
  59. package/dist/in-store/edit/metadata-clone-effective.js.map +1 -0
  60. package/dist/in-store/edit/metadata-clone.d.ts +40 -0
  61. package/dist/in-store/edit/metadata-clone.d.ts.map +1 -0
  62. package/dist/in-store/edit/metadata-clone.js +107 -0
  63. package/dist/in-store/edit/metadata-clone.js.map +1 -0
  64. package/dist/in-store/edit/placement-core.d.ts +140 -0
  65. package/dist/in-store/edit/placement-core.d.ts.map +1 -0
  66. package/dist/in-store/edit/placement-core.js +317 -0
  67. package/dist/in-store/edit/placement-core.js.map +1 -0
  68. package/dist/in-store/edit/polygon-clip.d.ts +58 -0
  69. package/dist/in-store/edit/polygon-clip.d.ts.map +1 -0
  70. package/dist/in-store/edit/polygon-clip.js +153 -0
  71. package/dist/in-store/edit/polygon-clip.js.map +1 -0
  72. package/dist/in-store/edit/read-profile.d.ts +6 -0
  73. package/dist/in-store/edit/read-profile.d.ts.map +1 -0
  74. package/dist/in-store/edit/read-profile.js +95 -0
  75. package/dist/in-store/edit/read-profile.js.map +1 -0
  76. package/dist/in-store/edit/slab-edit-frame.d.ts +40 -0
  77. package/dist/in-store/edit/slab-edit-frame.d.ts.map +1 -0
  78. package/dist/in-store/edit/slab-edit-frame.js +146 -0
  79. package/dist/in-store/edit/slab-edit-frame.js.map +1 -0
  80. package/dist/in-store/edit/slab-edit.d.ts +112 -0
  81. package/dist/in-store/edit/slab-edit.d.ts.map +1 -0
  82. package/dist/in-store/edit/slab-edit.js +275 -0
  83. package/dist/in-store/edit/slab-edit.js.map +1 -0
  84. package/dist/in-store/edit/slab-opening-carry.d.ts +10 -0
  85. package/dist/in-store/edit/slab-opening-carry.d.ts.map +1 -0
  86. package/dist/in-store/edit/slab-opening-carry.js +65 -0
  87. package/dist/in-store/edit/slab-opening-carry.js.map +1 -0
  88. package/dist/in-store/edit/split-guid.d.ts +29 -0
  89. package/dist/in-store/edit/split-guid.d.ts.map +1 -0
  90. package/dist/in-store/edit/split-guid.js +64 -0
  91. package/dist/in-store/edit/split-guid.js.map +1 -0
  92. package/dist/in-store/edit/split-target.d.ts +90 -0
  93. package/dist/in-store/edit/split-target.d.ts.map +1 -0
  94. package/dist/in-store/edit/split-target.js +116 -0
  95. package/dist/in-store/edit/split-target.js.map +1 -0
  96. package/dist/in-store/edit/target.d.ts +8 -0
  97. package/dist/in-store/edit/target.d.ts.map +1 -0
  98. package/dist/in-store/edit/target.js +5 -0
  99. package/dist/in-store/edit/target.js.map +1 -0
  100. package/dist/in-store/edit/trim-extend-geometry.d.ts +99 -0
  101. package/dist/in-store/edit/trim-extend-geometry.d.ts.map +1 -0
  102. package/dist/in-store/edit/trim-extend-geometry.js +105 -0
  103. package/dist/in-store/edit/trim-extend-geometry.js.map +1 -0
  104. package/dist/in-store/edit/wall-axis-edit.d.ts +16 -0
  105. package/dist/in-store/edit/wall-axis-edit.d.ts.map +1 -0
  106. package/dist/in-store/edit/wall-axis-edit.js +40 -0
  107. package/dist/in-store/edit/wall-axis-edit.js.map +1 -0
  108. package/dist/in-store/edit/wall-edit.d.ts +157 -0
  109. package/dist/in-store/edit/wall-edit.d.ts.map +1 -0
  110. package/dist/in-store/edit/wall-edit.js +276 -0
  111. package/dist/in-store/edit/wall-edit.js.map +1 -0
  112. package/dist/in-store/edit/wall-hosted-cuts.d.ts +35 -0
  113. package/dist/in-store/edit/wall-hosted-cuts.d.ts.map +1 -0
  114. package/dist/in-store/edit/wall-hosted-cuts.js +27 -0
  115. package/dist/in-store/edit/wall-hosted-cuts.js.map +1 -0
  116. package/dist/in-store/edit/wall-opening-reassign.d.ts +18 -0
  117. package/dist/in-store/edit/wall-opening-reassign.d.ts.map +1 -0
  118. package/dist/in-store/edit/wall-opening-reassign.js +50 -0
  119. package/dist/in-store/edit/wall-opening-reassign.js.map +1 -0
  120. package/dist/in-store/element-align.d.ts +13 -0
  121. package/dist/in-store/element-align.d.ts.map +1 -0
  122. package/dist/in-store/element-align.js +90 -0
  123. package/dist/in-store/element-align.js.map +1 -0
  124. package/dist/in-store/element-replacement.d.ts +26 -0
  125. package/dist/in-store/element-replacement.d.ts.map +1 -0
  126. package/dist/in-store/element-replacement.js +68 -0
  127. package/dist/in-store/element-replacement.js.map +1 -0
  128. package/dist/in-store/element-size-edit.d.ts +40 -0
  129. package/dist/in-store/element-size-edit.d.ts.map +1 -0
  130. package/dist/in-store/element-size-edit.js +103 -0
  131. package/dist/in-store/element-size-edit.js.map +1 -0
  132. package/dist/in-store/element-split-axis.d.ts +6 -0
  133. package/dist/in-store/element-split-axis.d.ts.map +1 -0
  134. package/dist/in-store/element-split-axis.js +87 -0
  135. package/dist/in-store/element-split-axis.js.map +1 -0
  136. package/dist/in-store/element-split-joined.d.ts +13 -0
  137. package/dist/in-store/element-split-joined.d.ts.map +1 -0
  138. package/dist/in-store/element-split-joined.js +74 -0
  139. package/dist/in-store/element-split-joined.js.map +1 -0
  140. package/dist/in-store/element-split-placement.d.ts +19 -0
  141. package/dist/in-store/element-split-placement.d.ts.map +1 -0
  142. package/dist/in-store/element-split-placement.js +48 -0
  143. package/dist/in-store/element-split-placement.js.map +1 -0
  144. package/dist/in-store/element-split-slab.d.ts +19 -0
  145. package/dist/in-store/element-split-slab.d.ts.map +1 -0
  146. package/dist/in-store/element-split-slab.js +86 -0
  147. package/dist/in-store/element-split-slab.js.map +1 -0
  148. package/dist/in-store/element-split.d.ts +49 -0
  149. package/dist/in-store/element-split.d.ts.map +1 -0
  150. package/dist/in-store/element-split.js +52 -0
  151. package/dist/in-store/element-split.js.map +1 -0
  152. package/dist/in-store/element-transform-edit.d.ts +33 -0
  153. package/dist/in-store/element-transform-edit.d.ts.map +1 -0
  154. package/dist/in-store/element-transform-edit.js +97 -0
  155. package/dist/in-store/element-transform-edit.js.map +1 -0
  156. package/dist/in-store/element-transform-frames.d.ts +58 -0
  157. package/dist/in-store/element-transform-frames.d.ts.map +1 -0
  158. package/dist/in-store/element-transform-frames.js +110 -0
  159. package/dist/in-store/element-transform-frames.js.map +1 -0
  160. package/dist/in-store/element-transform-joins.d.ts +4 -0
  161. package/dist/in-store/element-transform-joins.d.ts.map +1 -0
  162. package/dist/in-store/element-transform-joins.js +62 -0
  163. package/dist/in-store/element-transform-joins.js.map +1 -0
  164. package/dist/in-store/element-transform-plan.d.ts +38 -0
  165. package/dist/in-store/element-transform-plan.d.ts.map +1 -0
  166. package/dist/in-store/element-transform-plan.js +115 -0
  167. package/dist/in-store/element-transform-plan.js.map +1 -0
  168. package/dist/in-store/element-trim-extend.d.ts +25 -0
  169. package/dist/in-store/element-trim-extend.d.ts.map +1 -0
  170. package/dist/in-store/element-trim-extend.js +97 -0
  171. package/dist/in-store/element-trim-extend.js.map +1 -0
  172. package/dist/in-store/extract-grids.d.ts +7 -17
  173. package/dist/in-store/extract-grids.d.ts.map +1 -1
  174. package/dist/in-store/extract-grids.js +11 -2
  175. package/dist/in-store/extract-grids.js.map +1 -1
  176. package/dist/in-store/grid-column.d.ts +23 -0
  177. package/dist/in-store/grid-column.d.ts.map +1 -0
  178. package/dist/in-store/grid-column.js +73 -0
  179. package/dist/in-store/grid-column.js.map +1 -0
  180. package/dist/in-store/grid-intersection-read.d.ts +10 -0
  181. package/dist/in-store/grid-intersection-read.d.ts.map +1 -0
  182. package/dist/in-store/grid-intersection-read.js +45 -0
  183. package/dist/in-store/grid-intersection-read.js.map +1 -0
  184. package/dist/in-store/grid.d.ts +7 -1
  185. package/dist/in-store/grid.d.ts.map +1 -1
  186. package/dist/in-store/grid.js +12 -2
  187. package/dist/in-store/grid.js.map +1 -1
  188. package/dist/in-store/group-evidence.d.ts +49 -0
  189. package/dist/in-store/group-evidence.d.ts.map +1 -0
  190. package/dist/in-store/group-evidence.js +111 -0
  191. package/dist/in-store/group-evidence.js.map +1 -0
  192. package/dist/in-store/group-graph.d.ts +51 -0
  193. package/dist/in-store/group-graph.d.ts.map +1 -0
  194. package/dist/in-store/group-graph.js +213 -0
  195. package/dist/in-store/group-graph.js.map +1 -0
  196. package/dist/in-store/group.d.ts +34 -0
  197. package/dist/in-store/group.d.ts.map +1 -0
  198. package/dist/in-store/group.js +181 -0
  199. package/dist/in-store/group.js.map +1 -0
  200. package/dist/in-store/host-geometry-frame.d.ts +5 -1
  201. package/dist/in-store/host-geometry-frame.d.ts.map +1 -1
  202. package/dist/in-store/host-geometry-frame.js +46 -2
  203. package/dist/in-store/host-geometry-frame.js.map +1 -1
  204. package/dist/in-store/index.d.ts +7 -0
  205. package/dist/in-store/index.d.ts.map +1 -1
  206. package/dist/in-store/index.js +7 -0
  207. package/dist/in-store/index.js.map +1 -1
  208. package/dist/in-store/linear-profile-frame.d.ts +10 -0
  209. package/dist/in-store/linear-profile-frame.d.ts.map +1 -0
  210. package/dist/in-store/linear-profile-frame.js +17 -0
  211. package/dist/in-store/linear-profile-frame.js.map +1 -0
  212. package/dist/in-store/material.d.ts.map +1 -1
  213. package/dist/in-store/material.js +17 -6
  214. package/dist/in-store/material.js.map +1 -1
  215. package/dist/in-store/member.d.ts.map +1 -1
  216. package/dist/in-store/member.js +3 -7
  217. package/dist/in-store/member.js.map +1 -1
  218. package/dist/in-store/ordinary-element.d.ts +47 -0
  219. package/dist/in-store/ordinary-element.d.ts.map +1 -0
  220. package/dist/in-store/ordinary-element.js +38 -0
  221. package/dist/in-store/ordinary-element.js.map +1 -0
  222. package/dist/in-store/placement-frame.d.ts +6 -1
  223. package/dist/in-store/placement-frame.d.ts.map +1 -1
  224. package/dist/in-store/placement-frame.js +5 -1
  225. package/dist/in-store/placement-frame.js.map +1 -1
  226. package/dist/in-store/resolve-anchor.d.ts +3 -2
  227. package/dist/in-store/resolve-anchor.d.ts.map +1 -1
  228. package/dist/in-store/resolve-anchor.js +7 -5
  229. package/dist/in-store/resolve-anchor.js.map +1 -1
  230. package/dist/in-store/resolve-relations.d.ts +3 -1
  231. package/dist/in-store/resolve-relations.d.ts.map +1 -1
  232. package/dist/in-store/resolve-relations.js +8 -3
  233. package/dist/in-store/resolve-relations.js.map +1 -1
  234. package/dist/in-store/room-candidates.d.ts +58 -0
  235. package/dist/in-store/room-candidates.d.ts.map +1 -0
  236. package/dist/in-store/room-candidates.js +135 -0
  237. package/dist/in-store/room-candidates.js.map +1 -0
  238. package/dist/in-store/room-creation-plan.d.ts +16 -0
  239. package/dist/in-store/room-creation-plan.d.ts.map +1 -0
  240. package/dist/in-store/room-creation-plan.js +28 -0
  241. package/dist/in-store/room-creation-plan.js.map +1 -0
  242. package/dist/in-store/room-floor-height.d.ts +24 -0
  243. package/dist/in-store/room-floor-height.d.ts.map +1 -0
  244. package/dist/in-store/room-floor-height.js +32 -0
  245. package/dist/in-store/room-floor-height.js.map +1 -0
  246. package/dist/in-store/room-footprint-native.d.ts +19 -0
  247. package/dist/in-store/room-footprint-native.d.ts.map +1 -0
  248. package/dist/in-store/room-footprint-native.js +117 -0
  249. package/dist/in-store/room-footprint-native.js.map +1 -0
  250. package/dist/in-store/room-layout-cache.d.ts +23 -0
  251. package/dist/in-store/room-layout-cache.d.ts.map +1 -0
  252. package/dist/in-store/room-layout-cache.js +84 -0
  253. package/dist/in-store/room-layout-cache.js.map +1 -0
  254. package/dist/in-store/room-layout-core.d.ts +68 -0
  255. package/dist/in-store/room-layout-core.d.ts.map +1 -0
  256. package/dist/in-store/room-layout-core.js +153 -0
  257. package/dist/in-store/room-layout-core.js.map +1 -0
  258. package/dist/in-store/room-population.d.ts +5 -0
  259. package/dist/in-store/room-population.d.ts.map +1 -0
  260. package/dist/in-store/room-population.js +28 -0
  261. package/dist/in-store/room-population.js.map +1 -0
  262. package/dist/in-store/room-space-meshes.d.ts +15 -0
  263. package/dist/in-store/room-space-meshes.d.ts.map +1 -0
  264. package/dist/in-store/room-space-meshes.js +38 -0
  265. package/dist/in-store/room-space-meshes.js.map +1 -0
  266. package/dist/in-store/room-store.d.ts +55 -0
  267. package/dist/in-store/room-store.d.ts.map +1 -0
  268. package/dist/in-store/room-store.js +173 -0
  269. package/dist/in-store/room-store.js.map +1 -0
  270. package/dist/in-store/room-storey-elevation.d.ts +5 -0
  271. package/dist/in-store/room-storey-elevation.d.ts.map +1 -0
  272. package/dist/in-store/room-storey-elevation.js +42 -0
  273. package/dist/in-store/room-storey-elevation.js.map +1 -0
  274. package/dist/in-store/room-storey-frame.d.ts +47 -0
  275. package/dist/in-store/room-storey-frame.d.ts.map +1 -0
  276. package/dist/in-store/room-storey-frame.js +48 -0
  277. package/dist/in-store/room-storey-frame.js.map +1 -0
  278. package/dist/in-store/room-wall-rects.d.ts +117 -0
  279. package/dist/in-store/room-wall-rects.d.ts.map +1 -0
  280. package/dist/in-store/room-wall-rects.js +157 -0
  281. package/dist/in-store/room-wall-rects.js.map +1 -0
  282. package/dist/in-store/schema-attributes.d.ts +3 -3
  283. package/dist/in-store/schema-attributes.d.ts.map +1 -1
  284. package/dist/in-store/schema-attributes.js +9 -7
  285. package/dist/in-store/schema-attributes.js.map +1 -1
  286. package/dist/in-store/slab.d.ts.map +1 -1
  287. package/dist/in-store/slab.js +1 -4
  288. package/dist/in-store/slab.js.map +1 -1
  289. package/dist/in-store/stair-removal.d.ts +17 -0
  290. package/dist/in-store/stair-removal.d.ts.map +1 -0
  291. package/dist/in-store/stair-removal.js +134 -0
  292. package/dist/in-store/stair-removal.js.map +1 -0
  293. package/dist/in-store/storey-plan-frame.d.ts +2 -1
  294. package/dist/in-store/storey-plan-frame.d.ts.map +1 -1
  295. package/dist/in-store/storey-plan-frame.js +20 -11
  296. package/dist/in-store/storey-plan-frame.js.map +1 -1
  297. package/dist/in-store/storey-reassignment-plan.d.ts +53 -0
  298. package/dist/in-store/storey-reassignment-plan.d.ts.map +1 -0
  299. package/dist/in-store/storey-reassignment-plan.js +237 -0
  300. package/dist/in-store/storey-reassignment-plan.js.map +1 -0
  301. package/dist/in-store/storey-reassignment.d.ts +8 -0
  302. package/dist/in-store/storey-reassignment.d.ts.map +1 -0
  303. package/dist/in-store/storey-reassignment.js +52 -0
  304. package/dist/in-store/storey-reassignment.js.map +1 -0
  305. package/dist/in-store/trim-extend-plan.d.ts +27 -0
  306. package/dist/in-store/trim-extend-plan.d.ts.map +1 -0
  307. package/dist/in-store/trim-extend-plan.js +49 -0
  308. package/dist/in-store/trim-extend-plan.js.map +1 -0
  309. package/dist/in-store/wall-join-edit.d.ts +0 -17
  310. package/dist/in-store/wall-join-edit.d.ts.map +1 -1
  311. package/dist/in-store/wall-join-edit.js +41 -7
  312. package/dist/in-store/wall-join-edit.js.map +1 -1
  313. package/dist/in-store/wall-section-edit.d.ts +16 -0
  314. package/dist/in-store/wall-section-edit.d.ts.map +1 -0
  315. package/dist/in-store/wall-section-edit.js +75 -0
  316. package/dist/in-store/wall-section-edit.js.map +1 -0
  317. package/dist/in-store/wall-size-edit.d.ts +29 -0
  318. package/dist/in-store/wall-size-edit.d.ts.map +1 -0
  319. package/dist/in-store/wall-size-edit.js +65 -0
  320. package/dist/in-store/wall-size-edit.js.map +1 -0
  321. package/dist/index.d.ts +24 -0
  322. package/dist/index.d.ts.map +1 -1
  323. package/dist/index.js +23 -0
  324. package/dist/index.js.map +1 -1
  325. package/package.json +8 -7
@@ -0,0 +1,168 @@
1
+ /* This Source Code Form is subject to the terms of the Mozilla Public
2
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
3
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
+ /**
5
+ * Keep a host's openings valid when its body changes size (charter #6232, C4).
6
+ *
7
+ * A wall or slab authored here carries its openings as `IfcOpeningElement`
8
+ * voids whose cut runs across the host's body plus 50 mm each side
9
+ * (`addOpeningToStore`). A thicker wall, or a slab pulled up, leaves that cut
10
+ * too short: it stops in the body and the door or window no longer opens
11
+ * through it. A shorter wall can leave an opening's top above the wall. This
12
+ * module plans the fix as positional writes the caller batches with the
13
+ * host's own resize (one undo step), or names the opening that stops the
14
+ * change:
15
+ *
16
+ * - `planCutRefit`: the cut no longer spans the new body along the axis it
17
+ * is extruded on. It is lengthened, keeping the overshoot, when it is the
18
+ * builders' shape (a rectangle extruded along the host's Y for a wall, Z
19
+ * for a slab, from the placement); another opening shape is refused
20
+ * rather than rewritten blind. A cut that still spans the body is left.
21
+ * - `heightRefusal`: an opening reaching above a wall's new top.
22
+ *
23
+ * Lengths here are the file's NATIVE unit, like the STEP entities they edit;
24
+ * callers convert at the edge.
25
+ */
26
+ import { placedBodyExtent, resolveHostAnchor } from '../resolve-host.js';
27
+ import { toNativeLength } from '../anchor.js';
28
+ import { iterateEffectiveEntityIds } from '@ifc-lite/mutations';
29
+ import { asCoordinateTriple, asDirectionRatios, asExpressIdRef, readAttributes } from './placement-core.js';
30
+ /** Metres a cut overshoots each face of its host, as the opening builder writes it. */
31
+ const CLEARANCE_M = 0.05;
32
+ const EPS = 1e-6;
33
+ /** The openings voiding `hostId` (IfcRelVoidsElement), live in the source and the overlay. */
34
+ export function openingsOf(target, hostId) {
35
+ const { dataStore, view, editor } = target;
36
+ const openings = [];
37
+ for (const { expressId: relId } of iterateEffectiveEntityIds(dataStore, view, ['IFCRELVOIDSELEMENT'])) {
38
+ const rel = readAttributes(dataStore, view, editor, relId);
39
+ const opening = rel && asExpressIdRef(rel[4]) === hostId ? asExpressIdRef(rel[5]) : null;
40
+ if (opening !== null)
41
+ openings.push(opening);
42
+ }
43
+ return openings;
44
+ }
45
+ function cutLayout(target, openingId, axis) {
46
+ const { dataStore, view, editor } = target;
47
+ const read = (id) => (id === null ? null : readAttributes(dataStore, view, editor, id));
48
+ const opening = read(openingId);
49
+ const placement = read(opening ? asExpressIdRef(opening[5]) : null);
50
+ const axis3 = read(placement ? asExpressIdRef(placement[1]) : null);
51
+ const point = read(axis3 ? asExpressIdRef(axis3[0]) : null);
52
+ const location = point ? asCoordinateTriple(point[0]) : null;
53
+ if (!axis3 || !location)
54
+ return null;
55
+ // No Axis is the default +Z; otherwise it must run straight along the axis being cut across.
56
+ const dir = axis3[1] == null ? [0, 0, 1] : asDirectionRatios(read(asExpressIdRef(axis3[1]))?.[0]);
57
+ const len = dir ? Math.hypot(dir[0], dir[1], dir[2]) : 0;
58
+ if (!dir || len < EPS)
59
+ return null;
60
+ const unit = dir.map((v) => v / len);
61
+ if (Math.abs(unit[axis]) < 1 - 1e-6)
62
+ return null;
63
+ const shape = read(opening ? asExpressIdRef(opening[6]) : null);
64
+ const reps = Array.isArray(shape?.[2]) ? shape[2] : [];
65
+ const rep = read(reps.length > 0 ? asExpressIdRef(reps[0]) : null);
66
+ const items = Array.isArray(rep?.[3]) ? rep[3] : [];
67
+ const solidId = items.length > 0 ? asExpressIdRef(items[0]) : null;
68
+ const solid = read(solidId);
69
+ const depth = solid?.[3];
70
+ if (solidId === null || typeof depth !== 'number' || !(depth > 0))
71
+ return null;
72
+ // A solid position of its own would move the cut off the placement the formulas assume.
73
+ if (solid?.[1] != null) {
74
+ const position = read(asExpressIdRef(solid[1]));
75
+ const at = position ? asCoordinateTriple(read(asExpressIdRef(position[0]))?.[0]) : null;
76
+ if (!at || at.some((v) => Math.abs(v) > EPS) || position?.[1] != null || position?.[2] != null)
77
+ return null;
78
+ }
79
+ return { pointId: asExpressIdRef(axis3[0]), location, sign: unit[axis] > 0 ? 1 : -1, solidId, depth };
80
+ }
81
+ /**
82
+ * The writes that make every opening of `hostId` span `newExtent` (native
83
+ * units, the host's frame) along `axis` (1: across a wall, 2: through a slab)
84
+ * with the builders' overshoot, or why one of them cannot.
85
+ */
86
+ export function planCutRefit(target, hostId, axis, newExtent, lengthUnitScale) {
87
+ const { dataStore, view } = target;
88
+ const span = newExtent[1] - newExtent[0];
89
+ if (!newExtent.every(Number.isFinite) || !Number.isFinite(span) || span <= 0
90
+ || !Number.isFinite(lengthUnitScale) || lengthUnitScale <= 0) {
91
+ return { ok: false, reason: 'The host extent and model length unit scale must be finite and positive' };
92
+ }
93
+ let over;
94
+ try {
95
+ over = toNativeLength({ lengthUnitScale }, CLEARANCE_M);
96
+ }
97
+ catch (error) {
98
+ console.warn('[modeling] Opening cut clearance conversion failed; host resize refused', error);
99
+ return { ok: false, reason: 'The opening cut extent exceeds the supported numeric range' };
100
+ }
101
+ const depth = span + 2 * over;
102
+ if (!Number.isFinite(over) || !Number.isFinite(depth))
103
+ return { ok: false, reason: 'The opening cut extent exceeds the supported numeric range' };
104
+ const fit = over / 10;
105
+ const updates = [];
106
+ const openings = [];
107
+ for (const openingId of openingsOf(target, hostId)) {
108
+ const extent = placedBodyExtent(dataStore, openingId, view);
109
+ if (!extent)
110
+ return { ok: false, reason: `The size of opening #${openingId} can't be read, so the host can't be resized safely` };
111
+ if (extent.min[axis] <= newExtent[0] + EPS && extent.max[axis] >= newExtent[1] - EPS)
112
+ continue;
113
+ const layout = cutLayout(target, openingId, axis);
114
+ const expected = layout && (layout.sign > 0
115
+ ? [layout.location[axis], layout.location[axis] + layout.depth]
116
+ : [layout.location[axis] - layout.depth, layout.location[axis]]);
117
+ // Rewrite only the layout whose extent the formulas reproduce.
118
+ if (!layout || !expected || Math.abs(expected[0] - extent.min[axis]) > fit || Math.abs(expected[1] - extent.max[axis]) > fit) {
119
+ return { ok: false, reason: `Opening #${openingId} is not a plain cut, so it can't follow the resize; move or delete it first` };
120
+ }
121
+ const location = [...layout.location];
122
+ location[axis] = layout.sign > 0 ? newExtent[0] - over : newExtent[1] + over;
123
+ if (!location.every(Number.isFinite))
124
+ return { ok: false, reason: 'The opening location exceeds the supported numeric range' };
125
+ updates.push({ entityId: layout.pointId, index: 0, value: location });
126
+ updates.push({ entityId: layout.solidId, index: 3, value: depth });
127
+ openings.push(openingId);
128
+ }
129
+ return { ok: true, updates, openings };
130
+ }
131
+ /** Why a wall cannot be `topNative` high (the host's frame, native units): an opening reaches above it. Null when all fit. */
132
+ export function heightRefusal(target, hostId, topNative, lengthUnitScale) {
133
+ const { dataStore, view } = target;
134
+ if (!Number.isFinite(topNative) || topNative <= 0
135
+ || !Number.isFinite(lengthUnitScale) || lengthUnitScale <= 0) {
136
+ return 'The wall height and model length unit scale must be finite and positive';
137
+ }
138
+ let slack;
139
+ try {
140
+ slack = toNativeLength({ lengthUnitScale }, 1e-4);
141
+ }
142
+ catch (error) {
143
+ console.warn('[modeling] Wall height tolerance conversion failed; host resize refused', error);
144
+ return 'The wall height exceeds the supported numeric range';
145
+ }
146
+ if (!Number.isFinite(slack) || !Number.isFinite(topNative + slack)) {
147
+ return 'The wall height exceeds the supported numeric range';
148
+ }
149
+ for (const openingId of openingsOf(target, hostId)) {
150
+ const extent = placedBodyExtent(dataStore, openingId, view);
151
+ if (!extent)
152
+ return `The size of opening #${openingId} can't be read, so the wall can't be resized safely`;
153
+ if (extent.max[2] > topNative + slack)
154
+ return `Opening #${openingId} reaches above the new top of the wall: lower or delete it first`;
155
+ }
156
+ return null;
157
+ }
158
+ /** The host's body extent in its own frame (native units), or null when its geometry is unreadable. */
159
+ export function hostBodyExtent(target, hostId) {
160
+ try {
161
+ return resolveHostAnchor(target.dataStore, hostId, target.view).hostBounds;
162
+ }
163
+ catch (error) {
164
+ console.warn(`[modeling] host #${hostId} is unreadable; its openings are not refitted`, error);
165
+ return null;
166
+ }
167
+ }
168
+ //# sourceMappingURL=hosted-opening-refit.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hosted-opening-refit.js","sourceRoot":"","sources":["../../../src/in-store/edit/hosted-opening-refit.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Model length-unit → metres scale, memoised per `IfcDataStore`.
3
+ *
4
+ * The viewer's render + authoring space is **metres**: the geometry
5
+ * pipeline bakes the file's length-unit scale into tessellated vertices,
6
+ * raycast hit-points come back in metres, and `spatialHierarchy.
7
+ * storeyElevations` are pre-scaled. But raw coordinate reads straight off
8
+ * the STEP model — split footprints, placement chains — arrive in the
9
+ * file's **native** units (e.g. millimetres). Multiply those by this
10
+ * factor to bring them into the same metre space as everything else.
11
+ *
12
+ * Bounded geometry without retained source uses identity when no validated
13
+ * scale is cached. Retained source uses the builders' validated extraction;
14
+ * an unreliable extraction refuses the edit rather than guessing units.
15
+ */
16
+ import type { IfcDataStore } from '@ifc-lite/parser';
17
+ type Vec3 = [number, number, number];
18
+ export declare function getModelLengthUnitScale(dataStore: IfcDataStore | null | undefined): number;
19
+ /** A native-unit STEP point in metres (#6233). Rounded like `fromNativeLength`. */
20
+ export declare function pointToMetres(dataStore: IfcDataStore, point: readonly number[]): Vec3;
21
+ /** A metre point in the model's native unit, ready to write to STEP (#6233). */
22
+ export declare function pointToNative(dataStore: IfcDataStore, point: readonly number[]): Vec3;
23
+ export {};
24
+ //# sourceMappingURL=length-unit-scale.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"length-unit-scale.d.ts","sourceRoot":"","sources":["../../../src/in-store/edit/length-unit-scale.ts"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAIrD,KAAK,IAAI,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;AAIrC,wBAAgB,uBAAuB,CAAC,SAAS,EAAE,YAAY,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,CAkB1F;AAED,mFAAmF;AACnF,wBAAgB,aAAa,CAAC,SAAS,EAAE,YAAY,EAAE,KAAK,EAAE,SAAS,MAAM,EAAE,GAAG,IAAI,CAGrF;AAED,gFAAgF;AAChF,wBAAgB,aAAa,CAAC,SAAS,EAAE,YAAY,EAAE,KAAK,EAAE,SAAS,MAAM,EAAE,GAAG,IAAI,CAGrF"}
@@ -0,0 +1,37 @@
1
+ /* This Source Code Form is subject to the terms of the Mozilla Public
2
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
3
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
+ import { safeLengthUnitScale } from '../length-unit-scale.js';
5
+ import { fromNativeLength, toNativeLength } from '../anchor.js';
6
+ const scaleCache = new WeakMap();
7
+ export function getModelLengthUnitScale(dataStore) {
8
+ if (!dataStore)
9
+ return 1;
10
+ const cached = scaleCache.get(dataStore);
11
+ if (cached !== undefined)
12
+ return cached;
13
+ // The columnar parser stashes the scale on the store; the wasm fast
14
+ // path does not, so fall back to extracting it from the source bytes.
15
+ let scale = typeof dataStore.lengthUnitScale === 'number' ? dataStore.lengthUnitScale : undefined;
16
+ if (scale === undefined || !Number.isFinite(scale) || scale <= 0) {
17
+ if (!dataStore.source?.length || !dataStore.entityIndex)
18
+ return 1;
19
+ const extracted = safeLengthUnitScale(dataStore.source, dataStore.entityIndex, 'getModelLengthUnitScale', dataStore.spatialHierarchy?.project?.expressId);
20
+ if (extracted === null)
21
+ throw new Error('Cannot edit geometry without a reliable model length unit scale');
22
+ scale = extracted;
23
+ }
24
+ scaleCache.set(dataStore, scale);
25
+ return scale;
26
+ }
27
+ /** A native-unit STEP point in metres (#6233). Rounded like `fromNativeLength`. */
28
+ export function pointToMetres(dataStore, point) {
29
+ const unit = { lengthUnitScale: getModelLengthUnitScale(dataStore) };
30
+ return [fromNativeLength(unit, point[0]), fromNativeLength(unit, point[1]), fromNativeLength(unit, point[2])];
31
+ }
32
+ /** A metre point in the model's native unit, ready to write to STEP (#6233). */
33
+ export function pointToNative(dataStore, point) {
34
+ const unit = { lengthUnitScale: getModelLengthUnitScale(dataStore) };
35
+ return [toNativeLength(unit, point[0]), toNativeLength(unit, point[1]), toNativeLength(unit, point[2])];
36
+ }
37
+ //# sourceMappingURL=length-unit-scale.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"length-unit-scale.js","sourceRoot":"","sources":["../../../src/in-store/edit/length-unit-scale.ts"],"names":[],"mappings":"AAAA;;+DAE+D;AAmB/D,OAAO,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAC9D,OAAO,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAIhE,MAAM,UAAU,GAAG,IAAI,OAAO,EAAwB,CAAC;AAEvD,MAAM,UAAU,uBAAuB,CAAC,SAA0C;IAChF,IAAI,CAAC,SAAS;QAAE,OAAO,CAAC,CAAC;IACzB,MAAM,MAAM,GAAG,UAAU,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;IACzC,IAAI,MAAM,KAAK,SAAS;QAAE,OAAO,MAAM,CAAC;IAExC,oEAAoE;IACpE,sEAAsE;IACtE,IAAI,KAAK,GAAG,OAAO,SAAS,CAAC,eAAe,KAAK,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,eAAe,CAAC,CAAC,CAAC,SAAS,CAAC;IAClG,IAAI,KAAK,KAAK,SAAS,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,KAAK,IAAI,CAAC,EAAE,CAAC;QACjE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,MAAM,IAAI,CAAC,SAAS,CAAC,WAAW;YAAE,OAAO,CAAC,CAAC;QAClE,MAAM,SAAS,GAAG,mBAAmB,CAAC,SAAS,CAAC,MAAM,EAAE,SAAS,CAAC,WAAW,EAC3E,yBAAyB,EAAE,SAAS,CAAC,gBAAgB,EAAE,OAAO,EAAE,SAAS,CAAC,CAAC;QAC7E,IAAI,SAAS,KAAK,IAAI;YAAE,MAAM,IAAI,KAAK,CAAC,iEAAiE,CAAC,CAAC;QAC3G,KAAK,GAAG,SAAS,CAAC;IACpB,CAAC;IAED,UAAU,CAAC,GAAG,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;IACjC,OAAO,KAAK,CAAC;AACf,CAAC;AAED,mFAAmF;AACnF,MAAM,UAAU,aAAa,CAAC,SAAuB,EAAE,KAAwB;IAC7E,MAAM,IAAI,GAAG,EAAE,eAAe,EAAE,uBAAuB,CAAC,SAAS,CAAC,EAAE,CAAC;IACrE,OAAO,CAAC,gBAAgB,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,gBAAgB,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,gBAAgB,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAChH,CAAC;AAED,gFAAgF;AAChF,MAAM,UAAU,aAAa,CAAC,SAAuB,EAAE,KAAwB;IAC7E,MAAM,IAAI,GAAG,EAAE,eAAe,EAAE,uBAAuB,CAAC,SAAS,CAAC,EAAE,CAAC;IACrE,OAAO,CAAC,cAAc,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,cAAc,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,cAAc,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC1G,CAAC"}
@@ -0,0 +1,131 @@
1
+ /**
2
+ * Linear-element split helpers for IfcBeam, IfcColumn, and
3
+ * IfcMember — entities built by `@ifc-lite/create`'s in-store
4
+ * builders that share the shape:
5
+ *
6
+ * IfcExtrudedAreaSolid
7
+ * ├── SweptArea : IfcRectangleProfileDef (Width × Height)
8
+ * └── Depth : extrusion length along the placement's
9
+ * local Z (= world axis direction for
10
+ * beams/members; world +Z for columns
11
+ * because their placement's Axis is `$`)
12
+ *
13
+ * The split logic is meaningfully different from walls: a wall's
14
+ * "length" is its profile XDim, so splitting requires rewriting
15
+ * four entities. A beam / column / member's "length" is the
16
+ * extrusion `Depth`, so we can shrink the source in place (one
17
+ * positional write) and add a fresh element at the cut point.
18
+ * Source identity (GlobalId, Pset rels) is preserved for the
19
+ * "left" half — cleaner downstream than the wall's two-new-walls
20
+ * approach, but the choice is dictated by the IFC representation,
21
+ * not preference.
22
+ */
23
+ import type { IfcDataStore } from '@ifc-lite/parser';
24
+ import type { MutablePropertyView, StoreEditor } from '@ifc-lite/mutations';
25
+ import { type ProfileSection } from '../profile.js';
26
+ import { asCoordinateTriple } from './placement-core.js';
27
+ export declare const MIN_LINEAR_SEGMENT_LENGTH = 0.05;
28
+ /**
29
+ * Element types this module handles. Maps to the STEP storage form
30
+ * (`IFCBEAM`, …) — the slice's `splitLinearElementAtDistance` action
31
+ * picks the right `addBeam` / `addColumn` / `addMember` follow-up
32
+ * based on this value.
33
+ */
34
+ export type LinearElementType = 'IfcBeam' | 'IfcColumn' | 'IfcMember';
35
+ export interface LinearElementEditChain {
36
+ /** STEP type name, for the slice's dispatch (`IfcBeam` / `IfcColumn` / `IfcMember`). */
37
+ elementType: LinearElementType;
38
+ /** Placement origin point id (storey-local). */
39
+ startPointId: number;
40
+ /** Current start coordinates in storey-local space. */
41
+ startCoordinates: [number, number, number];
42
+ /**
43
+ * World-axis direction of the extrusion in storey-local space.
44
+ * For beams / members this is the explicit
45
+ * `IfcAxis2Placement3D.Axis` IfcDirection. For columns it's the
46
+ * implicit default `[0, 0, 1]` (placement Axis = `$`).
47
+ */
48
+ axisDirection: [number, number, number];
49
+ /** IfcExtrudedAreaSolid id; holds the length on attribute 3 (`Depth`). */
50
+ extrudedSolidId: number;
51
+ /** IfcExtrudedAreaSolid.SweptArea: the profile entity. For a rectangle, XDim (attr 3) is the width and YDim (attr 4) the other side; not for a picker section. */
52
+ profileId: number;
53
+ /** Current extrusion length (metres). */
54
+ depth: number;
55
+ /** Profile cross-section width (X dimension, metres); a profiled section's outer width. */
56
+ profileWidth: number;
57
+ /** Profile cross-section height (Y dimension, metres); a profiled section's outer depth. */
58
+ profileHeight: number;
59
+ /**
60
+ * The section when it is one of the picker's parametric kinds (I, L, T, U,
61
+ * C, circle, hollow); null for the rectangle, whose `profileWidth` x
62
+ * `profileHeight` are its XDim and YDim. Anything that writes those two as
63
+ * a rectangle's must refuse a non-null section.
64
+ */
65
+ profile: ProfileSection | null;
66
+ /**
67
+ * The native-unit → metre factor every length above was scaled by. Raw
68
+ * STEP reads are native (e.g. millimetres) for imported AND in-store
69
+ * authored elements alike; a writer divides by this to go back (#6233).
70
+ */
71
+ lengthUnitScale: number;
72
+ }
73
+ /**
74
+ * Resolve the chain for an IfcBeam / IfcColumn / IfcMember whose
75
+ * representation matches what `addBeamToStore` / `addColumnToStore`
76
+ * / `addMemberToStore` produce. Returns null when the chain doesn't
77
+ * match (mapped representation, non-rectangle profile, missing
78
+ * placement, etc.) so the caller can hide the split affordance.
79
+ */
80
+ export declare function resolveLinearElementChain(dataStore: IfcDataStore, view: MutablePropertyView, editor: StoreEditor, expressId: number, lengthUnitScale?: number): LinearElementEditChain | null;
81
+ export interface LinearSplitGeometry {
82
+ /** Length the source's extrusion shrinks to (= split distance from start). */
83
+ leftDepth: number;
84
+ /** Cut point in storey-local space. */
85
+ cutPoint: [number, number, number];
86
+ /** End of the source (storey-local) — also the end of the new right half. */
87
+ endPoint: [number, number, number];
88
+ /** Length the new right-half element takes. */
89
+ rightDepth: number;
90
+ /** Cross-section dimensions to copy onto the new element. */
91
+ width: number;
92
+ height: number;
93
+ }
94
+ export type LinearSplitResult = {
95
+ ok: true;
96
+ geometry: LinearSplitGeometry;
97
+ } | {
98
+ ok: false;
99
+ reason: string;
100
+ };
101
+ /**
102
+ * Pure split-geometry math. Splits the linear element at
103
+ * `distance` metres from start. Returns the cut point + remaining
104
+ * lengths so the caller can shrink the source and add the right
105
+ * half via the matching `addBeam` / `addColumn` / `addMember`
106
+ * action.
107
+ *
108
+ * Same min-segment guard as walls (`MIN_LINEAR_SEGMENT_LENGTH`)
109
+ * so dragging the cursor to the very end of a column doesn't
110
+ * produce a sliver.
111
+ */
112
+ export declare function computeLinearElementSplitGeometry(chain: LinearElementEditChain, distance: number): LinearSplitResult;
113
+ /**
114
+ * Project an arbitrary storey-local 3D cursor onto the element's
115
+ * axis and return how far along the element (in metres from start)
116
+ * it lands. Clamps to `[0, depth]`.
117
+ */
118
+ export declare function projectOntoLinearAxis(chain: LinearElementEditChain, pointStoreyLocal: [number, number, number]): number;
119
+ /**
120
+ * Shrink the source linear element's extrusion to `newDepth`. Used
121
+ * by the split action's "left half" branch — the source's
122
+ * placement, axis, profile, and Pset relationships all stay; only
123
+ * the IfcExtrudedAreaSolid.Depth changes.
124
+ *
125
+ * Coerce-only: this is the equivalent of `setPositionalAttribute`
126
+ * for a known slot; we expose it via the helper module for
127
+ * symmetry with the other split helpers.
128
+ */
129
+ export declare function shrinkLinearElementDepth(editor: StoreEditor, chain: LinearElementEditChain, newDepth: number): void;
130
+ export { asCoordinateTriple };
131
+ //# sourceMappingURL=linear-element-edit.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"linear-element-edit.d.ts","sourceRoot":"","sources":["../../../src/in-store/edit/linear-element-edit.ts"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,KAAK,EAAE,mBAAmB,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAE5E,OAAO,EAAwB,KAAK,cAAc,EAAE,MAAM,eAAe,CAAC;AAE1E,OAAO,EAEL,kBAAkB,EAKnB,MAAM,qBAAqB,CAAC;AAE7B,eAAO,MAAM,yBAAyB,OAAO,CAAC;AAE9C;;;;;GAKG;AACH,MAAM,MAAM,iBAAiB,GAAG,SAAS,GAAG,WAAW,GAAG,WAAW,CAAC;AAiBtE,MAAM,WAAW,sBAAsB;IACrC,wFAAwF;IACxF,WAAW,EAAE,iBAAiB,CAAC;IAC/B,gDAAgD;IAChD,YAAY,EAAE,MAAM,CAAC;IACrB,uDAAuD;IACvD,gBAAgB,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IAC3C;;;;;OAKG;IACH,aAAa,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IACxC,0EAA0E;IAC1E,eAAe,EAAE,MAAM,CAAC;IACxB,kKAAkK;IAClK,SAAS,EAAE,MAAM,CAAC;IAClB,yCAAyC;IACzC,KAAK,EAAE,MAAM,CAAC;IACd,2FAA2F;IAC3F,YAAY,EAAE,MAAM,CAAC;IACrB,4FAA4F;IAC5F,aAAa,EAAE,MAAM,CAAC;IACtB;;;;;OAKG;IACH,OAAO,EAAE,cAAc,GAAG,IAAI,CAAC;IAC/B;;;;OAIG;IACH,eAAe,EAAE,MAAM,CAAC;CACzB;AA0BD;;;;;;GAMG;AACH,wBAAgB,yBAAyB,CACvC,SAAS,EAAE,YAAY,EACvB,IAAI,EAAE,mBAAmB,EACzB,MAAM,EAAE,WAAW,EACnB,SAAS,EAAE,MAAM,EACjB,eAAe,SAAI,GAClB,sBAAsB,GAAG,IAAI,CAkH/B;AAED,MAAM,WAAW,mBAAmB;IAClC,8EAA8E;IAC9E,SAAS,EAAE,MAAM,CAAC;IAClB,uCAAuC;IACvC,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IACnC,6EAA6E;IAC7E,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IACnC,+CAA+C;IAC/C,UAAU,EAAE,MAAM,CAAC;IACnB,6DAA6D;IAC7D,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,MAAM,iBAAiB,GACzB;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,QAAQ,EAAE,mBAAmB,CAAA;CAAE,GAC3C;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAElC;;;;;;;;;;GAUG;AACH,wBAAgB,iCAAiC,CAC/C,KAAK,EAAE,sBAAsB,EAC7B,QAAQ,EAAE,MAAM,GACf,iBAAiB,CAgCnB;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,sBAAsB,EAC7B,gBAAgB,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,GACzC,MAAM,CAaR;AAED;;;;;;;;;GASG;AACH,wBAAgB,wBAAwB,CACtC,MAAM,EAAE,WAAW,EACnB,KAAK,EAAE,sBAAsB,EAC7B,QAAQ,EAAE,MAAM,GACf,IAAI,CAGN;AAKD,OAAO,EAAE,kBAAkB,EAAE,CAAC"}
@@ -0,0 +1,259 @@
1
+ /* This Source Code Form is subject to the terms of the Mozilla Public
2
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
3
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
+ import { fromNativeLength } from '../anchor.js';
5
+ import { profileSectionExtent } from '../profile.js';
6
+ import { sectionFromProfile } from './read-profile.js';
7
+ import { asExpressIdRef, asCoordinateTriple, asDirectionRatios, readAttributes, readPlacementAttributes, resolvePlacementChain, } from './placement-core.js';
8
+ export const MIN_LINEAR_SEGMENT_LENGTH = 0.05; // metres
9
+ const LINEAR_ELEMENT_STEP_TYPES = new Set(['IFCBEAM', 'IFCCOLUMN', 'IFCMEMBER']);
10
+ function stepTypeToLinearType(stepType) {
11
+ switch (stepType.toUpperCase()) {
12
+ case 'IFCBEAM':
13
+ return 'IfcBeam';
14
+ case 'IFCCOLUMN':
15
+ return 'IfcColumn';
16
+ case 'IFCMEMBER':
17
+ return 'IfcMember';
18
+ default:
19
+ return null;
20
+ }
21
+ }
22
+ const EPS = 1e-9;
23
+ function isPoint(value, expected) {
24
+ const p = asCoordinateTriple(value);
25
+ return p !== null && p.every((v, i) => Math.abs(v - expected[i]) < EPS);
26
+ }
27
+ function isDirection(value, expected) {
28
+ const d = asDirectionRatios(value);
29
+ const len = d ? Math.hypot(d[0], d[1], d[2]) : 0;
30
+ return d !== null && len > EPS && d.every((v, i) => Math.abs(v / len - expected[i]) < 1e-6);
31
+ }
32
+ /** An `IfcAxis2Placement3D` (or none) that neither moves nor rotates. */
33
+ function isIdentitySolidPosition(read, positionId) {
34
+ if (positionId === null)
35
+ return true;
36
+ const position = read(positionId);
37
+ if (!position || !isPoint(read(asExpressIdRef(position[0]))?.[0], [0, 0, 0]))
38
+ return false;
39
+ if (position[1] != null && !isDirection(read(asExpressIdRef(position[1]))?.[0], [0, 0, 1]))
40
+ return false;
41
+ return position[2] == null || isDirection(read(asExpressIdRef(position[2]))?.[0], [1, 0, 0]);
42
+ }
43
+ /**
44
+ * Resolve the chain for an IfcBeam / IfcColumn / IfcMember whose
45
+ * representation matches what `addBeamToStore` / `addColumnToStore`
46
+ * / `addMemberToStore` produce. Returns null when the chain doesn't
47
+ * match (mapped representation, non-rectangle profile, missing
48
+ * placement, etc.) so the caller can hide the split affordance.
49
+ */
50
+ export function resolveLinearElementChain(dataStore, view, editor, expressId, lengthUnitScale = 1) {
51
+ const rawType = editor.getEntityType(expressId);
52
+ if (!rawType || !LINEAR_ELEMENT_STEP_TYPES.has(rawType.toUpperCase()))
53
+ return null;
54
+ const elementType = stepTypeToLinearType(rawType);
55
+ if (!elementType)
56
+ return null;
57
+ // ObjectPlacement chain — gives us the start point AND the
58
+ // IfcAxis2Placement3D id for axis lookup.
59
+ const chain = resolvePlacementChain(dataStore, view, editor, expressId);
60
+ if (!chain)
61
+ return null;
62
+ // Pull the axis direction. IfcAxis2Placement3D.Axis (index 1) may
63
+ // be null → implicit world +Z (matches the column builder).
64
+ const axisAttrs = readPlacementAttributes(dataStore, view, editor, chain.axisPlacementId);
65
+ if (!axisAttrs)
66
+ return null;
67
+ const axisDirId = asExpressIdRef(axisAttrs[1]);
68
+ let axisDirection = [0, 0, 1];
69
+ if (axisDirId !== null) {
70
+ const dirAttrs = readPlacementAttributes(dataStore, view, editor, axisDirId);
71
+ if (!dirAttrs)
72
+ return null;
73
+ const ratios = asDirectionRatios(dirAttrs[0]);
74
+ if (!ratios)
75
+ return null;
76
+ // Reject NaN / Infinity components — those would propagate into
77
+ // every downstream split / projection call. The builder writes
78
+ // unit vectors but source-buffer entities can be malformed.
79
+ if (!Number.isFinite(ratios[0]) || !Number.isFinite(ratios[1]) || !Number.isFinite(ratios[2])) {
80
+ return null;
81
+ }
82
+ const len = Math.hypot(ratios[0], ratios[1], ratios[2]);
83
+ // Zero-length or unrepresentable axis isn't translatable; refuse rather than fall
84
+ // back silently to world +Z (which would silently mis-orient
85
+ // every downstream operation).
86
+ if (!Number.isFinite(len) || len < 1e-9)
87
+ return null;
88
+ axisDirection = [ratios[0] / len, ratios[1] / len, ratios[2] / len];
89
+ }
90
+ // Representation chain: same shape as walls but the length lives
91
+ // on the extrusion depth, not the profile XDim.
92
+ const elementAttrs = readAttributes(dataStore, view, editor, expressId);
93
+ if (!elementAttrs)
94
+ return null;
95
+ const productShapeId = asExpressIdRef(elementAttrs[6]);
96
+ if (productShapeId === null)
97
+ return null;
98
+ const productShapeAttrs = readAttributes(dataStore, view, editor, productShapeId);
99
+ if (!productShapeAttrs)
100
+ return null;
101
+ const reps = productShapeAttrs[2];
102
+ if (!Array.isArray(reps) || reps.length === 0)
103
+ return null;
104
+ const shapeRepId = asExpressIdRef(reps[0]);
105
+ if (shapeRepId === null)
106
+ return null;
107
+ const shapeRepAttrs = readAttributes(dataStore, view, editor, shapeRepId);
108
+ if (!shapeRepAttrs)
109
+ return null;
110
+ const items = shapeRepAttrs[3];
111
+ if (!Array.isArray(items) || items.length === 0)
112
+ return null;
113
+ const solidId = asExpressIdRef(items[0]);
114
+ if (solidId === null)
115
+ return null;
116
+ const solidAttrs = readAttributes(dataStore, view, editor, solidId);
117
+ if (!solidAttrs)
118
+ return null;
119
+ // The length runs along the PLACEMENT's axis only when the solid adds no
120
+ // rotation or offset of its own and extrudes along local +Z — the layout
121
+ // the in-store builders write. An imported beam that extrudes along a
122
+ // rotated solid position (AC20's `Unterzug-1`: solid Axis = +Y) must be
123
+ // refused, not cut along the wrong axis (#6233).
124
+ const read = (id) => (id === null ? null : readAttributes(dataStore, view, editor, id));
125
+ if (!isIdentitySolidPosition(read, asExpressIdRef(solidAttrs[1])))
126
+ return null;
127
+ if (solidAttrs[2] != null && !isDirection(read(asExpressIdRef(solidAttrs[2]))?.[0], [0, 0, 1]))
128
+ return null;
129
+ const profileId = asExpressIdRef(solidAttrs[0]);
130
+ const depthRaw = solidAttrs[3];
131
+ if (profileId === null ||
132
+ typeof depthRaw !== 'number' ||
133
+ !Number.isFinite(depthRaw) ||
134
+ depthRaw <= 0) {
135
+ return null;
136
+ }
137
+ // Cross-section dimensions from the IfcRectangleProfileDef
138
+ // (Width = XDim attr 3, Height = YDim attr 4). Not strictly
139
+ // needed for the split math, but exposed so callers building the
140
+ // new element can carry the same cross-section forward. Reject
141
+ // non-finite / non-positive — would silently produce zero-area
142
+ // or NaN-area profiles downstream.
143
+ const profileAttrs = readAttributes(dataStore, view, editor, profileId);
144
+ if (!profileAttrs)
145
+ return null;
146
+ // Centred, unrotated cross-section, as the builders write (the split
147
+ // re-authors a piece with a centred profile).
148
+ const profilePosition = read(asExpressIdRef(profileAttrs[2]));
149
+ if (profileAttrs[2] != null) {
150
+ if (!profilePosition || !isPoint(read(asExpressIdRef(profilePosition[0]))?.[0], [0, 0, 0]))
151
+ return null;
152
+ if (profilePosition[1] != null && !isDirection(read(asExpressIdRef(profilePosition[1]))?.[0], [1, 0, 0]))
153
+ return null;
154
+ }
155
+ // A rectangle reads as its XDim x YDim; the picker's other sections as their
156
+ // outer size, with the section itself carried for whoever writes a piece.
157
+ const profileType = editor.getEntityType(profileId);
158
+ const parsed = profileType ? sectionFromProfile(profileType, profileAttrs, lengthUnitScale, dataStore.schemaVersion ?? 'IFC4') : null;
159
+ if (!parsed)
160
+ return null;
161
+ const section = parsed.Type === 'Rectangle' ? null : parsed;
162
+ const [profileWidth, profileHeight] = profileSectionExtent(parsed);
163
+ const m = (native) => fromNativeLength({ lengthUnitScale }, native);
164
+ const [sx, sy, sz] = chain.coordinates;
165
+ return {
166
+ elementType,
167
+ startPointId: chain.cartesianPointId,
168
+ startCoordinates: [m(sx), m(sy), m(sz)],
169
+ axisDirection,
170
+ extrudedSolidId: solidId,
171
+ profileId,
172
+ depth: m(depthRaw),
173
+ profileWidth,
174
+ profileHeight,
175
+ profile: section,
176
+ lengthUnitScale,
177
+ };
178
+ }
179
+ /**
180
+ * Pure split-geometry math. Splits the linear element at
181
+ * `distance` metres from start. Returns the cut point + remaining
182
+ * lengths so the caller can shrink the source and add the right
183
+ * half via the matching `addBeam` / `addColumn` / `addMember`
184
+ * action.
185
+ *
186
+ * Same min-segment guard as walls (`MIN_LINEAR_SEGMENT_LENGTH`)
187
+ * so dragging the cursor to the very end of a column doesn't
188
+ * produce a sliver.
189
+ */
190
+ export function computeLinearElementSplitGeometry(chain, distance) {
191
+ if (!Number.isFinite(distance)) {
192
+ return { ok: false, reason: 'Split distance must be a finite number' };
193
+ }
194
+ if (distance <= MIN_LINEAR_SEGMENT_LENGTH ||
195
+ distance >= chain.depth - MIN_LINEAR_SEGMENT_LENGTH) {
196
+ return {
197
+ ok: false,
198
+ reason: `Split must be at least ${MIN_LINEAR_SEGMENT_LENGTH} m from each end (element is ${chain.depth.toFixed(2)} m)`,
199
+ };
200
+ }
201
+ const [sx, sy, sz] = chain.startCoordinates;
202
+ const [dx, dy, dz] = chain.axisDirection;
203
+ const cut = [sx + dx * distance, sy + dy * distance, sz + dz * distance];
204
+ const end = [
205
+ sx + dx * chain.depth,
206
+ sy + dy * chain.depth,
207
+ sz + dz * chain.depth,
208
+ ];
209
+ return {
210
+ ok: true,
211
+ geometry: {
212
+ leftDepth: distance,
213
+ cutPoint: cut,
214
+ endPoint: end,
215
+ rightDepth: chain.depth - distance,
216
+ width: chain.profileWidth,
217
+ height: chain.profileHeight,
218
+ },
219
+ };
220
+ }
221
+ /**
222
+ * Project an arbitrary storey-local 3D cursor onto the element's
223
+ * axis and return how far along the element (in metres from start)
224
+ * it lands. Clamps to `[0, depth]`.
225
+ */
226
+ export function projectOntoLinearAxis(chain, pointStoreyLocal) {
227
+ const [px, py, pz] = pointStoreyLocal;
228
+ const [sx, sy, sz] = chain.startCoordinates;
229
+ const [dx, dy, dz] = chain.axisDirection;
230
+ const ux = px - sx;
231
+ const uy = py - sy;
232
+ const uz = pz - sz;
233
+ // Axis is unit-length by resolveLinearElementChain's contract; we
234
+ // still divide through for robustness.
235
+ const denom = dx * dx + dy * dy + dz * dz;
236
+ if (denom < 1e-9)
237
+ return 0;
238
+ const t = (ux * dx + uy * dy + uz * dz) / denom;
239
+ return Math.max(0, Math.min(chain.depth, t));
240
+ }
241
+ /**
242
+ * Shrink the source linear element's extrusion to `newDepth`. Used
243
+ * by the split action's "left half" branch — the source's
244
+ * placement, axis, profile, and Pset relationships all stay; only
245
+ * the IfcExtrudedAreaSolid.Depth changes.
246
+ *
247
+ * Coerce-only: this is the equivalent of `setPositionalAttribute`
248
+ * for a known slot; we expose it via the helper module for
249
+ * symmetry with the other split helpers.
250
+ */
251
+ export function shrinkLinearElementDepth(editor, chain, newDepth) {
252
+ // `newDepth` is metres like the chain; the slot is native units.
253
+ editor.setPositionalAttribute(chain.extrudedSolidId, 3, newDepth / chain.lengthUnitScale);
254
+ }
255
+ // Re-export the asCoordinateTriple helper so callers that import
256
+ // linear-element-edit don't have to reach into placement-core too.
257
+ // Keeps the import surface tight for the slice action.
258
+ export { asCoordinateTriple };
259
+ //# sourceMappingURL=linear-element-edit.js.map