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,85 @@
1
+ import { Cylinder } from '../BREP/primitives.js';
2
+ import { OffsetShellSolid } from '../BREP/OffsetShellSolid.js';
3
+
4
+ /**
5
+ * Ensure offset-shell face grouping keeps the new caps aligned with their source faces.
6
+ * We offset a simple analytic cylinder inward and measure how far the labelled cap
7
+ * triangles drift away from the expected offset plane. A large deviation indicates
8
+ * that triangles from the opposite side of the solid were mis-bucketed.
9
+ */
10
+ export async function test_offsetShellGrouping(partHistory) {
11
+ const radius = 2;
12
+ const height = 4;
13
+ const resolution = 16;
14
+ const offsetDistance = -1;
15
+
16
+ const source = new Cylinder({ radius, height, resolution, name: 'CYL' });
17
+ const shell = OffsetShellSolid.generate(source, offsetDistance, {
18
+ newSolidName: 'CYL_shell',
19
+ featureId: 'TEST',
20
+ });
21
+
22
+ const faces = shell.getFaces(false);
23
+ const topFaceName = 'CYL_shell_CYL_T';
24
+ const bottomFaceName = 'CYL_shell_CYL_B';
25
+
26
+ const topFace = faces.find((f) => f.faceName === topFaceName);
27
+ const bottomFace = faces.find((f) => f.faceName === bottomFaceName);
28
+
29
+ if (!topFace) {
30
+ throw new Error(`Offset shell test could not find expected top face "${topFaceName}".`);
31
+ }
32
+ if (!bottomFace) {
33
+ throw new Error(`Offset shell test could not find expected bottom face "${bottomFaceName}".`);
34
+ }
35
+ if (!Array.isArray(topFace.triangles) || !topFace.triangles.length) {
36
+ throw new Error(`Offset shell top face "${topFaceName}" has no triangles to validate.`);
37
+ }
38
+ if (!Array.isArray(bottomFace.triangles) || !bottomFace.triangles.length) {
39
+ throw new Error(`Offset shell bottom face "${bottomFaceName}" has no triangles to validate.`);
40
+ }
41
+
42
+ const expectedDot = offsetDistance;
43
+ const tolerance = 0.35; // allow a generous margin for marching-cubes artefacts
44
+
45
+ const centroidY = (tri) => (tri.p1[1] + tri.p2[1] + tri.p3[1]) / 3;
46
+
47
+ const checkFaceOffsets = (face, normal, planePoint, label) => {
48
+ const [nx, ny, nz] = normal;
49
+ const [px, py, pz] = planePoint;
50
+ let worstDeviation = 0;
51
+
52
+ for (const tri of face.triangles) {
53
+ const cx = (tri.p1[0] + tri.p2[0] + tri.p3[0]) / 3;
54
+ const cy = centroidY(tri);
55
+ const cz = (tri.p1[2] + tri.p2[2] + tri.p3[2]) / 3;
56
+ const dot = nx * (cx - px) + ny * (cy - py) + nz * (cz - pz);
57
+ const deviation = Math.abs(dot - expectedDot);
58
+ if (deviation > worstDeviation) worstDeviation = deviation;
59
+ }
60
+
61
+ if (worstDeviation > tolerance) {
62
+ const faceRange = face.triangles.reduce(
63
+ (acc, tri) => {
64
+ const cy = centroidY(tri);
65
+ if (cy < acc.min) acc.min = cy;
66
+ if (cy > acc.max) acc.max = cy;
67
+ return acc;
68
+ },
69
+ { min: Infinity, max: -Infinity },
70
+ );
71
+ throw new Error(
72
+ [
73
+ `Offset shell ${label} face deviated ${worstDeviation.toFixed(3)} (tolerance ${tolerance}).`,
74
+ `Centroid Y range: ${faceRange.min.toFixed(3)} .. ${faceRange.max.toFixed(3)}`,
75
+ `Triangles: ${face.triangles.length}`,
76
+ ].join(' '),
77
+ );
78
+ }
79
+ };
80
+
81
+ checkFaceOffsets(topFace, [0, 1, 0], [0, height, 0], 'top');
82
+ checkFaceOffsets(bottomFace, [0, -1, 0], [0, 0, 0], 'bottom');
83
+
84
+ return partHistory;
85
+ }
@@ -0,0 +1,4 @@
1
+ export async function test_plane(partHistory) {
2
+ await partHistory.newFeature("PLANE");
3
+ return partHistory;
4
+ }
@@ -0,0 +1,11 @@
1
+
2
+
3
+ export async function test_primitiveCone(partHistory) {
4
+ const cone = await partHistory.newFeature("P.CO");
5
+ cone.inputParams.radiusTop = 3;
6
+ cone.inputParams.radiusBottom = .5;
7
+ cone.inputParams.height = 5.2;
8
+ cone.inputParams.resolution = 20;
9
+
10
+ return partHistory;
11
+ }
@@ -0,0 +1,7 @@
1
+ export async function test_primitiveCube(partHistory) {
2
+ const cube = await partHistory.newFeature("P.CU");
3
+ cube.inputParams.sizeX = 5;
4
+ cube.inputParams.sizeY = 10;
5
+ cube.inputParams.sizeZ = 15;
6
+ return partHistory;
7
+ }
@@ -0,0 +1,8 @@
1
+ export async function test_primitiveCylinder(partHistory) {
2
+ const cylinder = await partHistory.newFeature("P.CY");
3
+ cylinder.inputParams.radius = 1;
4
+ cylinder.inputParams.height = 5;
5
+ cylinder.inputParams.resolution = 30;
6
+
7
+ return partHistory;
8
+ }
@@ -0,0 +1,9 @@
1
+ export async function test_primitivePyramid(partHistory) {
2
+ const pyramid = await partHistory.newFeature("P.PY");
3
+ pyramid.inputParams.baseSideLength = 5;
4
+ pyramid.inputParams.height = 8;
5
+ pyramid.inputParams.sides = 4;
6
+
7
+ return partHistory;
8
+ }
9
+
@@ -0,0 +1,17 @@
1
+
2
+ export async function test_primitiveSphere(partHistory) {
3
+ const sphere = await partHistory.newFeature("P.S");
4
+ sphere.inputParams.radius = 5;
5
+ sphere.inputParams.resolution =10;
6
+
7
+ return partHistory;
8
+ }
9
+
10
+
11
+
12
+
13
+
14
+
15
+
16
+
17
+
@@ -0,0 +1,21 @@
1
+
2
+
3
+ export async function test_primitiveTorus(partHistory) {
4
+ const torus = await partHistory.newFeature("P.T");
5
+ torus.inputParams.majorRadius = 20;
6
+ torus.inputParams.tubeRadius = 5;
7
+ torus.inputParams.resolution = 10;
8
+ // arc with 90 degrees
9
+ torus.inputParams.arc = 300;
10
+
11
+
12
+ const torus2 = await partHistory.newFeature("P.T");
13
+ torus2.inputParams.majorRadius = 5;
14
+ torus2.inputParams.tubeRadius = 3;
15
+ torus2.inputParams.resolution = 30;
16
+ // arc with 90 degrees
17
+ torus2.inputParams.arc = 360;
18
+
19
+
20
+ return partHistory;
21
+ }
@@ -0,0 +1,126 @@
1
+ const CUBE_ID = 'PUSHFACE_CUBE';
2
+ const CYLINDER_ID = 'PUSHFACE_CYL';
3
+ const BOX_SIZE = 6;
4
+ const CYL_RADIUS = 1.25;
5
+ const PUSH_DISTANCE = 0.5;
6
+
7
+ export async function test_pushFace(partHistory) {
8
+ const cube = await partHistory.newFeature("P.CU");
9
+ cube.inputParams.id = CUBE_ID;
10
+ cube.inputParams.sizeX = BOX_SIZE;
11
+ cube.inputParams.sizeY = BOX_SIZE;
12
+ cube.inputParams.sizeZ = BOX_SIZE;
13
+
14
+ const cyl = await partHistory.newFeature("P.CY");
15
+ cyl.inputParams.id = CYLINDER_ID;
16
+ cyl.inputParams.radius = CYL_RADIUS;
17
+ cyl.inputParams.height = BOX_SIZE;
18
+ cyl.inputParams.transform = {
19
+ position: [BOX_SIZE / 2, 0, BOX_SIZE / 2],
20
+ rotationEuler: [0, 0, 0],
21
+ scale: [1, 1, 1],
22
+ };
23
+
24
+ const booleanFeature = await partHistory.newFeature("B");
25
+ booleanFeature.inputParams.targetSolid = cube.inputParams.featureID;
26
+ booleanFeature.inputParams.boolean = {
27
+ operation: "SUBTRACT",
28
+ targets: [cyl.inputParams.featureID],
29
+ };
30
+
31
+ return partHistory;
32
+ }
33
+
34
+ function measureRadialExtent(solid, faceName, centerX, centerZ) {
35
+ if (typeof solid.getFace !== 'function') throw new Error('Solid missing getFace()');
36
+ const face = solid.getFace(faceName);
37
+ if (!Array.isArray(face) || face.length === 0) throw new Error(`Face "${faceName}" not found on solid ${solid.name || ''}`);
38
+
39
+ const seen = new Set();
40
+ const radii = [];
41
+ for (const tri of face) {
42
+ for (const p of [tri.p1, tri.p2, tri.p3]) {
43
+ if (!Array.isArray(p) || p.length < 3) continue;
44
+ const key = `${p[0]},${p[1]},${p[2]}`;
45
+ if (seen.has(key)) continue;
46
+ seen.add(key);
47
+ const x = p[0];
48
+ const z = p[2];
49
+ radii.push(Math.hypot(x - centerX, z - centerZ));
50
+ }
51
+ }
52
+ if (!radii.length) throw new Error(`No vertices collected for face "${faceName}"`);
53
+ const sum = radii.reduce((a, b) => a + b, 0);
54
+ const avg = sum / radii.length;
55
+ const min = Math.min(...radii);
56
+ const max = Math.max(...radii);
57
+ return { avg, min, max };
58
+ }
59
+
60
+ function estimateRadialNormalSign(solid, faceName, centerX, centerZ) {
61
+ const face = solid.getFace(faceName);
62
+ if (!Array.isArray(face) || face.length === 0) return 0;
63
+
64
+ let sum = 0;
65
+ for (const tri of face) {
66
+ if (!Array.isArray(tri.p1) || !Array.isArray(tri.p2) || !Array.isArray(tri.p3)) continue;
67
+ const ax = tri.p1[0], ay = tri.p1[1], az = tri.p1[2];
68
+ const bx = tri.p2[0], by = tri.p2[1], bz = tri.p2[2];
69
+ const cx = tri.p3[0], cy = tri.p3[1], cz = tri.p3[2];
70
+ const ux = bx - ax, uy = by - ay, uz = bz - az;
71
+ const vx = cx - ax, vy = cy - ay, vz = cz - az;
72
+ const nx = uy * vz - uz * vy;
73
+ const nz = ux * vy - uy * vx;
74
+ const mx = (ax + bx + cx) / 3;
75
+ const mz = (az + bz + cz) / 3;
76
+ const rx = mx - centerX;
77
+ const rz = mz - centerZ;
78
+ sum += rx * nx + rz * nz;
79
+ }
80
+ if (sum === 0) return 0;
81
+ return sum > 0 ? 1 : -1;
82
+ }
83
+
84
+ export async function afterRun_pushFace(partHistory) {
85
+ const solids = (partHistory.scene?.children || []).filter(o => o?.type === 'SOLID');
86
+ if (!solids.length) throw new Error('[pushFace] No solids created');
87
+
88
+ const solid = solids[0];
89
+ const cavityFace = `${CYLINDER_ID}_S`;
90
+ const center = { x: BOX_SIZE / 2, z: BOX_SIZE / 2 };
91
+
92
+ const baseline = measureRadialExtent(solid, cavityFace, center.x, center.z);
93
+ const inwardTest = solid.clone();
94
+ const control = measureRadialExtent(inwardTest, cavityFace, center.x, center.z);
95
+
96
+ solid.pushFace(cavityFace, PUSH_DISTANCE);
97
+ const pushedOut = measureRadialExtent(solid, cavityFace, center.x, center.z);
98
+
99
+ inwardTest.pushFace(cavityFace, -PUSH_DISTANCE);
100
+ const pushedIn = measureRadialExtent(inwardTest, cavityFace, center.x, center.z);
101
+
102
+ const normalSign = estimateRadialNormalSign(solid, cavityFace, center.x, center.z);
103
+ const tol = 1e-6;
104
+ if (normalSign === 0) {
105
+ const outDelta = pushedOut.avg - baseline.avg;
106
+ const inDelta = pushedIn.avg - control.avg;
107
+ const opposite = (outDelta > tol && inDelta < -tol) || (outDelta < -tol && inDelta > tol);
108
+ if (!opposite) {
109
+ throw new Error(`[pushFace] Expected opposite radial motion, got ${outDelta} and ${inDelta}`);
110
+ }
111
+ } else if (normalSign > 0) {
112
+ if (!(pushedOut.avg > baseline.avg + tol && pushedOut.min > baseline.min + tol / 10)) {
113
+ throw new Error(`[pushFace] Positive distance failed to move face outward (avg ${baseline.avg} → ${pushedOut.avg})`);
114
+ }
115
+ if (!(pushedIn.avg < control.avg - tol && pushedIn.max < control.max - tol / 10)) {
116
+ throw new Error(`[pushFace] Negative distance failed to move face inward (avg ${control.avg} → ${pushedIn.avg})`);
117
+ }
118
+ } else {
119
+ if (!(pushedOut.avg < baseline.avg - tol && pushedOut.max < baseline.max - tol / 10)) {
120
+ throw new Error(`[pushFace] Positive distance failed to move face inward (avg ${baseline.avg} → ${pushedOut.avg})`);
121
+ }
122
+ if (!(pushedIn.avg > control.avg + tol && pushedIn.min > control.min + tol / 10)) {
123
+ throw new Error(`[pushFace] Negative distance failed to move face outward (avg ${control.avg} → ${pushedIn.avg})`);
124
+ }
125
+ }
126
+ }
@@ -0,0 +1,125 @@
1
+ /**
2
+ * Test for Sheet Metal Contour Flange geometry generation
3
+ * Validates that the feature correctly creates sweep profiles and geometries
4
+ */
5
+
6
+ export async function test_SheetMetalContourFlange_Basic(partHistory) {
7
+ console.log("[TEST] Starting Sheet Metal Contour Flange basic test");
8
+
9
+ // Create a simple L-shaped sketch path
10
+ const plane = await partHistory.newFeature("P");
11
+ plane.inputParams.orientation = "XY"; // XY plane at Z=0
12
+
13
+ const sketch = await partHistory.newFeature("S");
14
+ sketch.inputParams.sketchPlane = plane.inputParams.featureID;
15
+
16
+ // Define L-shaped path: start at origin, go right 20 units, then up 15 units
17
+ sketch.persistentData.sketch = {
18
+ points: [
19
+ { id: 0, x: 0, y: 0, fixed: true }, // Origin
20
+ { id: 1, x: 20, y: 0, fixed: false }, // Right 20 units
21
+ { id: 2, x: 20, y: 15, fixed: false }, // Up 15 units
22
+ ],
23
+ geometries: [
24
+ { id: 100, type: "line", points: [0, 1], construction: false }, // Horizontal segment
25
+ { id: 101, type: "line", points: [1, 2], construction: false }, // Vertical segment
26
+ ],
27
+ constraints: [
28
+ { id: 0, type: "⏚", points: [0] }, // Ground point 0
29
+ ],
30
+ };
31
+
32
+ // Create the contour flange
33
+ const contourFlange = await partHistory.newFeature("SM.CF");
34
+ contourFlange.inputParams.path = [sketch.inputParams.featureID];
35
+ contourFlange.inputParams.distance = 10; // 10 units wide
36
+ contourFlange.inputParams.thickness = 2; // 2 units thick
37
+ contourFlange.inputParams.bendRadius = 1; // 1 unit bend radius
38
+ contourFlange.inputParams.sheetSide = "left";
39
+ contourFlange.inputParams.consumePathSketch = false; // Keep sketch for inspection
40
+
41
+ console.log("[TEST] Contour flange created:", contourFlange.inputParams);
42
+
43
+ return partHistory;
44
+ }
45
+
46
+ export async function test_SheetMetalContourFlange_StraightLine(partHistory) {
47
+ console.log("[TEST] Starting Sheet Metal Contour Flange straight line test");
48
+
49
+ // Create a simple straight line sketch
50
+ const plane = await partHistory.newFeature("P");
51
+ plane.inputParams.orientation = "XY";
52
+
53
+ const sketch = await partHistory.newFeature("S");
54
+ sketch.inputParams.sketchPlane = plane.inputParams.featureID;
55
+
56
+ // Define straight line path
57
+ sketch.persistentData.sketch = {
58
+ points: [
59
+ { id: 0, x: 0, y: 0, fixed: true },
60
+ { id: 1, x: 30, y: 0, fixed: false },
61
+ ],
62
+ geometries: [
63
+ { id: 100, type: "line", points: [0, 1], construction: false },
64
+ ],
65
+ constraints: [
66
+ { id: 0, type: "⏚", points: [0] },
67
+ ],
68
+ };
69
+
70
+ // Create the contour flange
71
+ const contourFlange = await partHistory.newFeature("SM.CF");
72
+ contourFlange.inputParams.path = [sketch.inputParams.featureID];
73
+ contourFlange.inputParams.distance = 5;
74
+ contourFlange.inputParams.thickness = 1;
75
+ contourFlange.inputParams.bendRadius = 0; // No bends for straight line
76
+ contourFlange.inputParams.sheetSide = "right";
77
+ contourFlange.inputParams.consumePathSketch = false;
78
+
79
+ console.log("[TEST] Straight line contour flange created");
80
+
81
+ return partHistory;
82
+ }
83
+
84
+ function findContourFlangeFeature(partHistory) {
85
+ const entry = partHistory.features.find((f) => f?.type === "SM.CF");
86
+ if (!entry) throw new Error("Contour flange feature missing from history");
87
+ const featureId = entry?.inputParams?.featureID;
88
+ if (!featureId) throw new Error("Contour flange feature missing featureID");
89
+ return featureId;
90
+ }
91
+
92
+ function collectContourFlangeSolids(partHistory, featureId) {
93
+ const children = Array.isArray(partHistory.scene?.children) ? partHistory.scene.children : [];
94
+ return children.filter((obj) => {
95
+ if (!obj || obj.type !== "SOLID") return false;
96
+ if (obj?.owningFeatureID && String(obj.owningFeatureID) === String(featureId)) return true;
97
+ return !!(obj?.name && obj.name.includes(featureId));
98
+ });
99
+ }
100
+
101
+ function validateContourFlangeGeometry(partHistory, label) {
102
+ const featureId = findContourFlangeFeature(partHistory);
103
+ const solids = collectContourFlangeSolids(partHistory, featureId);
104
+ if (!solids.length) {
105
+ throw new Error(`[${label}] No solids were generated by the contour flange feature`);
106
+ }
107
+
108
+ let triCount = 0;
109
+ for (const solid of solids) {
110
+ const triVerts = Array.isArray(solid?._triVerts) ? solid._triVerts.length : 0;
111
+ triCount += Math.floor(triVerts / 3);
112
+ }
113
+
114
+ if (triCount === 0) {
115
+ throw new Error(`[${label}] Generated geometry has no triangles`);
116
+ }
117
+ }
118
+
119
+ export async function afterRun_SheetMetalContourFlange_Basic(partHistory) {
120
+ validateContourFlangeGeometry(partHistory, "contour_flange_basic");
121
+ }
122
+
123
+ export async function afterRun_SheetMetalContourFlange_StraightLine(partHistory) {
124
+ validateContourFlangeGeometry(partHistory, "contour_flange_straight");
125
+ }
@@ -0,0 +1,80 @@
1
+ const makeRectSketch = (x0, y0, x1, y1, geomBase = 100) => ({
2
+ points: [
3
+ { id: 0, x: x0, y: y0, fixed: true },
4
+ { id: 1, x: x1, y: y0, fixed: false },
5
+ { id: 2, x: x1, y: y1, fixed: false },
6
+ { id: 3, x: x0, y: y1, fixed: false },
7
+ ],
8
+ geometries: [
9
+ { id: geomBase + 0, type: "line", points: [0, 1], construction: false },
10
+ { id: geomBase + 1, type: "line", points: [1, 2], construction: false },
11
+ { id: geomBase + 2, type: "line", points: [2, 3], construction: false },
12
+ { id: geomBase + 3, type: "line", points: [3, 0], construction: false },
13
+ ],
14
+ constraints: [{ id: 0, type: "⏚", points: [0] }],
15
+ });
16
+
17
+ async function buildBaseTab(partHistory, { size = 10, thickness = 1, geomBase = 100 } = {}) {
18
+ const plane = await partHistory.newFeature("P");
19
+ plane.inputParams.orientation = "XY";
20
+
21
+ const sketch = await partHistory.newFeature("S");
22
+ sketch.inputParams.sketchPlane = plane.inputParams.featureID;
23
+ sketch.persistentData.sketch = makeRectSketch(0, 0, size, size, geomBase);
24
+
25
+ const tab = await partHistory.newFeature("SM.TAB");
26
+ tab.inputParams.profile = sketch.inputParams.featureID;
27
+ tab.inputParams.thickness = thickness;
28
+ tab.inputParams.consumeProfileSketch = false;
29
+
30
+ const edgeFaceName = `${tab.inputParams.featureID}:${sketch.inputParams.featureID}:G${geomBase}_SW`;
31
+ return { plane, sketch, tab, edgeFaceName };
32
+ }
33
+
34
+ export async function test_sheetMetal_tab(partHistory) {
35
+ await buildBaseTab(partHistory, { size: 12, thickness: 1, geomBase: 100 });
36
+ return partHistory;
37
+ }
38
+
39
+ export async function test_sheetMetal_flange(partHistory) {
40
+ const { edgeFaceName } = await buildBaseTab(partHistory, { size: 16, thickness: 1, geomBase: 100 });
41
+
42
+ const flange = await partHistory.newFeature("SM.F");
43
+ flange.inputParams.faces = [edgeFaceName];
44
+ flange.inputParams.angle = 90;
45
+
46
+ return partHistory;
47
+ }
48
+
49
+ export async function test_sheetMetal_hem(partHistory) {
50
+ const { edgeFaceName } = await buildBaseTab(partHistory, { size: 14, thickness: 1, geomBase: 110 });
51
+
52
+ const hem = await partHistory.newFeature("SM.HEM");
53
+ hem.inputParams.faces = [edgeFaceName];
54
+
55
+ return partHistory;
56
+ }
57
+
58
+ export async function test_sheetMetal_cutout(partHistory) {
59
+ const sheetSize = 20;
60
+ const { tab } = await buildBaseTab(partHistory, { size: sheetSize, thickness: 1, geomBase: 100 });
61
+
62
+ const datum = await partHistory.newFeature("D");
63
+ datum.inputParams.transform = {
64
+ position: [sheetSize / 2, sheetSize / 2, 0],
65
+ rotationEuler: [45, 0, 0],
66
+ scale: [1, 1, 1],
67
+ };
68
+
69
+ const cutSketch = await partHistory.newFeature("S");
70
+ cutSketch.inputParams.sketchPlane = `${datum.inputParams.featureID}:XY`;
71
+ cutSketch.persistentData.sketch = makeRectSketch(-2, -2, 2, 2, 200);
72
+
73
+ const cutout = await partHistory.newFeature("SM.CUTOUT");
74
+ cutout.inputParams.sheet = tab.inputParams.featureID;
75
+ cutout.inputParams.profile = cutSketch.inputParams.featureID;
76
+ cutout.inputParams.forwardDistance = 5;
77
+ cutout.inputParams.backDistance = 5;
78
+
79
+ return partHistory;
80
+ }
@@ -0,0 +1,45 @@
1
+ export async function test_sketch_openLoop(partHistory) {
2
+ const plane = await partHistory.newFeature("P");
3
+ plane.inputParams.orientation = "XY";
4
+
5
+ const sketch = await partHistory.newFeature("S");
6
+ sketch.inputParams.sketchPlane = plane.inputParams.featureID;
7
+ sketch.persistentData.sketch = {
8
+ points: [
9
+ { id: 0, x: 0, y: 0, fixed: true },
10
+ { id: 1, x: 20, y: 0, fixed: false },
11
+ { id: 2, x: 20, y: 15, fixed: false },
12
+ ],
13
+ geometries: [
14
+ { id: 100, type: "line", points: [0, 1], construction: false },
15
+ { id: 101, type: "line", points: [1, 2], construction: false },
16
+ ],
17
+ constraints: [
18
+ { id: 0, type: "⏚", points: [0] },
19
+ ],
20
+ };
21
+ }
22
+
23
+ export async function afterRun_sketch_openLoop(partHistory) {
24
+ const sketchFeature = partHistory.features.find((f) => f?.type === "S");
25
+ if (!sketchFeature) {
26
+ throw new Error("Sketch feature missing from history");
27
+ }
28
+ const sketchGroup = partHistory.scene.getObjectByName(sketchFeature.inputParams.featureID);
29
+ if (!sketchGroup) {
30
+ throw new Error("Sketch group not found in scene");
31
+ }
32
+ let faceCount = 0;
33
+ let edgeCount = 0;
34
+ sketchGroup.traverse((obj) => {
35
+ if (!obj) return;
36
+ if (obj.type === "FACE") faceCount++;
37
+ else if (obj.type === "EDGE") edgeCount++;
38
+ });
39
+ if (faceCount !== 0) {
40
+ throw new Error(`Open sketch generated ${faceCount} face(s)`);
41
+ }
42
+ if (edgeCount === 0) {
43
+ throw new Error("Open sketch should expose at least one EDGE");
44
+ }
45
+ }
@@ -0,0 +1,58 @@
1
+ // Builds a rectangular prism and validates Solid.volume(), Solid.surfaceArea(),
2
+ // Face.surfaceArea(), and Edge.length() via console output.
3
+ export async function test_solidMetrics(partHistory) {
4
+ const cube = await partHistory.newFeature("P.CU");
5
+ cube.inputParams.sizeX = 2;
6
+ cube.inputParams.sizeY = 3;
7
+ cube.inputParams.sizeZ = 4;
8
+ // Name will be the featureID; visualize() is called by the feature implementation.
9
+ return partHistory;
10
+ }
11
+
12
+ export async function afterRun_solidMetrics(partHistory) {
13
+ try {
14
+ const solids = (partHistory.scene?.children || []).filter(o => o && o.type === 'SOLID');
15
+ if (!solids.length) { console.warn('[solidMetrics] No solids in scene.'); return; }
16
+ const solid = solids[0];
17
+
18
+ const X = 2, Y = 3, Z = 4;
19
+ const expectedVolume = X * Y * Z; // 24
20
+ const expectedSurfaceArea = 2 * (X * Y + Y * Z + Z * X); // 52
21
+
22
+ const vol = typeof solid.volume === 'function' ? solid.volume() : NaN;
23
+ const sa = typeof solid.surfaceArea === 'function' ? solid.surfaceArea() : NaN;
24
+
25
+ const approx = (a, b, eps = 1e-6) => Math.abs(a - b) <= eps * Math.max(1, Math.abs(b));
26
+ const fmt = (n) => Number.isFinite(n) ? n.toFixed(6) : String(n);
27
+
28
+ console.log(`[solidMetrics] Solid volume: ${fmt(vol)} (expected ${fmt(expectedVolume)}) ${approx(vol, expectedVolume) ? 'OK' : 'MISMATCH'}`);
29
+ console.log(`[solidMetrics] Solid surface area: ${fmt(sa)} (expected ${fmt(expectedSurfaceArea)}) ${approx(sa, expectedSurfaceArea) ? 'OK' : 'MISMATCH'}`);
30
+
31
+ // Face areas by suffix: NX/PX = Y*Z, NY/PY = X*Z, NZ/PZ = X*Y
32
+ const faces = solid.children.filter(ch => ch?.type === 'FACE');
33
+ const faceAreaBySuffix = new Map([
34
+ ['_NX', Y * Z],
35
+ ['_PX', Y * Z],
36
+ ['_NY', X * Z],
37
+ ['_PY', X * Z],
38
+ ['_NZ', X * Y],
39
+ ['_PZ', X * Y],
40
+ ]);
41
+ for (const f of faces) {
42
+ const name = String(f?.name || '');
43
+ const suffix = Array.from(faceAreaBySuffix.keys()).find(suf => name.endsWith(suf));
44
+ if (!suffix) continue;
45
+ const area = typeof f.surfaceArea === 'function' ? f.surfaceArea() : NaN;
46
+ const expected = faceAreaBySuffix.get(suffix);
47
+ console.log(`[solidMetrics] Face ${name} area: ${fmt(area)} (expected ${fmt(expected)}) ${approx(area, expected) ? 'OK' : 'MISMATCH'}`);
48
+ }
49
+
50
+ // Edge lengths: should be one of {X, Y, Z}
51
+ const edges = solid.children.filter(ch => ch?.type === 'EDGE');
52
+ const lens = edges.map(e => (typeof e.length === 'function') ? e.length() : NaN);
53
+ const uniq = Array.from(new Set(lens.map(v => Number.isFinite(v) ? v.toFixed(6) : String(v))));
54
+ console.log(`[solidMetrics] Distinct edge lengths: ${uniq.join(', ')} (expected ${[X,Y,Z].map(n=>n.toFixed(6)).join(', ')})`);
55
+ } catch (e) {
56
+ console.warn('[solidMetrics] afterRun error:', e?.message || e);
57
+ }
58
+ }