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,248 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8" />
5
+ <meta name="viewport" content="width=device-width,initial-scale=1" />
6
+ <title>Assembly Component - BREP</title>
7
+ <style>
8
+ :root{
9
+ --bg:#0b0f14; --panel:#0f141b; --text:#d7dde6; --muted:#9aa7b2;
10
+ --border:#1b2430; --accent:#5cc8ff; --chip:#121823;
11
+ }
12
+ *{box-sizing:border-box}
13
+ html,body{margin:0;background:var(--bg);color:var(--text);font:14px/1.5 ui-monospace,SFMono-Regular,Menlo,Consolas,'Liberation Mono','Courier New',monospace}
14
+ main{max-width:1100px;margin:0 auto;padding:28px}
15
+ h1{margin:0 0 18px;font-size:22px;color:var(--accent);font-weight:700}
16
+ .summary{color:var(--muted);margin-bottom:22px}
17
+ .card{background:var(--panel);border:1px solid var(--border);border-radius:14px;padding:18px;margin:0 0 18px}
18
+ .readme{padding:0}
19
+ .readme .header{padding:16px 18px;border-bottom:1px solid var(--border)}
20
+ .readme .content{padding:18px}
21
+ .doc-card{padding:18px}
22
+ .doc-nav{margin:0 0 18px;display:flex;gap:12px;flex-wrap:wrap;align-items:center;color:var(--muted)}
23
+ .doc-nav-links{display:flex;gap:12px;flex-wrap:wrap;align-items:center}
24
+ .doc-nav a{color:var(--accent);font-weight:600}
25
+ .doc-list{list-style:none;margin:18px 0;padding:0}
26
+ .doc-list li{margin:6px 0}
27
+ .doc-list a{color:var(--accent)}
28
+ .nav-search{margin-left:auto;position:relative;display:flex;align-items:center;gap:8px;flex-wrap:wrap;justify-content:flex-end;min-width:240px;max-width:520px}
29
+ .search-title{font-weight:700;font-size:14px;margin-bottom:4px}
30
+ .search-hint{color:var(--muted);font-size:12px;margin:0}
31
+ .search-input-row{display:flex;gap:8px;align-items:center;width:100%}
32
+ .search-input{flex:1;border:1px solid var(--border);border-radius:10px;background:var(--chip);color:var(--text);padding:10px 12px}
33
+ .search-input:focus{outline:1px solid var(--accent);box-shadow:0 0 0 3px rgba(92,200,255,0.15)}
34
+ .search-clear{border:1px solid var(--border);background:var(--panel);color:var(--muted);border-radius:10px;padding:9px 12px;cursor:pointer;font-weight:600}
35
+ .search-clear:hover{border-color:var(--accent);color:var(--accent)}
36
+ .search-status{color:var(--muted);font-size:12px;margin-top:4px;width:100%;text-align:right}
37
+ .search-results{position:absolute;top:100%;right:0;margin-top:10px;border:1px solid var(--border);border-radius:12px;background:var(--panel);max-height:360px;overflow:auto;min-width:320px;max-width:520px;box-shadow:0 12px 30px rgba(0,0,0,0.35);z-index:25}
38
+ .search-results ul{list-style:none;margin:0;padding:0}
39
+ .search-item{padding:10px 12px;border-bottom:1px solid var(--border)}
40
+ .search-item:last-child{border-bottom:none}
41
+ .search-item a{display:block;color:var(--accent);font-weight:600}
42
+ .search-snippet{color:var(--muted);font-size:13px;margin-top:4px}
43
+ .search-results mark{background:rgba(92,200,255,0.2);color:var(--text);border-radius:4px;padding:0 2px}
44
+ .prose h1{font-size:24px;margin:0 0 12px}
45
+ .prose h2{font-size:18px;margin:18px 0 8px}
46
+ .prose h3{font-size:16px;margin:14px 0 6px}
47
+ .prose p{margin:0 0 10px}
48
+ .prose ul,.prose ol{margin:0 0 10px 18px}
49
+ .prose li{margin:4px 0}
50
+ .prose code{background:#0d1520;border:1px solid var(--border);padding:1px 5px;border-radius:6px;font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,'Liberation Mono','Courier New',monospace;font-size:12px}
51
+ .prose pre{background:#0d1520;border:1px solid var(--border);padding:12px;border-radius:12px;overflow:auto}
52
+ .prose a{color:var(--accent)}
53
+ .prose img{max-width:100%;height:auto;}
54
+ .prose table{border-collapse:collapse;width:100%;margin:16px 0;background:var(--panel);border:1px solid var(--border);border-radius:8px;overflow:hidden}
55
+ .prose th,.prose td{padding:8px 12px;text-align:left;border-bottom:1px solid var(--border)}
56
+ .prose th{background:var(--chip);color:var(--text);font-weight:600;font-size:13px}
57
+ .prose tr:last-child td{border-bottom:none}
58
+ .prose tbody tr:hover{background:rgba(92,200,255,0.05)}
59
+ .license{
60
+ background:var(--panel);border:1px solid var(--border);border-radius:14px;
61
+ padding:16px 16px 8px;margin:0 0 18px;
62
+ }
63
+ .license > h2{margin:0 0 10px;font-size:16px;font-weight:700}
64
+ .pkg{
65
+ border-top:1px solid var(--border);padding:10px 0;
66
+ display:grid;grid-template-columns:1fr auto;gap:10px;align-items:center;
67
+ }
68
+ .pkg:first-of-type{border-top:none}
69
+ .pkg .meta{display:flex;gap:10px;flex-wrap:wrap}
70
+ .pkg .name{font-weight:600}
71
+ .pkg .desc{color:var(--muted);margin-top:2px}
72
+ a{color:var(--accent);text-decoration:none} a:hover{text-decoration:underline}
73
+ .chip{background:var(--chip);border:1px solid var(--border);border-radius:999px;padding:2px 8px;font-size:12px;color:var(--muted)}
74
+ .footer{margin-top:26px;color:var(--muted);font-size:12px}
75
+ </style>
76
+ </head>
77
+ <body>
78
+ <main>
79
+ <nav class="doc-nav">
80
+ <div class="doc-nav-links">
81
+ <a href="index.html">Help Home</a><span>&middot;</span><a href="/help/table-of-contents.html">Table of Contents</a><span>&middot;</span><a href="https://github.com/mmiscool/BREP" target="_blank" rel="noopener noreferrer">GitHub</a>
82
+ </div>
83
+ <div class="nav-search">
84
+ <div class="search-input-row">
85
+ <input type="search" id="doc-search" class="search-input" placeholder="Search docs... Type at least 2 characters to search" autocomplete="off" spellcheck="false" />
86
+ <button type="button" class="search-clear" id="doc-search-clear">Clear</button>
87
+ </div>
88
+ <div class="search-status" id="doc-search-status"></div>
89
+ <div class="search-results" id="doc-search-results" hidden>
90
+ <ul id="doc-search-list"></ul>
91
+ </div>
92
+ </div>
93
+ </nav>
94
+ <section class="card doc-card">
95
+
96
+ <div class="prose">
97
+ <h1>Assembly Component</h1><p>Status: Implemented</p><p><img src="features__Assembly_Component_dialog.png" alt="Assembly Component dialog" width="280" loading="lazy" /></p><p>Assembly Component inserts a saved 3MF component into the current assembly, optionally fixing it in place and positioning it with a transform gizmo.</p><h2>Inputs</h2><ul><li><code>componentName</code> – Pick a saved component from the library (3MF payload with optional embedded feature history).</li><li><code>isFixed</code> – Lock the component so assembly constraints treat it as immobile.</li><li><code>transform</code> – Placement transform (position/rotation/scale) applied to the inserted component bodies.</li></ul><h2>Behaviour</h2><ul><li>Loads the selected 3MF, rebuilds solids from meshes (or from embedded feature history when present), and groups them under a single assembly component node.</li><li>Applies the feature ID prefix to body/face names for stable selections, then visualizes the inserted bodies.</li><li>Persists the component payload in <code>persistentData</code> so reruns do not depend on local storage or library lookups.</li></ul>
98
+ </div>
99
+ </section>
100
+ </main>
101
+ <script>
102
+ (() => {
103
+ const searchInput = document.getElementById("doc-search");
104
+ const resultsBox = document.getElementById("doc-search-results");
105
+ const resultsList = document.getElementById("doc-search-list");
106
+ const statusEl = document.getElementById("doc-search-status");
107
+ const clearBtn = document.getElementById("doc-search-clear");
108
+ if (!searchInput || !resultsBox || !resultsList || !statusEl || !clearBtn) return;
109
+ const indexUrl = "./search-index.json";
110
+ let indexPromise = null;
111
+ let cachedEntries = null;
112
+
113
+ const escapeHtml = (text = "") =>
114
+ text
115
+ .replace(/&/g, "&amp;")
116
+ .replace(/</g, "&lt;")
117
+ .replace(/>/g, "&gt;");
118
+
119
+ const escapeRegExp = (text = "") => text.replace(/[.*+?^{}()|[]\$]/g, "\$&");
120
+
121
+ const highlight = (text, terms) => {
122
+ if (!terms.length) return escapeHtml(text);
123
+ const pattern = terms.map(escapeRegExp).join("|");
124
+ const regex = new RegExp(`(${pattern})`, "gi");
125
+ return escapeHtml(text).replace(regex, "<mark>$1</mark>");
126
+ };
127
+
128
+ const buildSnippet = (entry, terms) => {
129
+ const source = entry.content || entry.summary || "";
130
+ if (!source) return { plain: "", highlighted: "" };
131
+ let hit = source.length;
132
+ for (const term of terms) {
133
+ const idx = entry.contentLower.indexOf(term);
134
+ if (idx !== -1 && idx < hit) hit = idx;
135
+ }
136
+ if (!Number.isFinite(hit) || hit === source.length) hit = 0;
137
+ const start = Math.max(0, hit - 60);
138
+ const end = Math.min(source.length, hit + 140);
139
+ const snippet = source.slice(start, end);
140
+ return { plain: snippet, highlighted: highlight(snippet, terms) };
141
+ };
142
+
143
+ const updateStatus = (message) => {
144
+ statusEl.textContent = message;
145
+ };
146
+
147
+ const loadIndex = async () => {
148
+ if (cachedEntries) return cachedEntries;
149
+ if (!indexPromise) {
150
+ indexPromise = fetch(indexUrl, { cache: "no-store" })
151
+ .then((res) => {
152
+ if (!res.ok) throw new Error("Failed to load search index");
153
+ return res.json();
154
+ })
155
+ .then((json) => {
156
+ cachedEntries = Array.isArray(json)
157
+ ? json.map((entry) => ({
158
+ ...entry,
159
+ contentLower: (entry.content || "").toLowerCase(),
160
+ titleLower: (entry.title || "").toLowerCase(),
161
+ }))
162
+ : [];
163
+ return cachedEntries;
164
+ })
165
+ .catch((err) => {
166
+ console.error("Search index load failed", err);
167
+ cachedEntries = [];
168
+ throw err;
169
+ });
170
+ }
171
+ return indexPromise;
172
+ };
173
+
174
+ const renderResults = (entries, terms) => {
175
+ if (!terms.length) {
176
+ resultsBox.hidden = true;
177
+ return;
178
+ }
179
+ if (!entries.length) {
180
+ resultsList.innerHTML = '<li class="search-item"><div class="search-snippet">No matches found.</div></li>';
181
+ resultsBox.hidden = false;
182
+ return;
183
+ }
184
+ const rendered = entries
185
+ .slice(0, 30)
186
+ .map((entry) => {
187
+ const snippet = buildSnippet(entry, terms);
188
+ const title = highlight(entry.title || entry.href, terms);
189
+ const hasFragment = snippet.plain && snippet.plain.trim().length > 0;
190
+ const fragment = hasFragment ? `#:~:text=${encodeURIComponent(snippet.plain.trim())}` : "";
191
+ const hrefWithFragment = hasFragment
192
+ ? (entry.href.includes("#") ? `${entry.href}&:~:text=${encodeURIComponent(snippet.plain.trim())}` : `${entry.href}${fragment}`)
193
+ : entry.href;
194
+ const snippetHtml = snippet.highlighted ? `<div class="search-snippet">${snippet.highlighted}</div>` : "";
195
+ return `<li class="search-item"><a href="${hrefWithFragment}">${title}</a>${snippetHtml}</li>`;
196
+ })
197
+ .join("");
198
+ resultsList.innerHTML = rendered;
199
+ resultsBox.hidden = false;
200
+ };
201
+
202
+ const performSearch = async () => {
203
+ const rawQuery = searchInput.value.trim();
204
+ if (rawQuery.length < 2) {
205
+ updateStatus("Type at least 2 characters to search.");
206
+ resultsBox.hidden = true;
207
+ return;
208
+ }
209
+ const terms = rawQuery.toLowerCase().split(/\s+/).filter(Boolean);
210
+ updateStatus("Searching...");
211
+ try {
212
+ const entries = await loadIndex();
213
+ const matches = entries.filter((entry) =>
214
+ terms.every((term) => entry.contentLower.includes(term) || entry.titleLower.includes(term))
215
+ );
216
+ renderResults(matches, terms);
217
+ updateStatus(matches.length ? `${matches.length} result${matches.length === 1 ? "" : "s"} for "${rawQuery}"` : "No matches found.");
218
+ } catch (err) {
219
+ updateStatus("Search unavailable (could not load index).");
220
+ }
221
+ };
222
+
223
+ searchInput.addEventListener("input", performSearch);
224
+
225
+ searchInput.addEventListener("focus", () => {
226
+ if (!cachedEntries) {
227
+ loadIndex().catch(() => updateStatus("Search unavailable (could not load index)."));
228
+ }
229
+ });
230
+
231
+ clearBtn.addEventListener("click", () => {
232
+ searchInput.value = "";
233
+ resultsBox.hidden = true;
234
+ updateStatus("Type at least 2 characters to search.");
235
+ searchInput.focus();
236
+ });
237
+
238
+ document.addEventListener("keydown", (evt) => {
239
+ if (evt.key === "Escape" && document.activeElement === searchInput) {
240
+ searchInput.value = "";
241
+ resultsBox.hidden = true;
242
+ updateStatus("Type at least 2 characters to search.");
243
+ }
244
+ });
245
+ })();
246
+ </script>
247
+ </body>
248
+ </html>
@@ -0,0 +1,248 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8" />
5
+ <meta name="viewport" content="width=device-width,initial-scale=1" />
6
+ <title>Boolean - BREP</title>
7
+ <style>
8
+ :root{
9
+ --bg:#0b0f14; --panel:#0f141b; --text:#d7dde6; --muted:#9aa7b2;
10
+ --border:#1b2430; --accent:#5cc8ff; --chip:#121823;
11
+ }
12
+ *{box-sizing:border-box}
13
+ html,body{margin:0;background:var(--bg);color:var(--text);font:14px/1.5 ui-monospace,SFMono-Regular,Menlo,Consolas,'Liberation Mono','Courier New',monospace}
14
+ main{max-width:1100px;margin:0 auto;padding:28px}
15
+ h1{margin:0 0 18px;font-size:22px;color:var(--accent);font-weight:700}
16
+ .summary{color:var(--muted);margin-bottom:22px}
17
+ .card{background:var(--panel);border:1px solid var(--border);border-radius:14px;padding:18px;margin:0 0 18px}
18
+ .readme{padding:0}
19
+ .readme .header{padding:16px 18px;border-bottom:1px solid var(--border)}
20
+ .readme .content{padding:18px}
21
+ .doc-card{padding:18px}
22
+ .doc-nav{margin:0 0 18px;display:flex;gap:12px;flex-wrap:wrap;align-items:center;color:var(--muted)}
23
+ .doc-nav-links{display:flex;gap:12px;flex-wrap:wrap;align-items:center}
24
+ .doc-nav a{color:var(--accent);font-weight:600}
25
+ .doc-list{list-style:none;margin:18px 0;padding:0}
26
+ .doc-list li{margin:6px 0}
27
+ .doc-list a{color:var(--accent)}
28
+ .nav-search{margin-left:auto;position:relative;display:flex;align-items:center;gap:8px;flex-wrap:wrap;justify-content:flex-end;min-width:240px;max-width:520px}
29
+ .search-title{font-weight:700;font-size:14px;margin-bottom:4px}
30
+ .search-hint{color:var(--muted);font-size:12px;margin:0}
31
+ .search-input-row{display:flex;gap:8px;align-items:center;width:100%}
32
+ .search-input{flex:1;border:1px solid var(--border);border-radius:10px;background:var(--chip);color:var(--text);padding:10px 12px}
33
+ .search-input:focus{outline:1px solid var(--accent);box-shadow:0 0 0 3px rgba(92,200,255,0.15)}
34
+ .search-clear{border:1px solid var(--border);background:var(--panel);color:var(--muted);border-radius:10px;padding:9px 12px;cursor:pointer;font-weight:600}
35
+ .search-clear:hover{border-color:var(--accent);color:var(--accent)}
36
+ .search-status{color:var(--muted);font-size:12px;margin-top:4px;width:100%;text-align:right}
37
+ .search-results{position:absolute;top:100%;right:0;margin-top:10px;border:1px solid var(--border);border-radius:12px;background:var(--panel);max-height:360px;overflow:auto;min-width:320px;max-width:520px;box-shadow:0 12px 30px rgba(0,0,0,0.35);z-index:25}
38
+ .search-results ul{list-style:none;margin:0;padding:0}
39
+ .search-item{padding:10px 12px;border-bottom:1px solid var(--border)}
40
+ .search-item:last-child{border-bottom:none}
41
+ .search-item a{display:block;color:var(--accent);font-weight:600}
42
+ .search-snippet{color:var(--muted);font-size:13px;margin-top:4px}
43
+ .search-results mark{background:rgba(92,200,255,0.2);color:var(--text);border-radius:4px;padding:0 2px}
44
+ .prose h1{font-size:24px;margin:0 0 12px}
45
+ .prose h2{font-size:18px;margin:18px 0 8px}
46
+ .prose h3{font-size:16px;margin:14px 0 6px}
47
+ .prose p{margin:0 0 10px}
48
+ .prose ul,.prose ol{margin:0 0 10px 18px}
49
+ .prose li{margin:4px 0}
50
+ .prose code{background:#0d1520;border:1px solid var(--border);padding:1px 5px;border-radius:6px;font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,'Liberation Mono','Courier New',monospace;font-size:12px}
51
+ .prose pre{background:#0d1520;border:1px solid var(--border);padding:12px;border-radius:12px;overflow:auto}
52
+ .prose a{color:var(--accent)}
53
+ .prose img{max-width:100%;height:auto;}
54
+ .prose table{border-collapse:collapse;width:100%;margin:16px 0;background:var(--panel);border:1px solid var(--border);border-radius:8px;overflow:hidden}
55
+ .prose th,.prose td{padding:8px 12px;text-align:left;border-bottom:1px solid var(--border)}
56
+ .prose th{background:var(--chip);color:var(--text);font-weight:600;font-size:13px}
57
+ .prose tr:last-child td{border-bottom:none}
58
+ .prose tbody tr:hover{background:rgba(92,200,255,0.05)}
59
+ .license{
60
+ background:var(--panel);border:1px solid var(--border);border-radius:14px;
61
+ padding:16px 16px 8px;margin:0 0 18px;
62
+ }
63
+ .license > h2{margin:0 0 10px;font-size:16px;font-weight:700}
64
+ .pkg{
65
+ border-top:1px solid var(--border);padding:10px 0;
66
+ display:grid;grid-template-columns:1fr auto;gap:10px;align-items:center;
67
+ }
68
+ .pkg:first-of-type{border-top:none}
69
+ .pkg .meta{display:flex;gap:10px;flex-wrap:wrap}
70
+ .pkg .name{font-weight:600}
71
+ .pkg .desc{color:var(--muted);margin-top:2px}
72
+ a{color:var(--accent);text-decoration:none} a:hover{text-decoration:underline}
73
+ .chip{background:var(--chip);border:1px solid var(--border);border-radius:999px;padding:2px 8px;font-size:12px;color:var(--muted)}
74
+ .footer{margin-top:26px;color:var(--muted);font-size:12px}
75
+ </style>
76
+ </head>
77
+ <body>
78
+ <main>
79
+ <nav class="doc-nav">
80
+ <div class="doc-nav-links">
81
+ <a href="index.html">Help Home</a><span>&middot;</span><a href="/help/table-of-contents.html">Table of Contents</a><span>&middot;</span><a href="https://github.com/mmiscool/BREP" target="_blank" rel="noopener noreferrer">GitHub</a>
82
+ </div>
83
+ <div class="nav-search">
84
+ <div class="search-input-row">
85
+ <input type="search" id="doc-search" class="search-input" placeholder="Search docs... Type at least 2 characters to search" autocomplete="off" spellcheck="false" />
86
+ <button type="button" class="search-clear" id="doc-search-clear">Clear</button>
87
+ </div>
88
+ <div class="search-status" id="doc-search-status"></div>
89
+ <div class="search-results" id="doc-search-results" hidden>
90
+ <ul id="doc-search-list"></ul>
91
+ </div>
92
+ </div>
93
+ </nav>
94
+ <section class="card doc-card">
95
+
96
+ <div class="prose">
97
+ <h1>Boolean</h1><p>Status: Implemented</p><p><img src="features__Boolean_dialog.png" alt="Boolean feature dialog" width="280" loading="lazy" /></p><p>Boolean combines existing solids by running Manifold CSG through <code>BREP.applyBooleanOperation</code>. The feature keeps face labels intact so downstream selections survive.</p><h2>Inputs</h2><ul><li><code>targetSolid</code> – the solid that supplies the base body for UNION/INTERSECT operations.</li><li><code>boolean.targets</code> – additional solids to use as tools. Duplicate entries are ignored.</li><li><code>boolean.operation</code> – <code>UNION</code>, <code>SUBTRACT</code>, or <code>INTERSECT</code>. <code>NONE</code> leaves the scene unchanged.</li></ul><p>- <code>boolean.simplify</code> – optional. If <code>true</code>, simplifies the boolean result using a tolerance (see below). If a number, it is treated as the tolerance directly. If omitted, a global default may apply. - <code>boolean.simplifyTolerance</code> – optional numeric tolerance to use when simplifying. Takes precedence when provided.</p><h2>Behaviour</h2><ul><li>UNION and INTERSECT treat the target as the base body and remove the original target from the scene once the new solid is created.</li><li>SUBTRACT unions all tool solids first, then removes that volume from the target so complex multi-tool cuts stay watertight.</li><li>Each tool and the original target solid is flagged for removal after the operation; only the new solids returned by the kernel remain in the timeline.</li></ul><p>When simplification is enabled, the output solid(s) are passed through <code>Solid.simplify(tol)</code>. By default, a small global tolerance is used if configured internally; you can override per-feature via <code>boolean.simplify</code>/<code>boolean.simplifyTolerance</code>.</p>
98
+ </div>
99
+ </section>
100
+ </main>
101
+ <script>
102
+ (() => {
103
+ const searchInput = document.getElementById("doc-search");
104
+ const resultsBox = document.getElementById("doc-search-results");
105
+ const resultsList = document.getElementById("doc-search-list");
106
+ const statusEl = document.getElementById("doc-search-status");
107
+ const clearBtn = document.getElementById("doc-search-clear");
108
+ if (!searchInput || !resultsBox || !resultsList || !statusEl || !clearBtn) return;
109
+ const indexUrl = "./search-index.json";
110
+ let indexPromise = null;
111
+ let cachedEntries = null;
112
+
113
+ const escapeHtml = (text = "") =>
114
+ text
115
+ .replace(/&/g, "&amp;")
116
+ .replace(/</g, "&lt;")
117
+ .replace(/>/g, "&gt;");
118
+
119
+ const escapeRegExp = (text = "") => text.replace(/[.*+?^{}()|[]\$]/g, "\$&");
120
+
121
+ const highlight = (text, terms) => {
122
+ if (!terms.length) return escapeHtml(text);
123
+ const pattern = terms.map(escapeRegExp).join("|");
124
+ const regex = new RegExp(`(${pattern})`, "gi");
125
+ return escapeHtml(text).replace(regex, "<mark>$1</mark>");
126
+ };
127
+
128
+ const buildSnippet = (entry, terms) => {
129
+ const source = entry.content || entry.summary || "";
130
+ if (!source) return { plain: "", highlighted: "" };
131
+ let hit = source.length;
132
+ for (const term of terms) {
133
+ const idx = entry.contentLower.indexOf(term);
134
+ if (idx !== -1 && idx < hit) hit = idx;
135
+ }
136
+ if (!Number.isFinite(hit) || hit === source.length) hit = 0;
137
+ const start = Math.max(0, hit - 60);
138
+ const end = Math.min(source.length, hit + 140);
139
+ const snippet = source.slice(start, end);
140
+ return { plain: snippet, highlighted: highlight(snippet, terms) };
141
+ };
142
+
143
+ const updateStatus = (message) => {
144
+ statusEl.textContent = message;
145
+ };
146
+
147
+ const loadIndex = async () => {
148
+ if (cachedEntries) return cachedEntries;
149
+ if (!indexPromise) {
150
+ indexPromise = fetch(indexUrl, { cache: "no-store" })
151
+ .then((res) => {
152
+ if (!res.ok) throw new Error("Failed to load search index");
153
+ return res.json();
154
+ })
155
+ .then((json) => {
156
+ cachedEntries = Array.isArray(json)
157
+ ? json.map((entry) => ({
158
+ ...entry,
159
+ contentLower: (entry.content || "").toLowerCase(),
160
+ titleLower: (entry.title || "").toLowerCase(),
161
+ }))
162
+ : [];
163
+ return cachedEntries;
164
+ })
165
+ .catch((err) => {
166
+ console.error("Search index load failed", err);
167
+ cachedEntries = [];
168
+ throw err;
169
+ });
170
+ }
171
+ return indexPromise;
172
+ };
173
+
174
+ const renderResults = (entries, terms) => {
175
+ if (!terms.length) {
176
+ resultsBox.hidden = true;
177
+ return;
178
+ }
179
+ if (!entries.length) {
180
+ resultsList.innerHTML = '<li class="search-item"><div class="search-snippet">No matches found.</div></li>';
181
+ resultsBox.hidden = false;
182
+ return;
183
+ }
184
+ const rendered = entries
185
+ .slice(0, 30)
186
+ .map((entry) => {
187
+ const snippet = buildSnippet(entry, terms);
188
+ const title = highlight(entry.title || entry.href, terms);
189
+ const hasFragment = snippet.plain && snippet.plain.trim().length > 0;
190
+ const fragment = hasFragment ? `#:~:text=${encodeURIComponent(snippet.plain.trim())}` : "";
191
+ const hrefWithFragment = hasFragment
192
+ ? (entry.href.includes("#") ? `${entry.href}&:~:text=${encodeURIComponent(snippet.plain.trim())}` : `${entry.href}${fragment}`)
193
+ : entry.href;
194
+ const snippetHtml = snippet.highlighted ? `<div class="search-snippet">${snippet.highlighted}</div>` : "";
195
+ return `<li class="search-item"><a href="${hrefWithFragment}">${title}</a>${snippetHtml}</li>`;
196
+ })
197
+ .join("");
198
+ resultsList.innerHTML = rendered;
199
+ resultsBox.hidden = false;
200
+ };
201
+
202
+ const performSearch = async () => {
203
+ const rawQuery = searchInput.value.trim();
204
+ if (rawQuery.length < 2) {
205
+ updateStatus("Type at least 2 characters to search.");
206
+ resultsBox.hidden = true;
207
+ return;
208
+ }
209
+ const terms = rawQuery.toLowerCase().split(/\s+/).filter(Boolean);
210
+ updateStatus("Searching...");
211
+ try {
212
+ const entries = await loadIndex();
213
+ const matches = entries.filter((entry) =>
214
+ terms.every((term) => entry.contentLower.includes(term) || entry.titleLower.includes(term))
215
+ );
216
+ renderResults(matches, terms);
217
+ updateStatus(matches.length ? `${matches.length} result${matches.length === 1 ? "" : "s"} for "${rawQuery}"` : "No matches found.");
218
+ } catch (err) {
219
+ updateStatus("Search unavailable (could not load index).");
220
+ }
221
+ };
222
+
223
+ searchInput.addEventListener("input", performSearch);
224
+
225
+ searchInput.addEventListener("focus", () => {
226
+ if (!cachedEntries) {
227
+ loadIndex().catch(() => updateStatus("Search unavailable (could not load index)."));
228
+ }
229
+ });
230
+
231
+ clearBtn.addEventListener("click", () => {
232
+ searchInput.value = "";
233
+ resultsBox.hidden = true;
234
+ updateStatus("Type at least 2 characters to search.");
235
+ searchInput.focus();
236
+ });
237
+
238
+ document.addEventListener("keydown", (evt) => {
239
+ if (evt.key === "Escape" && document.activeElement === searchInput) {
240
+ searchInput.value = "";
241
+ resultsBox.hidden = true;
242
+ updateStatus("Type at least 2 characters to search.");
243
+ }
244
+ });
245
+ })();
246
+ </script>
247
+ </body>
248
+ </html>