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,389 @@
1
+ // ViewCube.js
2
+ // Minimal view cube overlay rendered with scissor viewport.
3
+ // - Syncs orientation with a target camera
4
+ // - Click faces to reorient target camera to axis-aligned views
5
+
6
+ import * as THREE from 'three';
7
+
8
+ export class ViewCube {
9
+ /**
10
+ * @param {Object} opts
11
+ * @param {THREE.WebGLRenderer} opts.renderer
12
+ * @param {THREE.Camera} opts.targetCamera
13
+ * @param {Object} [opts.controls] - ArcballControls (optional)
14
+ * @param {number} [opts.size=110] - widget size in pixels
15
+ * @param {number} [opts.margin=10] - margin from top-right
16
+ */
17
+ constructor({ renderer, targetCamera, controls = null, size = 110, margin = 10, colors = null } = {}) {
18
+ if (!renderer || !targetCamera) throw new Error('ViewCube requires { renderer, targetCamera }');
19
+ this.renderer = renderer;
20
+ this.targetCamera = targetCamera;
21
+ this.controls = controls;
22
+ this.size = size;
23
+ this.margin = margin;
24
+
25
+ // Scene + camera for the cube
26
+ this.scene = new THREE.Scene();
27
+ this.scene.autoUpdate = true;
28
+ this.camera = new THREE.OrthographicCamera(-1, 1, 1, -1, 0.1, 10);
29
+ this.camera.position.set(0, 0, 3);
30
+ this.camera.lookAt(0, 0, 0);
31
+
32
+ // Root that mirrors target camera orientation
33
+ this.root = new THREE.Group();
34
+ this.scene.add(this.root);
35
+
36
+ // Sub-group for picking faces
37
+ this.pickGroup = new THREE.Group();
38
+ this.root.add(this.pickGroup);
39
+
40
+ // Visual cube (subtle base)
41
+ const baseGeom = new THREE.BoxGeometry(1, 1, 1);
42
+ const baseMat = new THREE.MeshBasicMaterial({ color: 0x9a9a9a, opacity: 0.18, transparent: true });
43
+ const baseMesh = new THREE.Mesh(baseGeom, baseMat);
44
+ this.root.add(baseMesh);
45
+
46
+ // Edges for contrast
47
+ try {
48
+ const edges = new THREE.EdgesGeometry(baseGeom);
49
+ const line = new THREE.LineSegments(edges, new THREE.LineBasicMaterial({ color: 0xffffff }));
50
+ this.root.add(line);
51
+ } catch { }
52
+
53
+ // Small helpers for color + label texture
54
+ const hexToRgb = (hex) => ({ r: (hex >> 16) & 255, g: (hex >> 8) & 255, b: hex & 255 });
55
+ const relLuma = (hex) => {
56
+ const { r, g, b } = hexToRgb(hex);
57
+ const s = [r, g, b].map(v => v / 255);
58
+ const lin = (c) => (c <= 0.03928 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4));
59
+ const [R, G, B] = s.map(lin);
60
+ return 0.2126 * R + 0.7152 * G + 0.0722 * B;
61
+ };
62
+ // Convert a CSS color or hex-int to a normalized css hex string and hex-int
63
+ const toCssAndHex = (input) => {
64
+ let css = '#ffffff';
65
+ if (typeof input === 'number') {
66
+ css = `#${input.toString(16).padStart(6, '0')}`;
67
+ } else if (typeof input === 'string') {
68
+ try {
69
+ const c = document.createElement('canvas');
70
+ c.width = c.height = 1;
71
+ const ctx2 = c.getContext('2d');
72
+ ctx2.fillStyle = '#000';
73
+ ctx2.fillStyle = input; // lets canvas parse CSS colors
74
+ const val = ctx2.fillStyle; // canonical string
75
+ if (typeof val === 'string') {
76
+ if (val.startsWith('#')) {
77
+ // #rgb, #rrggbb, or #rrggbbaa
78
+ let hex = val.replace('#', '');
79
+ if (hex.length === 3) hex = hex.split('').map(ch => ch + ch).join('');
80
+ else if (hex.length === 8) hex = hex.slice(0, 6);
81
+ css = `#${hex.toLowerCase()}`;
82
+ } else {
83
+ // rgb/rgba(r,g,b[,a])
84
+ const m = val.match(/rgba?\((\d+)\s*,\s*(\d+)\s*,\s*(\d+)(?:\s*,\s*([0-9.]+))?\)/i);
85
+ if (m) {
86
+ const r = Math.max(0, Math.min(255, parseInt(m[1], 10)));
87
+ const g = Math.max(0, Math.min(255, parseInt(m[2], 10)));
88
+ const b = Math.max(0, Math.min(255, parseInt(m[3], 10)));
89
+ const hex = ((r << 16) | (g << 8) | b).toString(16).padStart(6, '0');
90
+ css = `#${hex}`;
91
+ }
92
+ }
93
+ }
94
+ } catch { }
95
+ }
96
+ const hex = parseInt(css.slice(1), 16) & 0xffffff;
97
+ return { css, hex };
98
+ };
99
+
100
+ // Create a texture with the face color and imprinted label
101
+ const makeFaceTexture = (text, faceColor) => {
102
+ const size = 512; // square to avoid distortion on a square plane
103
+ const canvas = document.createElement('canvas');
104
+ canvas.width = size; canvas.height = size;
105
+ const ctx = canvas.getContext('2d');
106
+ // Background fill
107
+ const { css: faceCss, hex: faceHex } = toCssAndHex(faceColor);
108
+ ctx.fillStyle = faceCss;
109
+ ctx.fillRect(0, 0, size, size);
110
+ // Imprinted text effect: shadow + highlight to look engraved
111
+ const fontSize = 100; // smaller labels for better balance
112
+ ctx.font = `bold ${fontSize}px ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace`;
113
+ ctx.textAlign = 'center';
114
+ ctx.textBaseline = 'middle';
115
+ const cx = size / 2, cy = size / 2;
116
+ const luma = relLuma(faceHex);
117
+ const baseText = luma < 0.45 ? '#f0f0f0' : '#111111';
118
+ const shadow = luma < 0.45 ? 'rgba(0,0,0,0.55)' : 'rgba(0,0,0,0.35)';
119
+ const highlight = luma < 0.45 ? 'rgba(255,255,255,0.35)' : 'rgba(255,255,255,0.55)';
120
+ // Soft inner shadow (dark offset)
121
+ ctx.fillStyle = shadow;
122
+ ctx.fillText(text, cx + 3, cy + 3);
123
+ // Highlight edge (light offset)
124
+ ctx.fillStyle = highlight;
125
+ ctx.fillText(text, cx - 1, cy - 1);
126
+ // Base text color chosen for contrast
127
+ ctx.fillStyle = baseText;
128
+ ctx.fillText(text, cx, cy);
129
+ const tex = new THREE.CanvasTexture(canvas);
130
+ tex.minFilter = THREE.LinearFilter;
131
+ tex.magFilter = THREE.LinearFilter;
132
+ return tex;
133
+ };
134
+
135
+ // Helper: distance from origin so a plane with normal from {0,±1}^3 passes through cube boundary
136
+ const planeOffsetForMask = (maskVec) => {
137
+ const k = Math.abs(maskVec.x) + Math.abs(maskVec.y) + Math.abs(maskVec.z); // 1, 2 or 3
138
+ return 0.5 * Math.sqrt(k);
139
+ };
140
+
141
+ // Face planes for picking + labels (main 6 faces)
142
+ const mkFace = (dir, color, name) => {
143
+ const g = new THREE.PlaneGeometry(0.98, 0.98);
144
+ const m = new THREE.MeshBasicMaterial({ map: makeFaceTexture(name, color), side: THREE.FrontSide });
145
+ const p = new THREE.Mesh(g, m);
146
+ // place at distance where face coincides with cube side (0.5)
147
+ const off = planeOffsetForMask(dir);
148
+ const n = dir.clone().normalize();
149
+ p.position.copy(n.multiplyScalar(off));
150
+ // orient plane to face outward
151
+ const q = new THREE.Quaternion();
152
+ q.setFromUnitVectors(new THREE.Vector3(0, 0, 1), dir.clone().normalize());
153
+ p.quaternion.copy(q);
154
+ p.userData = { dir: dir.clone().normalize(), name };
155
+ p.renderOrder = 1; // draw on top of base box
156
+ this.pickGroup.add(p);
157
+
158
+ return p;
159
+ };
160
+
161
+ // Dark-mode friendly distinct colors for the 6 faces
162
+ // Accept any CSS color string or hex. You can override via constructor
163
+ // with { colors: { faces: { RIGHT: 'tomato', ... }, edge: '...', corner: '...' } }
164
+ const FACE_DEFAULTS = {
165
+ RIGHT: '#ff0000',
166
+ LEFT: '#0055ffff',
167
+ TOP: '#00ff77ff',
168
+ BOTTOM: '#ffb300ff',
169
+ FRONT: '#ff00b7ff',
170
+ BACK: '#00ffe5ff',
171
+ };
172
+ let faceOverrides = {};
173
+ if (colors) {
174
+ if (colors.faces) faceOverrides = colors.faces;
175
+ else if (colors.RIGHT || colors.LEFT || colors.TOP || colors.BOTTOM || colors.FRONT || colors.BACK) faceOverrides = colors;
176
+ }
177
+ const FACE = Object.assign({}, FACE_DEFAULTS, faceOverrides);
178
+
179
+ // Edge/corner colors (define before creating materials)
180
+ const EDGE_COLOR = (colors && colors.edge) || '#ffffffff';
181
+ const CORNER_COLOR = (colors && colors.corner) || '#3a3636ff';
182
+ const EDGE_COLOR_CSS = toCssAndHex(EDGE_COLOR).css;
183
+ const CORNER_COLOR_CSS = toCssAndHex(CORNER_COLOR).css;
184
+ mkFace(new THREE.Vector3(1, 0, 0), FACE.RIGHT, 'RIGHT');
185
+ mkFace(new THREE.Vector3(-1, 0, 0), FACE.LEFT, 'LEFT');
186
+ mkFace(new THREE.Vector3(0, 1, 0), FACE.TOP, 'TOP');
187
+ mkFace(new THREE.Vector3(0, -1, 0), FACE.BOTTOM, 'BOTTOM');
188
+ mkFace(new THREE.Vector3(0, 0, 1), FACE.FRONT, 'FRONT');
189
+ mkFace(new THREE.Vector3(0, 0, -1), FACE.BACK, 'BACK');
190
+
191
+ // Edge faces (12) - beveled rectangles to mimic chamfered edges
192
+ const mkEdge = (normalMask, along, name) => {
193
+ const n = normalMask.clone().normalize();
194
+ const u = along.clone().normalize(); // width axis on the plane (edge direction)
195
+ const v = new THREE.Vector3().crossVectors(n, u).normalize();
196
+ const matBasis = new THREE.Matrix4().makeBasis(u, v, n);
197
+ const q = new THREE.Quaternion().setFromRotationMatrix(matBasis);
198
+ const g = new THREE.PlaneGeometry(0.98, 0.16);
199
+ const m = new THREE.MeshBasicMaterial({ color: EDGE_COLOR_CSS, opacity: 1.0, transparent: false, side: THREE.FrontSide });
200
+ const mesh = new THREE.Mesh(g, m);
201
+ mesh.quaternion.copy(q);
202
+ const off = planeOffsetForMask(normalMask);
203
+ mesh.position.copy(n.clone().multiplyScalar(off));
204
+ mesh.userData = { dir: n.clone(), name };
205
+ mesh.renderOrder = 2;
206
+ this.pickGroup.add(mesh);
207
+ return mesh;
208
+ };
209
+
210
+ // X± Y± edges -> along Z
211
+ mkEdge(new THREE.Vector3(1, 1, 0), new THREE.Vector3(0, 0, 1), 'TOP RIGHT EDGE');
212
+ mkEdge(new THREE.Vector3(-1, 1, 0), new THREE.Vector3(0, 0, 1), 'TOP LEFT EDGE');
213
+ mkEdge(new THREE.Vector3(1, -1, 0), new THREE.Vector3(0, 0, 1), 'BOTTOM RIGHT EDGE');
214
+ mkEdge(new THREE.Vector3(-1, -1, 0), new THREE.Vector3(0, 0, 1), 'BOTTOM LEFT EDGE');
215
+
216
+ // X± Z± edges -> along Y
217
+ mkEdge(new THREE.Vector3(1, 0, 1), new THREE.Vector3(0, 1, 0), 'FRONT RIGHT EDGE');
218
+ mkEdge(new THREE.Vector3(-1, 0, 1), new THREE.Vector3(0, 1, 0), 'FRONT LEFT EDGE');
219
+ mkEdge(new THREE.Vector3(1, 0, -1), new THREE.Vector3(0, 1, 0), 'BACK RIGHT EDGE');
220
+ mkEdge(new THREE.Vector3(-1, 0, -1), new THREE.Vector3(0, 1, 0), 'BACK LEFT EDGE');
221
+
222
+ // Y± Z± edges -> along X
223
+ mkEdge(new THREE.Vector3(0, 1, 1), new THREE.Vector3(1, 0, 0), 'TOP FRONT EDGE');
224
+ mkEdge(new THREE.Vector3(0, -1, 1), new THREE.Vector3(1, 0, 0), 'BOTTOM FRONT EDGE');
225
+ mkEdge(new THREE.Vector3(0, 1, -1), new THREE.Vector3(1, 0, 0), 'TOP BACK EDGE');
226
+ mkEdge(new THREE.Vector3(0, -1, -1), new THREE.Vector3(1, 0, 0), 'BOTTOM BACK EDGE');
227
+
228
+ // Corner knobs for isometric views (clickable)
229
+ // Slightly protruding spheres at cube corners, each maps to a diagonal view
230
+ const mkCorner = (dirMask, color, name) => {
231
+ const n = dirMask.clone().normalize();
232
+ // Triangular disk to resemble a chamfered corner
233
+ const g = new THREE.CircleGeometry(0.14, 3);
234
+ const m = new THREE.MeshBasicMaterial({ color: CORNER_COLOR_CSS, opacity: 1.0, transparent: false, side: THREE.FrontSide });
235
+ const tri = new THREE.Mesh(g, m);
236
+ // Build basis so X axis is some stable vector in the plane
237
+ let u = new THREE.Vector3(0, 1, 0);
238
+ if (Math.abs(n.dot(u)) > 0.9) u = new THREE.Vector3(1, 0, 0); // avoid parallel
239
+ u = new THREE.Vector3().crossVectors(u, n).normalize();
240
+ const v = new THREE.Vector3().crossVectors(n, u).normalize();
241
+ const matBasis = new THREE.Matrix4().makeBasis(u, v, n);
242
+ const q = new THREE.Quaternion().setFromRotationMatrix(matBasis);
243
+ tri.quaternion.copy(q);
244
+ const off = planeOffsetForMask(dirMask);
245
+ tri.position.copy(n.clone().multiplyScalar(off));
246
+ tri.userData = { dir: n, name };
247
+ tri.renderOrder = 3;
248
+ this.pickGroup.add(tri);
249
+ return tri;
250
+ };
251
+
252
+ // Define all 8 corners with readable names
253
+ const C = (x, y, z) => new THREE.Vector3(x, y, z);
254
+ mkCorner(C(1, 1, 1), CORNER_COLOR, 'TOP FRONT RIGHT');
255
+ mkCorner(C(-1, 1, 1), CORNER_COLOR, 'TOP FRONT LEFT');
256
+ mkCorner(C(1, 1, -1), CORNER_COLOR, 'TOP BACK RIGHT');
257
+ mkCorner(C(-1, 1, -1), CORNER_COLOR, 'TOP BACK LEFT');
258
+ mkCorner(C(1, -1, 1), CORNER_COLOR, 'BOTTOM FRONT RIGHT');
259
+ mkCorner(C(-1, -1, 1), CORNER_COLOR, 'BOTTOM FRONT LEFT');
260
+ mkCorner(C(1, -1, -1), CORNER_COLOR, 'BOTTOM BACK RIGHT');
261
+ mkCorner(C(-1, -1, -1), CORNER_COLOR, 'BOTTOM BACK LEFT');
262
+
263
+ // Soft ambient to ensure steady colors regardless of renderer state
264
+ const amb = new THREE.AmbientLight(0xffffff, 0.9);
265
+ this.scene.add(amb);
266
+
267
+ // Raycaster for cube picking
268
+ this._raycaster = new THREE.Raycaster();
269
+ }
270
+
271
+ // Keep cube orientation in sync with target camera
272
+ syncWithCamera() {
273
+ if (!this.targetCamera) return;
274
+ // Use the inverse of the target camera's rotation so the widget
275
+ // represents world orientation as seen from the camera (avoids mirroring).
276
+ this.root.quaternion.copy(this.targetCamera.quaternion).invert();
277
+ }
278
+
279
+ // Compute viewport rectangle (bottom-right). Returns both CSS(top-left) and GL(bottom-left) coords.
280
+ _viewportRect() {
281
+ const el = this.renderer.domElement;
282
+ const width = el.clientWidth || 1;
283
+ const height = el.clientHeight || 1;
284
+ const w = Math.min(this.size, width);
285
+ const h = Math.min(this.size, height);
286
+ const xCss = width - w - this.margin; // from top-left
287
+ const yCss = height - h - this.margin; // bottom-right in CSS coords
288
+ const xGL = xCss; // same horizontally
289
+ const yGL = this.margin; // bottom margin in GL coords
290
+ return { xCss, yCss, xGL, yGL, w, h, width, height };
291
+ }
292
+
293
+ // Render the view cube using scissor in the top-right corner
294
+ render() {
295
+ const { xGL, yGL, w, h, width, height } = this._viewportRect();
296
+ const r = this.renderer;
297
+ const prev = {
298
+ scissorTest: r.getScissorTest && r.getScissorTest(),
299
+ autoClear: r.autoClear,
300
+ };
301
+
302
+ // Update camera for aspect
303
+ const aspect = w / h || 1;
304
+ this.camera.left = -1 * aspect;
305
+ this.camera.right = 1 * aspect;
306
+ this.camera.top = 1;
307
+ this.camera.bottom = -1;
308
+ this.camera.updateProjectionMatrix();
309
+
310
+ // Render cube without clearing color to keep background transparent
311
+ r.setScissorTest(true);
312
+ r.autoClear = false;
313
+ r.setScissor(xGL, yGL, w, h);
314
+ r.setViewport(xGL, yGL, w, h);
315
+ r.clearDepth();
316
+ this.syncWithCamera();
317
+ r.render(this.scene, this.camera);
318
+
319
+ // Restore viewport/scissor for main renderer
320
+ r.setViewport(0, 0, width, height);
321
+ r.setScissor(0, 0, width, height);
322
+ r.setScissorTest(!!prev.scissorTest);
323
+ r.autoClear = prev.autoClear;
324
+ }
325
+
326
+ // Check if a DOM pointer event is inside the cube viewport
327
+ isEventInside(event) {
328
+ const rect = this._viewportRect();
329
+ const elRect = this.renderer.domElement.getBoundingClientRect();
330
+ const px = event.clientX - elRect.left;
331
+ const py = event.clientY - elRect.top;
332
+ return (px >= rect.xCss && px <= rect.xCss + rect.w &&
333
+ py >= rect.yCss && py <= rect.yCss + rect.h);
334
+ }
335
+
336
+ // Attempt to handle a click; returns true if consumed
337
+ handleClick(event) {
338
+ if (!this.isEventInside(event)) return false;
339
+ const { xCss, yCss, w, h } = this._viewportRect();
340
+ const elRect = this.renderer.domElement.getBoundingClientRect();
341
+ const cx = event.clientX - elRect.left;
342
+ const cy = event.clientY - elRect.top;
343
+ const nx = ((cx - xCss) / w) * 2 - 1;
344
+ const ny = -((cy - yCss) / h) * 2 + 1;
345
+ const ndc = new THREE.Vector2(nx, ny);
346
+
347
+ this._raycaster.setFromCamera(ndc, this.camera);
348
+ const intersects = this._raycaster.intersectObjects(this.pickGroup.children, false);
349
+ if (intersects && intersects.length) {
350
+ const face = intersects[0].object;
351
+ const dir = face?.userData?.dir;
352
+ const name = face?.userData?.name || '';
353
+ if (dir) this._reorientCamera(dir, name);
354
+ return true;
355
+ }
356
+ return false;
357
+ }
358
+
359
+ _reorientCamera(dir, faceName = '') {
360
+ const cam = this.targetCamera;
361
+ if (!cam) return;
362
+
363
+ // Determine current pivot (ArcballControls center) and keep distance to it
364
+ const pivot = (this.controls && this.controls._gizmos && this.controls._gizmos.position)
365
+ ? this.controls._gizmos.position.clone()
366
+ : new THREE.Vector3(0, 0, 0);
367
+ const dist = cam.position.distanceTo(pivot) || cam.position.length() || 10;
368
+ const pos = pivot.clone().add(dir.clone().normalize().multiplyScalar(dist));
369
+
370
+ // Choose a stable up vector for the final view
371
+ const useZup = Math.abs(dir.y) > 0.9; // top/bottom -> Z up to avoid roll
372
+ const up = useZup ? new THREE.Vector3(0, 0, 1) : new THREE.Vector3(0, 1, 0);
373
+
374
+ const toPos = pos;
375
+
376
+ // Immediate reorientation: absolute pose using lookAt toward pivot
377
+ cam.position.copy(toPos);
378
+ cam.up.copy(up);
379
+ cam.lookAt(pivot);
380
+ cam.updateMatrixWorld(true);
381
+
382
+ // Sync controls to the new absolute state
383
+ const controls = this.controls;
384
+ if (controls && controls.updateMatrixState) {
385
+ try { controls.updateMatrixState(); } catch { }
386
+ }
387
+ if (controls) controls.enabled = true;
388
+ }
389
+ }