brep-io-kernel 1.0.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 (403) hide show
  1. package/LICENSE.md +32 -0
  2. package/README.md +144 -0
  3. package/dist-kernel/brep-kernel.js +74699 -0
  4. package/dist-kernel/help/CONTRIBUTING.html +248 -0
  5. package/dist-kernel/help/LICENSE.html +248 -0
  6. package/dist-kernel/help/MODELING.png +0 -0
  7. package/dist-kernel/help/PMI.png +0 -0
  8. package/dist-kernel/help/SKETCH.png +0 -0
  9. package/dist-kernel/help/assembly-constraints__Coincident_Constraint_dialog.png +0 -0
  10. package/dist-kernel/help/assembly-constraints___Angle_Constraint_dialog.png +0 -0
  11. package/dist-kernel/help/assembly-constraints___Distance_Constraint_dialog.png +0 -0
  12. package/dist-kernel/help/assembly-constraints___Fixed_Constraint_dialog.png +0 -0
  13. package/dist-kernel/help/assembly-constraints___Parallel_Constraint_dialog.png +0 -0
  14. package/dist-kernel/help/assembly-constraints___Touch_Align_Constraint_dialog.png +0 -0
  15. package/dist-kernel/help/assembly-constraints__angle-constraint.html +248 -0
  16. package/dist-kernel/help/assembly-constraints__coincident-constraint.html +248 -0
  17. package/dist-kernel/help/assembly-constraints__distance-constraint.html +248 -0
  18. package/dist-kernel/help/assembly-constraints__fixed-constraint.html +248 -0
  19. package/dist-kernel/help/assembly-constraints__parallel-constraint.html +248 -0
  20. package/dist-kernel/help/assembly-constraints__solver.html +248 -0
  21. package/dist-kernel/help/assembly-constraints__touch-align-constraint.html +248 -0
  22. package/dist-kernel/help/brep-api.html +263 -0
  23. package/dist-kernel/help/brep-kernel.html +258 -0
  24. package/dist-kernel/help/brep-model.html +248 -0
  25. package/dist-kernel/help/cylindrical-face-radius-embedding.html +290 -0
  26. package/dist-kernel/help/dialog-screenshots.html +248 -0
  27. package/dist-kernel/help/extruded-sketch-radius-embedding.html +336 -0
  28. package/dist-kernel/help/features__Assembly_Component_dialog.png +0 -0
  29. package/dist-kernel/help/features__Boolean_dialog.png +0 -0
  30. package/dist-kernel/help/features__Chamfer_dialog.png +0 -0
  31. package/dist-kernel/help/features__Datium_dialog.png +0 -0
  32. package/dist-kernel/help/features__Extrude_dialog.png +0 -0
  33. package/dist-kernel/help/features__Fillet_dialog.png +0 -0
  34. package/dist-kernel/help/features__Helix_dialog.png +0 -0
  35. package/dist-kernel/help/features__Hole_dialog.png +0 -0
  36. package/dist-kernel/help/features__Image_Heightmap_Solid_dialog.png +0 -0
  37. package/dist-kernel/help/features__Image_to_Face_dialog.png +0 -0
  38. package/dist-kernel/help/features__Import_3D_Model_dialog.png +0 -0
  39. package/dist-kernel/help/features__Loft_dialog.png +0 -0
  40. package/dist-kernel/help/features__Mirror_dialog.png +0 -0
  41. package/dist-kernel/help/features__Offset_Shell_dialog.png +0 -0
  42. package/dist-kernel/help/features__Overlap_Cleanup_dialog.png +0 -0
  43. package/dist-kernel/help/features__Pattern_Linear_dialog.png +0 -0
  44. package/dist-kernel/help/features__Pattern_Radial_dialog.png +0 -0
  45. package/dist-kernel/help/features__Pattern_dialog.png +0 -0
  46. package/dist-kernel/help/features__Plane_dialog.png +0 -0
  47. package/dist-kernel/help/features__Primitive_Cone_dialog.png +0 -0
  48. package/dist-kernel/help/features__Primitive_Cube_dialog.png +0 -0
  49. package/dist-kernel/help/features__Primitive_Cylinder_dialog.png +0 -0
  50. package/dist-kernel/help/features__Primitive_Pyramid_dialog.png +0 -0
  51. package/dist-kernel/help/features__Primitive_Sphere_dialog.png +0 -0
  52. package/dist-kernel/help/features__Primitive_Torus_dialog.png +0 -0
  53. package/dist-kernel/help/features__Remesh_dialog.png +0 -0
  54. package/dist-kernel/help/features__Revolve_dialog.png +0 -0
  55. package/dist-kernel/help/features__Sheet_Metal_Contour_Flange_dialog.png +0 -0
  56. package/dist-kernel/help/features__Sheet_Metal_Cutout_dialog.png +0 -0
  57. package/dist-kernel/help/features__Sheet_Metal_Flange_dialog.png +0 -0
  58. package/dist-kernel/help/features__Sheet_Metal_Tab_dialog.png +0 -0
  59. package/dist-kernel/help/features__Sketch_dialog.png +0 -0
  60. package/dist-kernel/help/features__Spline_dialog.png +0 -0
  61. package/dist-kernel/help/features__Sweep_dialog.png +0 -0
  62. package/dist-kernel/help/features__Transform_dialog.png +0 -0
  63. package/dist-kernel/help/features__Tube_dialog.png +0 -0
  64. package/dist-kernel/help/features__assembly-component.html +248 -0
  65. package/dist-kernel/help/features__boolean.html +248 -0
  66. package/dist-kernel/help/features__chamfer.html +248 -0
  67. package/dist-kernel/help/features__datium.html +248 -0
  68. package/dist-kernel/help/features__datum.html +248 -0
  69. package/dist-kernel/help/features__extrude.html +248 -0
  70. package/dist-kernel/help/features__fillet.html +248 -0
  71. package/dist-kernel/help/features__helix.html +248 -0
  72. package/dist-kernel/help/features__hole.html +248 -0
  73. package/dist-kernel/help/features__image-heightmap-solid.html +248 -0
  74. package/dist-kernel/help/features__image-to-face-2D_dialog.png +0 -0
  75. package/dist-kernel/help/features__image-to-face-3D_dialog.png +0 -0
  76. package/dist-kernel/help/features__image-to-face.html +248 -0
  77. package/dist-kernel/help/features__import-3d-model.html +248 -0
  78. package/dist-kernel/help/features__index.html +248 -0
  79. package/dist-kernel/help/features__loft.html +248 -0
  80. package/dist-kernel/help/features__mirror.html +248 -0
  81. package/dist-kernel/help/features__offset-shell.html +248 -0
  82. package/dist-kernel/help/features__pattern-linear.html +248 -0
  83. package/dist-kernel/help/features__pattern-radial.html +248 -0
  84. package/dist-kernel/help/features__pattern.html +248 -0
  85. package/dist-kernel/help/features__plane.html +248 -0
  86. package/dist-kernel/help/features__primitive-cone.html +248 -0
  87. package/dist-kernel/help/features__primitive-cube.html +248 -0
  88. package/dist-kernel/help/features__primitive-cylinder.html +248 -0
  89. package/dist-kernel/help/features__primitive-pyramid.html +248 -0
  90. package/dist-kernel/help/features__primitive-sphere.html +248 -0
  91. package/dist-kernel/help/features__primitive-torus.html +248 -0
  92. package/dist-kernel/help/features__remesh.html +248 -0
  93. package/dist-kernel/help/features__revolve.html +248 -0
  94. package/dist-kernel/help/features__sheet-metal-contour-flange.html +248 -0
  95. package/dist-kernel/help/features__sheet-metal-flange.html +248 -0
  96. package/dist-kernel/help/features__sheet-metal-tab.html +248 -0
  97. package/dist-kernel/help/features__sketch.html +248 -0
  98. package/dist-kernel/help/features__spline.html +248 -0
  99. package/dist-kernel/help/features__sweep.html +248 -0
  100. package/dist-kernel/help/features__transform.html +248 -0
  101. package/dist-kernel/help/features__tube.html +248 -0
  102. package/dist-kernel/help/file-formats.html +248 -0
  103. package/dist-kernel/help/getting-started.html +248 -0
  104. package/dist-kernel/help/highlights.html +248 -0
  105. package/dist-kernel/help/history-systems.html +248 -0
  106. package/dist-kernel/help/how-it-works.html +248 -0
  107. package/dist-kernel/help/index.html +862 -0
  108. package/dist-kernel/help/input-params-schema.html +363 -0
  109. package/dist-kernel/help/inspector-improvements.html +248 -0
  110. package/dist-kernel/help/inspector.html +248 -0
  111. package/dist-kernel/help/modes__modeling.html +248 -0
  112. package/dist-kernel/help/modes__pmi.html +248 -0
  113. package/dist-kernel/help/modes__sketch.html +248 -0
  114. package/dist-kernel/help/plugins.html +248 -0
  115. package/dist-kernel/help/pmi-annotations__Angle_Dimension_dialog.png +0 -0
  116. package/dist-kernel/help/pmi-annotations__Explode_Body_dialog.png +0 -0
  117. package/dist-kernel/help/pmi-annotations__Hole_Callout_dialog.png +0 -0
  118. package/dist-kernel/help/pmi-annotations__Leader_dialog.png +0 -0
  119. package/dist-kernel/help/pmi-annotations__Linear_Dimension_dialog.png +0 -0
  120. package/dist-kernel/help/pmi-annotations__Note_dialog.png +0 -0
  121. package/dist-kernel/help/pmi-annotations__Radial_Dimension_dialog.png +0 -0
  122. package/dist-kernel/help/pmi-annotations__angle-dimension.html +248 -0
  123. package/dist-kernel/help/pmi-annotations__explode-body.html +248 -0
  124. package/dist-kernel/help/pmi-annotations__hole-callout.html +248 -0
  125. package/dist-kernel/help/pmi-annotations__index.html +248 -0
  126. package/dist-kernel/help/pmi-annotations__leader.html +248 -0
  127. package/dist-kernel/help/pmi-annotations__linear-dimension.html +248 -0
  128. package/dist-kernel/help/pmi-annotations__note.html +248 -0
  129. package/dist-kernel/help/pmi-annotations__radial-dimension.html +248 -0
  130. package/dist-kernel/help/search-index.json +464 -0
  131. package/dist-kernel/help/simplified-radial-dimensions.html +298 -0
  132. package/dist-kernel/help/solid-methods.html +359 -0
  133. package/dist-kernel/help/table-of-contents.html +330 -0
  134. package/dist-kernel/help/ui-overview.html +248 -0
  135. package/dist-kernel/help/whats-new.html +248 -0
  136. package/package.json +54 -0
  137. package/src/BREP/AssemblyComponent.js +42 -0
  138. package/src/BREP/BREP.js +43 -0
  139. package/src/BREP/BetterSolid.js +805 -0
  140. package/src/BREP/Edge.js +103 -0
  141. package/src/BREP/Extrude.js +403 -0
  142. package/src/BREP/Face.js +187 -0
  143. package/src/BREP/MeshRepairer.js +634 -0
  144. package/src/BREP/OffsetShellSolid.js +614 -0
  145. package/src/BREP/PointCloudWrap.js +302 -0
  146. package/src/BREP/Revolve.js +345 -0
  147. package/src/BREP/SolidMethods/authoring.js +112 -0
  148. package/src/BREP/SolidMethods/booleanOps.js +230 -0
  149. package/src/BREP/SolidMethods/chamfer.js +122 -0
  150. package/src/BREP/SolidMethods/edgeResolution.js +25 -0
  151. package/src/BREP/SolidMethods/fillet.js +792 -0
  152. package/src/BREP/SolidMethods/index.js +72 -0
  153. package/src/BREP/SolidMethods/io.js +105 -0
  154. package/src/BREP/SolidMethods/lifecycle.js +103 -0
  155. package/src/BREP/SolidMethods/manifoldOps.js +375 -0
  156. package/src/BREP/SolidMethods/meshCleanup.js +2512 -0
  157. package/src/BREP/SolidMethods/meshQueries.js +264 -0
  158. package/src/BREP/SolidMethods/metadata.js +106 -0
  159. package/src/BREP/SolidMethods/metrics.js +51 -0
  160. package/src/BREP/SolidMethods/transforms.js +361 -0
  161. package/src/BREP/SolidMethods/visualize.js +508 -0
  162. package/src/BREP/SolidShared.js +26 -0
  163. package/src/BREP/Sweep.js +1596 -0
  164. package/src/BREP/Tube.js +857 -0
  165. package/src/BREP/Vertex.js +43 -0
  166. package/src/BREP/applyBooleanOperation.js +704 -0
  167. package/src/BREP/boundsUtils.js +48 -0
  168. package/src/BREP/chamfer.js +551 -0
  169. package/src/BREP/edgePolylineUtils.js +85 -0
  170. package/src/BREP/fillets/common.js +388 -0
  171. package/src/BREP/fillets/fillet.js +1422 -0
  172. package/src/BREP/fillets/filletGeometry.js +15 -0
  173. package/src/BREP/fillets/inset.js +389 -0
  174. package/src/BREP/fillets/offsetHelper.js +143 -0
  175. package/src/BREP/fillets/outset.js +88 -0
  176. package/src/BREP/helix.js +193 -0
  177. package/src/BREP/meshToBrep.js +234 -0
  178. package/src/BREP/primitives.js +279 -0
  179. package/src/BREP/setupManifold.js +71 -0
  180. package/src/BREP/threadGeometry.js +1120 -0
  181. package/src/BREP/triangleUtils.js +8 -0
  182. package/src/BREP/triangulate.js +608 -0
  183. package/src/FeatureRegistry.js +183 -0
  184. package/src/PartHistory.js +1132 -0
  185. package/src/UI/AccordionWidget.js +292 -0
  186. package/src/UI/CADmaterials.js +850 -0
  187. package/src/UI/EnvMonacoEditor.js +522 -0
  188. package/src/UI/FloatingWindow.js +396 -0
  189. package/src/UI/HistoryWidget.js +457 -0
  190. package/src/UI/MainToolbar.js +131 -0
  191. package/src/UI/ModelLibraryView.js +194 -0
  192. package/src/UI/OrthoCameraIdle.js +206 -0
  193. package/src/UI/PluginsWidget.js +280 -0
  194. package/src/UI/SceneListing.js +606 -0
  195. package/src/UI/SelectionFilter.js +629 -0
  196. package/src/UI/ViewCube.js +389 -0
  197. package/src/UI/assembly/AssemblyConstraintCollectionWidget.js +329 -0
  198. package/src/UI/assembly/AssemblyConstraintControlsWidget.js +282 -0
  199. package/src/UI/assembly/AssemblyConstraintsWidget.css +292 -0
  200. package/src/UI/assembly/AssemblyConstraintsWidget.js +1373 -0
  201. package/src/UI/assembly/constraintFaceUtils.js +115 -0
  202. package/src/UI/assembly/constraintHighlightUtils.js +70 -0
  203. package/src/UI/assembly/constraintLabelUtils.js +31 -0
  204. package/src/UI/assembly/constraintPointUtils.js +64 -0
  205. package/src/UI/assembly/constraintSelectionUtils.js +185 -0
  206. package/src/UI/assembly/constraintStatusUtils.js +142 -0
  207. package/src/UI/componentSelectorModal.js +240 -0
  208. package/src/UI/controls/CombinedTransformControls.js +386 -0
  209. package/src/UI/dialogs.js +351 -0
  210. package/src/UI/expressionsManager.js +100 -0
  211. package/src/UI/featureDialogWidgets/booleanField.js +25 -0
  212. package/src/UI/featureDialogWidgets/booleanOperationField.js +97 -0
  213. package/src/UI/featureDialogWidgets/buttonField.js +45 -0
  214. package/src/UI/featureDialogWidgets/componentSelectorField.js +102 -0
  215. package/src/UI/featureDialogWidgets/defaultField.js +23 -0
  216. package/src/UI/featureDialogWidgets/fileField.js +66 -0
  217. package/src/UI/featureDialogWidgets/index.js +34 -0
  218. package/src/UI/featureDialogWidgets/numberField.js +165 -0
  219. package/src/UI/featureDialogWidgets/optionsField.js +33 -0
  220. package/src/UI/featureDialogWidgets/referenceSelectionField.js +208 -0
  221. package/src/UI/featureDialogWidgets/stringField.js +24 -0
  222. package/src/UI/featureDialogWidgets/textareaField.js +28 -0
  223. package/src/UI/featureDialogWidgets/threadDesignationField.js +160 -0
  224. package/src/UI/featureDialogWidgets/transformField.js +252 -0
  225. package/src/UI/featureDialogWidgets/utils.js +43 -0
  226. package/src/UI/featureDialogWidgets/vec3Field.js +133 -0
  227. package/src/UI/featureDialogs.js +1414 -0
  228. package/src/UI/fileManagerWidget.js +615 -0
  229. package/src/UI/history/HistoryCollectionWidget.js +1294 -0
  230. package/src/UI/history/historyCollectionWidget.css.js +257 -0
  231. package/src/UI/history/historyDisplayInfo.js +133 -0
  232. package/src/UI/mobile.js +28 -0
  233. package/src/UI/objectDump.js +442 -0
  234. package/src/UI/pmi/AnnotationCollectionWidget.js +120 -0
  235. package/src/UI/pmi/AnnotationHistory.js +353 -0
  236. package/src/UI/pmi/AnnotationRegistry.js +90 -0
  237. package/src/UI/pmi/BaseAnnotation.js +269 -0
  238. package/src/UI/pmi/LabelOverlay.css +102 -0
  239. package/src/UI/pmi/LabelOverlay.js +191 -0
  240. package/src/UI/pmi/PMIMode.js +1550 -0
  241. package/src/UI/pmi/PMIViewsWidget.js +1098 -0
  242. package/src/UI/pmi/annUtils.js +729 -0
  243. package/src/UI/pmi/dimensions/AngleDimensionAnnotation.js +647 -0
  244. package/src/UI/pmi/dimensions/ExplodeBodyAnnotation.js +507 -0
  245. package/src/UI/pmi/dimensions/HoleCalloutAnnotation.js +462 -0
  246. package/src/UI/pmi/dimensions/LeaderAnnotation.js +403 -0
  247. package/src/UI/pmi/dimensions/LinearDimensionAnnotation.js +532 -0
  248. package/src/UI/pmi/dimensions/NoteAnnotation.js +110 -0
  249. package/src/UI/pmi/dimensions/RadialDimensionAnnotation.js +659 -0
  250. package/src/UI/pmi/pmiStyle.js +44 -0
  251. package/src/UI/sketcher/SketchMode3D.js +4095 -0
  252. package/src/UI/sketcher/dimensions.js +674 -0
  253. package/src/UI/sketcher/glyphs.js +236 -0
  254. package/src/UI/sketcher/highlights.js +60 -0
  255. package/src/UI/toolbarButtons/aboutButton.js +5 -0
  256. package/src/UI/toolbarButtons/exportButton.js +609 -0
  257. package/src/UI/toolbarButtons/flatPatternButton.js +307 -0
  258. package/src/UI/toolbarButtons/importButton.js +160 -0
  259. package/src/UI/toolbarButtons/inspectorToggleButton.js +12 -0
  260. package/src/UI/toolbarButtons/metadataButton.js +1063 -0
  261. package/src/UI/toolbarButtons/orientToFaceButton.js +114 -0
  262. package/src/UI/toolbarButtons/registerDefaultButtons.js +46 -0
  263. package/src/UI/toolbarButtons/saveButton.js +99 -0
  264. package/src/UI/toolbarButtons/scriptRunnerButton.js +302 -0
  265. package/src/UI/toolbarButtons/testsButton.js +26 -0
  266. package/src/UI/toolbarButtons/undoRedoButtons.js +25 -0
  267. package/src/UI/toolbarButtons/wireframeToggleButton.js +5 -0
  268. package/src/UI/toolbarButtons/zoomToFitButton.js +5 -0
  269. package/src/UI/triangleDebuggerWindow.js +945 -0
  270. package/src/UI/viewer.js +4228 -0
  271. package/src/assemblyConstraints/AssemblyConstraintHistory.js +1576 -0
  272. package/src/assemblyConstraints/AssemblyConstraintRegistry.js +120 -0
  273. package/src/assemblyConstraints/BaseAssemblyConstraint.js +66 -0
  274. package/src/assemblyConstraints/constraintExpressionUtils.js +35 -0
  275. package/src/assemblyConstraints/constraintUtils/parallelAlignment.js +676 -0
  276. package/src/assemblyConstraints/constraints/AngleConstraint.js +485 -0
  277. package/src/assemblyConstraints/constraints/CoincidentConstraint.js +194 -0
  278. package/src/assemblyConstraints/constraints/DistanceConstraint.js +616 -0
  279. package/src/assemblyConstraints/constraints/FixedConstraint.js +78 -0
  280. package/src/assemblyConstraints/constraints/ParallelConstraint.js +252 -0
  281. package/src/assemblyConstraints/constraints/TouchAlignConstraint.js +961 -0
  282. package/src/core/entities/HistoryCollectionBase.js +72 -0
  283. package/src/core/entities/ListEntityBase.js +109 -0
  284. package/src/core/entities/schemaProcesser.js +121 -0
  285. package/src/exporters/sheetMetalFlatPattern.js +659 -0
  286. package/src/exporters/sheetMetalUnfold.js +862 -0
  287. package/src/exporters/step.js +1135 -0
  288. package/src/exporters/threeMF.js +575 -0
  289. package/src/features/assemblyComponent/AssemblyComponentFeature.js +780 -0
  290. package/src/features/boolean/BooleanFeature.js +94 -0
  291. package/src/features/chamfer/ChamferFeature.js +116 -0
  292. package/src/features/datium/DatiumFeature.js +80 -0
  293. package/src/features/edgeFeatureUtils.js +41 -0
  294. package/src/features/extrude/ExtrudeFeature.js +143 -0
  295. package/src/features/fillet/FilletFeature.js +197 -0
  296. package/src/features/helix/HelixFeature.js +405 -0
  297. package/src/features/hole/HoleFeature.js +1050 -0
  298. package/src/features/hole/screwClearance.js +86 -0
  299. package/src/features/hole/threadDesignationCatalog.js +149 -0
  300. package/src/features/imageHeightSolid/ImageHeightmapSolidFeature.js +463 -0
  301. package/src/features/imageToFace/ImageToFaceFeature.js +727 -0
  302. package/src/features/imageToFace/imageEditor.js +1270 -0
  303. package/src/features/imageToFace/traceUtils.js +971 -0
  304. package/src/features/import3dModel/Import3dModelFeature.js +151 -0
  305. package/src/features/loft/LoftFeature.js +605 -0
  306. package/src/features/mirror/MirrorFeature.js +151 -0
  307. package/src/features/offsetFace/OffsetFaceFeature.js +370 -0
  308. package/src/features/offsetShell/OffsetShellFeature.js +89 -0
  309. package/src/features/overlapCleanup/OverlapCleanupFeature.js +85 -0
  310. package/src/features/pattern/PatternFeature.js +275 -0
  311. package/src/features/patternLinear/PatternLinearFeature.js +120 -0
  312. package/src/features/patternRadial/PatternRadialFeature.js +186 -0
  313. package/src/features/plane/PlaneFeature.js +154 -0
  314. package/src/features/primitiveCone/primitiveConeFeature.js +99 -0
  315. package/src/features/primitiveCube/primitiveCubeFeature.js +70 -0
  316. package/src/features/primitiveCylinder/primitiveCylinderFeature.js +91 -0
  317. package/src/features/primitivePyramid/primitivePyramidFeature.js +72 -0
  318. package/src/features/primitiveSphere/primitiveSphereFeature.js +62 -0
  319. package/src/features/primitiveTorus/primitiveTorusFeature.js +109 -0
  320. package/src/features/remesh/RemeshFeature.js +97 -0
  321. package/src/features/revolve/RevolveFeature.js +111 -0
  322. package/src/features/selectionUtils.js +118 -0
  323. package/src/features/sheetMetal/SheetMetalContourFlangeFeature.js +1656 -0
  324. package/src/features/sheetMetal/SheetMetalCutoutFeature.js +1056 -0
  325. package/src/features/sheetMetal/SheetMetalFlangeFeature.js +1568 -0
  326. package/src/features/sheetMetal/SheetMetalHemFeature.js +43 -0
  327. package/src/features/sheetMetal/SheetMetalObject.js +141 -0
  328. package/src/features/sheetMetal/SheetMetalTabFeature.js +176 -0
  329. package/src/features/sheetMetal/UNFOLD_NEUTRAL_REQUIREMENTS.md +153 -0
  330. package/src/features/sheetMetal/contour-flange-rebuild-spec.md +261 -0
  331. package/src/features/sheetMetal/profileUtils.js +25 -0
  332. package/src/features/sheetMetal/sheetMetalCleanup.js +9 -0
  333. package/src/features/sheetMetal/sheetMetalFaceTypes.js +146 -0
  334. package/src/features/sheetMetal/sheetMetalMetadata.js +165 -0
  335. package/src/features/sheetMetal/sheetMetalPipeline.js +169 -0
  336. package/src/features/sheetMetal/sheetMetalProfileUtils.js +216 -0
  337. package/src/features/sheetMetal/sheetMetalTabUtils.js +29 -0
  338. package/src/features/sheetMetal/sheetMetalTree.js +210 -0
  339. package/src/features/sketch/SketchFeature.js +955 -0
  340. package/src/features/sketch/sketchSolver2D/ConstraintEngine.js +800 -0
  341. package/src/features/sketch/sketchSolver2D/constraintDefinitions.js +704 -0
  342. package/src/features/sketch/sketchSolver2D/mathHelpersMod.js +307 -0
  343. package/src/features/spline/SplineEditorSession.js +988 -0
  344. package/src/features/spline/SplineFeature.js +1388 -0
  345. package/src/features/spline/splineUtils.js +218 -0
  346. package/src/features/sweep/SweepFeature.js +110 -0
  347. package/src/features/transform/TransformFeature.js +152 -0
  348. package/src/features/tube/TubeFeature.js +635 -0
  349. package/src/fs.proxy.js +625 -0
  350. package/src/idbStorage.js +254 -0
  351. package/src/index.js +12 -0
  352. package/src/main.js +15 -0
  353. package/src/metadataManager.js +64 -0
  354. package/src/path.proxy.js +277 -0
  355. package/src/plugins/ghLoader.worker.js +151 -0
  356. package/src/plugins/pluginManager.js +286 -0
  357. package/src/pmi/PMIViewsManager.js +134 -0
  358. package/src/services/componentLibrary.js +198 -0
  359. package/src/tests/ConsoleCapture.js +189 -0
  360. package/src/tests/S7-diagnostics-2025-12-23T18-37-23-570Z.json +630 -0
  361. package/src/tests/browserTests.js +597 -0
  362. package/src/tests/debugBoolean.js +225 -0
  363. package/src/tests/partFiles/badBoolean.json +957 -0
  364. package/src/tests/partFiles/extrudeTest.json +88 -0
  365. package/src/tests/partFiles/filletFail.json +58 -0
  366. package/src/tests/partFiles/import_TEst.part.part.json +646 -0
  367. package/src/tests/partFiles/sheetMetalHem.BREP.json +734 -0
  368. package/src/tests/test_boolean_subtract.js +27 -0
  369. package/src/tests/test_chamfer.js +17 -0
  370. package/src/tests/test_extrudeFace.js +24 -0
  371. package/src/tests/test_fillet.js +17 -0
  372. package/src/tests/test_fillet_nonClosed.js +45 -0
  373. package/src/tests/test_filletsMoreDifficult.js +46 -0
  374. package/src/tests/test_history_features_basic.js +149 -0
  375. package/src/tests/test_hole.js +282 -0
  376. package/src/tests/test_mirror.js +16 -0
  377. package/src/tests/test_offsetShellGrouping.js +85 -0
  378. package/src/tests/test_plane.js +4 -0
  379. package/src/tests/test_primitiveCone.js +11 -0
  380. package/src/tests/test_primitiveCube.js +7 -0
  381. package/src/tests/test_primitiveCylinder.js +8 -0
  382. package/src/tests/test_primitivePyramid.js +9 -0
  383. package/src/tests/test_primitiveSphere.js +17 -0
  384. package/src/tests/test_primitiveTorus.js +21 -0
  385. package/src/tests/test_pushFace.js +126 -0
  386. package/src/tests/test_sheetMetalContourFlange.js +125 -0
  387. package/src/tests/test_sheetMetal_features.js +80 -0
  388. package/src/tests/test_sketch_openLoop.js +45 -0
  389. package/src/tests/test_solidMetrics.js +58 -0
  390. package/src/tests/test_stlLoader.js +1889 -0
  391. package/src/tests/test_sweepFace.js +55 -0
  392. package/src/tests/test_tube.js +45 -0
  393. package/src/tests/test_tube_closedLoop.js +67 -0
  394. package/src/tests/tests.js +493 -0
  395. package/src/tools/assemblyConstraintDialogCapturePage.js +56 -0
  396. package/src/tools/dialogCapturePageFactory.js +227 -0
  397. package/src/tools/featureDialogCapturePage.js +47 -0
  398. package/src/tools/pmiAnnotationDialogCapturePage.js +60 -0
  399. package/src/utils/axisHelpers.js +99 -0
  400. package/src/utils/deepClone.js +69 -0
  401. package/src/utils/geometryTolerance.js +37 -0
  402. package/src/utils/normalizeTypeString.js +8 -0
  403. package/src/utils/xformMath.js +51 -0
@@ -0,0 +1,988 @@
1
+ import * as THREE from "three";
2
+ import { CombinedTransformControls } from "../../UI/controls/CombinedTransformControls.js";
3
+ import { BREP } from "../../BREP/BREP.js";
4
+ import {
5
+ DEFAULT_RESOLUTION,
6
+ normalizeSplineData,
7
+ buildHermitePolyline,
8
+ cloneSplineData,
9
+ } from "./splineUtils.js";
10
+
11
+ const noop = () => { };
12
+
13
+ export class SplineEditorSession {
14
+ constructor(viewer, featureID, options = {}) {
15
+ this.viewer = viewer || null;
16
+ this.featureID =
17
+ featureID != null ? String(featureID) : options?.featureID || null;
18
+ this.options = options || {};
19
+
20
+ this._featureRef = options.featureRef || null;
21
+ this._previewResolution = DEFAULT_RESOLUTION;
22
+ this._splineData = normalizeSplineData(
23
+ cloneSplineData(this._featureRef?.persistentData?.spline || null)
24
+ );
25
+
26
+ this._objectsById = new Map();
27
+ this._extensionLines = new Map();
28
+ this._selectedId = null;
29
+ this._hiddenArtifacts = [];
30
+
31
+ this._transformsById = new Map();
32
+ this._transformListeners = new Map();
33
+ this._isTransformDragging = false;
34
+
35
+ this._extensionLineMaterial = null;
36
+
37
+ this._previewGroup = null;
38
+ this._line = null;
39
+
40
+ this._onSplineChange =
41
+ typeof options.onSplineChange === "function"
42
+ ? options.onSplineChange
43
+ : noop;
44
+ this._onSelectionChange =
45
+ typeof options.onSelectionChange === "function"
46
+ ? options.onSelectionChange
47
+ : noop;
48
+
49
+ this._active = false;
50
+ }
51
+
52
+ _updateTransformVisibility() {
53
+ if (!this._transformsById) {
54
+ return;
55
+ }
56
+
57
+ // Check if preview group exists, if not rebuild it
58
+ this._ensurePreviewGroup();
59
+
60
+ for (const [id, transformEntry] of this._transformsById.entries()) {
61
+ if (!transformEntry) {
62
+ continue;
63
+ }
64
+ const { control } = transformEntry;
65
+ const active = id === this._selectedId;
66
+
67
+ if (control) {
68
+ control.enabled = active;
69
+ control.visible = active;
70
+
71
+ // Ensure proper scene management - remove from scene when inactive
72
+ if (this.viewer?.scene) {
73
+ if (active) {
74
+ // Add to scene if not already present
75
+ if (!this.viewer.scene.children.includes(control)) {
76
+ this.viewer.scene.add(control);
77
+ }
78
+ } else {
79
+ // Remove from scene when inactive
80
+ if (this.viewer.scene.children.includes(control)) {
81
+ this.viewer.scene.remove(control);
82
+ }
83
+ }
84
+ }
85
+ }
86
+ }
87
+ if (!this._selectedId) {
88
+ this._isTransformDragging = false;
89
+ }
90
+ }
91
+
92
+ isActive() {
93
+ return this._active;
94
+ }
95
+
96
+ hasTransformControls() {
97
+ return this._transformsById && this._transformsById.size > 0;
98
+ }
99
+
100
+ getTransformControlCount() {
101
+ return this._transformsById ? this._transformsById.size : 0;
102
+ }
103
+
104
+ getSplineData() {
105
+ return cloneSplineData(this._splineData);
106
+ }
107
+
108
+ getSelectedId() {
109
+ return this._selectedId;
110
+ }
111
+
112
+ setFeatureRef(featureRef) {
113
+ this._featureRef = featureRef || null;
114
+ }
115
+
116
+ /**
117
+ * Activate the editing session. Builds preview geometry and attaches transform controls.
118
+ * @param {Object|null} initialSpline
119
+ * @param {Object} [options]
120
+ * @param {Object} [options.featureRef]
121
+ * @param {number} [options.previewResolution]
122
+ * @param {string} [options.initialSelection]
123
+ * @returns {boolean}
124
+ */
125
+ activate(initialSpline = null, options = {}) {
126
+ if (!this.viewer) {
127
+ return false;
128
+ }
129
+
130
+ if (this._active) {
131
+ this.dispose();
132
+ }
133
+
134
+ const featureRef = options.featureRef ?? this._featureRef ?? null;
135
+ this._featureRef = featureRef;
136
+
137
+ const resCandidate =
138
+ options.previewResolution ??
139
+ Number(featureRef?.inputParams?.curveResolution);
140
+ if (Number.isFinite(resCandidate) && resCandidate >= 4) {
141
+ this._previewResolution = Math.max(4, Math.floor(resCandidate));
142
+ } else {
143
+ this._previewResolution = DEFAULT_RESOLUTION;
144
+ }
145
+
146
+ const source = initialSpline
147
+ ? cloneSplineData(initialSpline)
148
+ : cloneSplineData(featureRef?.persistentData?.spline || null);
149
+ this._splineData = normalizeSplineData(source);
150
+
151
+ this._hideExistingArtifacts();
152
+ this._initMaterials();
153
+ this._buildPreviewGroup();
154
+ // Set up initial selection before rebuild
155
+ const initialSelection = options.initialSelection || null;
156
+ if (initialSelection) {
157
+ this._selectedId = initialSelection;
158
+ }
159
+
160
+ this._rebuildAll({ preserveSelection: !!initialSelection });
161
+
162
+ this._active = true;
163
+
164
+ // Register with viewer to enable spline mode (suppress normal scene picking)
165
+ if (this.viewer && typeof this.viewer.startSplineMode === 'function') {
166
+ this.viewer.startSplineMode(this);
167
+ }
168
+
169
+ // Hook into viewer's controls change event to update transform controls
170
+ this._setupControlsListener();
171
+
172
+ this._notifySelectionChange(this._selectedId);
173
+ this._renderOnce();
174
+ return true;
175
+ }
176
+
177
+ /**
178
+ * Tear down preview/controls and restore original artifacts.
179
+ */
180
+ dispose() {
181
+ // Unregister from viewer to disable spline mode
182
+ if (this.viewer && typeof this.viewer.endSplineMode === 'function') {
183
+ this.viewer.endSplineMode();
184
+ }
185
+
186
+ // Remove controls change listener
187
+ this._teardownControlsListener();
188
+
189
+ this._teardownAllTransforms();
190
+ this._destroyPreviewGroup();
191
+ this._restoreArtifacts();
192
+ this._disposeMaterials();
193
+ if (this._selectedId !== null) {
194
+ this._selectedId = null;
195
+ this._notifySelectionChange(null);
196
+ }
197
+ this._active = false;
198
+ }
199
+
200
+ /**
201
+ * Update session spline data and rebuild preview.
202
+ * @param {Object} spline
203
+ * @param {Object} [options]
204
+ * @param {boolean} [options.preserveSelection=true]
205
+ * @param {boolean} [options.silent=false]
206
+ * @param {string} [options.reason="manual"]
207
+ */
208
+ setSplineData(spline, options = {}) {
209
+
210
+ const {
211
+ preserveSelection = true,
212
+ silent = false,
213
+ reason = "manual",
214
+ } = options;
215
+
216
+ const normalized = normalizeSplineData(cloneSplineData(spline));
217
+ this._splineData = normalized;
218
+
219
+ // Update the feature's persistent data immediately
220
+ this._updateFeaturePersistentData();
221
+
222
+ // CRITICAL FIX: Don't rebuild everything if this is just a transform update
223
+ if (reason === "transform" && preserveSelection) {
224
+ // Just update the preview line, don't rebuild point handles (which destroys transforms)
225
+ this._rebuildPreviewLine();
226
+ this._updateExtensionLinesForAllPoints();
227
+ } else {
228
+ this._rebuildAll({ preserveSelection });
229
+ }
230
+
231
+ if (!silent) {
232
+ this._notifySplineChange(reason);
233
+ } else {
234
+ this._renderOnce();
235
+ }
236
+ }
237
+
238
+ selectObject(id, options = {}) {
239
+ const { silent = false, forceRedraw = false } = options || {};
240
+ const nextId = id == null ? null : String(id);
241
+
242
+ if (this._selectedId === nextId && !forceRedraw) {
243
+ if (!silent) {
244
+ this._notifySelectionChange(this._selectedId);
245
+ }
246
+ return;
247
+ }
248
+
249
+ // Ensure preview group exists before changing selection
250
+ this._ensurePreviewGroup();
251
+
252
+ this._selectedId = nextId;
253
+
254
+ // If forcing redraw, rebuild everything to ensure fresh state
255
+ if (forceRedraw) {
256
+ this._rebuildAll({ preserveSelection: true });
257
+ }
258
+
259
+ this._updateSelectionVisuals();
260
+
261
+ this._updateTransformVisibility();
262
+
263
+ if (!silent) {
264
+ this._notifySelectionChange(this._selectedId);
265
+ }
266
+
267
+ this._renderOnce();
268
+ }
269
+
270
+ clearSelection() {
271
+ this.selectObject(null);
272
+ }
273
+
274
+ hideGizmo() {
275
+ this.clearSelection();
276
+ }
277
+
278
+ /**
279
+ * Force cleanup of any stale objects in the scene
280
+ */
281
+ forceCleanup() {
282
+
283
+ if (!this.viewer?.scene) return;
284
+
285
+ // Find and remove any stale transform controls
286
+ const toRemove = [];
287
+ this.viewer.scene.traverse((obj) => {
288
+ // Look for transform controls that might be stale
289
+ if (obj.type === 'CombinedTransformControls' || obj.isTransformGizmo) {
290
+ // Check if this control is in our current transforms map
291
+ let isValid = false;
292
+ if (this._transformsById) {
293
+ for (const entry of this._transformsById.values()) {
294
+ if (entry.control === obj) {
295
+ isValid = true;
296
+ break;
297
+ }
298
+ }
299
+ }
300
+ if (!isValid) {
301
+ toRemove.push(obj);
302
+ }
303
+ }
304
+ });
305
+
306
+ // Remove stale objects
307
+ for (const obj of toRemove) {
308
+ try {
309
+ this.viewer.scene.remove(obj);
310
+ obj.dispose?.();
311
+ } catch (error) {
312
+ /* ignore */
313
+ }
314
+ }
315
+
316
+ this._renderOnce();
317
+ }
318
+
319
+ _renderOnce() {
320
+ try {
321
+ this.viewer?.render?.();
322
+ } catch {
323
+ /* noop */
324
+ }
325
+ }
326
+
327
+ _setupControlsListener() {
328
+ // Listen to camera/controls changes to update transform controls screen size
329
+ this._controlsChangeHandler = () => {
330
+ if (this._transformsById) {
331
+ for (const [id, transformEntry] of this._transformsById.entries()) {
332
+ const control = transformEntry?.control;
333
+ if (control && typeof control.update === 'function') {
334
+ try {
335
+ control.update();
336
+ } catch (error) {
337
+ console.warn(`SplineEditorSession: Failed to update transform control ${id}:`, error);
338
+ }
339
+ }
340
+ }
341
+ }
342
+ };
343
+
344
+ // Hook into the viewer's controls change event
345
+ if (this.viewer?.controls && typeof this.viewer.controls.addEventListener === 'function') {
346
+ this.viewer.controls.addEventListener('change', this._controlsChangeHandler);
347
+ this.viewer.controls.addEventListener('end', this._controlsChangeHandler);
348
+ }
349
+ }
350
+
351
+ _teardownControlsListener() {
352
+ if (this._controlsChangeHandler && this.viewer?.controls) {
353
+ try {
354
+ this.viewer.controls.removeEventListener('change', this._controlsChangeHandler);
355
+ this.viewer.controls.removeEventListener('end', this._controlsChangeHandler);
356
+ } catch (error) {
357
+ console.warn('SplineEditorSession: Failed to remove controls listeners:', error);
358
+ }
359
+ }
360
+ this._controlsChangeHandler = null;
361
+ }
362
+
363
+ _notifySplineChange(reason, extra = null) {
364
+ try {
365
+ this._onSplineChange(this.getSplineData(), reason, extra);
366
+ } catch {
367
+ /* ignore listener errors */
368
+ }
369
+ }
370
+
371
+ _updateFeaturePersistentData() {
372
+ // Update the feature's persistent data immediately
373
+ if (this._featureRef) {
374
+ this._featureRef.persistentData = this._featureRef.persistentData || {};
375
+ this._featureRef.persistentData.spline = cloneSplineData(this._splineData);
376
+
377
+ // Mark the feature as dirty for rebuild
378
+ this._featureRef.lastRunInputParams = {};
379
+ this._featureRef.timestamp = 0;
380
+ this._featureRef.dirty = true;
381
+ }
382
+ }
383
+
384
+ _notifySelectionChange(id) {
385
+ try {
386
+ this._onSelectionChange(id);
387
+ } catch {
388
+ /* ignore listener errors */
389
+ }
390
+ }
391
+
392
+ _hideExistingArtifacts() {
393
+ const scene = this.viewer?.scene;
394
+ if (!scene) return;
395
+ this._hiddenArtifacts = [];
396
+ scene.traverse((obj) => {
397
+ if (obj && obj.owningFeatureID === this.featureID && obj.visible) {
398
+ this._hiddenArtifacts.push({ obj, visible: obj.visible });
399
+ obj.visible = false;
400
+ }
401
+ });
402
+ }
403
+
404
+ _restoreArtifacts() {
405
+ for (const entry of this._hiddenArtifacts) {
406
+ try {
407
+ entry.obj.visible = entry.visible;
408
+ } catch {
409
+ /* ignore */
410
+ }
411
+ }
412
+ this._hiddenArtifacts = [];
413
+ }
414
+
415
+ _initMaterials() {
416
+ // Extension line material - thicker than the main spline
417
+ this._extensionLineMaterial = new THREE.LineBasicMaterial({
418
+ color: "blue",
419
+ linewidth: 3, // Thicker than the main spline
420
+ transparent: true,
421
+ opacity: 0.85,
422
+ depthTest: false,
423
+ });
424
+ }
425
+
426
+ _disposeMaterials() {
427
+ try {
428
+ this._extensionLineMaterial?.dispose?.();
429
+ } catch {
430
+ /* noop */
431
+ }
432
+ this._extensionLineMaterial = null;
433
+ }
434
+
435
+ _buildPreviewGroup() {
436
+ const scene = this.viewer?.scene;
437
+ if (!scene) return;
438
+
439
+
440
+
441
+ // remove the actual spline from the scene. The spline generated by the feature it self, not the preview
442
+ // The object to be removed from the scene will have the same name as the feature ID
443
+ const existingSpline = scene.getObjectByName(this.featureID);
444
+ if (existingSpline) {
445
+ scene.remove(existingSpline);
446
+ }
447
+
448
+ // Search the scene for an existing preview group and reuse it rather than creating a new one
449
+ const existingGroupName = `SplineEditorPreview:${this.featureID || ""}`;
450
+ const existingGroup = scene.getObjectByName(existingGroupName);
451
+ if (existingGroup) {
452
+ this._previewGroup = existingGroup;
453
+ // remove all children from existing group
454
+ while (this._previewGroup.children.length > 0) {
455
+ this._previewGroup.remove(this._previewGroup.children[0]);
456
+ }
457
+ } else {
458
+ this._previewGroup = new THREE.Group();
459
+ }
460
+
461
+
462
+ this._previewGroup.name = `SplineEditorPreview:${this.featureID || ""}`;
463
+ this._previewGroup.userData = this._previewGroup.userData || {};
464
+ this._previewGroup.userData.excludeFromFit = true;
465
+ this._previewGroup.userData.preventRemove = true;
466
+
467
+ const lineMaterial = new THREE.LineBasicMaterial({
468
+ color: 0xffffff,
469
+ linewidth: 2,
470
+ });
471
+
472
+ const geometry = new THREE.BufferGeometry();
473
+ geometry.setAttribute("position", new THREE.Float32BufferAttribute([], 3));
474
+
475
+ this._line = new THREE.Line(geometry, lineMaterial);
476
+ this._line.userData = this._line.userData || {};
477
+ this._line.userData.excludeFromFit = true;
478
+ this._line.renderOrder = 10000;
479
+ this._previewGroup.add(this._line);
480
+
481
+ scene.add(this._previewGroup);
482
+ }
483
+
484
+ _ensurePreviewGroup() {
485
+ const scene = this.viewer.scene;
486
+
487
+ // Check if the preview group still exists in the scene
488
+ if (!this._previewGroup || !this.viewer?.scene) {
489
+ this._buildPreviewGroup();
490
+ return;
491
+ }
492
+
493
+ // Check if the preview group was removed from the scene
494
+
495
+ const existingGroupName = `SplineEditorPreview:${this.featureID || ""}`;
496
+ const foundInScene = scene.getObjectByName(existingGroupName);
497
+
498
+ if (!foundInScene) {
499
+ // Preview group was removed, sync with latest persistent data and rebuild
500
+ const latestSplineData = this._featureRef?.persistentData?.spline;
501
+ if (latestSplineData) {
502
+ this._splineData = normalizeSplineData(cloneSplineData(latestSplineData));
503
+ }
504
+
505
+ // Update preview resolution from current feature parameters
506
+ const resCandidate = Number(this._featureRef?.inputParams?.curveResolution);
507
+ if (Number.isFinite(resCandidate) && resCandidate >= 4) {
508
+ this._previewResolution = Math.max(4, Math.floor(resCandidate));
509
+ }
510
+
511
+ this._buildPreviewGroup();
512
+ this._rebuildAll({ preserveSelection: true });
513
+ }
514
+ }
515
+
516
+ _destroyPreviewGroup() {
517
+ if (!this._previewGroup || !this.viewer?.scene) {
518
+ this._teardownAllTransforms();
519
+ return;
520
+ }
521
+ this._teardownAllTransforms();
522
+ this._removeExtensionLines();
523
+ try {
524
+ if (this._line) {
525
+ this._line.geometry?.dispose();
526
+ this._line.material?.dispose();
527
+ }
528
+ } catch {
529
+ /* noop */
530
+ }
531
+ try {
532
+ // Clear the preventRemove flag before removing from scene
533
+ if (this._previewGroup.userData) {
534
+ this._previewGroup.userData.preventRemove = false;
535
+ }
536
+ this.viewer.scene.remove(this._previewGroup);
537
+ } catch {
538
+ /* noop */
539
+ }
540
+ this._previewGroup = null;
541
+ this._line = null;
542
+ this._objectsById.clear();
543
+ this._extensionLines.clear();
544
+ }
545
+
546
+ _createTransformControl(id, mesh) {
547
+ if (!this.viewer?.scene || !this.viewer?.camera || !this.viewer?.renderer) {
548
+
549
+ return null;
550
+ }
551
+ if (!CombinedTransformControls) {
552
+
553
+ return null;
554
+ }
555
+ const control = new CombinedTransformControls(
556
+ this.viewer.camera,
557
+ this.viewer.renderer.domElement
558
+ );
559
+
560
+ control.name = `SplineEditorControl:${id}`;
561
+
562
+ control.setMode("translate");
563
+ control.showX = true;
564
+ control.showY = true;
565
+ control.showZ = true;
566
+ control.enabled = false; // Will be enabled when selected
567
+ control.attach(mesh);
568
+ control.userData = control.userData || {};
569
+ control.userData.excludeFromFit = true;
570
+
571
+ // Add the transform control directly to the scene
572
+ this.viewer.scene.add(control);
573
+
574
+ const changeHandler = () => this._handleTransformChangeFor(id);
575
+ const dragHandler = (event) => {
576
+ this._handleTransformDragging(!!event?.value);
577
+ };
578
+ control.addEventListener("change", changeHandler);
579
+ control.addEventListener("dragging-changed", dragHandler);
580
+
581
+ this._transformsById.set(id, { control });
582
+ this._transformListeners.set(id, { changeHandler, dragHandler });
583
+ return control;
584
+ }
585
+
586
+ _teardownAllTransforms() {
587
+ if (!this._transformsById?.size) {
588
+ this._isTransformDragging = false;
589
+ return;
590
+ }
591
+
592
+ for (const [id, transformEntry] of this._transformsById.entries()) {
593
+
594
+ const control = transformEntry?.control || null;
595
+ const listeners = this._transformListeners.get(id);
596
+
597
+ if (control && listeners) {
598
+ try {
599
+ control.removeEventListener("change", listeners.changeHandler);
600
+ } catch (error) {
601
+ /* ignore */
602
+ }
603
+ try {
604
+ control.removeEventListener("dragging-changed", listeners.dragHandler);
605
+ } catch (error) {
606
+ /* ignore */
607
+ }
608
+ }
609
+
610
+ try {
611
+ control?.detach?.();
612
+ } catch (error) {
613
+ /* ignore */
614
+ }
615
+
616
+ // Remove control from scene
617
+ if (control) {
618
+ try {
619
+ this.viewer?.scene?.remove(control);
620
+ } catch (error) {
621
+ /* ignore */
622
+ }
623
+ }
624
+
625
+ try {
626
+ control?.dispose?.();
627
+ } catch (error) {
628
+ /* ignore */
629
+ }
630
+ }
631
+ this._transformsById.clear();
632
+ this._transformListeners.clear();
633
+ this._isTransformDragging = false;
634
+ }
635
+
636
+ _rebuildAll({ preserveSelection }) {
637
+
638
+ // Force cleanup of any stale objects before rebuild
639
+ this.forceCleanup();
640
+
641
+ const previousSelection = preserveSelection ? this._selectedId : null;
642
+
643
+ this._buildPointHandles();
644
+
645
+ this._rebuildPreviewLine();
646
+
647
+ if (preserveSelection && previousSelection) {
648
+ this.selectObject(previousSelection, { silent: true });
649
+ } else if (!preserveSelection) {
650
+ this.selectObject(null, { silent: true });
651
+ }
652
+
653
+ }
654
+
655
+ _buildPointHandles() {
656
+
657
+ if (!this._previewGroup) return;
658
+
659
+ this._teardownAllTransforms();
660
+
661
+ // Clear EVERYTHING from the preview group - no preservation
662
+ while (this._previewGroup.children.length > 0) {
663
+ const child = this._previewGroup.children[0];
664
+ this._previewGroup.remove(child);
665
+ try {
666
+ child.geometry?.dispose();
667
+ child.material?.dispose();
668
+ } catch {
669
+ /* noop */
670
+ }
671
+ }
672
+
673
+ // Clear all tracking maps completely
674
+ this._objectsById.clear();
675
+ this._extensionLines.clear();
676
+
677
+ this._initMaterials();
678
+
679
+ // Create fresh spline line
680
+ const lineMaterial = new THREE.LineBasicMaterial({
681
+ color: 0xffffff,
682
+ linewidth: 2,
683
+ });
684
+ const geometry = new THREE.BufferGeometry();
685
+ geometry.setAttribute("position", new THREE.Float32BufferAttribute([], 3));
686
+ this._line = new THREE.Line(geometry, lineMaterial);
687
+ this._line.name = "SplinePreviewLine";
688
+ this._previewGroup.add(this._line);
689
+
690
+ // Create handles for each point - no separate extension handles
691
+ this._splineData.points.forEach((pt, index) => {
692
+ // Create a simple point geometry for invisible click target
693
+ const pointGeometry = new THREE.BufferGeometry();
694
+ const position = new Float32Array([
695
+ Number(pt.position[0]) || 0,
696
+ Number(pt.position[1]) || 0,
697
+ Number(pt.position[2]) || 0
698
+ ]);
699
+ pointGeometry.setAttribute('position', new THREE.BufferAttribute(position, 3));
700
+
701
+ // Create an invisible mesh for raycasting and transform attachment
702
+ const pointMaterial = new THREE.MeshBasicMaterial({ visible: false });
703
+ const mesh = new THREE.Mesh(new THREE.SphereGeometry(0.15, 8, 8), pointMaterial);
704
+ mesh.position.set(position[0], position[1], position[2]);
705
+
706
+ // Apply stored rotation to the mesh
707
+ if (pt.rotation && Array.isArray(pt.rotation) && pt.rotation.length === 9) {
708
+ const rotMatrix = new THREE.Matrix3().fromArray(pt.rotation);
709
+ const matrix4 = new THREE.Matrix4().setFromMatrix3(rotMatrix);
710
+ mesh.setRotationFromMatrix(matrix4);
711
+ }
712
+
713
+ mesh.name = `SplinePoint:${pt.id}`;
714
+ this._previewGroup.add(mesh);
715
+
716
+ // Create a clickable vertex at the same position using BREP.Vertex
717
+ const vertex = new BREP.Vertex([position[0], position[1], position[2]], {
718
+ name: `SplineVertex:${pt.id}`,
719
+ });
720
+
721
+ // Add click handler to the vertex to trigger selection
722
+ vertex.onClick = () => {
723
+ this.selectObject(`point:${pt.id}`);
724
+ };
725
+
726
+ // Store reference to the point for identification - set on both vertex and internal point
727
+ vertex.userData = vertex.userData || {};
728
+ vertex.userData.splineFeatureId = this.featureID;
729
+ vertex.userData.splinePointId = pt.id;
730
+ vertex.userData.isSplineVertex = true;
731
+
732
+ // Also set userData on the internal Points object that gets hit by raycaster
733
+ if (vertex._point) {
734
+ vertex._point.userData = vertex._point.userData || {};
735
+ vertex._point.userData.splineFeatureId = this.featureID;
736
+ vertex._point.userData.splinePointId = pt.id;
737
+ vertex._point.userData.isSplineVertex = true;
738
+ // Copy the onClick handler to the internal point
739
+ vertex._point.onClick = vertex.onClick;
740
+ }
741
+
742
+ // Add vertex to preview group
743
+ this._previewGroup.add(vertex);
744
+
745
+ const entryId = `point:${pt.id}`;
746
+ const transform = this._createTransformControl(entryId, mesh);
747
+ this._objectsById.set(entryId, {
748
+ type: "point",
749
+ mesh,
750
+ vertex, // Store reference to the clickable vertex
751
+ data: pt,
752
+ transform,
753
+ });
754
+
755
+ // Create extension lines for this point
756
+ const forwardKey = `forward-line:${pt.id}`;
757
+ const backwardKey = `backward-line:${pt.id}`;
758
+
759
+ // Forward extension line
760
+ const forwardGeometry = new THREE.BufferGeometry();
761
+ const forwardLine = new THREE.Line(forwardGeometry, this._extensionLineMaterial);
762
+ forwardLine.name = `SplineForwardLine:${pt.id}`;
763
+ forwardLine.visible = true;
764
+ forwardLine.frustumCulled = false;
765
+ this._previewGroup.add(forwardLine);
766
+ this._extensionLines.set(forwardKey, forwardLine);
767
+
768
+ // Backward extension line
769
+ const backwardGeometry = new THREE.BufferGeometry();
770
+ const backwardLine = new THREE.Line(backwardGeometry, this._extensionLineMaterial);
771
+ backwardLine.name = `SplineBackwardLine:${pt.id}`;
772
+ backwardLine.visible = true;
773
+ backwardLine.frustumCulled = false;
774
+ this._previewGroup.add(backwardLine);
775
+ this._extensionLines.set(backwardKey, backwardLine);
776
+
777
+ // Set the geometry for the extension lines
778
+ const rotation = pt.rotation || [1, 0, 0, 0, 1, 0, 0, 0, 1];
779
+ let xAxisDirection = [rotation[0], rotation[1], rotation[2]];
780
+
781
+ const length = Math.sqrt(xAxisDirection[0] * xAxisDirection[0] + xAxisDirection[1] * xAxisDirection[1] + xAxisDirection[2] * xAxisDirection[2]);
782
+ if (length > 0) {
783
+ xAxisDirection = [xAxisDirection[0] / length, xAxisDirection[1] / length, xAxisDirection[2] / length];
784
+ }
785
+
786
+ const forwardDir = pt.flipDirection ? [-xAxisDirection[0], -xAxisDirection[1], -xAxisDirection[2]] : xAxisDirection;
787
+ const backwardDir = pt.flipDirection ? xAxisDirection : [-xAxisDirection[0], -xAxisDirection[1], -xAxisDirection[2]];
788
+
789
+ // Forward line geometry
790
+ if (pt.forwardDistance > 0) {
791
+ const forwardEnd = [
792
+ pt.position[0] + forwardDir[0] * pt.forwardDistance,
793
+ pt.position[1] + forwardDir[1] * pt.forwardDistance,
794
+ pt.position[2] + forwardDir[2] * pt.forwardDistance
795
+ ];
796
+ forwardGeometry.setAttribute("position", new THREE.Float32BufferAttribute([
797
+ pt.position[0], pt.position[1], pt.position[2],
798
+ forwardEnd[0], forwardEnd[1], forwardEnd[2]
799
+ ], 3));
800
+ }
801
+
802
+ // Backward line geometry
803
+ if (pt.backwardDistance > 0) {
804
+ const backwardEnd = [
805
+ pt.position[0] + backwardDir[0] * pt.backwardDistance,
806
+ pt.position[1] + backwardDir[1] * pt.backwardDistance,
807
+ pt.position[2] + backwardDir[2] * pt.backwardDistance
808
+ ];
809
+ backwardGeometry.setAttribute("position", new THREE.Float32BufferAttribute([
810
+ pt.position[0], pt.position[1], pt.position[2],
811
+ backwardEnd[0], backwardEnd[1], backwardEnd[2]
812
+ ], 3));
813
+ }
814
+ });
815
+
816
+ this._updateTransformVisibility();
817
+
818
+ // Rebuild the spline curve as well
819
+ this._rebuildPreviewLine();
820
+ }
821
+
822
+ _rebuildPreviewLine() {
823
+ if (!this._line) return;
824
+
825
+ // Clean up old geometry to prevent memory leaks
826
+ const oldGeometry = this._line.geometry;
827
+ if (oldGeometry) {
828
+ // Clear old attributes
829
+ const positionAttr = oldGeometry.getAttribute("position");
830
+ if (positionAttr) {
831
+ positionAttr.needsUpdate = true;
832
+ }
833
+ }
834
+
835
+ const bendRadius = Number.isFinite(Number(this._featureRef?.inputParams?.bendRadius))
836
+ ? Math.max(0.1, Math.min(5.0, Number(this._featureRef.inputParams.bendRadius)))
837
+ : 1.0;
838
+
839
+ const { positions } = buildHermitePolyline(
840
+ this._splineData,
841
+ this._previewResolution || DEFAULT_RESOLUTION,
842
+ bendRadius
843
+ );
844
+
845
+ const array = new Float32Array(positions);
846
+ this._line.geometry.setAttribute(
847
+ "position",
848
+ new THREE.BufferAttribute(array, 3)
849
+ );
850
+ if (positions.length >= 3) {
851
+ this._line.geometry.computeBoundingSphere();
852
+ }
853
+
854
+ }
855
+
856
+ _updateSelectionVisuals() {
857
+ // Update vertex selection states to show which vertex is selected
858
+ for (const [id, entry] of this._objectsById.entries()) {
859
+ if (entry.vertex) {
860
+ const isSelected = id === this._selectedId;
861
+ entry.vertex.selected = isSelected;
862
+ }
863
+ }
864
+ }
865
+
866
+ _handleTransformChangeFor(id = null) {
867
+
868
+ const targetId =
869
+ id && this._objectsById.has(id) ? id : this._selectedId;
870
+ if (!targetId) return;
871
+ const entry = this._objectsById.get(targetId);
872
+ if (!entry || !entry.mesh || !entry.data) return;
873
+
874
+ const pos = entry.mesh.position;
875
+ if (entry.type === "point") {
876
+ // Update point position
877
+ entry.data.position = [pos.x, pos.y, pos.z];
878
+
879
+ // Update point rotation - extract rotation matrix from mesh
880
+ const rotMatrix = new THREE.Matrix3().setFromMatrix4(entry.mesh.matrix);
881
+ entry.data.rotation = rotMatrix.elements.slice(); // Store as flat array
882
+
883
+ // Update the vertex position to match the mesh
884
+ if (entry.vertex) {
885
+ entry.vertex.position.set(pos.x, pos.y, pos.z);
886
+ }
887
+ }
888
+
889
+ // Update persistent data immediately after transform changes
890
+ this._updateFeaturePersistentData();
891
+
892
+ this._rebuildPreviewLine();
893
+ this._updateExtensionLinesForAllPoints();
894
+ this._notifySplineChange("transform", { selection: targetId });
895
+ this._renderOnce();
896
+ }
897
+
898
+ _handleTransformDragging(isDragging) {
899
+ const dragging = !!isDragging;
900
+
901
+ this._isTransformDragging = dragging;
902
+
903
+ try {
904
+ if (this.viewer?.controls) {
905
+ this.viewer.controls.enabled = !dragging;
906
+ }
907
+ } catch (error) {
908
+ /* ignore */
909
+ }
910
+
911
+ // Important: Do NOT clear transforms when dragging stops!
912
+ // This was causing the gizmos to disappear after dragging
913
+ }
914
+
915
+ _updateExtensionLinesForAllPoints() {
916
+ // Update extension lines for all points based on current spline data
917
+ this._splineData.points.forEach((pt) => {
918
+ this._updateExtensionLinesForPoint(pt);
919
+ });
920
+ }
921
+
922
+ _updateExtensionLinesForPoint(pt) {
923
+ const forwardKey = `forward-line:${pt.id}`;
924
+ const backwardKey = `backward-line:${pt.id}`;
925
+
926
+ const forwardLine = this._extensionLines.get(forwardKey);
927
+ const backwardLine = this._extensionLines.get(backwardKey);
928
+
929
+ if (!forwardLine || !backwardLine) return;
930
+
931
+ // Get direction from rotation matrix
932
+ const rotation = pt.rotation || [1, 0, 0, 0, 1, 0, 0, 0, 1];
933
+ let xAxisDirection = [rotation[0], rotation[1], rotation[2]];
934
+
935
+ const length = Math.sqrt(xAxisDirection[0] * xAxisDirection[0] + xAxisDirection[1] * xAxisDirection[1] + xAxisDirection[2] * xAxisDirection[2]);
936
+ if (length > 0) {
937
+ xAxisDirection = [xAxisDirection[0] / length, xAxisDirection[1] / length, xAxisDirection[2] / length];
938
+ }
939
+
940
+ const forwardDir = pt.flipDirection ? [-xAxisDirection[0], -xAxisDirection[1], -xAxisDirection[2]] : xAxisDirection;
941
+ const backwardDir = pt.flipDirection ? xAxisDirection : [-xAxisDirection[0], -xAxisDirection[1], -xAxisDirection[2]];
942
+
943
+ // Update forward line geometry
944
+ if (pt.forwardDistance > 0) {
945
+ const forwardEnd = [
946
+ pt.position[0] + forwardDir[0] * pt.forwardDistance,
947
+ pt.position[1] + forwardDir[1] * pt.forwardDistance,
948
+ pt.position[2] + forwardDir[2] * pt.forwardDistance
949
+ ];
950
+
951
+ const forwardPosAttr = forwardLine.geometry.getAttribute("position");
952
+ if (!forwardPosAttr) {
953
+ forwardLine.geometry.setAttribute("position", new THREE.Float32BufferAttribute([
954
+ pt.position[0], pt.position[1], pt.position[2],
955
+ forwardEnd[0], forwardEnd[1], forwardEnd[2]
956
+ ], 3));
957
+ } else {
958
+ const arr = forwardPosAttr.array;
959
+ arr[0] = pt.position[0]; arr[1] = pt.position[1]; arr[2] = pt.position[2];
960
+ arr[3] = forwardEnd[0]; arr[4] = forwardEnd[1]; arr[5] = forwardEnd[2];
961
+ forwardPosAttr.needsUpdate = true;
962
+ }
963
+ }
964
+
965
+ // Update backward line geometry
966
+ if (pt.backwardDistance > 0) {
967
+ const backwardEnd = [
968
+ pt.position[0] + backwardDir[0] * pt.backwardDistance,
969
+ pt.position[1] + backwardDir[1] * pt.backwardDistance,
970
+ pt.position[2] + backwardDir[2] * pt.backwardDistance
971
+ ];
972
+
973
+ const backwardPosAttr = backwardLine.geometry.getAttribute("position");
974
+ if (!backwardPosAttr) {
975
+ backwardLine.geometry.setAttribute("position", new THREE.Float32BufferAttribute([
976
+ pt.position[0], pt.position[1], pt.position[2],
977
+ backwardEnd[0], backwardEnd[1], backwardEnd[2]
978
+ ], 3));
979
+ } else {
980
+ const arr = backwardPosAttr.array;
981
+ arr[0] = pt.position[0]; arr[1] = pt.position[1]; arr[2] = pt.position[2];
982
+ arr[3] = backwardEnd[0]; arr[4] = backwardEnd[1]; arr[5] = backwardEnd[2];
983
+ backwardPosAttr.needsUpdate = true;
984
+ }
985
+ }
986
+ }
987
+
988
+ }