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,94 @@
1
+ import { BREP } from '../../BREP/BREP.js'
2
+
3
+ const inputParamsSchema = {
4
+ id: {
5
+ type: "string",
6
+ default_value: null,
7
+ hint: "unique identifier for the boolean feature",
8
+ },
9
+ targetSolid: {
10
+ type: "reference_selection",
11
+ selectionFilter: ["SOLID"],
12
+ multiple: false,
13
+ default_value: null,
14
+ hint: "Primary target solid",
15
+ },
16
+ boolean: {
17
+ type: "boolean_operation",
18
+ // For the Boolean feature, the widget's targets represent the OTHER solids to combine with the targetSolid
19
+ default_value: { targets: [], operation: 'UNION' },
20
+ hint: "Operation + other solids (as tools)",
21
+ }
22
+ };
23
+
24
+ export class BooleanFeature {
25
+ static shortName = "B";
26
+ static longName = "Boolean";
27
+ static inputParamsSchema = inputParamsSchema;
28
+
29
+ constructor() {
30
+ this.inputParams = {};
31
+ this.persistentData = {};
32
+ }
33
+
34
+ async run(partHistory) {
35
+ const scene = partHistory.scene;
36
+ const targetObj = Array.isArray(this.inputParams.targetSolid) ? (this.inputParams.targetSolid[0] || null) : (this.inputParams.targetSolid || null);
37
+ const target = (targetObj && typeof targetObj === 'object') ? targetObj : (targetObj ? await scene.getObjectByName(String(targetObj)) : null);
38
+ if (!target) throw new Error(`Target solid not found`);
39
+
40
+ const bool = this.inputParams.boolean || { targets: [], operation: 'NONE' };
41
+ const op = String((bool.operation ?? 'NONE')).toUpperCase();
42
+ const toolEntries = Array.isArray(bool.targets) ? bool.targets.filter(Boolean) : [];
43
+ if (op === 'NONE' || toolEntries.length === 0) {
44
+ // No-op: leave scene unchanged
45
+ return { added: [], removed: [] };
46
+ }
47
+
48
+ // Collect tool solids (objects preferred, fallback to names)
49
+ const seen = new Set();
50
+ const tools = [];
51
+ for (const entry of toolEntries) {
52
+ if (!entry) continue;
53
+ if (typeof entry === 'object') {
54
+ const key = entry.uuid || entry.id || entry.name || `${tools.length}`;
55
+ if (seen.has(key)) continue;
56
+ seen.add(key);
57
+ tools.push(entry);
58
+ } else {
59
+ const key = String(entry);
60
+ if (seen.has(key)) continue;
61
+ seen.add(key);
62
+ const obj = await scene.getObjectByName(key);
63
+ if (obj) tools.push(obj);
64
+ }
65
+ }
66
+ if (tools.length === 0) return { added: [], removed: [] };
67
+
68
+ // Use the shared helper semantics:
69
+ // - For UNION/INTERSECT: base = target, targets = tools → returns [result]; tools removed; we remove target.
70
+ // - For SUBTRACT: invert per helper by passing base = union(tools), targets = [target] → returns [result];
71
+ // helper will remove target and the base union; also mark the original tool solids as removed here.
72
+ let effects = { added: [], removed: [] };
73
+ if (op === 'SUBTRACT') {
74
+ let toolUnion = tools[0];
75
+ for (let i = 1; i < tools.length; i++) toolUnion = toolUnion.union(tools[i]);
76
+ const param = { operation: 'SUBTRACT', targets: [target] };
77
+ effects = await BREP.applyBooleanOperation(partHistory, toolUnion, param, this.inputParams.featureID);
78
+ // Also consider original tools as removed
79
+ effects.removed = [...tools, ...effects.removed];
80
+ } else {
81
+ const param = { operation: op, targets: tools };
82
+ effects = await BREP.applyBooleanOperation(partHistory, target, param, this.inputParams.featureID);
83
+ // Ensure original target is removed to avoid duplication
84
+ effects.removed = [target, ...effects.removed];
85
+ }
86
+
87
+ // Mark removals and return only additions
88
+ try { for (const obj of effects.removed || []) { if (obj) obj.__removeFlag = true; } } catch { }
89
+ return {
90
+ added: Array.isArray(effects.added) ? effects.added : [],
91
+ removed: Array.isArray(effects.removed) ? effects.removed : [],
92
+ };
93
+ }
94
+ }
@@ -0,0 +1,116 @@
1
+ import {
2
+ collectEdgesFromSelection,
3
+ getSolidGeometryCounts,
4
+ resolveSingleSolidFromEdges,
5
+ } from "../edgeFeatureUtils.js";
6
+
7
+ const inputParamsSchema = {
8
+ id: {
9
+ type: "string",
10
+ default_value: null,
11
+ hint: "unique identifier for the chamfer feature",
12
+ },
13
+ edges: {
14
+ type: "reference_selection",
15
+ selectionFilter: ["EDGE", "FACE"],
16
+ multiple: true,
17
+ default_value: null,
18
+ hint: "Select edges or faces to apply the chamfer",
19
+ },
20
+ distance: {
21
+ type: "number",
22
+ step: 0.1,
23
+ default_value: 1,
24
+ hint: "Chamfer distance (equal offset along both faces)",
25
+ },
26
+ inflate: {
27
+ type: "number",
28
+ default_value: 0.1,
29
+ step: 0.1,
30
+ hint: "Grow the cutting solid by this amount (units). Very small values (e.g., 0.0005) help avoid residual slivers after CSG.",
31
+ },
32
+ direction: {
33
+ type: "options",
34
+ options: ["INSET", "OUTSET"],
35
+ default_value: "INSET",
36
+ hint: "Prefer chamfer inside (INSET) or outside (OUTSET)",
37
+ },
38
+ debug: {
39
+ type: "boolean",
40
+ default_value: false,
41
+ hint: "Draw diagnostic helpers for section frames",
42
+ }
43
+ };
44
+
45
+ export class ChamferFeature {
46
+ static shortName = "CH";
47
+ static longName = "Chamfer";
48
+ static inputParamsSchema = inputParamsSchema;
49
+
50
+ constructor() {
51
+ this.inputParams = {};
52
+ this.persistentData = {};
53
+ }
54
+ async run(partHistory) {
55
+ const inputObjects = Array.isArray(this.inputParams.edges) ? this.inputParams.edges.filter(Boolean) : [];
56
+ const edgeObjs = collectEdgesFromSelection(inputObjects);
57
+
58
+ if (edgeObjs.length === 0) {
59
+ console.warn("No edges selected for chamfer");
60
+ return { added: [], removed: [] };
61
+ }
62
+
63
+ const { solid: targetSolid, solids } = resolveSingleSolidFromEdges(edgeObjs);
64
+ if (!targetSolid) {
65
+ if (solids.size === 0) {
66
+ console.warn("Selected edges do not belong to any solid");
67
+ } else {
68
+ console.warn("Selected edges belong to multiple solids");
69
+ }
70
+ return { added: [], removed: [] };
71
+ }
72
+ const direction = String(this.inputParams.direction || "INSET").toUpperCase();
73
+ const distance = Number(this.inputParams.distance);
74
+ if (!Number.isFinite(distance) || !(distance > 0)) {
75
+ console.warn("Invalid chamfer distance supplied; aborting.", { distance: this.inputParams.distance });
76
+ return { added: [], removed: [] };
77
+ }
78
+
79
+ const fid = this.inputParams.featureID;
80
+ const result = await targetSolid.chamfer({
81
+ distance,
82
+ edges: edgeObjs,
83
+ direction,
84
+ inflate: Number(this.inputParams.inflate),
85
+ debug: !!this.inputParams.debug,
86
+ featureID: fid,
87
+ });
88
+
89
+ const { triCount, vertCount } = getSolidGeometryCounts(result);
90
+ if (!result || triCount === 0 || vertCount === 0) {
91
+ console.error("[ChamferFeature] Chamfer produced an empty result; skipping scene replacement.", {
92
+ featureID: fid,
93
+ triangleCount: triCount,
94
+ vertexCount: vertCount,
95
+ direction,
96
+ distance,
97
+ inflate: this.inputParams.inflate,
98
+ });
99
+ return { added: [], removed: [] };
100
+ }
101
+
102
+ try { result.name = targetSolid.name; } catch {}
103
+ try { targetSolid.__removeFlag = true; } catch {}
104
+ result.visualize();
105
+
106
+ const added = [result];
107
+ if (this.inputParams.debug && Array.isArray(result.__debugChamferSolids)) {
108
+ for (const dbg of result.__debugChamferSolids) {
109
+ if (!dbg) continue;
110
+ try { dbg.name = `${fid || "CHAMFER"}_${dbg.name || "DEBUG"}`; } catch {}
111
+ added.push(dbg);
112
+ }
113
+ }
114
+ return { added, removed: [targetSolid] };
115
+ }
116
+ }
@@ -0,0 +1,80 @@
1
+
2
+ import { BREP } from "../../BREP/BREP.js";
3
+ const THREE = BREP.THREE;
4
+ import { createPlaneBaseMesh } from '../plane/PlaneFeature.js';
5
+ import { createAxisHelperGroup } from "../../utils/axisHelpers.js";
6
+
7
+ const inputParamsSchema = {
8
+ id: {
9
+ type: "string",
10
+ default_value: null,
11
+ hint: "unique identifier for the datium feature",
12
+ },
13
+ // Optional placement/orientation via TRS
14
+ transform: {
15
+ type: 'transform',
16
+ default_value: { position: [0, 0, 0], rotationEuler: [0, 0, 0], scale: [1, 1, 1] },
17
+ hint: 'Position, rotation, and scale'
18
+ },
19
+ };
20
+
21
+ export class DatiumFeature {
22
+ static shortName = "D";
23
+ static longName = "Datium";
24
+ static inputParamsSchema = inputParamsSchema;
25
+
26
+ constructor() {
27
+ this.inputParams = {};
28
+ this.persistentData = {};
29
+ }
30
+
31
+ async run(/* partHistory */) {
32
+ // Build a group with 3 orthogonal plane meshes (XY, XZ, YZ)
33
+ const group = new THREE.Group();
34
+ const baseName = this.inputParams.featureID || 'Datium';
35
+ group.name = baseName;
36
+ group.type = 'DATUM';
37
+ // Provide a no-op click handler for UI safety
38
+ group.onClick = () => {};
39
+
40
+ const mkPlane = (orientation, suffix) => {
41
+ const mesh = createPlaneBaseMesh();
42
+ mesh.name = `${baseName}:${suffix}`;
43
+ mesh.userData = mesh.userData || {};
44
+ mesh.userData.orientation = orientation;
45
+ // Orient like PlaneFeature for consistency
46
+ if (orientation === 'XZ') mesh.rotation.x = Math.PI / 2; // normal ±Y
47
+ if (orientation === 'YZ') mesh.rotation.y = Math.PI / 2; // normal ±X
48
+ return mesh;
49
+ };
50
+
51
+ const pXY = mkPlane('XY', 'XY');
52
+ const pXZ = mkPlane('XZ', 'XZ');
53
+ const pYZ = mkPlane('YZ', 'YZ');
54
+ group.add(pXY, pXZ, pYZ);
55
+ group.renderOrder = 1; // Render on top of most things
56
+
57
+ const axisHelper = createAxisHelperGroup({
58
+ name: `${baseName}:Axes`,
59
+ selectable: true,
60
+ });
61
+ group.add(axisHelper);
62
+
63
+ // Apply TRS to the whole datum group (position/orient in 3D space)
64
+ try {
65
+ const trs = this.inputParams?.transform || {};
66
+ const p = Array.isArray(trs.position) ? trs.position : [0, 0, 0];
67
+ const r = Array.isArray(trs.rotationEuler) ? trs.rotationEuler : [0, 0, 0];
68
+ const s = Array.isArray(trs.scale) ? trs.scale : [1, 1, 1];
69
+ group.position.set(Number(p[0] || 0), Number(p[1] || 0), Number(p[2] || 0));
70
+ group.rotation.set(
71
+ THREE.MathUtils.degToRad(Number(r[0] || 0)),
72
+ THREE.MathUtils.degToRad(Number(r[1] || 0)),
73
+ THREE.MathUtils.degToRad(Number(r[2] || 0))
74
+ );
75
+ group.scale.set(Number(s[0] || 1), Number(s[1] || 1), Number(s[2] || 1));
76
+ } catch (_) { /* ignore */ }
77
+
78
+ return { added: [group], removed: [] };
79
+ }
80
+ }
@@ -0,0 +1,41 @@
1
+ export function collectEdgesFromSelection(inputObjects) {
2
+ if (!Array.isArray(inputObjects) || inputObjects.length === 0) return [];
3
+ const edges = [];
4
+ for (const obj of inputObjects) {
5
+ if (!obj) continue;
6
+ if (obj.type === 'EDGE') {
7
+ edges.push(obj);
8
+ continue;
9
+ }
10
+ if (obj.type === 'FACE' && Array.isArray(obj.edges)) {
11
+ for (const e of obj.edges) edges.push(e);
12
+ }
13
+ }
14
+ const unique = [];
15
+ const seen = new Set();
16
+ for (const edge of edges) {
17
+ if (!edge || seen.has(edge)) continue;
18
+ if (!(edge.parentSolid || edge.parent)) continue;
19
+ seen.add(edge);
20
+ unique.push(edge);
21
+ }
22
+ return unique;
23
+ }
24
+
25
+ export function resolveSingleSolidFromEdges(edges) {
26
+ const solids = new Set();
27
+ if (Array.isArray(edges)) {
28
+ for (const edge of edges) {
29
+ const solid = edge?.parentSolid || edge?.parent;
30
+ if (solid) solids.add(solid);
31
+ }
32
+ }
33
+ const solid = solids.size === 1 ? solids.values().next().value : null;
34
+ return { solid, solids };
35
+ }
36
+
37
+ export function getSolidGeometryCounts(solid) {
38
+ const triCount = Array.isArray(solid?._triVerts) ? (solid._triVerts.length / 3) : 0;
39
+ const vertCount = Array.isArray(solid?._vertProperties) ? (solid._vertProperties.length / 3) : 0;
40
+ return { triCount, vertCount };
41
+ }
@@ -0,0 +1,143 @@
1
+ import { increment } from "three/tsl";
2
+ import { BREP } from "../../BREP/BREP.js";
3
+ import { selectionHasSketch } from "../selectionUtils.js";
4
+
5
+ const inputParamsSchema = {
6
+ id: {
7
+ type: "string",
8
+ default_value: null,
9
+ hint: "unique identifier for the extrude feature",
10
+ },
11
+ profile: {
12
+ type: "reference_selection",
13
+ selectionFilter: ["FACE", "SKETCH"],
14
+ multiple: false,
15
+ default_value: null,
16
+ hint: "Select the profile to extrude",
17
+ },
18
+ consumeProfileSketch: {
19
+ type: "boolean",
20
+ default_value: true,
21
+ hint: "Remove the referenced sketch after creating the extrusion. Turn off to keep it in the scene.",
22
+ },
23
+ distance: {
24
+ type: "number",
25
+ default_value: 1,
26
+ hint: "Extrude distance when no path is provided",
27
+ },
28
+ distanceBack: {
29
+ type: "number",
30
+ default_value: 0,
31
+ hint: "Optional backward extrude distance (two-sided extrude)",
32
+ },
33
+ boolean: {
34
+ type: "boolean_operation",
35
+ default_value: { targets: [], operation: 'NONE' },
36
+ hint: "Optional boolean operation with selected solids"
37
+ }
38
+ };
39
+
40
+ export class ExtrudeFeature {
41
+ static shortName = "E";
42
+ static longName = "Extrude";
43
+ static inputParamsSchema = inputParamsSchema;
44
+
45
+ constructor() {
46
+ this.inputParams = {};
47
+ this.persistentData = {};
48
+ }
49
+
50
+ uiFieldsTest(context) {
51
+ const params = this.inputParams || context?.params || {};
52
+ const partHistory = context?.history || null;
53
+ return selectionHasSketch(params.profile, partHistory) ? [] : ["consumeProfileSketch"];
54
+ }
55
+
56
+ async run(partHistory) {
57
+ // actual code to create the extrude feature.
58
+ const { profile, distance, distanceBack } = this.inputParams;
59
+
60
+ // Resolve profile object: accept FACE object or a SKETCH group object
61
+ const obj = Array.isArray(profile) ? (profile[0] || null) : (profile || null);
62
+ let faceObj = obj;
63
+ if (obj && obj.type === 'SKETCH') {
64
+ // Find child FACE named PROFILE (or any FACE child)
65
+ faceObj = obj.children.find(ch => ch.type === 'FACE') || obj.children.find(ch => ch.userData?.faceName);
66
+ }
67
+
68
+ const removed = [];
69
+ const consumeSketch = this.inputParams?.consumeProfileSketch !== false;
70
+ // if the face is a child of a sketch we need to remove the sketch from the scene
71
+ if (consumeSketch && faceObj && faceObj.type === 'FACE' && faceObj.parent && faceObj.parent.type === 'SKETCH') {
72
+ removed.push(faceObj.parent);
73
+ }
74
+
75
+
76
+
77
+ // Create the extrude using the robust Sweep implementation (handles holes and per-edge side faces)
78
+ // If user requests a UNION with the same solid the profile came from,
79
+ // bias both directions slightly so the sweep fully overlaps the parent
80
+ // instead of leaving a coplanar cap on the source face.
81
+ const op = String(this.inputParams?.boolean?.operation || 'NONE').toUpperCase();
82
+ const targets = Array.isArray(this.inputParams?.boolean?.targets) ? this.inputParams.boolean.targets : [];
83
+ const parentSolid = faceObj && faceObj.parent && typeof faceObj.parent.getFaceNames === 'function' ? faceObj.parent : null;
84
+ const unionTargetsIncludeParent = op === 'UNION' && parentSolid && targets && targets.some(t => t === parentSolid || (typeof t === 'string' && t === parentSolid.name));
85
+ const forwardBias = (op === 'SUBTRACT' ? 0.00001 : 0) + (op === 'UNION' ? 0.00001 : 0);
86
+ const backwardBias = unionTargetsIncludeParent ? 0.00001 : 0;
87
+
88
+ const extrude = new BREP.Sweep({
89
+ face: faceObj,
90
+ distance: distance + forwardBias, // small forward nudge helps avoid z-fighting for boolean ops
91
+ distanceBack: distanceBack + backwardBias,
92
+ mode: 'translate',
93
+ name: this.inputParams.featureID,
94
+ omitBaseCap: false,
95
+ });
96
+ // Attach centerlines for any circular/arc sketch edges in the profile
97
+ try {
98
+ const THREE = BREP.THREE;
99
+ const edges = Array.isArray(faceObj?.edges) ? faceObj.edges : (faceObj?.edges ? Array.from(faceObj.edges) : []);
100
+ const centers = [];
101
+ const addCenter = (arr) => {
102
+ if (!Array.isArray(arr) || arr.length !== 3) return;
103
+ centers.push(new THREE.Vector3(arr[0], arr[1], arr[2]));
104
+ };
105
+ for (const e of edges) {
106
+ const kind = e?.userData?.sketchGeomType;
107
+ if (kind === 'arc' && Array.isArray(e?.userData?.arcCenter)) addCenter(e.userData.arcCenter);
108
+ else if (kind === 'circle' && Array.isArray(e?.userData?.circleCenter)) addCenter(e.userData.circleCenter);
109
+ }
110
+ // Deduplicate centers by hashing rounded coords
111
+ const uniq = new Map();
112
+ const round = (v)=> Math.round(v*1e6)/1e6;
113
+ const uniqueCenters = [];
114
+ for (const c of centers) { const k = `${round(c.x)},${round(c.y)},${round(c.z)}`; if (!uniq.has(k)) { uniq.set(k, true); uniqueCenters.push(c); } }
115
+
116
+ if (uniqueCenters.length) {
117
+ // Compute face normal for direction
118
+ const n = (typeof faceObj.getAverageNormal === 'function') ? faceObj.getAverageNormal().clone() : new THREE.Vector3(0,1,0);
119
+ if (n.lengthSq() < 1e-20) n.set(0,1,0); n.normalize();
120
+ const fwd = n.clone().multiplyScalar(Number(distance) || 0);
121
+ const back = n.clone().multiplyScalar(-(Number(distanceBack) || 0));
122
+ let idx = 0;
123
+ for (const c of uniqueCenters) {
124
+ const a = new THREE.Vector3(c.x, c.y, c.z).add(back);
125
+ const b = new THREE.Vector3(c.x, c.y, c.z).add(fwd);
126
+ if (a.distanceToSquared(b) < 1e-16) continue;
127
+ const name = (this.inputParams.featureID ? `${this.inputParams.featureID}_AXIS_${idx++}` : 'AXIS');
128
+ extrude.addCenterline([a.x, a.y, a.z], [b.x, b.y, b.z], name, { materialKey: 'OVERLAY' });
129
+ }
130
+ }
131
+ } catch (_) { /* best-effort centerlines */ }
132
+ extrude.visualize();
133
+
134
+ // Apply optional boolean operation via shared helper
135
+ const effects = await BREP.applyBooleanOperation(partHistory || {}, extrude, this.inputParams.boolean, this.inputParams.featureID);
136
+ const booleanRemoved = Array.isArray(effects.removed) ? effects.removed : [];
137
+ const removedArtifacts = [...removed, ...booleanRemoved];
138
+ // Flag removals (sketch parent + boolean effects) for PartHistory to collect
139
+ try { for (const obj of removedArtifacts) { if (obj) obj.__removeFlag = true; } } catch {}
140
+ const added = Array.isArray(effects.added) ? effects.added : [];
141
+ return { added, removed: removedArtifacts };
142
+ }
143
+ }
@@ -0,0 +1,197 @@
1
+ import { clearFilletCaches } from "../../BREP/fillets/fillet.js";
2
+ import {
3
+ collectEdgesFromSelection,
4
+ getSolidGeometryCounts,
5
+ resolveSingleSolidFromEdges,
6
+ } from "../edgeFeatureUtils.js";
7
+
8
+ const inputParamsSchema = {
9
+ id: {
10
+ type: "string",
11
+ default_value: null,
12
+ hint: "unique identifier for the fillet feature",
13
+ },
14
+ edges: {
15
+ type: "reference_selection",
16
+ selectionFilter: ["FACE", "EDGE"],
17
+ multiple: true,
18
+ default_value: null,
19
+ hint: "Select faces (or an edge) to fillet along shared edges",
20
+ },
21
+ radius: {
22
+ type: "number",
23
+ step: 0.1,
24
+ default_value: 1,
25
+ hint: "Fillet radius",
26
+ },
27
+ resolution: {
28
+ type: "number",
29
+ step: 1,
30
+ default_value: 32,
31
+ hint: "Segments around the fillet tube circumference",
32
+ },
33
+ inflate: {
34
+ type: "number",
35
+ step: 0.1,
36
+ default_value: 0.1,
37
+ hint: "Grow the cutting solid by this amount (units). Keep tiny (e.g. 0.0005). Closed loops ignore inflation to avoid self‑intersection.",
38
+ },
39
+ direction: {
40
+ type: "options",
41
+ options: ["INSET", "OUTSET"],
42
+ default_value: "INSET",
43
+ hint: "Prefer fillet inside (INSET) or outside (OUTSET)",
44
+ },
45
+ combineEdges: {
46
+ type: "boolean",
47
+ default_value: false,
48
+ hint: "Combine connected edges into a single fillet path when possible",
49
+ },
50
+ showTangentOverlays: {
51
+ type: "boolean",
52
+ default_value: false,
53
+ hint: "Show pre-inflate tangent overlays on the fillet tube",
54
+ },
55
+ debug: {
56
+ type: "boolean",
57
+ default_value: false,
58
+ hint: "Draw diagnostic vectors for section frames (u,v, bisector, tangency)",
59
+ },
60
+ };
61
+
62
+ export class FilletFeature {
63
+ static shortName = "F";
64
+ static longName = "Fillet";
65
+ static inputParamsSchema = inputParamsSchema;
66
+
67
+ constructor() {
68
+ this.inputParams = {};
69
+ this.persistentData = {};
70
+ }
71
+
72
+ uiFieldsTest(context) {
73
+ const params = this.inputParams || context?.params || {};
74
+ const dir = String(params?.direction || 'INSET').toUpperCase();
75
+ return dir === 'INSET' ? ['combineEdges'] : [];
76
+ }
77
+
78
+ async run(partHistory) {
79
+ console.log('[FilletFeature] Starting fillet run...', {
80
+ featureID: this.inputParams?.featureID,
81
+ direction: this.inputParams?.direction,
82
+ combineEdges: this.inputParams?.combineEdges,
83
+ radius: this.inputParams?.radius,
84
+ resolution: this.inputParams?.resolution,
85
+ inflate: this.inputParams?.inflate,
86
+ showTangentOverlays: this.inputParams?.showTangentOverlays,
87
+ debug: this.inputParams?.debug,
88
+ });
89
+ try { clearFilletCaches(); } catch { }
90
+ const added = [];
91
+ const removed = [];
92
+
93
+ // Resolve inputs from sanitizeInputParams()
94
+ const inputObjects = Array.isArray(this.inputParams.edges) ? this.inputParams.edges.filter(Boolean) : [];
95
+ const edgeObjs = collectEdgesFromSelection(inputObjects);
96
+ if (edgeObjs.length === 0) {
97
+ console.warn('[FilletFeature] No edges resolved for fillet feature; aborting.');
98
+ return { added: [], removed: [] };
99
+ }
100
+
101
+ const { solid: targetSolid, solids } = resolveSingleSolidFromEdges(edgeObjs);
102
+ if (!targetSolid) {
103
+ if (solids.size > 1) {
104
+ console.warn('[FilletFeature] Edges reference multiple solids; aborting fillet.', { solids: Array.from(solids).map(s => s?.name) });
105
+ } else {
106
+ console.warn('[FilletFeature] Edges do not reference a target solid; aborting fillet.');
107
+ }
108
+ return { added: [], removed: [] };
109
+ }
110
+ console.log('[FilletFeature] Target solid resolved', {
111
+ name: targetSolid?.name,
112
+ edgeCount: edgeObjs.length,
113
+ edgeNames: edgeObjs.map(e => e?.name).filter(Boolean),
114
+ });
115
+
116
+ const dir = String(this.inputParams.direction || 'INSET').toUpperCase();
117
+ const r = Number(this.inputParams.radius);
118
+ if (!Number.isFinite(r) || !(r > 0)) {
119
+ console.warn('[FilletFeature] Invalid radius supplied; aborting.', { radius: this.inputParams.radius });
120
+ return { added: [], removed: [] };
121
+ }
122
+
123
+ const fid = this.inputParams.featureID;
124
+ let result = null;
125
+ try {
126
+ result = await targetSolid.fillet({
127
+ radius: r,
128
+ combineEdges: this.inputParams?.combineEdges,
129
+ resolution: this.inputParams?.resolution,
130
+ edges: edgeObjs,
131
+ featureID: fid,
132
+ direction: dir,
133
+ inflate: Number(this.inputParams.inflate) || 0,
134
+ debug: !!this.inputParams.debug,
135
+ showTangentOverlays: !!this.inputParams.showTangentOverlays,
136
+ cleanupTinyFaceIslandsArea: this.inputParams?.cleanupTinyFaceIslandsArea,
137
+ });
138
+ } catch (err) {
139
+ console.error('[FilletFeature] Fillet threw an error; attempting to continue with debug solids.', {
140
+ featureID: fid,
141
+ error: err?.message || err,
142
+ });
143
+ }
144
+ const collectDebugSolids = (res) => {
145
+ const out = [];
146
+ if (!this.inputParams.debug || !Array.isArray(res?.__debugAddedSolids)) return out;
147
+ for (const dbg of res.__debugAddedSolids) {
148
+ if (!dbg) continue;
149
+ try { dbg.name = `${fid}_${dbg.name || 'DEBUG'}`; } catch { }
150
+ console.log('[FilletFeature] Adding fillet debug solid', { featureID: fid, name: dbg.name });
151
+ out.push(dbg);
152
+ }
153
+ return out;
154
+ };
155
+ const debugSolids = collectDebugSolids(result);
156
+ const { triCount, vertCount } = getSolidGeometryCounts(result);
157
+ if (!result) {
158
+ console.error('[FilletFeature] Fillet returned no result; skipping scene replacement.', { featureID: fid });
159
+ if (debugSolids.length) {
160
+ console.warn('[FilletFeature] Returning fillet debug solids despite failure.', {
161
+ featureID: fid,
162
+ debugSolidCount: debugSolids.length,
163
+ });
164
+ added.push(...debugSolids);
165
+ }
166
+ return { added, removed };
167
+ }
168
+ if (triCount === 0 || vertCount === 0) {
169
+ console.error('[FilletFeature] Fillet produced an empty solid; skipping scene replacement.', {
170
+ featureID: fid,
171
+ triangleCount: triCount,
172
+ vertexCount: vertCount,
173
+ direction: dir,
174
+ radius: r,
175
+ inflate: this.inputParams.inflate,
176
+ });
177
+ if (debugSolids.length) {
178
+ console.warn('[FilletFeature] Returning fillet debug solids despite empty result.', {
179
+ featureID: fid,
180
+ debugSolidCount: debugSolids.length,
181
+ });
182
+ added.push(...debugSolids);
183
+ }
184
+ return { added, removed };
185
+ }
186
+ console.log('[FilletFeature] Fillet succeeded; replacing target solid.', {
187
+ featureID: fid,
188
+ triangles: triCount,
189
+ vertices: vertCount,
190
+ });
191
+ added.push(result);
192
+ added.push(...debugSolids);
193
+ // Replace the original geometry in the scene
194
+ removed.push(targetSolid);
195
+ return { added, removed };
196
+ }
197
+ }