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.
- package/LICENSE.md +32 -0
- package/README.md +144 -0
- package/dist-kernel/brep-kernel.js +74699 -0
- package/dist-kernel/help/CONTRIBUTING.html +248 -0
- package/dist-kernel/help/LICENSE.html +248 -0
- package/dist-kernel/help/MODELING.png +0 -0
- package/dist-kernel/help/PMI.png +0 -0
- package/dist-kernel/help/SKETCH.png +0 -0
- package/dist-kernel/help/assembly-constraints__Coincident_Constraint_dialog.png +0 -0
- package/dist-kernel/help/assembly-constraints___Angle_Constraint_dialog.png +0 -0
- package/dist-kernel/help/assembly-constraints___Distance_Constraint_dialog.png +0 -0
- package/dist-kernel/help/assembly-constraints___Fixed_Constraint_dialog.png +0 -0
- package/dist-kernel/help/assembly-constraints___Parallel_Constraint_dialog.png +0 -0
- package/dist-kernel/help/assembly-constraints___Touch_Align_Constraint_dialog.png +0 -0
- package/dist-kernel/help/assembly-constraints__angle-constraint.html +248 -0
- package/dist-kernel/help/assembly-constraints__coincident-constraint.html +248 -0
- package/dist-kernel/help/assembly-constraints__distance-constraint.html +248 -0
- package/dist-kernel/help/assembly-constraints__fixed-constraint.html +248 -0
- package/dist-kernel/help/assembly-constraints__parallel-constraint.html +248 -0
- package/dist-kernel/help/assembly-constraints__solver.html +248 -0
- package/dist-kernel/help/assembly-constraints__touch-align-constraint.html +248 -0
- package/dist-kernel/help/brep-api.html +263 -0
- package/dist-kernel/help/brep-kernel.html +258 -0
- package/dist-kernel/help/brep-model.html +248 -0
- package/dist-kernel/help/cylindrical-face-radius-embedding.html +290 -0
- package/dist-kernel/help/dialog-screenshots.html +248 -0
- package/dist-kernel/help/extruded-sketch-radius-embedding.html +336 -0
- package/dist-kernel/help/features__Assembly_Component_dialog.png +0 -0
- package/dist-kernel/help/features__Boolean_dialog.png +0 -0
- package/dist-kernel/help/features__Chamfer_dialog.png +0 -0
- package/dist-kernel/help/features__Datium_dialog.png +0 -0
- package/dist-kernel/help/features__Extrude_dialog.png +0 -0
- package/dist-kernel/help/features__Fillet_dialog.png +0 -0
- package/dist-kernel/help/features__Helix_dialog.png +0 -0
- package/dist-kernel/help/features__Hole_dialog.png +0 -0
- package/dist-kernel/help/features__Image_Heightmap_Solid_dialog.png +0 -0
- package/dist-kernel/help/features__Image_to_Face_dialog.png +0 -0
- package/dist-kernel/help/features__Import_3D_Model_dialog.png +0 -0
- package/dist-kernel/help/features__Loft_dialog.png +0 -0
- package/dist-kernel/help/features__Mirror_dialog.png +0 -0
- package/dist-kernel/help/features__Offset_Shell_dialog.png +0 -0
- package/dist-kernel/help/features__Overlap_Cleanup_dialog.png +0 -0
- package/dist-kernel/help/features__Pattern_Linear_dialog.png +0 -0
- package/dist-kernel/help/features__Pattern_Radial_dialog.png +0 -0
- package/dist-kernel/help/features__Pattern_dialog.png +0 -0
- package/dist-kernel/help/features__Plane_dialog.png +0 -0
- package/dist-kernel/help/features__Primitive_Cone_dialog.png +0 -0
- package/dist-kernel/help/features__Primitive_Cube_dialog.png +0 -0
- package/dist-kernel/help/features__Primitive_Cylinder_dialog.png +0 -0
- package/dist-kernel/help/features__Primitive_Pyramid_dialog.png +0 -0
- package/dist-kernel/help/features__Primitive_Sphere_dialog.png +0 -0
- package/dist-kernel/help/features__Primitive_Torus_dialog.png +0 -0
- package/dist-kernel/help/features__Remesh_dialog.png +0 -0
- package/dist-kernel/help/features__Revolve_dialog.png +0 -0
- package/dist-kernel/help/features__Sheet_Metal_Contour_Flange_dialog.png +0 -0
- package/dist-kernel/help/features__Sheet_Metal_Cutout_dialog.png +0 -0
- package/dist-kernel/help/features__Sheet_Metal_Flange_dialog.png +0 -0
- package/dist-kernel/help/features__Sheet_Metal_Tab_dialog.png +0 -0
- package/dist-kernel/help/features__Sketch_dialog.png +0 -0
- package/dist-kernel/help/features__Spline_dialog.png +0 -0
- package/dist-kernel/help/features__Sweep_dialog.png +0 -0
- package/dist-kernel/help/features__Transform_dialog.png +0 -0
- package/dist-kernel/help/features__Tube_dialog.png +0 -0
- package/dist-kernel/help/features__assembly-component.html +248 -0
- package/dist-kernel/help/features__boolean.html +248 -0
- package/dist-kernel/help/features__chamfer.html +248 -0
- package/dist-kernel/help/features__datium.html +248 -0
- package/dist-kernel/help/features__datum.html +248 -0
- package/dist-kernel/help/features__extrude.html +248 -0
- package/dist-kernel/help/features__fillet.html +248 -0
- package/dist-kernel/help/features__helix.html +248 -0
- package/dist-kernel/help/features__hole.html +248 -0
- package/dist-kernel/help/features__image-heightmap-solid.html +248 -0
- package/dist-kernel/help/features__image-to-face-2D_dialog.png +0 -0
- package/dist-kernel/help/features__image-to-face-3D_dialog.png +0 -0
- package/dist-kernel/help/features__image-to-face.html +248 -0
- package/dist-kernel/help/features__import-3d-model.html +248 -0
- package/dist-kernel/help/features__index.html +248 -0
- package/dist-kernel/help/features__loft.html +248 -0
- package/dist-kernel/help/features__mirror.html +248 -0
- package/dist-kernel/help/features__offset-shell.html +248 -0
- package/dist-kernel/help/features__pattern-linear.html +248 -0
- package/dist-kernel/help/features__pattern-radial.html +248 -0
- package/dist-kernel/help/features__pattern.html +248 -0
- package/dist-kernel/help/features__plane.html +248 -0
- package/dist-kernel/help/features__primitive-cone.html +248 -0
- package/dist-kernel/help/features__primitive-cube.html +248 -0
- package/dist-kernel/help/features__primitive-cylinder.html +248 -0
- package/dist-kernel/help/features__primitive-pyramid.html +248 -0
- package/dist-kernel/help/features__primitive-sphere.html +248 -0
- package/dist-kernel/help/features__primitive-torus.html +248 -0
- package/dist-kernel/help/features__remesh.html +248 -0
- package/dist-kernel/help/features__revolve.html +248 -0
- package/dist-kernel/help/features__sheet-metal-contour-flange.html +248 -0
- package/dist-kernel/help/features__sheet-metal-flange.html +248 -0
- package/dist-kernel/help/features__sheet-metal-tab.html +248 -0
- package/dist-kernel/help/features__sketch.html +248 -0
- package/dist-kernel/help/features__spline.html +248 -0
- package/dist-kernel/help/features__sweep.html +248 -0
- package/dist-kernel/help/features__transform.html +248 -0
- package/dist-kernel/help/features__tube.html +248 -0
- package/dist-kernel/help/file-formats.html +248 -0
- package/dist-kernel/help/getting-started.html +248 -0
- package/dist-kernel/help/highlights.html +248 -0
- package/dist-kernel/help/history-systems.html +248 -0
- package/dist-kernel/help/how-it-works.html +248 -0
- package/dist-kernel/help/index.html +862 -0
- package/dist-kernel/help/input-params-schema.html +363 -0
- package/dist-kernel/help/inspector-improvements.html +248 -0
- package/dist-kernel/help/inspector.html +248 -0
- package/dist-kernel/help/modes__modeling.html +248 -0
- package/dist-kernel/help/modes__pmi.html +248 -0
- package/dist-kernel/help/modes__sketch.html +248 -0
- package/dist-kernel/help/plugins.html +248 -0
- package/dist-kernel/help/pmi-annotations__Angle_Dimension_dialog.png +0 -0
- package/dist-kernel/help/pmi-annotations__Explode_Body_dialog.png +0 -0
- package/dist-kernel/help/pmi-annotations__Hole_Callout_dialog.png +0 -0
- package/dist-kernel/help/pmi-annotations__Leader_dialog.png +0 -0
- package/dist-kernel/help/pmi-annotations__Linear_Dimension_dialog.png +0 -0
- package/dist-kernel/help/pmi-annotations__Note_dialog.png +0 -0
- package/dist-kernel/help/pmi-annotations__Radial_Dimension_dialog.png +0 -0
- package/dist-kernel/help/pmi-annotations__angle-dimension.html +248 -0
- package/dist-kernel/help/pmi-annotations__explode-body.html +248 -0
- package/dist-kernel/help/pmi-annotations__hole-callout.html +248 -0
- package/dist-kernel/help/pmi-annotations__index.html +248 -0
- package/dist-kernel/help/pmi-annotations__leader.html +248 -0
- package/dist-kernel/help/pmi-annotations__linear-dimension.html +248 -0
- package/dist-kernel/help/pmi-annotations__note.html +248 -0
- package/dist-kernel/help/pmi-annotations__radial-dimension.html +248 -0
- package/dist-kernel/help/search-index.json +464 -0
- package/dist-kernel/help/simplified-radial-dimensions.html +298 -0
- package/dist-kernel/help/solid-methods.html +359 -0
- package/dist-kernel/help/table-of-contents.html +330 -0
- package/dist-kernel/help/ui-overview.html +248 -0
- package/dist-kernel/help/whats-new.html +248 -0
- package/package.json +54 -0
- package/src/BREP/AssemblyComponent.js +42 -0
- package/src/BREP/BREP.js +43 -0
- package/src/BREP/BetterSolid.js +805 -0
- package/src/BREP/Edge.js +103 -0
- package/src/BREP/Extrude.js +403 -0
- package/src/BREP/Face.js +187 -0
- package/src/BREP/MeshRepairer.js +634 -0
- package/src/BREP/OffsetShellSolid.js +614 -0
- package/src/BREP/PointCloudWrap.js +302 -0
- package/src/BREP/Revolve.js +345 -0
- package/src/BREP/SolidMethods/authoring.js +112 -0
- package/src/BREP/SolidMethods/booleanOps.js +230 -0
- package/src/BREP/SolidMethods/chamfer.js +122 -0
- package/src/BREP/SolidMethods/edgeResolution.js +25 -0
- package/src/BREP/SolidMethods/fillet.js +792 -0
- package/src/BREP/SolidMethods/index.js +72 -0
- package/src/BREP/SolidMethods/io.js +105 -0
- package/src/BREP/SolidMethods/lifecycle.js +103 -0
- package/src/BREP/SolidMethods/manifoldOps.js +375 -0
- package/src/BREP/SolidMethods/meshCleanup.js +2512 -0
- package/src/BREP/SolidMethods/meshQueries.js +264 -0
- package/src/BREP/SolidMethods/metadata.js +106 -0
- package/src/BREP/SolidMethods/metrics.js +51 -0
- package/src/BREP/SolidMethods/transforms.js +361 -0
- package/src/BREP/SolidMethods/visualize.js +508 -0
- package/src/BREP/SolidShared.js +26 -0
- package/src/BREP/Sweep.js +1596 -0
- package/src/BREP/Tube.js +857 -0
- package/src/BREP/Vertex.js +43 -0
- package/src/BREP/applyBooleanOperation.js +704 -0
- package/src/BREP/boundsUtils.js +48 -0
- package/src/BREP/chamfer.js +551 -0
- package/src/BREP/edgePolylineUtils.js +85 -0
- package/src/BREP/fillets/common.js +388 -0
- package/src/BREP/fillets/fillet.js +1422 -0
- package/src/BREP/fillets/filletGeometry.js +15 -0
- package/src/BREP/fillets/inset.js +389 -0
- package/src/BREP/fillets/offsetHelper.js +143 -0
- package/src/BREP/fillets/outset.js +88 -0
- package/src/BREP/helix.js +193 -0
- package/src/BREP/meshToBrep.js +234 -0
- package/src/BREP/primitives.js +279 -0
- package/src/BREP/setupManifold.js +71 -0
- package/src/BREP/threadGeometry.js +1120 -0
- package/src/BREP/triangleUtils.js +8 -0
- package/src/BREP/triangulate.js +608 -0
- package/src/FeatureRegistry.js +183 -0
- package/src/PartHistory.js +1132 -0
- package/src/UI/AccordionWidget.js +292 -0
- package/src/UI/CADmaterials.js +850 -0
- package/src/UI/EnvMonacoEditor.js +522 -0
- package/src/UI/FloatingWindow.js +396 -0
- package/src/UI/HistoryWidget.js +457 -0
- package/src/UI/MainToolbar.js +131 -0
- package/src/UI/ModelLibraryView.js +194 -0
- package/src/UI/OrthoCameraIdle.js +206 -0
- package/src/UI/PluginsWidget.js +280 -0
- package/src/UI/SceneListing.js +606 -0
- package/src/UI/SelectionFilter.js +629 -0
- package/src/UI/ViewCube.js +389 -0
- package/src/UI/assembly/AssemblyConstraintCollectionWidget.js +329 -0
- package/src/UI/assembly/AssemblyConstraintControlsWidget.js +282 -0
- package/src/UI/assembly/AssemblyConstraintsWidget.css +292 -0
- package/src/UI/assembly/AssemblyConstraintsWidget.js +1373 -0
- package/src/UI/assembly/constraintFaceUtils.js +115 -0
- package/src/UI/assembly/constraintHighlightUtils.js +70 -0
- package/src/UI/assembly/constraintLabelUtils.js +31 -0
- package/src/UI/assembly/constraintPointUtils.js +64 -0
- package/src/UI/assembly/constraintSelectionUtils.js +185 -0
- package/src/UI/assembly/constraintStatusUtils.js +142 -0
- package/src/UI/componentSelectorModal.js +240 -0
- package/src/UI/controls/CombinedTransformControls.js +386 -0
- package/src/UI/dialogs.js +351 -0
- package/src/UI/expressionsManager.js +100 -0
- package/src/UI/featureDialogWidgets/booleanField.js +25 -0
- package/src/UI/featureDialogWidgets/booleanOperationField.js +97 -0
- package/src/UI/featureDialogWidgets/buttonField.js +45 -0
- package/src/UI/featureDialogWidgets/componentSelectorField.js +102 -0
- package/src/UI/featureDialogWidgets/defaultField.js +23 -0
- package/src/UI/featureDialogWidgets/fileField.js +66 -0
- package/src/UI/featureDialogWidgets/index.js +34 -0
- package/src/UI/featureDialogWidgets/numberField.js +165 -0
- package/src/UI/featureDialogWidgets/optionsField.js +33 -0
- package/src/UI/featureDialogWidgets/referenceSelectionField.js +208 -0
- package/src/UI/featureDialogWidgets/stringField.js +24 -0
- package/src/UI/featureDialogWidgets/textareaField.js +28 -0
- package/src/UI/featureDialogWidgets/threadDesignationField.js +160 -0
- package/src/UI/featureDialogWidgets/transformField.js +252 -0
- package/src/UI/featureDialogWidgets/utils.js +43 -0
- package/src/UI/featureDialogWidgets/vec3Field.js +133 -0
- package/src/UI/featureDialogs.js +1414 -0
- package/src/UI/fileManagerWidget.js +615 -0
- package/src/UI/history/HistoryCollectionWidget.js +1294 -0
- package/src/UI/history/historyCollectionWidget.css.js +257 -0
- package/src/UI/history/historyDisplayInfo.js +133 -0
- package/src/UI/mobile.js +28 -0
- package/src/UI/objectDump.js +442 -0
- package/src/UI/pmi/AnnotationCollectionWidget.js +120 -0
- package/src/UI/pmi/AnnotationHistory.js +353 -0
- package/src/UI/pmi/AnnotationRegistry.js +90 -0
- package/src/UI/pmi/BaseAnnotation.js +269 -0
- package/src/UI/pmi/LabelOverlay.css +102 -0
- package/src/UI/pmi/LabelOverlay.js +191 -0
- package/src/UI/pmi/PMIMode.js +1550 -0
- package/src/UI/pmi/PMIViewsWidget.js +1098 -0
- package/src/UI/pmi/annUtils.js +729 -0
- package/src/UI/pmi/dimensions/AngleDimensionAnnotation.js +647 -0
- package/src/UI/pmi/dimensions/ExplodeBodyAnnotation.js +507 -0
- package/src/UI/pmi/dimensions/HoleCalloutAnnotation.js +462 -0
- package/src/UI/pmi/dimensions/LeaderAnnotation.js +403 -0
- package/src/UI/pmi/dimensions/LinearDimensionAnnotation.js +532 -0
- package/src/UI/pmi/dimensions/NoteAnnotation.js +110 -0
- package/src/UI/pmi/dimensions/RadialDimensionAnnotation.js +659 -0
- package/src/UI/pmi/pmiStyle.js +44 -0
- package/src/UI/sketcher/SketchMode3D.js +4095 -0
- package/src/UI/sketcher/dimensions.js +674 -0
- package/src/UI/sketcher/glyphs.js +236 -0
- package/src/UI/sketcher/highlights.js +60 -0
- package/src/UI/toolbarButtons/aboutButton.js +5 -0
- package/src/UI/toolbarButtons/exportButton.js +609 -0
- package/src/UI/toolbarButtons/flatPatternButton.js +307 -0
- package/src/UI/toolbarButtons/importButton.js +160 -0
- package/src/UI/toolbarButtons/inspectorToggleButton.js +12 -0
- package/src/UI/toolbarButtons/metadataButton.js +1063 -0
- package/src/UI/toolbarButtons/orientToFaceButton.js +114 -0
- package/src/UI/toolbarButtons/registerDefaultButtons.js +46 -0
- package/src/UI/toolbarButtons/saveButton.js +99 -0
- package/src/UI/toolbarButtons/scriptRunnerButton.js +302 -0
- package/src/UI/toolbarButtons/testsButton.js +26 -0
- package/src/UI/toolbarButtons/undoRedoButtons.js +25 -0
- package/src/UI/toolbarButtons/wireframeToggleButton.js +5 -0
- package/src/UI/toolbarButtons/zoomToFitButton.js +5 -0
- package/src/UI/triangleDebuggerWindow.js +945 -0
- package/src/UI/viewer.js +4228 -0
- package/src/assemblyConstraints/AssemblyConstraintHistory.js +1576 -0
- package/src/assemblyConstraints/AssemblyConstraintRegistry.js +120 -0
- package/src/assemblyConstraints/BaseAssemblyConstraint.js +66 -0
- package/src/assemblyConstraints/constraintExpressionUtils.js +35 -0
- package/src/assemblyConstraints/constraintUtils/parallelAlignment.js +676 -0
- package/src/assemblyConstraints/constraints/AngleConstraint.js +485 -0
- package/src/assemblyConstraints/constraints/CoincidentConstraint.js +194 -0
- package/src/assemblyConstraints/constraints/DistanceConstraint.js +616 -0
- package/src/assemblyConstraints/constraints/FixedConstraint.js +78 -0
- package/src/assemblyConstraints/constraints/ParallelConstraint.js +252 -0
- package/src/assemblyConstraints/constraints/TouchAlignConstraint.js +961 -0
- package/src/core/entities/HistoryCollectionBase.js +72 -0
- package/src/core/entities/ListEntityBase.js +109 -0
- package/src/core/entities/schemaProcesser.js +121 -0
- package/src/exporters/sheetMetalFlatPattern.js +659 -0
- package/src/exporters/sheetMetalUnfold.js +862 -0
- package/src/exporters/step.js +1135 -0
- package/src/exporters/threeMF.js +575 -0
- package/src/features/assemblyComponent/AssemblyComponentFeature.js +780 -0
- package/src/features/boolean/BooleanFeature.js +94 -0
- package/src/features/chamfer/ChamferFeature.js +116 -0
- package/src/features/datium/DatiumFeature.js +80 -0
- package/src/features/edgeFeatureUtils.js +41 -0
- package/src/features/extrude/ExtrudeFeature.js +143 -0
- package/src/features/fillet/FilletFeature.js +197 -0
- package/src/features/helix/HelixFeature.js +405 -0
- package/src/features/hole/HoleFeature.js +1050 -0
- package/src/features/hole/screwClearance.js +86 -0
- package/src/features/hole/threadDesignationCatalog.js +149 -0
- package/src/features/imageHeightSolid/ImageHeightmapSolidFeature.js +463 -0
- package/src/features/imageToFace/ImageToFaceFeature.js +727 -0
- package/src/features/imageToFace/imageEditor.js +1270 -0
- package/src/features/imageToFace/traceUtils.js +971 -0
- package/src/features/import3dModel/Import3dModelFeature.js +151 -0
- package/src/features/loft/LoftFeature.js +605 -0
- package/src/features/mirror/MirrorFeature.js +151 -0
- package/src/features/offsetFace/OffsetFaceFeature.js +370 -0
- package/src/features/offsetShell/OffsetShellFeature.js +89 -0
- package/src/features/overlapCleanup/OverlapCleanupFeature.js +85 -0
- package/src/features/pattern/PatternFeature.js +275 -0
- package/src/features/patternLinear/PatternLinearFeature.js +120 -0
- package/src/features/patternRadial/PatternRadialFeature.js +186 -0
- package/src/features/plane/PlaneFeature.js +154 -0
- package/src/features/primitiveCone/primitiveConeFeature.js +99 -0
- package/src/features/primitiveCube/primitiveCubeFeature.js +70 -0
- package/src/features/primitiveCylinder/primitiveCylinderFeature.js +91 -0
- package/src/features/primitivePyramid/primitivePyramidFeature.js +72 -0
- package/src/features/primitiveSphere/primitiveSphereFeature.js +62 -0
- package/src/features/primitiveTorus/primitiveTorusFeature.js +109 -0
- package/src/features/remesh/RemeshFeature.js +97 -0
- package/src/features/revolve/RevolveFeature.js +111 -0
- package/src/features/selectionUtils.js +118 -0
- package/src/features/sheetMetal/SheetMetalContourFlangeFeature.js +1656 -0
- package/src/features/sheetMetal/SheetMetalCutoutFeature.js +1056 -0
- package/src/features/sheetMetal/SheetMetalFlangeFeature.js +1568 -0
- package/src/features/sheetMetal/SheetMetalHemFeature.js +43 -0
- package/src/features/sheetMetal/SheetMetalObject.js +141 -0
- package/src/features/sheetMetal/SheetMetalTabFeature.js +176 -0
- package/src/features/sheetMetal/UNFOLD_NEUTRAL_REQUIREMENTS.md +153 -0
- package/src/features/sheetMetal/contour-flange-rebuild-spec.md +261 -0
- package/src/features/sheetMetal/profileUtils.js +25 -0
- package/src/features/sheetMetal/sheetMetalCleanup.js +9 -0
- package/src/features/sheetMetal/sheetMetalFaceTypes.js +146 -0
- package/src/features/sheetMetal/sheetMetalMetadata.js +165 -0
- package/src/features/sheetMetal/sheetMetalPipeline.js +169 -0
- package/src/features/sheetMetal/sheetMetalProfileUtils.js +216 -0
- package/src/features/sheetMetal/sheetMetalTabUtils.js +29 -0
- package/src/features/sheetMetal/sheetMetalTree.js +210 -0
- package/src/features/sketch/SketchFeature.js +955 -0
- package/src/features/sketch/sketchSolver2D/ConstraintEngine.js +800 -0
- package/src/features/sketch/sketchSolver2D/constraintDefinitions.js +704 -0
- package/src/features/sketch/sketchSolver2D/mathHelpersMod.js +307 -0
- package/src/features/spline/SplineEditorSession.js +988 -0
- package/src/features/spline/SplineFeature.js +1388 -0
- package/src/features/spline/splineUtils.js +218 -0
- package/src/features/sweep/SweepFeature.js +110 -0
- package/src/features/transform/TransformFeature.js +152 -0
- package/src/features/tube/TubeFeature.js +635 -0
- package/src/fs.proxy.js +625 -0
- package/src/idbStorage.js +254 -0
- package/src/index.js +12 -0
- package/src/main.js +15 -0
- package/src/metadataManager.js +64 -0
- package/src/path.proxy.js +277 -0
- package/src/plugins/ghLoader.worker.js +151 -0
- package/src/plugins/pluginManager.js +286 -0
- package/src/pmi/PMIViewsManager.js +134 -0
- package/src/services/componentLibrary.js +198 -0
- package/src/tests/ConsoleCapture.js +189 -0
- package/src/tests/S7-diagnostics-2025-12-23T18-37-23-570Z.json +630 -0
- package/src/tests/browserTests.js +597 -0
- package/src/tests/debugBoolean.js +225 -0
- package/src/tests/partFiles/badBoolean.json +957 -0
- package/src/tests/partFiles/extrudeTest.json +88 -0
- package/src/tests/partFiles/filletFail.json +58 -0
- package/src/tests/partFiles/import_TEst.part.part.json +646 -0
- package/src/tests/partFiles/sheetMetalHem.BREP.json +734 -0
- package/src/tests/test_boolean_subtract.js +27 -0
- package/src/tests/test_chamfer.js +17 -0
- package/src/tests/test_extrudeFace.js +24 -0
- package/src/tests/test_fillet.js +17 -0
- package/src/tests/test_fillet_nonClosed.js +45 -0
- package/src/tests/test_filletsMoreDifficult.js +46 -0
- package/src/tests/test_history_features_basic.js +149 -0
- package/src/tests/test_hole.js +282 -0
- package/src/tests/test_mirror.js +16 -0
- package/src/tests/test_offsetShellGrouping.js +85 -0
- package/src/tests/test_plane.js +4 -0
- package/src/tests/test_primitiveCone.js +11 -0
- package/src/tests/test_primitiveCube.js +7 -0
- package/src/tests/test_primitiveCylinder.js +8 -0
- package/src/tests/test_primitivePyramid.js +9 -0
- package/src/tests/test_primitiveSphere.js +17 -0
- package/src/tests/test_primitiveTorus.js +21 -0
- package/src/tests/test_pushFace.js +126 -0
- package/src/tests/test_sheetMetalContourFlange.js +125 -0
- package/src/tests/test_sheetMetal_features.js +80 -0
- package/src/tests/test_sketch_openLoop.js +45 -0
- package/src/tests/test_solidMetrics.js +58 -0
- package/src/tests/test_stlLoader.js +1889 -0
- package/src/tests/test_sweepFace.js +55 -0
- package/src/tests/test_tube.js +45 -0
- package/src/tests/test_tube_closedLoop.js +67 -0
- package/src/tests/tests.js +493 -0
- package/src/tools/assemblyConstraintDialogCapturePage.js +56 -0
- package/src/tools/dialogCapturePageFactory.js +227 -0
- package/src/tools/featureDialogCapturePage.js +47 -0
- package/src/tools/pmiAnnotationDialogCapturePage.js +60 -0
- package/src/utils/axisHelpers.js +99 -0
- package/src/utils/deepClone.js +69 -0
- package/src/utils/geometryTolerance.js +37 -0
- package/src/utils/normalizeTypeString.js +8 -0
- package/src/utils/xformMath.js +51 -0
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
import { BREP } from "../../BREP/BREP.js";
|
|
2
|
+
import { Manifold } from "../../BREP/SolidShared.js";
|
|
3
|
+
const THREE = BREP.THREE;
|
|
4
|
+
|
|
5
|
+
const inputParamsSchema = {
|
|
6
|
+
id: {
|
|
7
|
+
type: "string",
|
|
8
|
+
default_value: null,
|
|
9
|
+
hint: "unique identifier for the pattern feature",
|
|
10
|
+
},
|
|
11
|
+
solids: {
|
|
12
|
+
type: "reference_selection",
|
|
13
|
+
selectionFilter: ["SOLID"],
|
|
14
|
+
multiple: true,
|
|
15
|
+
default_value: [],
|
|
16
|
+
hint: "Select solids to pattern",
|
|
17
|
+
},
|
|
18
|
+
mode: {
|
|
19
|
+
type: "options",
|
|
20
|
+
options: ["LINEAR", "CIRCULAR"],
|
|
21
|
+
default_value: "LINEAR",
|
|
22
|
+
hint: "Pattern type",
|
|
23
|
+
},
|
|
24
|
+
// Linear params
|
|
25
|
+
count: {
|
|
26
|
+
type: "number",
|
|
27
|
+
default_value: 3,
|
|
28
|
+
step: 1,
|
|
29
|
+
hint: "Instance count (>= 1)",
|
|
30
|
+
},
|
|
31
|
+
offset: {
|
|
32
|
+
type: "transform",
|
|
33
|
+
default_value: { position: [10, 0, 0], rotationEuler: [0, 0, 0], scale: [1, 1, 1] },
|
|
34
|
+
label: "Offset (use gizmo)",
|
|
35
|
+
hint: "Use Move gizmo to set direction and distance (position only)",
|
|
36
|
+
},
|
|
37
|
+
// Circular params
|
|
38
|
+
axisRef: {
|
|
39
|
+
type: "reference_selection",
|
|
40
|
+
selectionFilter: ["FACE", "PLANE"],
|
|
41
|
+
multiple: false,
|
|
42
|
+
default_value: null,
|
|
43
|
+
hint: "Axis reference (FACE normal or plane normal through its centroid)",
|
|
44
|
+
},
|
|
45
|
+
centerOffset: {
|
|
46
|
+
type: "number",
|
|
47
|
+
default_value: 0,
|
|
48
|
+
hint: "Offset along axis from reference origin to pattern center",
|
|
49
|
+
},
|
|
50
|
+
totalAngleDeg: {
|
|
51
|
+
type: "number",
|
|
52
|
+
default_value: 360,
|
|
53
|
+
hint: "Total sweep angle for CIRCULAR",
|
|
54
|
+
},
|
|
55
|
+
booleanMode: {
|
|
56
|
+
type: "options",
|
|
57
|
+
options: ["NONE", "UNION"],
|
|
58
|
+
default_value: "NONE",
|
|
59
|
+
hint: "Optionally union instances together",
|
|
60
|
+
},
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
export class PatternFeature {
|
|
64
|
+
static shortName = "PATTERN";
|
|
65
|
+
static longName = "Pattern";
|
|
66
|
+
static inputParamsSchema = inputParamsSchema;
|
|
67
|
+
|
|
68
|
+
constructor() {
|
|
69
|
+
this.inputParams = {};
|
|
70
|
+
this.persistentData = {};
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
async run(partHistory) {
|
|
74
|
+
// Tolerant: accept SOLID directly, or objects with parentSolid
|
|
75
|
+
const raw = Array.isArray(this.inputParams.solids) ? this.inputParams.solids.filter(Boolean) : [];
|
|
76
|
+
const solids = [];
|
|
77
|
+
for (const o of raw) {
|
|
78
|
+
if (!o) continue;
|
|
79
|
+
if (o.type === 'SOLID') solids.push(o);
|
|
80
|
+
else if (o.parentSolid && o.parentSolid.type === 'SOLID') solids.push(o.parentSolid);
|
|
81
|
+
else if (o.parent && o.parent.type === 'SOLID') solids.push(o.parent);
|
|
82
|
+
}
|
|
83
|
+
if (solids.length === 0) {
|
|
84
|
+
console.warn('[PatternFeature] No solids resolved from selection.');
|
|
85
|
+
}
|
|
86
|
+
if (!solids.length) return { added: [], removed: [] };
|
|
87
|
+
|
|
88
|
+
const mode = (this.inputParams.mode || 'LINEAR').toUpperCase();
|
|
89
|
+
const count = Math.max(1, (this.inputParams.count | 0));
|
|
90
|
+
const booleanMode = (this.inputParams.booleanMode || 'NONE').toUpperCase();
|
|
91
|
+
|
|
92
|
+
// Fallbacks: if no solids resolved, try currently selected solids; else last SOLID in scene
|
|
93
|
+
let sources = solids;
|
|
94
|
+
if (!sources.length && partHistory && partHistory.scene) {
|
|
95
|
+
try {
|
|
96
|
+
const selected = [];
|
|
97
|
+
partHistory.scene.traverse((o) => { if (o && o.type === 'SOLID' && o.selected) selected.push(o); });
|
|
98
|
+
if (selected.length) sources = selected;
|
|
99
|
+
} catch (_) { /* ignore */ }
|
|
100
|
+
if (!sources.length) {
|
|
101
|
+
try {
|
|
102
|
+
const solidsInScene = partHistory.scene.children.filter(ch => ch && ch.type === 'SOLID');
|
|
103
|
+
if (solidsInScene.length) sources = [solidsInScene[solidsInScene.length - 1]]; // most recent
|
|
104
|
+
} catch (_) { /* ignore */ }
|
|
105
|
+
}
|
|
106
|
+
if (!sources.length) console.warn('[PatternFeature] No sources available (selection and scene empty).');
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// BOOLEAN UNION: fuse each source with its generated clones and replace original
|
|
110
|
+
if (booleanMode === 'UNION') {
|
|
111
|
+
const out = [];
|
|
112
|
+
for (const src of sources) {
|
|
113
|
+
const clones = (mode === 'LINEAR')
|
|
114
|
+
? this.#linearPattern(src, count, (this.inputParams.offset && this.inputParams.offset.position) || [10, 0, 0], /*doVisualize*/ false)
|
|
115
|
+
: this.#circularPattern(src, count, this.inputParams.axisRef, Number(this.inputParams.totalAngleDeg) || 360, Number(this.inputParams.centerOffset) || 0, /*doVisualize*/ false);
|
|
116
|
+
|
|
117
|
+
let acc = src;
|
|
118
|
+
for (const c of clones) acc = acc.union(c);
|
|
119
|
+
acc.name = `${src.name || 'Pattern'}::UNION`;
|
|
120
|
+
acc.visualize();
|
|
121
|
+
try { src.__removeFlag = true; } catch {}
|
|
122
|
+
out.push(acc);
|
|
123
|
+
}
|
|
124
|
+
const removedSources = sources.filter(Boolean);
|
|
125
|
+
return { added: out, removed: removedSources };
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// NON-BOOLEAN: return clones as separate bodies
|
|
129
|
+
const instances = [];
|
|
130
|
+
for (const src of sources) {
|
|
131
|
+
const clones = (mode === 'LINEAR')
|
|
132
|
+
? this.#linearPattern(src, count, (this.inputParams.offset && this.inputParams.offset.position) || [10, 0, 0])
|
|
133
|
+
: this.#circularPattern(src, count, this.inputParams.axisRef, Number(this.inputParams.totalAngleDeg) || 360, Number(this.inputParams.centerOffset) || 0);
|
|
134
|
+
for (const c of clones) instances.push(c);
|
|
135
|
+
}
|
|
136
|
+
return { added: instances, removed: [] };
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
#linearPattern(src, count, deltaPos, doVisualize = true) {
|
|
140
|
+
const d = toVec3(deltaPos, 10, 0, 0);
|
|
141
|
+
const out = [];
|
|
142
|
+
for (let i = 1; i <= count - 1; i++) {
|
|
143
|
+
const t = new THREE.Matrix4().makeTranslation(d.x * i, d.y * i, d.z * i);
|
|
144
|
+
const c = src.clone();
|
|
145
|
+
c.bakeTransform(t);
|
|
146
|
+
const fallbackId = PatternFeature.shortName || PatternFeature.longName || 'Pattern';
|
|
147
|
+
const featureID = this.inputParams.featureID || fallbackId;
|
|
148
|
+
const idx = i + 1;
|
|
149
|
+
try { retagSolidFaces(c, `${featureID}_${idx}`); } catch (_) {}
|
|
150
|
+
c.name = `${featureID}_${idx}`;
|
|
151
|
+
if (doVisualize) c.visualize();
|
|
152
|
+
out.push(c);
|
|
153
|
+
}
|
|
154
|
+
return out;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
#circularPattern(src, count, axisRef, totalAngleDeg, centerOffset, doVisualize = true) {
|
|
158
|
+
// Determine axis and center from reference
|
|
159
|
+
const ref = Array.isArray(axisRef) ? axisRef[0] : axisRef;
|
|
160
|
+
const plane = computeRefPlane(ref);
|
|
161
|
+
const axis = plane?.normal || new THREE.Vector3(0, 1, 0);
|
|
162
|
+
const center = (plane?.point || new THREE.Vector3()).clone().addScaledVector(axis, centerOffset || 0);
|
|
163
|
+
|
|
164
|
+
const out = [];
|
|
165
|
+
const step = (count <= 1) ? 0 : THREE.MathUtils.degToRad(totalAngleDeg) / count;
|
|
166
|
+
for (let i = 1; i <= count - 1; i++) {
|
|
167
|
+
const theta = step * i;
|
|
168
|
+
const q = new THREE.Quaternion().setFromAxisAngle(axis, theta);
|
|
169
|
+
const RS = new THREE.Matrix4().makeRotationFromQuaternion(q);
|
|
170
|
+
const T1 = new THREE.Matrix4().makeTranslation(center.x, center.y, center.z);
|
|
171
|
+
const T0 = new THREE.Matrix4().makeTranslation(-center.x, -center.y, -center.z);
|
|
172
|
+
const M = new THREE.Matrix4().multiply(T1).multiply(RS).multiply(T0);
|
|
173
|
+
|
|
174
|
+
const c = src.clone();
|
|
175
|
+
c.bakeTransform(M);
|
|
176
|
+
const fallbackId = PatternFeature.shortName || PatternFeature.longName || 'Pattern';
|
|
177
|
+
const featureID = this.inputParams.featureID || fallbackId;
|
|
178
|
+
const idx = i + 1;
|
|
179
|
+
try { retagSolidFaces(c, `${featureID}_${idx}`); } catch (_) {}
|
|
180
|
+
c.name = `${featureID}_${idx}`;
|
|
181
|
+
if (doVisualize) c.visualize();
|
|
182
|
+
out.push(c);
|
|
183
|
+
}
|
|
184
|
+
return out;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
function toVec3(v, dx, dy, dz) {
|
|
189
|
+
if (Array.isArray(v)) return new THREE.Vector3(v[0] ?? dx, v[1] ?? dy, v[2] ?? dz);
|
|
190
|
+
if (v && typeof v === 'object') return new THREE.Vector3(v.x ?? dx, v.y ?? dy, v.z ?? dz);
|
|
191
|
+
return new THREE.Vector3(dx, dy, dz);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
function computeRefPlane(refObj) {
|
|
195
|
+
if (!refObj) return null;
|
|
196
|
+
// FACE: use area-weighted centroid and average normal
|
|
197
|
+
if (refObj.type === 'FACE' && refObj.geometry) {
|
|
198
|
+
const pos = refObj.geometry.getAttribute('position');
|
|
199
|
+
if (!pos || pos.count < 3) return null;
|
|
200
|
+
const a = new THREE.Vector3();
|
|
201
|
+
const b = new THREE.Vector3();
|
|
202
|
+
const c = new THREE.Vector3();
|
|
203
|
+
const centroid = new THREE.Vector3();
|
|
204
|
+
const nAccum = new THREE.Vector3();
|
|
205
|
+
let areaSum = 0;
|
|
206
|
+
const toWorld = (out, i) => out.set(pos.getX(i), pos.getY(i), pos.getZ(i)).applyMatrix4(refObj.matrixWorld);
|
|
207
|
+
const triCount = (pos.count / 3) | 0;
|
|
208
|
+
for (let t = 0; t < triCount; t++) {
|
|
209
|
+
const i0 = 3 * t + 0, i1 = 3 * t + 1, i2 = 3 * t + 2;
|
|
210
|
+
toWorld(a, i0); toWorld(b, i1); toWorld(c, i2);
|
|
211
|
+
const ab = new THREE.Vector3().subVectors(b, a);
|
|
212
|
+
const ac = new THREE.Vector3().subVectors(c, a);
|
|
213
|
+
const cross = new THREE.Vector3().crossVectors(ac, ab);
|
|
214
|
+
const triArea = 0.5 * cross.length();
|
|
215
|
+
if (triArea > 0) {
|
|
216
|
+
centroid.copy(a).add(b).add(c).multiplyScalar(1 / 3);
|
|
217
|
+
nAccum.add(cross);
|
|
218
|
+
areaSum += triArea;
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
if (areaSum <= 0 || nAccum.lengthSq() === 0) return null;
|
|
222
|
+
const point = centroid.multiplyScalar(1); // centroid from last tri (good enough for axis ref)
|
|
223
|
+
const normal = nAccum.normalize();
|
|
224
|
+
return { point, normal };
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
// PLANE: use world position and +Z direction transformed by world quaternion
|
|
228
|
+
try {
|
|
229
|
+
const point = new THREE.Vector3();
|
|
230
|
+
refObj.getWorldPosition(point);
|
|
231
|
+
const q = new THREE.Quaternion();
|
|
232
|
+
refObj.getWorldQuaternion(q);
|
|
233
|
+
const normal = new THREE.Vector3(0, 0, 1).applyQuaternion(q).normalize();
|
|
234
|
+
return { point, normal };
|
|
235
|
+
} catch (_) { return null; }
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
// Retag all face labels in a Solid with a unique suffix so IDs remain distinct
|
|
239
|
+
// across patterned instances when booleaned together.
|
|
240
|
+
function retagSolidFaces(solid, suffix) {
|
|
241
|
+
if (!solid || !suffix) return;
|
|
242
|
+
try {
|
|
243
|
+
const oldIdToFace = (solid._idToFaceName instanceof Map) ? solid._idToFaceName : new Map();
|
|
244
|
+
const triIDs = Array.isArray(solid._triIDs) ? solid._triIDs : [];
|
|
245
|
+
const presentIDs = new Set();
|
|
246
|
+
for (const k of oldIdToFace.keys()) presentIDs.add(k);
|
|
247
|
+
if (presentIDs.size === 0 && triIDs.length) { for (const id of triIDs) presentIDs.add(id >>> 0); }
|
|
248
|
+
|
|
249
|
+
const idRemap = new Map();
|
|
250
|
+
const newIdToFace = new Map();
|
|
251
|
+
const newFaceToId = new Map();
|
|
252
|
+
for (const oldID of presentIDs) {
|
|
253
|
+
const fname = oldIdToFace.get(oldID);
|
|
254
|
+
const base = (fname != null) ? String(fname) : `FACE_${oldID}`;
|
|
255
|
+
const tagged = `${base}::${suffix}`;
|
|
256
|
+
const newID = Manifold.reserveIDs(1);
|
|
257
|
+
idRemap.set(oldID, newID);
|
|
258
|
+
newIdToFace.set(newID, tagged);
|
|
259
|
+
newFaceToId.set(tagged, newID);
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
if (triIDs.length && idRemap.size) {
|
|
263
|
+
for (let i = 0; i < triIDs.length; i++) {
|
|
264
|
+
const oldID = triIDs[i] >>> 0;
|
|
265
|
+
const mapped = idRemap.get(oldID);
|
|
266
|
+
if (mapped !== undefined) triIDs[i] = mapped;
|
|
267
|
+
}
|
|
268
|
+
solid._triIDs = triIDs;
|
|
269
|
+
solid._dirty = true;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
solid._idToFaceName = newIdToFace;
|
|
273
|
+
solid._faceNameToID = newFaceToId;
|
|
274
|
+
} catch (_) { /* best-effort */ }
|
|
275
|
+
}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import { BREP } from "../../BREP/BREP.js";
|
|
2
|
+
import { Manifold } from "../../BREP/SolidShared.js";
|
|
3
|
+
const THREE = BREP.THREE;
|
|
4
|
+
|
|
5
|
+
const inputParamsSchema = {
|
|
6
|
+
id: {
|
|
7
|
+
type: "string",
|
|
8
|
+
default_value: null,
|
|
9
|
+
hint: "unique identifier for the pattern feature",
|
|
10
|
+
},
|
|
11
|
+
solids: {
|
|
12
|
+
type: "reference_selection",
|
|
13
|
+
selectionFilter: ["SOLID"],
|
|
14
|
+
multiple: true,
|
|
15
|
+
default_value: [],
|
|
16
|
+
hint: "Select solids to pattern",
|
|
17
|
+
},
|
|
18
|
+
// Linear params
|
|
19
|
+
count: {
|
|
20
|
+
type: "number",
|
|
21
|
+
default_value: 3,
|
|
22
|
+
step: 1,
|
|
23
|
+
hint: "Instance count (>= 1)",
|
|
24
|
+
},
|
|
25
|
+
offset: {
|
|
26
|
+
type: "transform",
|
|
27
|
+
default_value: { position: [10, 0, 0], rotationEuler: [0, 0, 0], scale: [1, 1, 1] },
|
|
28
|
+
label: "Offset (use gizmo)",
|
|
29
|
+
hint: "Use Move gizmo to set direction and distance (position only)",
|
|
30
|
+
},
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
export class PatternLinearFeature {
|
|
34
|
+
static shortName = "PATLIN";
|
|
35
|
+
static longName = "Pattern Linear";
|
|
36
|
+
static inputParamsSchema = inputParamsSchema;
|
|
37
|
+
|
|
38
|
+
constructor() {
|
|
39
|
+
this.inputParams = {};
|
|
40
|
+
this.persistentData = {};
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
async run(partHistory) {
|
|
44
|
+
const raw = Array.isArray(this.inputParams.solids) ? this.inputParams.solids.filter(Boolean) : [];
|
|
45
|
+
const solids = [];
|
|
46
|
+
for (const o of raw) {
|
|
47
|
+
if (!o) continue;
|
|
48
|
+
if (o.type === 'SOLID') solids.push(o);
|
|
49
|
+
else if (o.parentSolid && o.parentSolid.type === 'SOLID') solids.push(o.parentSolid);
|
|
50
|
+
else if (o.parent && o.parent.type === 'SOLID') solids.push(o.parent);
|
|
51
|
+
}
|
|
52
|
+
if (!solids.length) return { added: [], removed: [] };
|
|
53
|
+
|
|
54
|
+
const count = Math.max(1, (this.inputParams.count | 0));
|
|
55
|
+
const d = toVec3(this.inputParams.offset?.position, 10, 0, 0);
|
|
56
|
+
|
|
57
|
+
const instances = [];
|
|
58
|
+
const fallbackId = PatternLinearFeature.shortName || PatternLinearFeature.longName || 'PatternLinear';
|
|
59
|
+
const featureID = this.inputParams.featureID || fallbackId;
|
|
60
|
+
for (const src of solids) {
|
|
61
|
+
for (let i = 1; i <= count - 1; i++) {
|
|
62
|
+
const t = new THREE.Matrix4().makeTranslation(d.x * i, d.y * i, d.z * i);
|
|
63
|
+
const c = src.clone();
|
|
64
|
+
c.bakeTransform(t);
|
|
65
|
+
const idx = i + 1;
|
|
66
|
+
try { retagSolidFaces(c, `${featureID}_${idx}`); } catch (_) {}
|
|
67
|
+
c.name = `${featureID}_${idx}`;
|
|
68
|
+
c.visualize();
|
|
69
|
+
instances.push(c);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
return { added: instances, removed: [] };
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function toVec3(v, dx, dy, dz) {
|
|
77
|
+
if (Array.isArray(v)) return new THREE.Vector3(v[0] ?? dx, v[1] ?? dy, v[2] ?? dz);
|
|
78
|
+
if (v && typeof v === 'object') return new THREE.Vector3(v.x ?? dx, v.y ?? dy, v.z ?? dz);
|
|
79
|
+
return new THREE.Vector3(dx, dy, dz);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function retagSolidFaces(solid, suffix) {
|
|
83
|
+
if (!solid || !suffix) return;
|
|
84
|
+
try {
|
|
85
|
+
const oldIdToFace = (solid._idToFaceName instanceof Map) ? solid._idToFaceName : new Map();
|
|
86
|
+
const triIDs = Array.isArray(solid._triIDs) ? solid._triIDs : [];
|
|
87
|
+
// Build set of IDs present (prefer map keys, fall back to triIDs)
|
|
88
|
+
const presentIDs = new Set();
|
|
89
|
+
for (const k of oldIdToFace.keys()) presentIDs.add(k);
|
|
90
|
+
if (presentIDs.size === 0 && triIDs.length) { for (const id of triIDs) presentIDs.add(id >>> 0); }
|
|
91
|
+
|
|
92
|
+
// Map oldID -> newID; and build new maps with tagged names
|
|
93
|
+
const idRemap = new Map();
|
|
94
|
+
const newIdToFace = new Map();
|
|
95
|
+
const newFaceToId = new Map();
|
|
96
|
+
for (const oldID of presentIDs) {
|
|
97
|
+
const fname = oldIdToFace.get(oldID);
|
|
98
|
+
const base = (fname != null) ? String(fname) : `FACE_${oldID}`;
|
|
99
|
+
const tagged = `${base}::${suffix}`;
|
|
100
|
+
const newID = Manifold.reserveIDs(1);
|
|
101
|
+
idRemap.set(oldID, newID);
|
|
102
|
+
newIdToFace.set(newID, tagged);
|
|
103
|
+
newFaceToId.set(tagged, newID);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// Remap per-triangle IDs
|
|
107
|
+
if (triIDs.length && idRemap.size) {
|
|
108
|
+
for (let i = 0; i < triIDs.length; i++) {
|
|
109
|
+
const oldID = triIDs[i] >>> 0;
|
|
110
|
+
const mapped = idRemap.get(oldID);
|
|
111
|
+
if (mapped !== undefined) triIDs[i] = mapped;
|
|
112
|
+
}
|
|
113
|
+
solid._triIDs = triIDs;
|
|
114
|
+
solid._dirty = true; // force rebuild so MeshGL.faceID updates
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
solid._idToFaceName = newIdToFace;
|
|
118
|
+
solid._faceNameToID = newFaceToId;
|
|
119
|
+
} catch (_) { /* best-effort */ }
|
|
120
|
+
}
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
import { BREP } from "../../BREP/BREP.js";
|
|
2
|
+
import { Manifold } from "../../BREP/SolidShared.js";
|
|
3
|
+
const THREE = BREP.THREE;
|
|
4
|
+
|
|
5
|
+
const inputParamsSchema = {
|
|
6
|
+
id: {
|
|
7
|
+
type: "string",
|
|
8
|
+
default_value: null,
|
|
9
|
+
hint: "unique identifier for the pattern feature",
|
|
10
|
+
},
|
|
11
|
+
solids: {
|
|
12
|
+
type: "reference_selection",
|
|
13
|
+
selectionFilter: ["SOLID"],
|
|
14
|
+
multiple: true,
|
|
15
|
+
default_value: [],
|
|
16
|
+
hint: "Select solids to pattern",
|
|
17
|
+
},
|
|
18
|
+
// Radial params (similar to Revolve)
|
|
19
|
+
axisRef: {
|
|
20
|
+
type: "reference_selection",
|
|
21
|
+
selectionFilter: ["EDGE"],
|
|
22
|
+
multiple: false,
|
|
23
|
+
default_value: null,
|
|
24
|
+
label: 'Axis',
|
|
25
|
+
hint: "Select an EDGE to define the radial axis",
|
|
26
|
+
},
|
|
27
|
+
centerOffset: {
|
|
28
|
+
type: "number",
|
|
29
|
+
default_value: 0,
|
|
30
|
+
label: 'Axis Offset',
|
|
31
|
+
hint: "Offset along axis from reference origin to pattern center",
|
|
32
|
+
},
|
|
33
|
+
count: {
|
|
34
|
+
type: "number",
|
|
35
|
+
default_value: 3,
|
|
36
|
+
step: 1,
|
|
37
|
+
label: 'Instances',
|
|
38
|
+
hint: "Instance count (>= 1)",
|
|
39
|
+
},
|
|
40
|
+
totalAngleDeg: {
|
|
41
|
+
type: "number",
|
|
42
|
+
default_value: 360,
|
|
43
|
+
label: 'Angle (deg)',
|
|
44
|
+
hint: "Total sweep angle",
|
|
45
|
+
},
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
export class PatternRadialFeature {
|
|
49
|
+
static shortName = "PATRAD";
|
|
50
|
+
static longName = "Pattern Radial";
|
|
51
|
+
static inputParamsSchema = inputParamsSchema;
|
|
52
|
+
|
|
53
|
+
constructor() {
|
|
54
|
+
this.inputParams = {};
|
|
55
|
+
this.persistentData = {};
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
async run(partHistory) {
|
|
59
|
+
const raw = Array.isArray(this.inputParams.solids) ? this.inputParams.solids.filter(Boolean) : [];
|
|
60
|
+
const solids = [];
|
|
61
|
+
for (const o of raw) {
|
|
62
|
+
if (!o) continue;
|
|
63
|
+
if (o.type === 'SOLID') solids.push(o);
|
|
64
|
+
else if (o.parentSolid && o.parentSolid.type === 'SOLID') solids.push(o.parentSolid);
|
|
65
|
+
else if (o.parent && o.parent.type === 'SOLID') solids.push(o.parent);
|
|
66
|
+
}
|
|
67
|
+
if (!solids.length) return { added: [], removed: [] };
|
|
68
|
+
|
|
69
|
+
const count = Math.max(1, (this.inputParams.count | 0));
|
|
70
|
+
const totalAngleDeg = Number(this.inputParams.totalAngleDeg) || 360;
|
|
71
|
+
const centerOffset = Number(this.inputParams.centerOffset) || 0;
|
|
72
|
+
const ref = Array.isArray(this.inputParams.axisRef) ? this.inputParams.axisRef[0] : this.inputParams.axisRef;
|
|
73
|
+
const axisInfo = computeAxisFromEdge(ref);
|
|
74
|
+
const axis = axisInfo?.dir || new THREE.Vector3(0, 1, 0);
|
|
75
|
+
const center = (axisInfo?.point || new THREE.Vector3()).clone().addScaledVector(axis, centerOffset || 0);
|
|
76
|
+
|
|
77
|
+
const instances = [];
|
|
78
|
+
const fallbackId = PatternRadialFeature.shortName || PatternRadialFeature.longName || 'PatternRadial';
|
|
79
|
+
const featureID = this.inputParams.featureID || fallbackId;
|
|
80
|
+
const step = (count <= 1) ? 0 : THREE.MathUtils.degToRad(totalAngleDeg) / count;
|
|
81
|
+
for (const src of solids) {
|
|
82
|
+
for (let i = 1; i <= count - 1; i++) {
|
|
83
|
+
const theta = step * i;
|
|
84
|
+
const q = new THREE.Quaternion().setFromAxisAngle(axis, theta);
|
|
85
|
+
const RS = new THREE.Matrix4().makeRotationFromQuaternion(q);
|
|
86
|
+
const T1 = new THREE.Matrix4().makeTranslation(center.x, center.y, center.z);
|
|
87
|
+
const T0 = new THREE.Matrix4().makeTranslation(-center.x, -center.y, -center.z);
|
|
88
|
+
const M = new THREE.Matrix4().multiply(T1).multiply(RS).multiply(T0);
|
|
89
|
+
|
|
90
|
+
const c = src.clone();
|
|
91
|
+
c.bakeTransform(M);
|
|
92
|
+
const idx = i + 1;
|
|
93
|
+
try { retagSolidFaces(c, `${featureID}_${idx}`); } catch (_) {}
|
|
94
|
+
c.name = `${featureID}_${idx}`;
|
|
95
|
+
c.visualize();
|
|
96
|
+
instances.push(c);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
return { added: instances, removed: [] };
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function computeAxisFromEdge(edgeObj) {
|
|
104
|
+
if (!edgeObj) return null;
|
|
105
|
+
const THREE = BREP.THREE;
|
|
106
|
+
const mat = edgeObj.matrixWorld;
|
|
107
|
+
let A = new THREE.Vector3(0, 0, 0), B = new THREE.Vector3(0, 1, 0);
|
|
108
|
+
// 1) Prefer cached polyline from visualize()
|
|
109
|
+
const cached = edgeObj?.userData?.polylineLocal;
|
|
110
|
+
const isWorld = !!(edgeObj?.userData?.polylineWorld);
|
|
111
|
+
if (Array.isArray(cached) && cached.length >= 2) {
|
|
112
|
+
const pick = [];
|
|
113
|
+
for (let i = 0; i < cached.length && pick.length < 2; i++) {
|
|
114
|
+
const p = cached[i];
|
|
115
|
+
if (!pick.length) { pick.push(p); continue; }
|
|
116
|
+
const q = pick[0];
|
|
117
|
+
if (Math.abs(p[0] - q[0]) > 1e-12 || Math.abs(p[1] - q[1]) > 1e-12 || Math.abs(p[2] - q[2]) > 1e-12) pick.push(p);
|
|
118
|
+
}
|
|
119
|
+
if (pick.length >= 2) {
|
|
120
|
+
if (isWorld) {
|
|
121
|
+
A.set(pick[0][0], pick[0][1], pick[0][2]);
|
|
122
|
+
B.set(pick[1][0], pick[1][1], pick[1][2]);
|
|
123
|
+
} else {
|
|
124
|
+
A.set(pick[0][0], pick[0][1], pick[0][2]).applyMatrix4(mat);
|
|
125
|
+
B.set(pick[1][0], pick[1][1], pick[1][2]).applyMatrix4(mat);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
} else {
|
|
129
|
+
// 2) Fat-line instanceStart/instanceEnd
|
|
130
|
+
const aStart = edgeObj?.geometry?.attributes?.instanceStart;
|
|
131
|
+
const aEnd = edgeObj?.geometry?.attributes?.instanceEnd;
|
|
132
|
+
if (aStart && aEnd && aStart.count >= 1) {
|
|
133
|
+
const s = new THREE.Vector3(aStart.getX(0), aStart.getY(0), aStart.getZ(0)).applyMatrix4(mat);
|
|
134
|
+
const e = new THREE.Vector3(aEnd.getX(0), aEnd.getY(0), aEnd.getZ(0)).applyMatrix4(mat);
|
|
135
|
+
A.copy(s); B.copy(e);
|
|
136
|
+
} else {
|
|
137
|
+
// 3) Positions
|
|
138
|
+
const pos = edgeObj?.geometry?.getAttribute?.('position');
|
|
139
|
+
if (pos && pos.count >= 2) {
|
|
140
|
+
const s = new THREE.Vector3(pos.getX(0), pos.getY(0), pos.getZ(0)).applyMatrix4(mat);
|
|
141
|
+
const e = new THREE.Vector3(pos.getX(pos.count - 1), pos.getY(pos.count - 1), pos.getZ(pos.count - 1)).applyMatrix4(mat);
|
|
142
|
+
A.copy(s); B.copy(e);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
const dir = B.clone().sub(A);
|
|
147
|
+
if (dir.lengthSq() < 1e-12) dir.set(0, 1, 0); else dir.normalize();
|
|
148
|
+
return { point: A, dir };
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
function retagSolidFaces(solid, suffix) {
|
|
152
|
+
if (!solid || !suffix) return;
|
|
153
|
+
try {
|
|
154
|
+
const oldIdToFace = (solid._idToFaceName instanceof Map) ? solid._idToFaceName : new Map();
|
|
155
|
+
const triIDs = Array.isArray(solid._triIDs) ? solid._triIDs : [];
|
|
156
|
+
const presentIDs = new Set();
|
|
157
|
+
for (const k of oldIdToFace.keys()) presentIDs.add(k);
|
|
158
|
+
if (presentIDs.size === 0 && triIDs.length) { for (const id of triIDs) presentIDs.add(id >>> 0); }
|
|
159
|
+
|
|
160
|
+
const idRemap = new Map();
|
|
161
|
+
const newIdToFace = new Map();
|
|
162
|
+
const newFaceToId = new Map();
|
|
163
|
+
for (const oldID of presentIDs) {
|
|
164
|
+
const fname = oldIdToFace.get(oldID);
|
|
165
|
+
const base = (fname != null) ? String(fname) : `FACE_${oldID}`;
|
|
166
|
+
const tagged = `${base}::${suffix}`;
|
|
167
|
+
const newID = Manifold.reserveIDs(1);
|
|
168
|
+
idRemap.set(oldID, newID);
|
|
169
|
+
newIdToFace.set(newID, tagged);
|
|
170
|
+
newFaceToId.set(tagged, newID);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
if (triIDs.length && idRemap.size) {
|
|
174
|
+
for (let i = 0; i < triIDs.length; i++) {
|
|
175
|
+
const oldID = triIDs[i] >>> 0;
|
|
176
|
+
const mapped = idRemap.get(oldID);
|
|
177
|
+
if (mapped !== undefined) triIDs[i] = mapped;
|
|
178
|
+
}
|
|
179
|
+
solid._triIDs = triIDs;
|
|
180
|
+
solid._dirty = true;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
solid._idToFaceName = newIdToFace;
|
|
184
|
+
solid._faceNameToID = newFaceToId;
|
|
185
|
+
} catch (_) { /* best-effort */ }
|
|
186
|
+
}
|