@faicad/faijs 0.22.2 → 0.29.5
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 +202 -28
- package/dist/api/api-namespace.d.ts +5 -5
- package/dist/api/api-namespace.d.ts.map +1 -1
- package/dist/api/api-namespace.js +4 -4
- package/dist/api/api-namespace.js.map +1 -1
- package/dist/api/appearance.d.ts +138 -0
- package/dist/api/appearance.d.ts.map +1 -0
- package/dist/api/appearance.js +230 -0
- package/dist/api/appearance.js.map +1 -0
- package/dist/api/assert.d.ts +2 -2
- package/dist/api/assert.js +8 -8
- package/dist/api/assert.js.map +1 -1
- package/dist/api/asset.d.ts +1 -1
- package/dist/api/asset.js +2 -2
- package/dist/api/asset.js.map +1 -1
- package/dist/api/boolean.d.ts +1 -1
- package/dist/api/boolean.d.ts.map +1 -1
- package/dist/api/boolean.js +128 -16
- package/dist/api/boolean.js.map +1 -1
- package/dist/api/cadquery-selectors/borrow-bridge.d.ts +14 -0
- package/dist/api/cadquery-selectors/borrow-bridge.d.ts.map +1 -0
- package/dist/api/cadquery-selectors/borrow-bridge.js +52 -0
- package/dist/api/cadquery-selectors/borrow-bridge.js.map +1 -0
- package/dist/api/cadquery-selectors/edge.d.ts +40 -0
- package/dist/api/cadquery-selectors/edge.d.ts.map +1 -0
- package/dist/api/cadquery-selectors/edge.js +70 -0
- package/dist/api/cadquery-selectors/edge.js.map +1 -0
- package/dist/api/cadquery-selectors/entity.d.ts +121 -0
- package/dist/api/cadquery-selectors/entity.d.ts.map +1 -0
- package/dist/api/cadquery-selectors/entity.js +167 -0
- package/dist/api/cadquery-selectors/entity.js.map +1 -0
- package/dist/api/cadquery-selectors/face.d.ts +33 -0
- package/dist/api/cadquery-selectors/face.d.ts.map +1 -0
- package/dist/api/cadquery-selectors/face.js +353 -0
- package/dist/api/cadquery-selectors/face.js.map +1 -0
- package/dist/api/cadquery-selectors/grammar.d.ts +50 -0
- package/dist/api/cadquery-selectors/grammar.d.ts.map +1 -0
- package/dist/api/cadquery-selectors/grammar.js +345 -0
- package/dist/api/cadquery-selectors/grammar.js.map +1 -0
- package/dist/api/cadquery-selectors/index.d.ts +18 -0
- package/dist/api/cadquery-selectors/index.d.ts.map +1 -0
- package/dist/api/cadquery-selectors/index.js +17 -0
- package/dist/api/cadquery-selectors/index.js.map +1 -0
- package/dist/api/cadquery-selectors/predicates.d.ts +76 -0
- package/dist/api/cadquery-selectors/predicates.d.ts.map +1 -0
- package/dist/api/cadquery-selectors/predicates.js +85 -0
- package/dist/api/cadquery-selectors/predicates.js.map +1 -0
- package/dist/api/cadquery-selectors/resolve.d.ts +41 -0
- package/dist/api/cadquery-selectors/resolve.d.ts.map +1 -0
- package/dist/api/cadquery-selectors/resolve.js +243 -0
- package/dist/api/cadquery-selectors/resolve.js.map +1 -0
- package/dist/api/cadquery-selectors/types.d.ts +96 -0
- package/dist/api/cadquery-selectors/types.d.ts.map +1 -0
- package/dist/api/cadquery-selectors/types.js +11 -0
- package/dist/api/cadquery-selectors/types.js.map +1 -0
- package/dist/api/chamfer.d.ts +13 -5
- package/dist/api/chamfer.d.ts.map +1 -1
- package/dist/api/chamfer.js +63 -7
- package/dist/api/chamfer.js.map +1 -1
- package/dist/api/compound-geom.d.ts +1 -1
- package/dist/api/compound-geom.js +1 -1
- package/dist/api/compound-geom.js.map +1 -1
- package/dist/api/draft.d.ts +1 -1
- package/dist/api/draft.js +1 -1
- package/dist/api/draft.js.map +1 -1
- package/dist/api/edge-ref.d.ts +1 -1
- package/dist/api/edge-ref.d.ts.map +1 -1
- package/dist/api/edge-ref.js +11 -3
- package/dist/api/edge-ref.js.map +1 -1
- package/dist/api/engrave.d.ts +1 -1
- package/dist/api/engrave.js +7 -7
- package/dist/api/engrave.js.map +1 -1
- package/dist/api/extrude.d.ts +6 -1
- package/dist/api/extrude.d.ts.map +1 -1
- package/dist/api/extrude.js +59 -5
- package/dist/api/extrude.js.map +1 -1
- package/dist/api/face-ref.d.ts +1 -1
- package/dist/api/face-ref.js +1 -1
- package/dist/api/face-ref.js.map +1 -1
- package/dist/api/feature-repair.d.ts +1 -1
- package/dist/api/feature-repair.js +1 -1
- package/dist/api/feature-repair.js.map +1 -1
- package/dist/api/fillet-variable.d.ts +1 -1
- package/dist/api/fillet-variable.js +1 -1
- package/dist/api/fillet-variable.js.map +1 -1
- package/dist/api/fillet.d.ts +28 -8
- package/dist/api/fillet.d.ts.map +1 -1
- package/dist/api/fillet.js +64 -9
- package/dist/api/fillet.js.map +1 -1
- package/dist/api/geom.d.ts +1 -1
- package/dist/api/geom.js +1 -1
- package/dist/api/geom.js.map +1 -1
- package/dist/api/helix.d.ts +1 -1
- package/dist/api/helix.js +1 -1
- package/dist/api/helix.js.map +1 -1
- package/dist/api/import-brep.d.ts +20 -2
- package/dist/api/import-brep.d.ts.map +1 -1
- package/dist/api/import-brep.js +28 -3
- package/dist/api/import-brep.js.map +1 -1
- package/dist/api/import-step.d.ts +17 -2
- package/dist/api/import-step.d.ts.map +1 -1
- package/dist/api/import-step.js +51 -3
- package/dist/api/import-step.js.map +1 -1
- package/dist/api/index.d.ts +6 -1
- package/dist/api/index.d.ts.map +1 -1
- package/dist/api/index.js +7 -2
- package/dist/api/index.js.map +1 -1
- package/dist/api/internal/compat-op.js +1 -1
- package/dist/api/internal/compat-op.js.map +1 -1
- package/dist/api/internal/mesh-solid-op.d.ts +236 -0
- package/dist/api/internal/mesh-solid-op.d.ts.map +1 -0
- package/dist/api/internal/mesh-solid-op.js +352 -0
- package/dist/api/internal/mesh-solid-op.js.map +1 -0
- package/dist/api/internal/svg-asset-resolver.d.ts +1 -1
- package/dist/api/internal/svg-asset-resolver.js +1 -1
- package/dist/api/internal/svg-asset-resolver.js.map +1 -1
- package/dist/api/knurl.d.ts +1 -1
- package/dist/api/knurl.js +2 -2
- package/dist/api/knurl.js.map +1 -1
- package/dist/api/loft.d.ts +1 -1
- package/dist/api/loft.js +1 -1
- package/dist/api/loft.js.map +1 -1
- package/dist/api/measurement/index.d.ts +9 -5
- package/dist/api/measurement/index.d.ts.map +1 -1
- package/dist/api/measurement/index.js +47 -20
- package/dist/api/measurement/index.js.map +1 -1
- package/dist/api/meta.d.ts +93 -0
- package/dist/api/meta.d.ts.map +1 -0
- package/dist/api/meta.js +99 -0
- package/dist/api/meta.js.map +1 -0
- package/dist/api/pattern.d.ts +5 -3
- package/dist/api/pattern.d.ts.map +1 -1
- package/dist/api/pattern.js +32 -4
- package/dist/api/pattern.js.map +1 -1
- package/dist/api/place.d.ts +1 -1
- package/dist/api/place.js +1 -1
- package/dist/api/place.js.map +1 -1
- package/dist/api/primitives.d.ts +1 -1
- package/dist/api/primitives.d.ts.map +1 -1
- package/dist/api/primitives.js +119 -4
- package/dist/api/primitives.js.map +1 -1
- package/dist/api/profile.d.ts +39 -12
- package/dist/api/profile.d.ts.map +1 -1
- package/dist/api/profile.js +4 -4
- package/dist/api/profile.js.map +1 -1
- package/dist/api/reconcile.d.ts +1 -1
- package/dist/api/reconcile.js +1 -1
- package/dist/api/reconcile.js.map +1 -1
- package/dist/api/replicate.d.ts.map +1 -1
- package/dist/api/replicate.js +122 -1
- package/dist/api/replicate.js.map +1 -1
- package/dist/api/screw.d.ts +1 -1
- package/dist/api/screw.js +3 -3
- package/dist/api/screw.js.map +1 -1
- package/dist/api/sdf.d.ts +1 -1
- package/dist/api/sdf.js +2 -2
- package/dist/api/sdf.js.map +1 -1
- package/dist/api/section-by-plane.d.ts +1 -1
- package/dist/api/section-by-plane.d.ts.map +1 -1
- package/dist/api/section-by-plane.js +2 -1
- package/dist/api/section-by-plane.js.map +1 -1
- package/dist/api/shell.d.ts +11 -4
- package/dist/api/shell.d.ts.map +1 -1
- package/dist/api/shell.js +53 -7
- package/dist/api/shell.js.map +1 -1
- package/dist/api/sketch-on-face.d.ts +41 -0
- package/dist/api/sketch-on-face.d.ts.map +1 -1
- package/dist/api/sketch-on-face.js +100 -1
- package/dist/api/sketch-on-face.js.map +1 -1
- package/dist/api/sketch-on-plane.d.ts +7 -5
- package/dist/api/sketch-on-plane.d.ts.map +1 -1
- package/dist/api/sketch-on-plane.js +6 -7
- package/dist/api/sketch-on-plane.js.map +1 -1
- package/dist/api/split-by-plane.d.ts +1 -1
- package/dist/api/split-by-plane.d.ts.map +1 -1
- package/dist/api/split-by-plane.js +2 -1
- package/dist/api/split-by-plane.js.map +1 -1
- package/dist/api/split.d.ts +1 -1
- package/dist/api/split.js +2 -2
- package/dist/api/split.js.map +1 -1
- package/dist/api/sweep.d.ts +1 -1
- package/dist/api/sweep.js +1 -1
- package/dist/api/sweep.js.map +1 -1
- package/dist/api/thicken.d.ts +1 -1
- package/dist/api/thicken.js +1 -1
- package/dist/api/thicken.js.map +1 -1
- package/dist/api/topo-resolve.d.ts +74 -1
- package/dist/api/topo-resolve.d.ts.map +1 -1
- package/dist/api/topo-resolve.js +180 -2
- package/dist/api/topo-resolve.js.map +1 -1
- package/dist/api/transform.d.ts +5 -1
- package/dist/api/transform.d.ts.map +1 -1
- package/dist/api/transform.js +62 -11
- package/dist/api/transform.js.map +1 -1
- package/dist/api/wire.d.ts +1 -1
- package/dist/api/wire.js +1 -1
- package/dist/api/wire.js.map +1 -1
- package/dist/brep/brep-ops.d.ts +9 -7
- package/dist/brep/brep-ops.d.ts.map +1 -1
- package/dist/brep/brep-ops.js +50 -26
- package/dist/brep/brep-ops.js.map +1 -1
- package/dist/brep/brep-topology.d.ts +5 -4
- package/dist/brep/brep-topology.d.ts.map +1 -1
- package/dist/brep/brep-topology.js +6 -5
- package/dist/brep/brep-topology.js.map +1 -1
- package/dist/brep/effective-deflection.d.ts +35 -0
- package/dist/brep/effective-deflection.d.ts.map +1 -0
- package/dist/brep/effective-deflection.js +49 -0
- package/dist/brep/effective-deflection.js.map +1 -0
- package/dist/brep/engine/adapters/brep-mock.d.ts.map +1 -1
- package/dist/brep/engine/adapters/brep-mock.js +27 -0
- package/dist/brep/engine/adapters/brep-mock.js.map +1 -1
- package/dist/brep/engine/adapters/brepkit.d.ts +18 -0
- package/dist/brep/engine/adapters/brepkit.d.ts.map +1 -1
- package/dist/brep/engine/adapters/brepkit.js +46 -1
- package/dist/brep/engine/adapters/brepkit.js.map +1 -1
- package/dist/brep/engine/adapters/occt.d.ts +1 -1
- package/dist/brep/engine/adapters/occt.d.ts.map +1 -1
- package/dist/brep/engine/adapters/occt.js +4 -2
- package/dist/brep/engine/adapters/occt.js.map +1 -1
- package/dist/brep/engine/primitives.d.ts +29 -7
- package/dist/brep/engine/primitives.d.ts.map +1 -1
- package/dist/brep/engine/primitives.js.map +1 -1
- package/dist/brep/engine/registry.d.ts +24 -1
- package/dist/brep/engine/registry.d.ts.map +1 -1
- package/dist/brep/engine/registry.js +24 -0
- package/dist/brep/engine/registry.js.map +1 -1
- package/dist/brep/engine/types.d.ts +54 -3
- package/dist/brep/engine/types.d.ts.map +1 -1
- package/dist/brep/engine/types.js +10 -0
- package/dist/brep/engine/types.js.map +1 -1
- package/dist/brep/export/export-model.d.ts +40 -0
- package/dist/brep/export/export-model.d.ts.map +1 -1
- package/dist/brep/export/export-model.js +274 -30
- package/dist/brep/export/export-model.js.map +1 -1
- package/dist/brep/export/step-meta-header.d.ts +102 -0
- package/dist/brep/export/step-meta-header.d.ts.map +1 -0
- package/dist/brep/export/step-meta-header.js +225 -0
- package/dist/brep/export/step-meta-header.js.map +1 -0
- package/dist/brep/export/step.d.ts +5 -1
- package/dist/brep/export/step.d.ts.map +1 -1
- package/dist/brep/export/step.js +11 -2
- package/dist/brep/export/step.js.map +1 -1
- package/dist/brep/face-evolution.d.ts +1 -1
- package/dist/brep/face-evolution.d.ts.map +1 -1
- package/dist/brep/face-evolution.js +20 -1
- package/dist/brep/face-evolution.js.map +1 -1
- package/dist/brep/handle-bridge.d.ts +1 -1
- package/dist/brep/handle-bridge.js +1 -1
- package/dist/brep/handle-bridge.js.map +1 -1
- package/dist/brep/mesh-solid.d.ts +218 -0
- package/dist/brep/mesh-solid.d.ts.map +1 -0
- package/dist/brep/mesh-solid.js +229 -0
- package/dist/brep/mesh-solid.js.map +1 -0
- package/dist/brep/text/fontRegistry.d.ts +32 -1
- package/dist/brep/text/fontRegistry.d.ts.map +1 -1
- package/dist/brep/text/fontRegistry.js +51 -1
- package/dist/brep/text/fontRegistry.js.map +1 -1
- package/dist/brep/text/text-to-solid.d.ts.map +1 -1
- package/dist/brep/text/text-to-solid.js +8 -3
- package/dist/brep/text/text-to-solid.js.map +1 -1
- package/dist/brepkit-kernel/brepkitKernel.d.ts +18 -2
- package/dist/brepkit-kernel/brepkitKernel.d.ts.map +1 -1
- package/dist/brepkit-kernel/brepkitKernel.js +449 -123
- package/dist/brepkit-kernel/brepkitKernel.js.map +1 -1
- package/dist/brepkit-kernel/brepkitWasm.d.ts +8 -0
- package/dist/brepkit-kernel/brepkitWasm.d.ts.map +1 -1
- package/dist/brepkit-kernel/brepkitWasm.js +10 -0
- package/dist/brepkit-kernel/brepkitWasm.js.map +1 -1
- package/dist/browser-host/browser-font-provider.d.ts +12 -0
- package/dist/browser-host/browser-font-provider.d.ts.map +1 -1
- package/dist/browser-host/browser-font-provider.js +25 -0
- package/dist/browser-host/browser-font-provider.js.map +1 -1
- package/dist/browser.d.ts +6 -3
- package/dist/browser.d.ts.map +1 -1
- package/dist/browser.js +10 -3
- package/dist/browser.js.map +1 -1
- package/dist/cad-runtime/backend-dispatch.d.ts +28 -3
- package/dist/cad-runtime/backend-dispatch.d.ts.map +1 -1
- package/dist/cad-runtime/backend-dispatch.js +119 -4
- package/dist/cad-runtime/backend-dispatch.js.map +1 -1
- package/dist/cad-runtime/browser-lib-loader.js.map +1 -1
- package/dist/cad-runtime/direct-executor.d.ts +15 -3
- package/dist/cad-runtime/direct-executor.d.ts.map +1 -1
- package/dist/cad-runtime/direct-executor.js +33 -1
- package/dist/cad-runtime/direct-executor.js.map +1 -1
- package/dist/cad-runtime/ports.d.ts +3 -3
- package/dist/cad-runtime/ports.d.ts.map +1 -1
- package/dist/cad-runtime/ports.js.map +1 -1
- package/dist/cad-runtime/preview-exec.d.ts +4 -4
- package/dist/cad-runtime/preview-exec.js +2 -2
- package/dist/cad-runtime/preview-exec.js.map +1 -1
- package/dist/cad-runtime/runtime.d.ts +42 -7
- package/dist/cad-runtime/runtime.d.ts.map +1 -1
- package/dist/cad-runtime/runtime.js +68 -5
- package/dist/cad-runtime/runtime.js.map +1 -1
- package/dist/define-op.d.ts +15 -1
- package/dist/define-op.d.ts.map +1 -1
- package/dist/define-op.js +73 -2
- package/dist/define-op.js.map +1 -1
- package/dist/env-agnostic.d.ts +2 -2
- package/dist/env-agnostic.d.ts.map +1 -1
- package/dist/env-agnostic.js +1 -1
- package/dist/env-agnostic.js.map +1 -1
- package/dist/geometry2d/adapt.d.ts +39 -4
- package/dist/geometry2d/adapt.d.ts.map +1 -1
- package/dist/geometry2d/adapt.js +14 -3
- package/dist/geometry2d/adapt.js.map +1 -1
- package/dist/geometry2d/blueprint.d.ts +2 -2
- package/dist/geometry2d/blueprint.js +2 -2
- package/dist/geometry2d/blueprint.js.map +1 -1
- package/dist/geometry2d/bridge/lift-on-plane.d.ts +18 -8
- package/dist/geometry2d/bridge/lift-on-plane.d.ts.map +1 -1
- package/dist/geometry2d/bridge/lift-on-plane.js +65 -12
- package/dist/geometry2d/bridge/lift-on-plane.js.map +1 -1
- package/dist/geometry2d/bridge/plane.d.ts +17 -0
- package/dist/geometry2d/bridge/plane.d.ts.map +1 -1
- package/dist/geometry2d/bridge/plane.js +22 -0
- package/dist/geometry2d/bridge/plane.js.map +1 -1
- package/dist/geometry2d/curve2d.d.ts +25 -0
- package/dist/geometry2d/curve2d.d.ts.map +1 -1
- package/dist/geometry2d/curve2d.js +41 -5
- package/dist/geometry2d/curve2d.js.map +1 -1
- package/dist/index.d.ts +6 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +10 -3
- package/dist/index.js.map +1 -1
- package/dist/io/bytes-node.d.ts +11 -0
- package/dist/io/bytes-node.d.ts.map +1 -0
- package/dist/io/bytes-node.js +28 -0
- package/dist/io/bytes-node.js.map +1 -0
- package/dist/io/bytes.d.ts +33 -0
- package/dist/io/bytes.d.ts.map +1 -0
- package/dist/io/bytes.js +41 -0
- package/dist/io/bytes.js.map +1 -0
- package/dist/io/fai-zip/container-read.d.ts +102 -0
- package/dist/io/fai-zip/container-read.d.ts.map +1 -0
- package/dist/io/fai-zip/container-read.js +305 -0
- package/dist/io/fai-zip/container-read.js.map +1 -0
- package/dist/io/fai-zip/container-write.d.ts +70 -0
- package/dist/io/fai-zip/container-write.d.ts.map +1 -0
- package/dist/io/fai-zip/container-write.js +186 -0
- package/dist/io/fai-zip/container-write.js.map +1 -0
- package/dist/io/fai-zip/container.d.ts +107 -0
- package/dist/io/fai-zip/container.d.ts.map +1 -0
- package/dist/io/fai-zip/container.js +89 -0
- package/dist/io/fai-zip/container.js.map +1 -0
- package/dist/io/fai-zip/index.d.ts +18 -0
- package/dist/io/fai-zip/index.d.ts.map +1 -0
- package/dist/io/fai-zip/index.js +4 -0
- package/dist/io/fai-zip/index.js.map +1 -0
- package/dist/io/index.d.ts +10 -0
- package/dist/io/index.d.ts.map +1 -0
- package/dist/io/index.js +13 -0
- package/dist/io/index.js.map +1 -0
- package/dist/io/zip.d.ts +68 -0
- package/dist/io/zip.d.ts.map +1 -0
- package/dist/io/zip.js +147 -0
- package/dist/io/zip.js.map +1 -0
- package/dist/lang/code-to-args.d.ts +1 -1
- package/dist/lang/code-to-args.js +1 -1
- package/dist/lang/code-to-args.js.map +1 -1
- package/dist/lang/metadata-extractor.d.ts.map +1 -1
- package/dist/lang/metadata-extractor.js +2 -21
- package/dist/lang/metadata-extractor.js.map +1 -1
- package/dist/lang/statement-summary.d.ts +1 -1
- package/dist/lang/statement-summary.js +1 -1
- package/dist/lang/statement-summary.js.map +1 -1
- package/dist/lang/types.d.ts +6 -7
- package/dist/lang/types.d.ts.map +1 -1
- package/dist/lang/types.js +1 -1
- package/dist/lang/types.js.map +1 -1
- package/dist/mesh/index.d.ts +2 -1
- package/dist/mesh/index.d.ts.map +1 -1
- package/dist/mesh/index.js +2 -1
- package/dist/mesh/index.js.map +1 -1
- package/dist/mesh/io.d.ts +13 -0
- package/dist/mesh/io.d.ts.map +1 -1
- package/dist/mesh/io.js +38 -17
- package/dist/mesh/io.js.map +1 -1
- package/dist/mesh/primitives.d.ts.map +1 -1
- package/dist/mesh/primitives.js +41 -6
- package/dist/mesh/primitives.js.map +1 -1
- package/dist/mesh/reconcile.d.ts +1 -1
- package/dist/mesh/reconcile.js +1 -1
- package/dist/mesh/reconcile.js.map +1 -1
- package/dist/mesh/rigid-transform.d.ts +3 -3
- package/dist/mesh/rigid-transform.js +3 -3
- package/dist/mesh/rigid-transform.js.map +1 -1
- package/dist/mesh/stl-unit.d.ts +24 -0
- package/dist/mesh/stl-unit.d.ts.map +1 -0
- package/dist/mesh/stl-unit.js +17 -0
- package/dist/mesh/stl-unit.js.map +1 -0
- package/dist/mesh/threemf-bambu.d.ts +142 -0
- package/dist/mesh/threemf-bambu.d.ts.map +1 -0
- package/dist/mesh/threemf-bambu.js +334 -0
- package/dist/mesh/threemf-bambu.js.map +1 -0
- package/dist/mesh/threemf-loader.d.ts +65 -7
- package/dist/mesh/threemf-loader.d.ts.map +1 -1
- package/dist/mesh/threemf-loader.js +738 -99
- package/dist/mesh/threemf-loader.js.map +1 -1
- package/dist/mesh/threemf-view.d.ts +71 -0
- package/dist/mesh/threemf-view.d.ts.map +1 -0
- package/dist/mesh/threemf-view.js +100 -0
- package/dist/mesh/threemf-view.js.map +1 -0
- package/dist/mesh/types.d.ts +38 -0
- package/dist/mesh/types.d.ts.map +1 -1
- package/dist/mesh/types.js.map +1 -1
- package/dist/node-host/cli.d.ts +44 -6
- package/dist/node-host/cli.d.ts.map +1 -1
- package/dist/node-host/cli.js +76 -26
- package/dist/node-host/cli.js.map +1 -1
- package/dist/node-host/font-family-index.d.ts +93 -0
- package/dist/node-host/font-family-index.d.ts.map +1 -0
- package/dist/node-host/font-family-index.js +273 -0
- package/dist/node-host/font-family-index.js.map +1 -0
- package/dist/node-host/fs-asset-resolver.d.ts +8 -3
- package/dist/node-host/fs-asset-resolver.d.ts.map +1 -1
- package/dist/node-host/fs-asset-resolver.js +13 -5
- package/dist/node-host/fs-asset-resolver.js.map +1 -1
- package/dist/node-host/index.d.ts +8 -0
- package/dist/node-host/index.d.ts.map +1 -1
- package/dist/node-host/index.js +1 -0
- package/dist/node-host/index.js.map +1 -1
- package/dist/node-host/node-font-provider.d.ts +28 -0
- package/dist/node-host/node-font-provider.d.ts.map +1 -1
- package/dist/node-host/node-font-provider.js +49 -0
- package/dist/node-host/node-font-provider.js.map +1 -1
- package/dist/node.d.ts +1 -0
- package/dist/node.d.ts.map +1 -1
- package/dist/node.js +1 -0
- package/dist/node.js.map +1 -1
- package/dist/occt-kernel/highLevelApi.d.ts +4 -1
- package/dist/occt-kernel/highLevelApi.d.ts.map +1 -1
- package/dist/occt-kernel/highLevelApi.js +4 -2
- package/dist/occt-kernel/highLevelApi.js.map +1 -1
- package/dist/occt-kernel/occt-primitives.d.ts.map +1 -1
- package/dist/occt-kernel/occt-primitives.js +36 -3
- package/dist/occt-kernel/occt-primitives.js.map +1 -1
- package/dist/occt-kernel/occtKernel.d.ts +19 -14
- package/dist/occt-kernel/occtKernel.d.ts.map +1 -1
- package/dist/occt-kernel/occtKernel.js +19 -32
- package/dist/occt-kernel/occtKernel.js.map +1 -1
- package/dist/occt-kernel/stepColorParser.d.ts +18 -0
- package/dist/occt-kernel/stepColorParser.d.ts.map +1 -1
- package/dist/occt-kernel/stepColorParser.js +38 -0
- package/dist/occt-kernel/stepColorParser.js.map +1 -1
- package/dist/occt-kernel/stepMetaParser.d.ts +44 -0
- package/dist/occt-kernel/stepMetaParser.d.ts.map +1 -0
- package/dist/occt-kernel/stepMetaParser.js +166 -0
- package/dist/occt-kernel/stepMetaParser.js.map +1 -0
- package/dist/occt-kernel/topologyExt.d.ts +1 -1
- package/dist/occt-kernel/topologyExt.d.ts.map +1 -1
- package/dist/occt-kernel/topologyExt.js +4 -5
- package/dist/occt-kernel/topologyExt.js.map +1 -1
- package/dist/primitives/text/cjk-font.d.ts +2 -15
- package/dist/primitives/text/cjk-font.d.ts.map +1 -1
- package/dist/primitives/text/cjk-font.js +13 -1
- package/dist/primitives/text/cjk-font.js.map +1 -1
- package/dist/runtime-state.d.ts +85 -9
- package/dist/runtime-state.d.ts.map +1 -1
- package/dist/runtime-state.js +72 -2
- package/dist/runtime-state.js.map +1 -1
- package/dist/sdk.d.ts +3 -3
- package/dist/sdk.d.ts.map +1 -1
- package/dist/sdk.js +5 -5
- package/dist/sdk.js.map +1 -1
- package/dist/shape.d.ts +108 -5
- package/dist/shape.d.ts.map +1 -1
- package/dist/shape.js +130 -3
- package/dist/shape.js.map +1 -1
- package/dist/step/stepMetaParser.d.ts +55 -0
- package/dist/step/stepMetaParser.d.ts.map +1 -0
- package/dist/step/stepMetaParser.js +177 -0
- package/dist/step/stepMetaParser.js.map +1 -0
- package/dist/topology/naming/lineage.d.ts +6 -0
- package/dist/topology/naming/lineage.d.ts.map +1 -1
- package/dist/topology/naming/lineage.js +8 -0
- package/dist/topology/naming/lineage.js.map +1 -1
- package/dist/topology/naming/resolve-edge.d.ts +20 -1
- package/dist/topology/naming/resolve-edge.d.ts.map +1 -1
- package/dist/topology/naming/resolve-edge.js +54 -20
- package/dist/topology/naming/resolve-edge.js.map +1 -1
- package/dist/weapp.d.ts +6 -2
- package/dist/weapp.d.ts.map +1 -1
- package/dist/weapp.js +7 -1
- package/dist/weapp.js.map +1 -1
- package/package.json +19 -3
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { getSolidColorsOrdered } from './stepColorParser.js';
|
|
2
|
-
import {
|
|
2
|
+
import { SEWING_TOLERANCE } from '../tolerance.js';
|
|
3
|
+
import { computeEffectiveDeflection } from '../brep/effective-deflection.js';
|
|
3
4
|
import { mm } from '../units.js';
|
|
4
5
|
// F5 设计意图说明:
|
|
5
6
|
// OCCT WASM 内核是环境级单例,不是实例级。在整个浏览器页面/Node 进程中只应
|
|
@@ -8,7 +9,7 @@ import { mm } from '../units.js';
|
|
|
8
9
|
// 2026-09-26 跨实例共享(随 0.18.2 发布):
|
|
9
10
|
// kernelInstance / initPromise / customInitFn 从"模块级单例"提升为挂在
|
|
10
11
|
// globalThis 上的共享状态(与 runtime-state.ts 的 `__FAICAD_FAIJS_RUNTIME__`
|
|
11
|
-
// 同款设计)。原因:CDN 装载的第三方库(sheetmetal/cq-compat/
|
|
12
|
+
// 同款设计)。原因:CDN 装载的第三方库(sheetmetal/cq-compat/faijs-gears)
|
|
12
13
|
// 在 jsDelivr +esm 打包时把 peer `@faicad/faijs` 外部化为**独立模块实例**
|
|
13
14
|
// (根入口与 /api/ 子路径是不同 URL → 不同 bundle),模块级单例导致:
|
|
14
15
|
// - 库实例的 occt 内核从未初始化 → `occt-wasm kernel not initialized`;
|
|
@@ -66,7 +67,7 @@ export function setOcctWasmInitFn(fn) {
|
|
|
66
67
|
/**
|
|
67
68
|
* Resolve the occt-wasm WASM file path (linker-agnostic).
|
|
68
69
|
*
|
|
69
|
-
* Walks the package exports (occt-wasm@
|
|
70
|
+
* Walks the package exports (occt-wasm@5.6.0 exports "./dist/occt-wasm.wasm"),
|
|
70
71
|
* independent of cwd / hoisting / pnpm|npm linker (verified pattern C).
|
|
71
72
|
* Replaces the old 4-level `..` path guessing + process.cwd() fallback.
|
|
72
73
|
*
|
|
@@ -111,9 +112,16 @@ export async function initOcctWasm() {
|
|
|
111
112
|
// Node.js 环境:从 node_modules 读取 WASM 文件
|
|
112
113
|
if (typeof process !== 'undefined' && process.versions?.node) {
|
|
113
114
|
const { OcctKernel: Ctor } = await import('occt-wasm');
|
|
114
|
-
|
|
115
|
+
// 与 resolveOcctWasmPath 同款:经 process.getBuiltinModule 取 node:fs,
|
|
116
|
+
// 不用 `await import('node:fs')`——后者会被 vite 打包器静态分析 externalize
|
|
117
|
+
// 并在浏览器构建时报 "node:fs has been externalized" warning(本分支运行时
|
|
118
|
+
// 不会在浏览器执行,但打包器仍会对动态 import 字符串告警)。
|
|
119
|
+
const fsBuiltin = process.getBuiltinModule?.('node:fs');
|
|
120
|
+
if (!fsBuiltin) {
|
|
121
|
+
throw new Error('[faijs] occt-wasm init requires Node.js (process.getBuiltinModule)');
|
|
122
|
+
}
|
|
115
123
|
const wasmPath = resolveOcctWasmPath();
|
|
116
|
-
const buf = readFileSync(wasmPath);
|
|
124
|
+
const buf = fsBuiltin.readFileSync(wasmPath);
|
|
117
125
|
const wasmBinary = buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.byteLength);
|
|
118
126
|
s.kernelInstance = await Ctor.init({ wasm: wasmBinary });
|
|
119
127
|
return s.kernelInstance;
|
|
@@ -152,38 +160,16 @@ export function disposeOcctWasm() {
|
|
|
152
160
|
* Compute the effective linear deflection, applying relative scaling
|
|
153
161
|
* exactly as OCCT does internally: `linDefl * bboxDiagonal` when relative=true.
|
|
154
162
|
*
|
|
163
|
+
* 实现已移到引擎中立的 `brep/effective-deflection.ts`(函数体只用
|
|
164
|
+
* `getBoundingBox`,与 OCCT 无关)——此处 re-export 保持既有导入面零迁移。
|
|
165
|
+
* 本模块内部仍要用它,故 import 后再 re-export(纯 re-export 不产生本地绑定)。
|
|
166
|
+
*
|
|
155
167
|
* @param kernel - the OCCT kernel
|
|
156
168
|
* @param shape - the shape whose bounding box drives relative scaling
|
|
157
169
|
* @param options - the requested deflection options
|
|
158
170
|
* @returns the effective linear and angular deflection values
|
|
159
171
|
*/
|
|
160
|
-
export
|
|
161
|
-
const ld = options.linearDeflection ?? DEFAULT_LINEAR_DEFLECTION.as(mm);
|
|
162
|
-
const ad = options.angularDeflection ?? 0.5;
|
|
163
|
-
const relative = options.relative ?? false;
|
|
164
|
-
if (!relative)
|
|
165
|
-
return { linearDeflection: ld, angularDeflection: ad };
|
|
166
|
-
// OCCT: BRepBndLib::AddOptimal → bbox diagonal → deflection *= diagonal
|
|
167
|
-
// 浏览器 WASM 中 compound shape 可能使 getBoundingBox 抛异常,需要容错
|
|
168
|
-
let bb;
|
|
169
|
-
try {
|
|
170
|
-
bb = kernel.getBoundingBox(shape, false);
|
|
171
|
-
}
|
|
172
|
-
catch {
|
|
173
|
-
try {
|
|
174
|
-
bb = kernel.getBoundingBox(shape, true);
|
|
175
|
-
}
|
|
176
|
-
catch {
|
|
177
|
-
// 无法获取 bbox → 返回非相对模式的默认值
|
|
178
|
-
return { linearDeflection: ld, angularDeflection: ad };
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
const dx = bb.xmax - bb.xmin;
|
|
182
|
-
const dy = bb.ymax - bb.ymin;
|
|
183
|
-
const dz = bb.zmax - bb.zmin;
|
|
184
|
-
const diag = Math.sqrt(dx * dx + dy * dy + dz * dz);
|
|
185
|
-
return { linearDeflection: ld * diag, angularDeflection: ad };
|
|
186
|
-
}
|
|
172
|
+
export { computeEffectiveDeflection };
|
|
187
173
|
/**
|
|
188
174
|
* Import a STEP file to ShapeHandle + Mesh (including face groups).
|
|
189
175
|
*
|
|
@@ -314,6 +300,7 @@ function walkLabel(kernel, doc, tag, path, solidColors, ctx) {
|
|
|
314
300
|
labelPath: path,
|
|
315
301
|
name,
|
|
316
302
|
isAssembly: true, // mark as assembly so it becomes a group node
|
|
303
|
+
syntheticGroup: true, // ...but it is NOT an assembly in the file
|
|
317
304
|
isComponent: false,
|
|
318
305
|
shapeHandle: null,
|
|
319
306
|
prototypeKey: null,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"occtKernel.js","sourceRoot":"","sources":["../../src/occt-kernel/occtKernel.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * occt-wasm 封装层 — 替代 occt-import-js\n *\n * 提供 STEP/BREP → Mesh 转换和 Mesh → STEP 导出能力。\n * 利用 occt-wasm 的 meshShape() 获取 faceGroups(面→三角形映射),\n * 利用 wireframe() 获取边折线数据,利用 edgeToFaceMap() 获取边→面关联。\n */\nimport type { OcctKernel, ShapeHandle, Mesh, EdgeData, SurfaceKind, CurveKind, BoundingBox, Vec3, XCAFDocument, LabelInfo, LabelTag } from 'occt-wasm'\n\nimport { getSolidColorsOrdered } from './stepColorParser'\nimport { DEFAULT_LINEAR_DEFLECTION, SEWING_TOLERANCE } from '../tolerance'\nimport { mm } from '../units'\n\n/** A single tessellated mesh produced by the OCCT kernel. */\nexport interface WasmTessellatedMesh {\n positions: Float32Array\n normals: Float32Array\n indices: Uint32Array\n}\n\n/** Result of importing a shape into the OCCT kernel. */\nexport interface WasmImportResult {\n shapeHandle: ShapeHandle\n meshes: WasmTessellatedMesh[]\n meshWithGroups: Mesh\n}\n\n// F5 设计意图说明:\n// OCCT WASM 内核是环境级单例,不是实例级。在整个浏览器页面/Node 进程中只应\n// 初始化一次;多个 CadRuntime 实例共享同一个 kernel 是正确的行为。\n//\n// 2026-09-26 跨实例共享(随 0.18.2 发布):\n// kernelInstance / initPromise / customInitFn 从\"模块级单例\"提升为挂在\n// globalThis 上的共享状态(与 runtime-state.ts 的 `__FAICAD_FAIJS_RUNTIME__`\n// 同款设计)。原因:CDN 装载的第三方库(sheetmetal/cq-compat/fai-cq-gears)\n// 在 jsDelivr +esm 打包时把 peer `@faicad/faijs` 外部化为**独立模块实例**\n// (根入口与 /api/ 子路径是不同 URL → 不同 bundle),模块级单例导致:\n// - 库实例的 occt 内核从未初始化 → `occt-wasm kernel not initialized`;\n// - 各实例持有不同内核 → 句柄不互通 → `meshShape: Invalid shape ID`。\n// 挂在 globalThis 后,任一实例 initOcctWasm() 产出的内核全局可见,句柄互通。\n// 构建期去重(external / dedupe)仍是主手段,这里是兜底(同 runtime-state 注释)。\n\nconst OCCT_KERNEL_KEY = '__FAICAD_FAIJS_OCCT_KERNEL__'\nconst OCCT_KERNEL_STATE_VERSION = 1\n\n/** occt 内核共享状态(跨 faijs 模块实例,浏览器/Node 双环境)。 */\ninterface OcctKernelSharedState {\n stateVersion: number\n kernelInstance: OcctKernel | null\n initPromise: Promise<OcctKernel> | null\n /** 浏览器 host 注入的 OCCT 初始化函数 */\n customInitFn: (() => Promise<OcctKernel>) | null\n}\n\n/**\n * 获取 occt 内核共享状态(单例)。\n *\n * 挂在 globalThis 上是为了让\"两份 faijs 代码\"(宿主 bundle 一份、第三方库\n * 外部化一份)共享同一份内核状态——否则两份 kernelInstance 导致内核各自\n * 初始化、句柄不互通(几何孤岛)。\n *\n * @returns the shared occt kernel state singleton.\n */\nfunction getOcctKernelSharedState(): OcctKernelSharedState {\n const g = globalThis as unknown as Record<string, unknown>\n const existing = g[OCCT_KERNEL_KEY] as OcctKernelSharedState | undefined\n if (existing) {\n if (existing.stateVersion !== OCCT_KERNEL_STATE_VERSION) {\n throw new Error(\n `[faijs] occt kernel state version mismatch: loaded=${existing.stateVersion}, expected=${OCCT_KERNEL_STATE_VERSION}`,\n )\n }\n return existing\n }\n const created: OcctKernelSharedState = {\n stateVersion: OCCT_KERNEL_STATE_VERSION,\n kernelInstance: null,\n initPromise: null,\n customInitFn: null,\n }\n g[OCCT_KERNEL_KEY] = created\n return created\n}\n\n/**\n * Let the browser host inject the OCCT initialization function.\n *\n * The browser host calls this to register its own init logic (dev/prod/CDN/e2e\n * branches); faijs's initOcctWasm() prefers the injected function. 注入的挂点\n * 写入共享状态——任意 faijs 实例(含 CDN 外部化实例)调 initOcctWasm() 时\n * 都优先使用同一份宿主初始化函数。\n *\n * When nothing is injected, initOcctWasm() reads the WASM from node_modules in\n * a Node environment.\n *\n * @param fn - the initialization function to use, or null to clear\n */\nexport function setOcctWasmInitFn(fn: (() => Promise<OcctKernel>) | null): void {\n const s = getOcctKernelSharedState()\n s.customInitFn = fn\n // 挂点变化后丢弃进行中的初始化(下一次 init 用新挂点重来)。\n s.initPromise = null\n}\n\n/**\n * Resolve the occt-wasm WASM file path (linker-agnostic).\n *\n * Walks the package exports (occt-wasm@3.8.4 exports \"./dist/occt-wasm.wasm\"),\n * independent of cwd / hoisting / pnpm|npm linker (verified pattern C).\n * Replaces the old 4-level `..` path guessing + process.cwd() fallback.\n *\n * Lazy-fetches node:module (Node >= 20.16 process.getBuiltinModule): a static\n * `import { createRequire } from 'node:module'` must not be used — occtKernel is\n * on the browser build's (demo vite build) import chain, and a static node:*\n * import would be externalized and error. This function is only called in the\n * Node branch (initOcctWasm); it never runs in a browser environment.\n *\n * @returns the resolved WASM file path\n */\nexport function resolveOcctWasmPath(): string {\n const builtin = (process as { getBuiltinModule?: (id: string) => unknown }).getBuiltinModule?.('node:module') as\n | { createRequire: (filename: string) => { resolve: (id: string) => string } }\n | undefined\n if (!builtin) {\n throw new Error('[faijs] resolveOcctWasmPath requires Node.js (process.getBuiltinModule)')\n }\n return builtin.createRequire(import.meta.url).resolve('occt-wasm/dist/occt-wasm.wasm')\n}\n\n/**\n * Initialize the occt-wasm kernel (singleton).\n *\n * - Node.js test environment: read the WASM file from node_modules, pass an ArrayBuffer.\n * - Development: direct ESM import, Vite resolves node_modules. The WASM file is loaded from public/wasm/occt-wasm.wasm.\n * - Production: dynamically import the whole module + WASM from a CDN.\n *\n * @returns the initialized raw OCCT kernel (native L2 face — NOT BrepEngineApi;\n * the L1 contract face is built separately by createOcctPrimitives()\n * in brep/engine/adapters/occt.ts as an explicit object literal).\n */\nexport async function initOcctWasm(): Promise<OcctKernel> {\n const s = getOcctKernelSharedState()\n if (s.kernelInstance) return s.kernelInstance\n if (s.initPromise) return s.initPromise\n\n s.initPromise = (async () => {\n // 优先使用浏览器 host 注入的初始化函数(共享挂点,跨实例生效)\n if (s.customInitFn) {\n s.kernelInstance = await s.customInitFn()\n return s.kernelInstance\n }\n\n // Node.js 环境:从 node_modules 读取 WASM 文件\n if (typeof process !== 'undefined' && process.versions?.node) {\n const { OcctKernel: Ctor } = await import('occt-wasm')\n const { readFileSync } = await import('node:fs')\n const wasmPath = resolveOcctWasmPath()\n const buf = readFileSync(wasmPath)\n const wasmBinary = buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.byteLength) as ArrayBuffer\n s.kernelInstance = await Ctor.init({ wasm: wasmBinary })\n return s.kernelInstance\n }\n\n throw new Error('initOcctWasm: no init function set and not in Node environment. Call setOcctWasmInitFn() first.')\n })()\n\n return s.initPromise\n}\n\n/**\n * Get the initialized kernel instance (initOcctWasm must be called first).\n *\n * @returns the initialized OCCT kernel\n */\nexport function getKernel(): OcctKernel {\n const k = getOcctKernelSharedState().kernelInstance\n if (!k) throw new Error('occt-wasm kernel not initialized — call initOcctWasm() first')\n return k\n}\n\n/**\n * Native-face alias for getKernel() (plan D3 ②): symmetric with\n * getBrepkitKernel() on the brepkit side. Platform-specific code uses this\n * name; the original getKernel() stays for existing host code.\n */\nexport const getOcctKernel = getKernel\n\n/** Release the kernel instance (call when the app unloads). */\nexport function disposeOcctWasm(): void {\n const s = getOcctKernelSharedState()\n if (s.kernelInstance) {\n s.kernelInstance[Symbol.dispose]()\n s.kernelInstance = null\n s.initPromise = null\n }\n}\n\n/** Options controlling mesh deflection during tessellation. */\nexport interface MeshDeflectionOptions {\n linearDeflection?: number\n angularDeflection?: number\n /** If true, linearDeflection is multiplied by the bounding-box diagonal\n * (matches OCCT's BRepMesh_IncrementalMesh relative=true behaviour). */\n relative?: boolean\n}\n\n/**\n * Compute the effective linear deflection, applying relative scaling\n * exactly as OCCT does internally: `linDefl * bboxDiagonal` when relative=true.\n *\n * @param kernel - the OCCT kernel\n * @param shape - the shape whose bounding box drives relative scaling\n * @param options - the requested deflection options\n * @returns the effective linear and angular deflection values\n */\nexport function computeEffectiveDeflection<S>(\n kernel: { getBoundingBox(shape: S, useTriangulation?: boolean): BoundingBox },\n shape: S,\n options: MeshDeflectionOptions = {},\n): { linearDeflection: number; angularDeflection: number } {\n const ld = options.linearDeflection ?? DEFAULT_LINEAR_DEFLECTION.as(mm)\n const ad = options.angularDeflection ?? 0.5\n const relative = options.relative ?? false\n if (!relative) return { linearDeflection: ld, angularDeflection: ad }\n\n // OCCT: BRepBndLib::AddOptimal → bbox diagonal → deflection *= diagonal\n // 浏览器 WASM 中 compound shape 可能使 getBoundingBox 抛异常,需要容错\n let bb: BoundingBox\n try {\n bb = kernel.getBoundingBox(shape, false)\n } catch {\n try {\n bb = kernel.getBoundingBox(shape, true)\n } catch {\n // 无法获取 bbox → 返回非相对模式的默认值\n return { linearDeflection: ld, angularDeflection: ad }\n }\n }\n const dx = bb.xmax - bb.xmin\n const dy = bb.ymax - bb.ymin\n const dz = bb.zmax - bb.zmin\n const diag = Math.sqrt(dx * dx + dy * dy + dz * dz)\n return { linearDeflection: ld * diag, angularDeflection: ad }\n}\n\n/**\n * Import a STEP file to ShapeHandle + Mesh (including face groups).\n *\n * Uses meshShape() rather than tessellate(), so face-group data is available\n * (each face's triangle range [triStart, triCount, faceHash]).\n *\n * @param stepData - STEP file bytes\n * @param deflection - optional mesh deflection options\n * @returns the import result with shape handle and meshes\n */\nexport async function importStepToMesh(\n stepData: ArrayBuffer | Uint8Array,\n deflection?: MeshDeflectionOptions,\n): Promise<WasmImportResult> {\n const kernel = await initOcctWasm()\n const ab = stepData instanceof Uint8Array ? stepData.buffer.slice(stepData.byteOffset, stepData.byteOffset + stepData.byteLength) as ArrayBuffer : stepData\n const shape = kernel.importStep(ab)\n\n const eff = computeEffectiveDeflection(kernel, shape, deflection)\n const mesh = kernel.meshShape(shape, { linearDeflection: eff.linearDeflection, angularDeflection: eff.angularDeflection })\n\n return {\n shapeHandle: shape,\n meshes: [{\n positions: mesh.positions,\n normals: mesh.normals,\n indices: mesh.indices,\n }],\n meshWithGroups: mesh,\n }\n}\n\n// ── Assembly (XCAF) support ──\n\n/** A node in the XCAF assembly tree (mirrors the STEP_T occurrence concept). */\nexport interface AssemblyPartNode {\n /** Dotted path: 'o0', 'o0.o1', 'o0.o1.o2' — matches STEP_T occurrence path. */\n labelPath: string\n /** XCAF label name (falls back to labelPath if empty). */\n name: string\n /** True if this node is an assembly (has child components). */\n isAssembly: boolean\n /** True if this node is a component reference (leaf part with location). */\n isComponent: boolean\n /** Shape handle with location baked in (for components) or raw shape (for roots).\n * Caller must release this handle. Null for empty assembly labels. */\n shapeHandle: ShapeHandle | null\n /** Deduplication key for prototype shapes (same geometry = same key).\n * Only set for leaf (non-assembly) nodes. */\n prototypeKey: string | null\n /** RGB color [r,g,b] in 0..1 range, or null if no color. */\n color: [number, number, number] | null\n /** Child nodes (recursive). Empty for leaf parts. */\n children: AssemblyPartNode[]\n}\n\nconst IDENTITY_MATRIX = [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0]\n\n/**\n * Import a STEP file via XCAF (STEPCAFControl_Reader), preserving the assembly\n * tree, names, colors, and per-component locations.\n *\n * Unlike `importStepToMesh` (which flattens via STEPControl_Reader.OneShape()),\n * this function returns the full assembly tree structure.\n *\n * The caller is responsible for releasing all shapeHandle values in the tree\n * (use `releaseAssemblyTree`).\n *\n * @param stepData - STEP file bytes\n * @returns the root assembly-part nodes\n */\nexport async function importAssemblyFromStep(\n stepData: ArrayBuffer | Uint8Array,\n): Promise<AssemblyPartNode[]> {\n const kernel = (await initOcctWasm()) as unknown as OcctKernel\n const stepText = stepData instanceof Uint8Array\n ? new TextDecoder().decode(stepData)\n : new TextDecoder().decode(new Uint8Array(stepData))\n\n // Parse sub-shape colors from STEP text (fallback for when XCAF label has no color).\n // STEP files from NX/SolidWorks often store colors as STYLED_ITEM on individual\n // solids rather than on XCAF labels, so getLabelInfo returns hasColor=false.\n const solidColors = getSolidColorsOrdered(stepText)\n\n // XCAFDocument.fromSTEP uses STEPCAFControl_Reader with color/name/layer modes\n const doc = kernel.importXCAFFromSTEP(stepText)\n try {\n const rootTags = doc.getRoots()\n const nodes: AssemblyPartNode[] = []\n const cursor = { idx: 0 }\n for (let i = 0; i < rootTags.length; i++) {\n nodes.push(walkLabel(kernel, doc, rootTags[i], `o${i}`, solidColors, cursor))\n }\n return nodes\n } finally {\n doc.close()\n }\n}\n\n/** Walk-context: tracks the current position in the solidColors array across\n * recursive walkLabel calls so that multi-solid compounds consume colors in order. */\ninterface WalkCtx {\n idx: number\n}\n\nfunction walkLabel(\n kernel: OcctKernel,\n doc: XCAFDocument,\n tag: LabelTag,\n path: string,\n solidColors: ([number, number, number] | null)[],\n ctx: WalkCtx,\n): AssemblyPartNode {\n const info: LabelInfo = doc.getLabelInfo(tag)\n const name = info.name || path\n const color = info.hasColor ? [info.color[0], info.color[1], info.color[2]] as [number, number, number] : null\n\n if (info.isAssembly) {\n const childTags = doc.getChildren(tag)\n const children: AssemblyPartNode[] = []\n for (let i = 0; i < childTags.length; i++) {\n children.push(walkLabel(kernel, doc, childTags[i], `${path}.o${i}`, solidColors, ctx))\n }\n // Assembly nodes have no shape of their own; release if one was returned\n if (info.shapeHandle) kernel.release(info.shapeHandle)\n return {\n labelPath: path,\n name,\n isAssembly: true,\n isComponent: false,\n shapeHandle: null,\n prototypeKey: null,\n color,\n children,\n }\n }\n\n // Leaf component — shapeHandle has location baked in (OCCT GetShape semantics)\n // Check if this is a compound with multiple solids — if so, split into\n // separate child nodes so each solid becomes its own mesh/scene-tree node.\n // This handles STEP files that have a single PRODUCT containing a compound\n // of multiple MANIFOLD_SOLID_BREP entities (common in NX/SolidWorks exports).\n if (info.shapeHandle) {\n const solids = kernel.getSubShapes(info.shapeHandle, 'solid')\n if (solids.length > 1) {\n // Multi-solid compound → split into virtual assembly children\n // Each child gets its own solid shapeHandle (already at correct location\n // because getSubShapes extracts from the located compound).\n const children: AssemblyPartNode[] = []\n for (let si = 0; si < solids.length; si++) {\n const childPath = `${path}.s${si}`\n const childName = `${name} [${si + 1}]`\n let childProtoKey: string | null\n try {\n childProtoKey = String(kernel.hashCode(solids[si], 2147483647))\n } catch {\n childProtoKey = null\n }\n // Use STEP-parsed color if label has no color (sub-shape level color)\n const childColor = color ?? (solidColors[ctx.idx] ?? null)\n ctx.idx++\n children.push({\n labelPath: childPath,\n name: childName,\n isAssembly: false,\n isComponent: true,\n shapeHandle: solids[si],\n prototypeKey: childProtoKey,\n color: childColor,\n children: [],\n })\n }\n // Release the compound shape itself — children hold individual solids\n kernel.release(info.shapeHandle)\n return {\n labelPath: path,\n name,\n isAssembly: true, // mark as assembly so it becomes a group node\n isComponent: false,\n shapeHandle: null,\n prototypeKey: null,\n color,\n children,\n }\n }\n // Single solid (or non-solid) — release the extra sub-shape handles\n for (const s of solids) kernel.release(s)\n }\n\n let prototypeKey: string | null = null\n if (info.shapeHandle) {\n // Get un-located shape for dedup (located with identity = remove location)\n try {\n const unlocated = kernel.located(info.shapeHandle, IDENTITY_MATRIX)\n prototypeKey = String(kernel.hashCode(unlocated, 2147483647))\n kernel.release(unlocated)\n } catch {\n // Fallback: use shapeHandle hash directly (less accurate dedup)\n prototypeKey = String(kernel.hashCode(info.shapeHandle, 2147483647))\n }\n }\n\n // For single-solid leaf parts, also try STEP-parsed color as fallback\n const finalColor = color ?? (solidColors[ctx.idx] ?? null)\n ctx.idx++\n\n return {\n labelPath: path,\n name,\n isAssembly: false,\n isComponent: info.isComponent,\n shapeHandle: info.shapeHandle,\n prototypeKey,\n color: finalColor,\n children: [],\n }\n}\n\n/** Recursively release all shapeHandle values in an assembly tree.\n *\n * @param kernel - the OCCT kernel used to release handles\n * @param nodes - the assembly tree nodes to release\n */\nexport function releaseAssemblyTree(kernel: OcctKernel, nodes: AssemblyPartNode[]): void {\n for (const node of nodes) {\n if (node.shapeHandle) kernel.release(node.shapeHandle)\n if (node.children.length > 0) releaseAssemblyTree(kernel, node.children)\n }\n}\n\n/** Collect all leaf (non-assembly) nodes from an assembly tree.\n *\n * @param nodes - the assembly tree nodes to traverse\n * @returns the collected leaf part nodes in depth-first order\n */\nexport function collectLeafParts(nodes: AssemblyPartNode[]): AssemblyPartNode[] {\n const leaves: AssemblyPartNode[] = []\n function walk(node: AssemblyPartNode) {\n if (node.isAssembly) {\n for (const child of node.children) walk(child)\n } else {\n leaves.push(node)\n }\n }\n for (const node of nodes) walk(node)\n return leaves\n}\n\n/**\n * Import BREP text to ShapeHandle + Mesh.\n *\n * @param brepData - BREP file content as a string\n * @param deflection - optional mesh deflection options\n * @returns the import result with shape handle and meshes\n */\nexport async function importBrepToMesh(\n brepData: string,\n deflection?: MeshDeflectionOptions,\n): Promise<WasmImportResult> {\n const kernel = await initOcctWasm()\n const shape = kernel.fromBREP(brepData)\n\n const eff = computeEffectiveDeflection(kernel, shape, deflection)\n const mesh = kernel.meshShape(shape, { linearDeflection: eff.linearDeflection, angularDeflection: eff.angularDeflection })\n\n return {\n shapeHandle: shape,\n meshes: [{\n positions: mesh.positions,\n normals: mesh.normals,\n indices: mesh.indices,\n }],\n meshWithGroups: mesh,\n }\n}\n\n/**\n * Mesh → STEP export: rebuild a STEP solid from a triangle mesh.\n * Follows the pattern from occt-wasm/examples/stl2step.mjs.\n *\n * @param positions - vertex array [x0,y0,z0, x1,y1,z1, ...]\n * @param indices - index array [i0,i1,i2, i3,i4,i5, ...]\n * @param tolerance - sewing tolerance in mm (default 0.01)\n * @returns the STEP file content string\n */\nexport function meshesToStep(\n positions: Float32Array,\n indices: Uint32Array,\n tolerance = SEWING_TOLERANCE.as(mm),\n): string {\n const kernel = getKernel()\n const faces: ShapeHandle[] = []\n let solid: ShapeHandle | null = null\n\n try {\n for (let i = 0; i < indices.length; i += 3) {\n const ia = indices[i] * 3\n const ib = indices[i + 1] * 3\n const ic = indices[i + 2] * 3\n const face = kernel.buildTriFace(\n { x: positions[ia], y: positions[ia + 1], z: positions[ia + 2] },\n { x: positions[ib], y: positions[ib + 1], z: positions[ib + 2] },\n { x: positions[ic], y: positions[ic + 1], z: positions[ic + 2] },\n )\n faces.push(face)\n }\n\n solid = kernel.sewAndSolidify(faces, tolerance)\n const unified = kernel.unifySameDomain(solid)\n kernel.release(solid)\n solid = unified\n return kernel.exportStep(solid)\n } finally {\n if (solid !== null) kernel.release(solid)\n for (const f of faces) kernel.release(f)\n }\n}\n\n/**\n * Release a shape handle.\n *\n * @param handle - the shape handle to release\n */\nexport function releaseShape(handle: ShapeHandle): void {\n const k = getOcctKernelSharedState().kernelInstance\n if (k) k.release(handle)\n}\n\n/** 导出类型供外部使用 */\nexport type { OcctKernel, ShapeHandle, Mesh, EdgeData, SurfaceKind, CurveKind, BoundingBox, Vec3, XCAFDocument, LabelInfo, LabelTag }\n"]}
|
|
1
|
+
{"version":3,"file":"occtKernel.js","sourceRoot":"","sources":["../../src/occt-kernel/occtKernel.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * occt-wasm 封装层 — 替代 occt-import-js\n *\n * 提供 STEP/BREP → Mesh 转换和 Mesh → STEP 导出能力。\n * 利用 occt-wasm 的 meshShape() 获取 faceGroups(面→三角形映射),\n * 利用 wireframe() 获取边折线数据,利用 edgeToFaceMap() 获取边→面关联。\n */\nimport type { OcctKernel, ShapeHandle, Mesh, EdgeData, SurfaceKind, CurveKind, BoundingBox, Vec3, XCAFDocument, LabelInfo, LabelTag } from 'occt-wasm'\n\nimport { getSolidColorsOrdered } from './stepColorParser'\nimport { SEWING_TOLERANCE } from '../tolerance'\nimport { computeEffectiveDeflection, type MeshDeflectionOptions } from '../brep/effective-deflection'\nimport { mm } from '../units'\n\n/** A single tessellated mesh produced by the OCCT kernel. */\nexport interface WasmTessellatedMesh {\n positions: Float32Array\n normals: Float32Array\n indices: Uint32Array\n}\n\n/** Result of importing a shape into the OCCT kernel. */\nexport interface WasmImportResult {\n shapeHandle: ShapeHandle\n meshes: WasmTessellatedMesh[]\n meshWithGroups: Mesh\n}\n\n// F5 设计意图说明:\n// OCCT WASM 内核是环境级单例,不是实例级。在整个浏览器页面/Node 进程中只应\n// 初始化一次;多个 CadRuntime 实例共享同一个 kernel 是正确的行为。\n//\n// 2026-09-26 跨实例共享(随 0.18.2 发布):\n// kernelInstance / initPromise / customInitFn 从\"模块级单例\"提升为挂在\n// globalThis 上的共享状态(与 runtime-state.ts 的 `__FAICAD_FAIJS_RUNTIME__`\n// 同款设计)。原因:CDN 装载的第三方库(sheetmetal/cq-compat/faijs-gears)\n// 在 jsDelivr +esm 打包时把 peer `@faicad/faijs` 外部化为**独立模块实例**\n// (根入口与 /api/ 子路径是不同 URL → 不同 bundle),模块级单例导致:\n// - 库实例的 occt 内核从未初始化 → `occt-wasm kernel not initialized`;\n// - 各实例持有不同内核 → 句柄不互通 → `meshShape: Invalid shape ID`。\n// 挂在 globalThis 后,任一实例 initOcctWasm() 产出的内核全局可见,句柄互通。\n// 构建期去重(external / dedupe)仍是主手段,这里是兜底(同 runtime-state 注释)。\n\nconst OCCT_KERNEL_KEY = '__FAICAD_FAIJS_OCCT_KERNEL__'\nconst OCCT_KERNEL_STATE_VERSION = 1\n\n/** occt 内核共享状态(跨 faijs 模块实例,浏览器/Node 双环境)。 */\ninterface OcctKernelSharedState {\n stateVersion: number\n kernelInstance: OcctKernel | null\n initPromise: Promise<OcctKernel> | null\n /** 浏览器 host 注入的 OCCT 初始化函数 */\n customInitFn: (() => Promise<OcctKernel>) | null\n}\n\n/**\n * 获取 occt 内核共享状态(单例)。\n *\n * 挂在 globalThis 上是为了让\"两份 faijs 代码\"(宿主 bundle 一份、第三方库\n * 外部化一份)共享同一份内核状态——否则两份 kernelInstance 导致内核各自\n * 初始化、句柄不互通(几何孤岛)。\n *\n * @returns the shared occt kernel state singleton.\n */\nfunction getOcctKernelSharedState(): OcctKernelSharedState {\n const g = globalThis as unknown as Record<string, unknown>\n const existing = g[OCCT_KERNEL_KEY] as OcctKernelSharedState | undefined\n if (existing) {\n if (existing.stateVersion !== OCCT_KERNEL_STATE_VERSION) {\n throw new Error(\n `[faijs] occt kernel state version mismatch: loaded=${existing.stateVersion}, expected=${OCCT_KERNEL_STATE_VERSION}`,\n )\n }\n return existing\n }\n const created: OcctKernelSharedState = {\n stateVersion: OCCT_KERNEL_STATE_VERSION,\n kernelInstance: null,\n initPromise: null,\n customInitFn: null,\n }\n g[OCCT_KERNEL_KEY] = created\n return created\n}\n\n/**\n * Let the browser host inject the OCCT initialization function.\n *\n * The browser host calls this to register its own init logic (dev/prod/CDN/e2e\n * branches); faijs's initOcctWasm() prefers the injected function. 注入的挂点\n * 写入共享状态——任意 faijs 实例(含 CDN 外部化实例)调 initOcctWasm() 时\n * 都优先使用同一份宿主初始化函数。\n *\n * When nothing is injected, initOcctWasm() reads the WASM from node_modules in\n * a Node environment.\n *\n * @param fn - the initialization function to use, or null to clear\n */\nexport function setOcctWasmInitFn(fn: (() => Promise<OcctKernel>) | null): void {\n const s = getOcctKernelSharedState()\n s.customInitFn = fn\n // 挂点变化后丢弃进行中的初始化(下一次 init 用新挂点重来)。\n s.initPromise = null\n}\n\n/**\n * Resolve the occt-wasm WASM file path (linker-agnostic).\n *\n * Walks the package exports (occt-wasm@5.6.0 exports \"./dist/occt-wasm.wasm\"),\n * independent of cwd / hoisting / pnpm|npm linker (verified pattern C).\n * Replaces the old 4-level `..` path guessing + process.cwd() fallback.\n *\n * Lazy-fetches node:module (Node >= 20.16 process.getBuiltinModule): a static\n * `import { createRequire } from 'node:module'` must not be used — occtKernel is\n * on the browser build's (demo vite build) import chain, and a static node:*\n * import would be externalized and error. This function is only called in the\n * Node branch (initOcctWasm); it never runs in a browser environment.\n *\n * @returns the resolved WASM file path\n */\nexport function resolveOcctWasmPath(): string {\n const builtin = (process as { getBuiltinModule?: (id: string) => unknown }).getBuiltinModule?.('node:module') as\n | { createRequire: (filename: string) => { resolve: (id: string) => string } }\n | undefined\n if (!builtin) {\n throw new Error('[faijs] resolveOcctWasmPath requires Node.js (process.getBuiltinModule)')\n }\n return builtin.createRequire(import.meta.url).resolve('occt-wasm/dist/occt-wasm.wasm')\n}\n\n/**\n * Initialize the occt-wasm kernel (singleton).\n *\n * - Node.js test environment: read the WASM file from node_modules, pass an ArrayBuffer.\n * - Development: direct ESM import, Vite resolves node_modules. The WASM file is loaded from public/wasm/occt-wasm.wasm.\n * - Production: dynamically import the whole module + WASM from a CDN.\n *\n * @returns the initialized raw OCCT kernel (native L2 face — NOT BrepEngineApi;\n * the L1 contract face is built separately by createOcctPrimitives()\n * in brep/engine/adapters/occt.ts as an explicit object literal).\n */\nexport async function initOcctWasm(): Promise<OcctKernel> {\n const s = getOcctKernelSharedState()\n if (s.kernelInstance) return s.kernelInstance\n if (s.initPromise) return s.initPromise\n\n s.initPromise = (async () => {\n // 优先使用浏览器 host 注入的初始化函数(共享挂点,跨实例生效)\n if (s.customInitFn) {\n s.kernelInstance = await s.customInitFn()\n return s.kernelInstance\n }\n\n // Node.js 环境:从 node_modules 读取 WASM 文件\n if (typeof process !== 'undefined' && process.versions?.node) {\n const { OcctKernel: Ctor } = await import('occt-wasm')\n // 与 resolveOcctWasmPath 同款:经 process.getBuiltinModule 取 node:fs,\n // 不用 `await import('node:fs')`——后者会被 vite 打包器静态分析 externalize\n // 并在浏览器构建时报 \"node:fs has been externalized\" warning(本分支运行时\n // 不会在浏览器执行,但打包器仍会对动态 import 字符串告警)。\n const fsBuiltin = (process as { getBuiltinModule?: (id: string) => unknown }).getBuiltinModule?.('node:fs') as\n | { readFileSync: (p: string) => Buffer }\n | undefined\n if (!fsBuiltin) {\n throw new Error('[faijs] occt-wasm init requires Node.js (process.getBuiltinModule)')\n }\n const wasmPath = resolveOcctWasmPath()\n const buf = fsBuiltin.readFileSync(wasmPath)\n const wasmBinary = buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.byteLength) as ArrayBuffer\n s.kernelInstance = await Ctor.init({ wasm: wasmBinary })\n return s.kernelInstance\n }\n\n throw new Error('initOcctWasm: no init function set and not in Node environment. Call setOcctWasmInitFn() first.')\n })()\n\n return s.initPromise\n}\n\n/**\n * Get the initialized kernel instance (initOcctWasm must be called first).\n *\n * @returns the initialized OCCT kernel\n */\nexport function getKernel(): OcctKernel {\n const k = getOcctKernelSharedState().kernelInstance\n if (!k) throw new Error('occt-wasm kernel not initialized — call initOcctWasm() first')\n return k\n}\n\n/**\n * Native-face alias for getKernel() (plan D3 ②): symmetric with\n * getBrepkitKernel() on the brepkit side. Platform-specific code uses this\n * name; the original getKernel() stays for existing host code.\n */\nexport const getOcctKernel = getKernel\n\n/** Release the kernel instance (call when the app unloads). */\nexport function disposeOcctWasm(): void {\n const s = getOcctKernelSharedState()\n if (s.kernelInstance) {\n s.kernelInstance[Symbol.dispose]()\n s.kernelInstance = null\n s.initPromise = null\n }\n}\n\n/** Options controlling mesh deflection during tessellation. */\nexport type { MeshDeflectionOptions } from '../brep/effective-deflection'\n\n/**\n * Compute the effective linear deflection, applying relative scaling\n * exactly as OCCT does internally: `linDefl * bboxDiagonal` when relative=true.\n *\n * 实现已移到引擎中立的 `brep/effective-deflection.ts`(函数体只用\n * `getBoundingBox`,与 OCCT 无关)——此处 re-export 保持既有导入面零迁移。\n * 本模块内部仍要用它,故 import 后再 re-export(纯 re-export 不产生本地绑定)。\n *\n * @param kernel - the OCCT kernel\n * @param shape - the shape whose bounding box drives relative scaling\n * @param options - the requested deflection options\n * @returns the effective linear and angular deflection values\n */\nexport { computeEffectiveDeflection }\n\n/**\n * Import a STEP file to ShapeHandle + Mesh (including face groups).\n *\n * Uses meshShape() rather than tessellate(), so face-group data is available\n * (each face's triangle range [triStart, triCount, faceHash]).\n *\n * @param stepData - STEP file bytes\n * @param deflection - optional mesh deflection options\n * @returns the import result with shape handle and meshes\n */\nexport async function importStepToMesh(\n stepData: ArrayBuffer | Uint8Array,\n deflection?: MeshDeflectionOptions,\n): Promise<WasmImportResult> {\n const kernel = await initOcctWasm()\n const ab = stepData instanceof Uint8Array ? stepData.buffer.slice(stepData.byteOffset, stepData.byteOffset + stepData.byteLength) as ArrayBuffer : stepData\n const shape = kernel.importStep(ab)\n\n const eff = computeEffectiveDeflection(kernel, shape, deflection)\n const mesh = kernel.meshShape(shape, { linearDeflection: eff.linearDeflection, angularDeflection: eff.angularDeflection })\n\n return {\n shapeHandle: shape,\n meshes: [{\n positions: mesh.positions,\n normals: mesh.normals,\n indices: mesh.indices,\n }],\n meshWithGroups: mesh,\n }\n}\n\n// ── Assembly (XCAF) support ──\n\n/** A node in the XCAF assembly tree (mirrors the STEP_T occurrence concept). */\nexport interface AssemblyPartNode {\n /** Dotted path: 'o0', 'o0.o1', 'o0.o1.o2' — matches STEP_T occurrence path. */\n labelPath: string\n /** XCAF label name (falls back to labelPath if empty). */\n name: string\n /** True if this node is an assembly (has child components). */\n isAssembly: boolean\n /**\n * True when `isAssembly` was **synthesised by this reader**, not read from the\n * file: a single XCAF product holding a multi-solid compound gets split into\n * virtual children so each solid becomes its own scene node.\n *\n * The distinction matters to callers that must answer \"is this file really an\n * assembly?\" — e.g. `Assembly.importStep` parity, where upstream rejects a STEP\n * with no assembly structure (`shape_tool.IsAssembly_s` is false for such a\n * product). Without this flag a flat multi-solid STEP looks like an assembly.\n */\n syntheticGroup?: boolean\n /** True if this node is a component reference (leaf part with location). */\n isComponent: boolean\n /** Shape handle with location baked in (for components) or raw shape (for roots).\n * Caller must release this handle. Null for empty assembly labels. */\n shapeHandle: ShapeHandle | null\n /** Deduplication key for prototype shapes (same geometry = same key).\n * Only set for leaf (non-assembly) nodes. */\n prototypeKey: string | null\n /** RGB color [r,g,b] in 0..1 range, or null if no color. */\n color: [number, number, number] | null\n /** Child nodes (recursive). Empty for leaf parts. */\n children: AssemblyPartNode[]\n}\n\nconst IDENTITY_MATRIX = [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0]\n\n/**\n * Import a STEP file via XCAF (STEPCAFControl_Reader), preserving the assembly\n * tree, names, colors, and per-component locations.\n *\n * Unlike `importStepToMesh` (which flattens via STEPControl_Reader.OneShape()),\n * this function returns the full assembly tree structure.\n *\n * The caller is responsible for releasing all shapeHandle values in the tree\n * (use `releaseAssemblyTree`).\n *\n * @param stepData - STEP file bytes\n * @returns the root assembly-part nodes\n */\nexport async function importAssemblyFromStep(\n stepData: ArrayBuffer | Uint8Array,\n): Promise<AssemblyPartNode[]> {\n const kernel = (await initOcctWasm()) as unknown as OcctKernel\n const stepText = stepData instanceof Uint8Array\n ? new TextDecoder().decode(stepData)\n : new TextDecoder().decode(new Uint8Array(stepData))\n\n // Parse sub-shape colors from STEP text (fallback for when XCAF label has no color).\n // STEP files from NX/SolidWorks often store colors as STYLED_ITEM on individual\n // solids rather than on XCAF labels, so getLabelInfo returns hasColor=false.\n const solidColors = getSolidColorsOrdered(stepText)\n\n // XCAFDocument.fromSTEP uses STEPCAFControl_Reader with color/name/layer modes\n const doc = kernel.importXCAFFromSTEP(stepText)\n try {\n const rootTags = doc.getRoots()\n const nodes: AssemblyPartNode[] = []\n const cursor = { idx: 0 }\n for (let i = 0; i < rootTags.length; i++) {\n nodes.push(walkLabel(kernel, doc, rootTags[i], `o${i}`, solidColors, cursor))\n }\n return nodes\n } finally {\n doc.close()\n }\n}\n\n/** Walk-context: tracks the current position in the solidColors array across\n * recursive walkLabel calls so that multi-solid compounds consume colors in order. */\ninterface WalkCtx {\n idx: number\n}\n\nfunction walkLabel(\n kernel: OcctKernel,\n doc: XCAFDocument,\n tag: LabelTag,\n path: string,\n solidColors: ([number, number, number] | null)[],\n ctx: WalkCtx,\n): AssemblyPartNode {\n const info: LabelInfo = doc.getLabelInfo(tag)\n const name = info.name || path\n const color = info.hasColor ? [info.color[0], info.color[1], info.color[2]] as [number, number, number] : null\n\n if (info.isAssembly) {\n const childTags = doc.getChildren(tag)\n const children: AssemblyPartNode[] = []\n for (let i = 0; i < childTags.length; i++) {\n children.push(walkLabel(kernel, doc, childTags[i], `${path}.o${i}`, solidColors, ctx))\n }\n // Assembly nodes have no shape of their own; release if one was returned\n if (info.shapeHandle) kernel.release(info.shapeHandle)\n return {\n labelPath: path,\n name,\n isAssembly: true,\n isComponent: false,\n shapeHandle: null,\n prototypeKey: null,\n color,\n children,\n }\n }\n\n // Leaf component — shapeHandle has location baked in (OCCT GetShape semantics)\n // Check if this is a compound with multiple solids — if so, split into\n // separate child nodes so each solid becomes its own mesh/scene-tree node.\n // This handles STEP files that have a single PRODUCT containing a compound\n // of multiple MANIFOLD_SOLID_BREP entities (common in NX/SolidWorks exports).\n if (info.shapeHandle) {\n const solids = kernel.getSubShapes(info.shapeHandle, 'solid')\n if (solids.length > 1) {\n // Multi-solid compound → split into virtual assembly children\n // Each child gets its own solid shapeHandle (already at correct location\n // because getSubShapes extracts from the located compound).\n const children: AssemblyPartNode[] = []\n for (let si = 0; si < solids.length; si++) {\n const childPath = `${path}.s${si}`\n const childName = `${name} [${si + 1}]`\n let childProtoKey: string | null\n try {\n childProtoKey = String(kernel.hashCode(solids[si], 2147483647))\n } catch {\n childProtoKey = null\n }\n // Use STEP-parsed color if label has no color (sub-shape level color)\n const childColor = color ?? (solidColors[ctx.idx] ?? null)\n ctx.idx++\n children.push({\n labelPath: childPath,\n name: childName,\n isAssembly: false,\n isComponent: true,\n shapeHandle: solids[si],\n prototypeKey: childProtoKey,\n color: childColor,\n children: [],\n })\n }\n // Release the compound shape itself — children hold individual solids\n kernel.release(info.shapeHandle)\n return {\n labelPath: path,\n name,\n isAssembly: true, // mark as assembly so it becomes a group node\n syntheticGroup: true, // ...but it is NOT an assembly in the file\n isComponent: false,\n shapeHandle: null,\n prototypeKey: null,\n color,\n children,\n }\n }\n // Single solid (or non-solid) — release the extra sub-shape handles\n for (const s of solids) kernel.release(s)\n }\n\n let prototypeKey: string | null = null\n if (info.shapeHandle) {\n // Get un-located shape for dedup (located with identity = remove location)\n try {\n const unlocated = kernel.located(info.shapeHandle, IDENTITY_MATRIX)\n prototypeKey = String(kernel.hashCode(unlocated, 2147483647))\n kernel.release(unlocated)\n } catch {\n // Fallback: use shapeHandle hash directly (less accurate dedup)\n prototypeKey = String(kernel.hashCode(info.shapeHandle, 2147483647))\n }\n }\n\n // For single-solid leaf parts, also try STEP-parsed color as fallback\n const finalColor = color ?? (solidColors[ctx.idx] ?? null)\n ctx.idx++\n\n return {\n labelPath: path,\n name,\n isAssembly: false,\n isComponent: info.isComponent,\n shapeHandle: info.shapeHandle,\n prototypeKey,\n color: finalColor,\n children: [],\n }\n}\n\n/** Recursively release all shapeHandle values in an assembly tree.\n *\n * @param kernel - the OCCT kernel used to release handles\n * @param nodes - the assembly tree nodes to release\n */\nexport function releaseAssemblyTree(kernel: OcctKernel, nodes: AssemblyPartNode[]): void {\n for (const node of nodes) {\n if (node.shapeHandle) kernel.release(node.shapeHandle)\n if (node.children.length > 0) releaseAssemblyTree(kernel, node.children)\n }\n}\n\n/** Collect all leaf (non-assembly) nodes from an assembly tree.\n *\n * @param nodes - the assembly tree nodes to traverse\n * @returns the collected leaf part nodes in depth-first order\n */\nexport function collectLeafParts(nodes: AssemblyPartNode[]): AssemblyPartNode[] {\n const leaves: AssemblyPartNode[] = []\n function walk(node: AssemblyPartNode) {\n if (node.isAssembly) {\n for (const child of node.children) walk(child)\n } else {\n leaves.push(node)\n }\n }\n for (const node of nodes) walk(node)\n return leaves\n}\n\n/**\n * Import BREP text to ShapeHandle + Mesh.\n *\n * @param brepData - BREP file content as a string\n * @param deflection - optional mesh deflection options\n * @returns the import result with shape handle and meshes\n */\nexport async function importBrepToMesh(\n brepData: string,\n deflection?: MeshDeflectionOptions,\n): Promise<WasmImportResult> {\n const kernel = await initOcctWasm()\n const shape = kernel.fromBREP(brepData)\n\n const eff = computeEffectiveDeflection(kernel, shape, deflection)\n const mesh = kernel.meshShape(shape, { linearDeflection: eff.linearDeflection, angularDeflection: eff.angularDeflection })\n\n return {\n shapeHandle: shape,\n meshes: [{\n positions: mesh.positions,\n normals: mesh.normals,\n indices: mesh.indices,\n }],\n meshWithGroups: mesh,\n }\n}\n\n/**\n * Mesh → STEP export: rebuild a STEP solid from a triangle mesh.\n * Follows the pattern from occt-wasm/examples/stl2step.mjs.\n *\n * @param positions - vertex array [x0,y0,z0, x1,y1,z1, ...]\n * @param indices - index array [i0,i1,i2, i3,i4,i5, ...]\n * @param tolerance - sewing tolerance in mm (default 0.01)\n * @returns the STEP file content string\n */\nexport function meshesToStep(\n positions: Float32Array,\n indices: Uint32Array,\n tolerance = SEWING_TOLERANCE.as(mm),\n): string {\n const kernel = getKernel()\n const faces: ShapeHandle[] = []\n let solid: ShapeHandle | null = null\n\n try {\n for (let i = 0; i < indices.length; i += 3) {\n const ia = indices[i] * 3\n const ib = indices[i + 1] * 3\n const ic = indices[i + 2] * 3\n const face = kernel.buildTriFace(\n { x: positions[ia], y: positions[ia + 1], z: positions[ia + 2] },\n { x: positions[ib], y: positions[ib + 1], z: positions[ib + 2] },\n { x: positions[ic], y: positions[ic + 1], z: positions[ic + 2] },\n )\n faces.push(face)\n }\n\n solid = kernel.sewAndSolidify(faces, tolerance)\n const unified = kernel.unifySameDomain(solid)\n kernel.release(solid)\n solid = unified\n return kernel.exportStep(solid)\n } finally {\n if (solid !== null) kernel.release(solid)\n for (const f of faces) kernel.release(f)\n }\n}\n\n/**\n * Release a shape handle.\n *\n * @param handle - the shape handle to release\n */\nexport function releaseShape(handle: ShapeHandle): void {\n const k = getOcctKernelSharedState().kernelInstance\n if (k) k.release(handle)\n}\n\n/** 导出类型供外部使用 */\nexport type { OcctKernel, ShapeHandle, Mesh, EdgeData, SurfaceKind, CurveKind, BoundingBox, Vec3, XCAFDocument, LabelInfo, LabelTag }\n"]}
|
|
@@ -6,12 +6,30 @@
|
|
|
6
6
|
* → SURFACE_SIDE_STYLE → SURFACE_STYLE_FILL_AREA → FILL_AREA_STYLE
|
|
7
7
|
* → FILL_AREA_STYLE_COLOUR → COLOUR_RGB
|
|
8
8
|
*
|
|
9
|
+
* 链尾有两种:`COLOUR_RGB('',r,g,b)`(任意色)和
|
|
10
|
+
* `DRAUGHTING_PRE_DEFINED_COLOUR('red')`(**恰好命中预定义色时**的紧凑写法,
|
|
11
|
+
* 见 STEP_PREDEFINED_COLOURS)。两者都必须认,否则整类颜色静默丢失。
|
|
12
|
+
*
|
|
9
13
|
* STYLED_ITEM 的第三个参数引用被着色的 shape entity(通常是 MANIFOLD_SOLID_BREP)。
|
|
10
14
|
* 我们解析这个引用链,建立 solid entity ID → color 的映射。
|
|
11
15
|
*
|
|
12
16
|
* 当 OCCT XCAF 的 getLabelInfo 返回 hasColor=false 时(颜色存储在 sub-shape 层级
|
|
13
17
|
* 而非 label 层级),此解析器作为后备方案提取颜色。
|
|
14
18
|
*/
|
|
19
|
+
/**
|
|
20
|
+
* STEP `draughting_pre_defined_colour` 名字 → RGB。
|
|
21
|
+
*
|
|
22
|
+
* 值与 OCCT 的 `Quantity_Color(Quantity_NOC_<NAME>)` 逐位一致(CadQuery 写出
|
|
23
|
+
* 预定义色后,OCCT 读回的就是这一步的结果),由一次性捕获
|
|
24
|
+
* `packages/faijs-cadquery/tests/ref-harness/predefined-colour-probe.py` 取得
|
|
25
|
+
* (CadQuery 2.8.0 / OCCT 7.9.3,不进 CI)——**不要手调这些数字**:它们只有
|
|
26
|
+
* 与 OCCT 同源才能让「写出 → 读回」逐位相等。
|
|
27
|
+
*
|
|
28
|
+
* 上游只会在这个 RGB 与预定义色**完全相等**时写名字形式;近似色仍写
|
|
29
|
+
* `COLOUR_RGB`(实测:0.5/0.5/0.5、0/0/0.5、(0.123,0.456,0.789) 都走 RGB)。
|
|
30
|
+
*/
|
|
31
|
+
export declare const STEP_PREDEFINED_COLOURS: Readonly<Record<string, readonly [number, number, number]>>;
|
|
32
|
+
/** A parsed STEP entity: its numeric id, type keyword, and raw parameter text. */
|
|
15
33
|
export interface StepEntity {
|
|
16
34
|
id: number;
|
|
17
35
|
type: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stepColorParser.d.ts","sourceRoot":"","sources":["../../src/occt-kernel/stepColorParser.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"stepColorParser.d.ts","sourceRoot":"","sources":["../../src/occt-kernel/stepColorParser.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,uBAAuB,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC,CAc/F,CAAA;AAGD,kFAAkF;AAClF,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,MAAM,CAAA;IACZ,kDAAkD;IAClD,MAAM,EAAE,MAAM,CAAA;CACf;AAED,6CAA6C;AAC7C,MAAM,WAAW,UAAU;IACzB,iDAAiD;IACjD,OAAO,EAAE,MAAM,CAAA;IACf,+BAA+B;IAC/B,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAA;CAChC;AA8ED;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC,CA2BvF;AAED;;;;;;;;;GASG;AACH,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,EAAE,CAS9D;AAED;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,MAAM,GAAG,CAAC,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,CAAC,EAAE,CAI3F"}
|
|
@@ -6,12 +6,43 @@
|
|
|
6
6
|
* → SURFACE_SIDE_STYLE → SURFACE_STYLE_FILL_AREA → FILL_AREA_STYLE
|
|
7
7
|
* → FILL_AREA_STYLE_COLOUR → COLOUR_RGB
|
|
8
8
|
*
|
|
9
|
+
* 链尾有两种:`COLOUR_RGB('',r,g,b)`(任意色)和
|
|
10
|
+
* `DRAUGHTING_PRE_DEFINED_COLOUR('red')`(**恰好命中预定义色时**的紧凑写法,
|
|
11
|
+
* 见 STEP_PREDEFINED_COLOURS)。两者都必须认,否则整类颜色静默丢失。
|
|
12
|
+
*
|
|
9
13
|
* STYLED_ITEM 的第三个参数引用被着色的 shape entity(通常是 MANIFOLD_SOLID_BREP)。
|
|
10
14
|
* 我们解析这个引用链,建立 solid entity ID → color 的映射。
|
|
11
15
|
*
|
|
12
16
|
* 当 OCCT XCAF 的 getLabelInfo 返回 hasColor=false 时(颜色存储在 sub-shape 层级
|
|
13
17
|
* 而非 label 层级),此解析器作为后备方案提取颜色。
|
|
14
18
|
*/
|
|
19
|
+
/**
|
|
20
|
+
* STEP `draughting_pre_defined_colour` 名字 → RGB。
|
|
21
|
+
*
|
|
22
|
+
* 值与 OCCT 的 `Quantity_Color(Quantity_NOC_<NAME>)` 逐位一致(CadQuery 写出
|
|
23
|
+
* 预定义色后,OCCT 读回的就是这一步的结果),由一次性捕获
|
|
24
|
+
* `packages/faijs-cadquery/tests/ref-harness/predefined-colour-probe.py` 取得
|
|
25
|
+
* (CadQuery 2.8.0 / OCCT 7.9.3,不进 CI)——**不要手调这些数字**:它们只有
|
|
26
|
+
* 与 OCCT 同源才能让「写出 → 读回」逐位相等。
|
|
27
|
+
*
|
|
28
|
+
* 上游只会在这个 RGB 与预定义色**完全相等**时写名字形式;近似色仍写
|
|
29
|
+
* `COLOUR_RGB`(实测:0.5/0.5/0.5、0/0/0.5、(0.123,0.456,0.789) 都走 RGB)。
|
|
30
|
+
*/
|
|
31
|
+
export const STEP_PREDEFINED_COLOURS = {
|
|
32
|
+
black: [0, 0, 0],
|
|
33
|
+
red: [1, 0, 0],
|
|
34
|
+
green: [0, 1, 0],
|
|
35
|
+
blue: [0, 0, 1],
|
|
36
|
+
yellow: [1, 1, 0],
|
|
37
|
+
magenta: [1, 0, 1],
|
|
38
|
+
cyan: [0, 1, 1],
|
|
39
|
+
white: [1, 1, 1],
|
|
40
|
+
orange: [1, 0.376262009, 0],
|
|
41
|
+
pink: [1, 0.527114987, 0.59720099],
|
|
42
|
+
brown: [0.376262009, 0.023153, 0.023153],
|
|
43
|
+
purple: [0.351532996, 0.014444, 0.871366024],
|
|
44
|
+
gold: [1, 0.679542005, 0],
|
|
45
|
+
};
|
|
15
46
|
/** Parse all entities from STEP text into a Map<id, StepEntity>. */
|
|
16
47
|
function parseStepEntities(stepText) {
|
|
17
48
|
const entities = new Map();
|
|
@@ -64,6 +95,13 @@ function resolveColorChain(entityId, entities, visited = new Set()) {
|
|
|
64
95
|
}
|
|
65
96
|
return null;
|
|
66
97
|
}
|
|
98
|
+
if (entity.type === 'DRAUGHTING_PRE_DEFINED_COLOUR') {
|
|
99
|
+
// Parse: 'red' — the whole chain collapses to one of the ISO names.
|
|
100
|
+
const name = entity.params.trim().replace(/^'/, '').replace(/'$/, '').toLowerCase();
|
|
101
|
+
const rgb = STEP_PREDEFINED_COLOURS[name];
|
|
102
|
+
// Unknown name: return null rather than inventing a colour.
|
|
103
|
+
return rgb ? [rgb[0], rgb[1], rgb[2]] : null;
|
|
104
|
+
}
|
|
67
105
|
// For all intermediate types, follow # references
|
|
68
106
|
const refs = extractRefs(entity.params);
|
|
69
107
|
for (const ref of refs) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stepColorParser.js","sourceRoot":"","sources":["../../src/occt-kernel/stepColorParser.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * STEP 颜色解析器 — 从 STEP 文本中提取每个 solid 的颜色。\n *\n * STEP 文件中的颜色引用链:\n * STYLED_ITEM → PRESENTATION_STYLE_ASSIGNMENT → SURFACE_STYLE_USAGE\n * → SURFACE_SIDE_STYLE → SURFACE_STYLE_FILL_AREA → FILL_AREA_STYLE\n * → FILL_AREA_STYLE_COLOUR → COLOUR_RGB\n *\n * STYLED_ITEM 的第三个参数引用被着色的 shape entity(通常是 MANIFOLD_SOLID_BREP)。\n * 我们解析这个引用链,建立 solid entity ID → color 的映射。\n *\n * 当 OCCT XCAF 的 getLabelInfo 返回 hasColor=false 时(颜色存储在 sub-shape 层级\n * 而非 label 层级),此解析器作为后备方案提取颜色。\n */\n\nexport interface StepEntity {\n id: number\n type: string\n /** Raw parameter string (between parentheses). */\n params: string\n}\n\n/** A solid's color parsed from STEP text. */\nexport interface SolidColor {\n /** STEP entity ID of the MANIFOLD_SOLID_BREP. */\n solidId: number\n /** RGB color in 0..1 range. */\n color: [number, number, number]\n}\n\n/** Parse all entities from STEP text into a Map<id, StepEntity>. */\nfunction parseStepEntities(stepText: string): Map<number, StepEntity> {\n const entities = new Map<number, StepEntity>()\n // Match lines like: #123=ENTITY_TYPE(params);\n // STEP entities can span multiple lines, but the closing ); is always at end\n const regex = /#(\\d+)\\s*=\\s*([A-Z_]+)\\s*\\(([^;]*)\\)/g\n let match: RegExpExecArray | null\n while ((match = regex.exec(stepText)) !== null) {\n const id = parseInt(match[1], 10)\n const type = match[2]\n const params = match[3]\n entities.set(id, { id, type, params })\n }\n return entities\n}\n\n/** Extract all # references from a parameter string. Returns array of IDs. */\nfunction extractRefs(params: string): number[] {\n const refs: number[] = []\n const regex = /#(\\d+)/g\n let match: RegExpExecArray | null\n while ((match = regex.exec(params)) !== null) {\n refs.push(parseInt(match[1], 10))\n }\n return refs\n}\n\n/**\n * Resolve the color reference chain starting from a STYLED_ITEM.\n * Returns the COLOUR_RGB values if found, or null if the chain is broken.\n */\nfunction resolveColorChain(\n entityId: number,\n entities: Map<number, StepEntity>,\n visited: Set<number> = new Set(),\n): [number, number, number] | null {\n if (visited.has(entityId)) return null // cycle guard\n visited.add(entityId)\n\n const entity = entities.get(entityId)\n if (!entity) return null\n\n if (entity.type === 'COLOUR_RGB') {\n // Parse: 'name', r, g, b\n const parts = entity.params.split(',')\n // Color values start after the name (which may contain commas if quoted)\n // Find the last 3 numeric values\n const nums: number[] = []\n for (let i = parts.length - 1; i >= 0 && nums.length < 3; i--) {\n const n = parseFloat(parts[i].trim())\n if (!isNaN(n)) nums.unshift(n)\n }\n if (nums.length === 3) {\n return [nums[0], nums[1], nums[2]]\n }\n return null\n }\n\n // For all intermediate types, follow # references\n const refs = extractRefs(entity.params)\n for (const ref of refs) {\n const color = resolveColorChain(ref, entities, visited)\n if (color) return color\n }\n\n return null\n}\n\n/**\n * Parse STEP text and extract colors for each solid.\n *\n * @param stepText Raw STEP file content\n * @returns Map<solidEntityId, [r, g, b]> where r,g,b are in 0..1 range\n */\nexport function parseStepColors(stepText: string): Map<number, [number, number, number]> {\n const entities = parseStepEntities(stepText)\n const colorMap = new Map<number, [number, number, number]>()\n\n for (const [, entity] of entities) {\n if (entity.type === 'STYLED_ITEM') {\n // STYLED_ITEM('', (#styleRef), #shapeRef)\n // The last # reference is the shape being styled\n const refs = extractRefs(entity.params)\n if (refs.length < 2) continue\n\n const shapeRef = refs[refs.length - 1] // last ref = styled shape\n const styleRef = refs[0] // first ref = presentation style\n\n // Verify the shape ref is a MANIFOLD_SOLID_BREP (or ADVANCED_BREP_SHAPE_REPRESENTATION)\n const shapeEntity = entities.get(shapeRef)\n if (!shapeEntity) continue\n\n // Resolve color from the style reference chain\n const color = resolveColorChain(styleRef, entities)\n if (color) {\n colorMap.set(shapeRef, color)\n }\n }\n }\n\n return colorMap\n}\n\n/**\n * Parse STEP text and return the ordered list of solid entity IDs.\n *\n * This order should match OCCT's getSubShapes(compound, 'solid') order,\n * because both iterate the compound's sub-shapes in the same order\n * they appear in the STEP file.\n *\n * @param stepText - raw STEP file content\n * @returns the ordered MANIFOLD_SOLID_BREP entity IDs\n */\nexport function parseStepSolidOrder(stepText: string): number[] {\n const entities = parseStepEntities(stepText)\n const solids: number[] = []\n for (const [id, entity] of entities) {\n if (entity.type === 'MANIFOLD_SOLID_BREP') {\n solids.push(id)\n }\n }\n return solids\n}\n\n/**\n * Get colors for each solid in order.\n *\n * @param stepText Raw STEP file content\n * @returns Array of colors [r,g,b] in 0..1, or null for solids without color.\n * Length matches the number of MANIFOLD_SOLID_BREP entities.\n */\nexport function getSolidColorsOrdered(stepText: string): ([number, number, number] | null)[] {\n const colorMap = parseStepColors(stepText)\n const solidOrder = parseStepSolidOrder(stepText)\n return solidOrder.map(id => colorMap.get(id) ?? null)\n}\n"]}
|
|
1
|
+
{"version":3,"file":"stepColorParser.js","sourceRoot":"","sources":["../../src/occt-kernel/stepColorParser.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,MAAM,uBAAuB,GAAgE;IAClG,KAAK,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;IAChB,GAAG,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;IACd,KAAK,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;IAChB,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;IACf,MAAM,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;IACjB,OAAO,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;IAClB,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;IACf,KAAK,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;IAChB,MAAM,EAAE,CAAC,CAAC,EAAE,WAAW,EAAE,CAAC,CAAC;IAC3B,IAAI,EAAE,CAAC,CAAC,EAAE,WAAW,EAAE,UAAU,CAAC;IAClC,KAAK,EAAE,CAAC,WAAW,EAAE,QAAQ,EAAE,QAAQ,CAAC;IACxC,MAAM,EAAE,CAAC,WAAW,EAAE,QAAQ,EAAE,WAAW,CAAC;IAC5C,IAAI,EAAE,CAAC,CAAC,EAAE,WAAW,EAAE,CAAC,CAAC;CAC1B,CAAA;AAmBD,oEAAoE;AACpE,SAAS,iBAAiB,CAAC,QAAgB;IACzC,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAsB,CAAA;IAC9C,8CAA8C;IAC9C,6EAA6E;IAC7E,MAAM,KAAK,GAAG,uCAAuC,CAAA;IACrD,IAAI,KAA6B,CAAA;IACjC,OAAO,CAAC,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;QAC/C,MAAM,EAAE,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAA;QACjC,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,CAAA;QACrB,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,CAAC,CAAA;QACvB,QAAQ,CAAC,GAAG,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAA;IACxC,CAAC;IACD,OAAO,QAAQ,CAAA;AACjB,CAAC;AAED,8EAA8E;AAC9E,SAAS,WAAW,CAAC,MAAc;IACjC,MAAM,IAAI,GAAa,EAAE,CAAA;IACzB,MAAM,KAAK,GAAG,SAAS,CAAA;IACvB,IAAI,KAA6B,CAAA;IACjC,OAAO,CAAC,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;QAC7C,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAA;IACnC,CAAC;IACD,OAAO,IAAI,CAAA;AACb,CAAC;AAED;;;GAGG;AACH,SAAS,iBAAiB,CACxB,QAAgB,EAChB,QAAiC,EACjC,UAAuB,IAAI,GAAG,EAAE;IAEhC,IAAI,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC;QAAE,OAAO,IAAI,CAAA,CAAC,cAAc;IACrD,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAA;IAErB,MAAM,MAAM,GAAG,QAAQ,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAA;IACrC,IAAI,CAAC,MAAM;QAAE,OAAO,IAAI,CAAA;IAExB,IAAI,MAAM,CAAC,IAAI,KAAK,YAAY,EAAE,CAAC;QACjC,yBAAyB;QACzB,MAAM,KAAK,GAAG,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;QACtC,yEAAyE;QACzE,iCAAiC;QACjC,MAAM,IAAI,GAAa,EAAE,CAAA;QACzB,KAAK,IAAI,CAAC,GAAG,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;YAC9D,MAAM,CAAC,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAA;YACrC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;gBAAE,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAA;QAChC,CAAC;QACD,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACtB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,CAAA;QACpC,CAAC;QACD,OAAO,IAAI,CAAA;IACb,CAAC;IAED,IAAI,MAAM,CAAC,IAAI,KAAK,+BAA+B,EAAE,CAAC;QACpD,oEAAoE;QACpE,MAAM,IAAI,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,WAAW,EAAE,CAAA;QACnF,MAAM,GAAG,GAAG,uBAAuB,CAAC,IAAI,CAAC,CAAA;QACzC,4DAA4D;QAC5D,OAAO,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAA;IAC9C,CAAC;IAED,kDAAkD;IAClD,MAAM,IAAI,GAAG,WAAW,CAAC,MAAM,CAAC,MAAM,CAAC,CAAA;IACvC,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;QACvB,MAAM,KAAK,GAAG,iBAAiB,CAAC,GAAG,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAA;QACvD,IAAI,KAAK;YAAE,OAAO,KAAK,CAAA;IACzB,CAAC;IAED,OAAO,IAAI,CAAA;AACb,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,eAAe,CAAC,QAAgB;IAC9C,MAAM,QAAQ,GAAG,iBAAiB,CAAC,QAAQ,CAAC,CAAA;IAC5C,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAoC,CAAA;IAE5D,KAAK,MAAM,CAAC,EAAE,MAAM,CAAC,IAAI,QAAQ,EAAE,CAAC;QAClC,IAAI,MAAM,CAAC,IAAI,KAAK,aAAa,EAAE,CAAC;YAClC,0CAA0C;YAC1C,iDAAiD;YACjD,MAAM,IAAI,GAAG,WAAW,CAAC,MAAM,CAAC,MAAM,CAAC,CAAA;YACvC,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC;gBAAE,SAAQ;YAE7B,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAA,CAAC,0BAA0B;YACjE,MAAM,QAAQ,GAAG,IAAI,CAAC,CAAC,CAAC,CAAA,CAAC,iCAAiC;YAE1D,wFAAwF;YACxF,MAAM,WAAW,GAAG,QAAQ,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAA;YAC1C,IAAI,CAAC,WAAW;gBAAE,SAAQ;YAE1B,+CAA+C;YAC/C,MAAM,KAAK,GAAG,iBAAiB,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAA;YACnD,IAAI,KAAK,EAAE,CAAC;gBACV,QAAQ,CAAC,GAAG,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAA;YAC/B,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,QAAQ,CAAA;AACjB,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,mBAAmB,CAAC,QAAgB;IAClD,MAAM,QAAQ,GAAG,iBAAiB,CAAC,QAAQ,CAAC,CAAA;IAC5C,MAAM,MAAM,GAAa,EAAE,CAAA;IAC3B,KAAK,MAAM,CAAC,EAAE,EAAE,MAAM,CAAC,IAAI,QAAQ,EAAE,CAAC;QACpC,IAAI,MAAM,CAAC,IAAI,KAAK,qBAAqB,EAAE,CAAC;YAC1C,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;QACjB,CAAC;IACH,CAAC;IACD,OAAO,MAAM,CAAA;AACf,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,qBAAqB,CAAC,QAAgB;IACpD,MAAM,QAAQ,GAAG,eAAe,CAAC,QAAQ,CAAC,CAAA;IAC1C,MAAM,UAAU,GAAG,mBAAmB,CAAC,QAAQ,CAAC,CAAA;IAChD,OAAO,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,IAAI,CAAC,CAAA;AACvD,CAAC","sourcesContent":["/**\n * STEP 颜色解析器 — 从 STEP 文本中提取每个 solid 的颜色。\n *\n * STEP 文件中的颜色引用链:\n * STYLED_ITEM → PRESENTATION_STYLE_ASSIGNMENT → SURFACE_STYLE_USAGE\n * → SURFACE_SIDE_STYLE → SURFACE_STYLE_FILL_AREA → FILL_AREA_STYLE\n * → FILL_AREA_STYLE_COLOUR → COLOUR_RGB\n *\n * 链尾有两种:`COLOUR_RGB('',r,g,b)`(任意色)和\n * `DRAUGHTING_PRE_DEFINED_COLOUR('red')`(**恰好命中预定义色时**的紧凑写法,\n * 见 STEP_PREDEFINED_COLOURS)。两者都必须认,否则整类颜色静默丢失。\n *\n * STYLED_ITEM 的第三个参数引用被着色的 shape entity(通常是 MANIFOLD_SOLID_BREP)。\n * 我们解析这个引用链,建立 solid entity ID → color 的映射。\n *\n * 当 OCCT XCAF 的 getLabelInfo 返回 hasColor=false 时(颜色存储在 sub-shape 层级\n * 而非 label 层级),此解析器作为后备方案提取颜色。\n */\n\n/**\n * STEP `draughting_pre_defined_colour` 名字 → RGB。\n *\n * 值与 OCCT 的 `Quantity_Color(Quantity_NOC_<NAME>)` 逐位一致(CadQuery 写出\n * 预定义色后,OCCT 读回的就是这一步的结果),由一次性捕获\n * `packages/faijs-cadquery/tests/ref-harness/predefined-colour-probe.py` 取得\n * (CadQuery 2.8.0 / OCCT 7.9.3,不进 CI)——**不要手调这些数字**:它们只有\n * 与 OCCT 同源才能让「写出 → 读回」逐位相等。\n *\n * 上游只会在这个 RGB 与预定义色**完全相等**时写名字形式;近似色仍写\n * `COLOUR_RGB`(实测:0.5/0.5/0.5、0/0/0.5、(0.123,0.456,0.789) 都走 RGB)。\n */\nexport const STEP_PREDEFINED_COLOURS: Readonly<Record<string, readonly [number, number, number]>> = {\n black: [0, 0, 0],\n red: [1, 0, 0],\n green: [0, 1, 0],\n blue: [0, 0, 1],\n yellow: [1, 1, 0],\n magenta: [1, 0, 1],\n cyan: [0, 1, 1],\n white: [1, 1, 1],\n orange: [1, 0.376262009, 0],\n pink: [1, 0.527114987, 0.59720099],\n brown: [0.376262009, 0.023153, 0.023153],\n purple: [0.351532996, 0.014444, 0.871366024],\n gold: [1, 0.679542005, 0],\n}\n\n\n/** A parsed STEP entity: its numeric id, type keyword, and raw parameter text. */\nexport interface StepEntity {\n id: number\n type: string\n /** Raw parameter string (between parentheses). */\n params: string\n}\n\n/** A solid's color parsed from STEP text. */\nexport interface SolidColor {\n /** STEP entity ID of the MANIFOLD_SOLID_BREP. */\n solidId: number\n /** RGB color in 0..1 range. */\n color: [number, number, number]\n}\n\n/** Parse all entities from STEP text into a Map<id, StepEntity>. */\nfunction parseStepEntities(stepText: string): Map<number, StepEntity> {\n const entities = new Map<number, StepEntity>()\n // Match lines like: #123=ENTITY_TYPE(params);\n // STEP entities can span multiple lines, but the closing ); is always at end\n const regex = /#(\\d+)\\s*=\\s*([A-Z_]+)\\s*\\(([^;]*)\\)/g\n let match: RegExpExecArray | null\n while ((match = regex.exec(stepText)) !== null) {\n const id = parseInt(match[1], 10)\n const type = match[2]\n const params = match[3]\n entities.set(id, { id, type, params })\n }\n return entities\n}\n\n/** Extract all # references from a parameter string. Returns array of IDs. */\nfunction extractRefs(params: string): number[] {\n const refs: number[] = []\n const regex = /#(\\d+)/g\n let match: RegExpExecArray | null\n while ((match = regex.exec(params)) !== null) {\n refs.push(parseInt(match[1], 10))\n }\n return refs\n}\n\n/**\n * Resolve the color reference chain starting from a STYLED_ITEM.\n * Returns the COLOUR_RGB values if found, or null if the chain is broken.\n */\nfunction resolveColorChain(\n entityId: number,\n entities: Map<number, StepEntity>,\n visited: Set<number> = new Set(),\n): [number, number, number] | null {\n if (visited.has(entityId)) return null // cycle guard\n visited.add(entityId)\n\n const entity = entities.get(entityId)\n if (!entity) return null\n\n if (entity.type === 'COLOUR_RGB') {\n // Parse: 'name', r, g, b\n const parts = entity.params.split(',')\n // Color values start after the name (which may contain commas if quoted)\n // Find the last 3 numeric values\n const nums: number[] = []\n for (let i = parts.length - 1; i >= 0 && nums.length < 3; i--) {\n const n = parseFloat(parts[i].trim())\n if (!isNaN(n)) nums.unshift(n)\n }\n if (nums.length === 3) {\n return [nums[0], nums[1], nums[2]]\n }\n return null\n }\n\n if (entity.type === 'DRAUGHTING_PRE_DEFINED_COLOUR') {\n // Parse: 'red' — the whole chain collapses to one of the ISO names.\n const name = entity.params.trim().replace(/^'/, '').replace(/'$/, '').toLowerCase()\n const rgb = STEP_PREDEFINED_COLOURS[name]\n // Unknown name: return null rather than inventing a colour.\n return rgb ? [rgb[0], rgb[1], rgb[2]] : null\n }\n\n // For all intermediate types, follow # references\n const refs = extractRefs(entity.params)\n for (const ref of refs) {\n const color = resolveColorChain(ref, entities, visited)\n if (color) return color\n }\n\n return null\n}\n\n/**\n * Parse STEP text and extract colors for each solid.\n *\n * @param stepText Raw STEP file content\n * @returns Map<solidEntityId, [r, g, b]> where r,g,b are in 0..1 range\n */\nexport function parseStepColors(stepText: string): Map<number, [number, number, number]> {\n const entities = parseStepEntities(stepText)\n const colorMap = new Map<number, [number, number, number]>()\n\n for (const [, entity] of entities) {\n if (entity.type === 'STYLED_ITEM') {\n // STYLED_ITEM('', (#styleRef), #shapeRef)\n // The last # reference is the shape being styled\n const refs = extractRefs(entity.params)\n if (refs.length < 2) continue\n\n const shapeRef = refs[refs.length - 1] // last ref = styled shape\n const styleRef = refs[0] // first ref = presentation style\n\n // Verify the shape ref is a MANIFOLD_SOLID_BREP (or ADVANCED_BREP_SHAPE_REPRESENTATION)\n const shapeEntity = entities.get(shapeRef)\n if (!shapeEntity) continue\n\n // Resolve color from the style reference chain\n const color = resolveColorChain(styleRef, entities)\n if (color) {\n colorMap.set(shapeRef, color)\n }\n }\n }\n\n return colorMap\n}\n\n/**\n * Parse STEP text and return the ordered list of solid entity IDs.\n *\n * This order should match OCCT's getSubShapes(compound, 'solid') order,\n * because both iterate the compound's sub-shapes in the same order\n * they appear in the STEP file.\n *\n * @param stepText - raw STEP file content\n * @returns the ordered MANIFOLD_SOLID_BREP entity IDs\n */\nexport function parseStepSolidOrder(stepText: string): number[] {\n const entities = parseStepEntities(stepText)\n const solids: number[] = []\n for (const [id, entity] of entities) {\n if (entity.type === 'MANIFOLD_SOLID_BREP') {\n solids.push(id)\n }\n }\n return solids\n}\n\n/**\n * Get colors for each solid in order.\n *\n * @param stepText Raw STEP file content\n * @returns Array of colors [r,g,b] in 0..1, or null for solids without color.\n * Length matches the number of MANIFOLD_SOLID_BREP entities.\n */\nexport function getSolidColorsOrdered(stepText: string): ([number, number, number] | null)[] {\n const colorMap = parseStepColors(stepText)\n const solidOrder = parseStepSolidOrder(stepText)\n return solidOrder.map(id => colorMap.get(id) ?? null)\n}\n"]}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* STEP 元数据解析器 — 从 STEP (P21) 文本头部与 PRODUCT 层提取
|
|
3
|
+
* FileMeta(文件级)与 ShapeMeta(零件级描述字/料号)。
|
|
4
|
+
*
|
|
5
|
+
* 与 stepColorParser 同一原则:纯文本扫描,不依赖 OCCT 内核(XCAF label 层
|
|
6
|
+
* 是否暴露 description/属性不确定,见设计文档 2026-10-05-meta §6.3 风险 2)。
|
|
7
|
+
*
|
|
8
|
+
* 读取面映射(§3.3):
|
|
9
|
+
* - HEADER FILE_NAME(name,time_stamp,author,organization,preprocessor,originator)
|
|
10
|
+
* → title / creationDate / author / organization / application / designer。
|
|
11
|
+
* - HEADER FILE_DESCRIPTION(...) → description(逗号拼接,去首尾引号)。
|
|
12
|
+
* - DATA PRODUCT(name,description,frame)(第一个、leaf 使用的)→ 零件 description。
|
|
13
|
+
* name 已由 OCCT label 提供(不在本解析器处理)。
|
|
14
|
+
* - PRODUCT → PRODUCT_DEFINITION_FORMATION/WITH_SPECIFIED_SOURCE-关联的料号通道:
|
|
15
|
+
* PART_NUMBER_PROPERTY/IDENTIFICATION 命名在 §3.3 表里列出的 PART 层通道(P4
|
|
16
|
+
* 标 "IDENTIFICATION 内核支持" 待实测),这里尽量从 PRODUCT_DEFINITION 挂的
|
|
17
|
+
* UDA(GENERAL_PROPERTY + PROPERTY_DEFINITION)捞自定义属性。
|
|
18
|
+
*
|
|
19
|
+
* 所有扫描都容错:找不到就不给对应字段,绝不让解析器抛(信息性收益)。
|
|
20
|
+
*/
|
|
21
|
+
/** Header 级人物贡献字段(FILE_NAME 组内的三四五参数)。 */
|
|
22
|
+
export interface StepFileMeta {
|
|
23
|
+
title?: string;
|
|
24
|
+
creationDate?: string;
|
|
25
|
+
designer?: string;
|
|
26
|
+
author?: string;
|
|
27
|
+
organization?: string;
|
|
28
|
+
application?: string;
|
|
29
|
+
description?: string;
|
|
30
|
+
/** 自定义 FILE_DESCRIPTION/FILE_NAME 之外的 vendor 属性(metadata 笼)。 */
|
|
31
|
+
metadata?: Record<string, string>;
|
|
32
|
+
}
|
|
33
|
+
/** STEP 伙伴级 P21 解析出的轻量属性。 */
|
|
34
|
+
export interface StepPartMeta {
|
|
35
|
+
/** 产品描述(PRODUCT( ..., description, id ))。空串/缺省不设。 */
|
|
36
|
+
description?: string;
|
|
37
|
+
/** 自定义属性:`PROPERTY_DEFINITION(...)` + `GENERAL_PROPERTY('name', value, ...)`。 */
|
|
38
|
+
metadata?: Record<string, string>;
|
|
39
|
+
}
|
|
40
|
+
/** Header 段整块(FILE_NAME / FILE_DESCRIPTION / FILE_SCHEMA)→ FileMeta。 */
|
|
41
|
+
export declare function parseStepHeaderMeta(text: string): StepFileMeta;
|
|
42
|
+
/** 伙伴层 PRODUCT 描述 + 根相关字段解析(简化:只取第一个 PRODUCT)。 */
|
|
43
|
+
export declare function parseStepPartMeta(text: string): StepPartMeta;
|
|
44
|
+
//# sourceMappingURL=stepMetaParser.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stepMetaParser.d.ts","sourceRoot":"","sources":["../../src/occt-kernel/stepMetaParser.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,0CAA0C;AAC1C,MAAM,WAAW,YAAY;IAC3B,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,gEAAgE;IAChE,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAClC;AAED,6BAA6B;AAC7B,MAAM,WAAW,YAAY;IAC3B,qDAAqD;IACrD,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,iFAAiF;IACjF,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAClC;AA2DD,wEAAwE;AACxE,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,YAAY,CA+C9D;AAED,kDAAkD;AAClD,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,YAAY,CAyB5D"}
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* STEP 元数据解析器 — 从 STEP (P21) 文本头部与 PRODUCT 层提取
|
|
3
|
+
* FileMeta(文件级)与 ShapeMeta(零件级描述字/料号)。
|
|
4
|
+
*
|
|
5
|
+
* 与 stepColorParser 同一原则:纯文本扫描,不依赖 OCCT 内核(XCAF label 层
|
|
6
|
+
* 是否暴露 description/属性不确定,见设计文档 2026-10-05-meta §6.3 风险 2)。
|
|
7
|
+
*
|
|
8
|
+
* 读取面映射(§3.3):
|
|
9
|
+
* - HEADER FILE_NAME(name,time_stamp,author,organization,preprocessor,originator)
|
|
10
|
+
* → title / creationDate / author / organization / application / designer。
|
|
11
|
+
* - HEADER FILE_DESCRIPTION(...) → description(逗号拼接,去首尾引号)。
|
|
12
|
+
* - DATA PRODUCT(name,description,frame)(第一个、leaf 使用的)→ 零件 description。
|
|
13
|
+
* name 已由 OCCT label 提供(不在本解析器处理)。
|
|
14
|
+
* - PRODUCT → PRODUCT_DEFINITION_FORMATION/WITH_SPECIFIED_SOURCE-关联的料号通道:
|
|
15
|
+
* PART_NUMBER_PROPERTY/IDENTIFICATION 命名在 §3.3 表里列出的 PART 层通道(P4
|
|
16
|
+
* 标 "IDENTIFICATION 内核支持" 待实测),这里尽量从 PRODUCT_DEFINITION 挂的
|
|
17
|
+
* UDA(GENERAL_PROPERTY + PROPERTY_DEFINITION)捞自定义属性。
|
|
18
|
+
*
|
|
19
|
+
* 所有扫描都容错:找不到就不给对应字段,绝不让解析器抛(信息性收益)。
|
|
20
|
+
*/
|
|
21
|
+
/** 剥离一层引号(STEP 字符串形如 `'abc'`),出双引号化转义;去末尾换行。 */
|
|
22
|
+
function unquote(s) {
|
|
23
|
+
const t = s.trim();
|
|
24
|
+
if (t.startsWith("'") && t.endsWith("'"))
|
|
25
|
+
return t.slice(1, -1);
|
|
26
|
+
return t;
|
|
27
|
+
}
|
|
28
|
+
/** 任一 `HEADER`/`DATA` 段中的实体文本(多行),从 header 段中取整行。 */
|
|
29
|
+
function headerLines(text) {
|
|
30
|
+
const m = /HEADER;\n([\s\S]*?)\nENDSEC;/.exec(text);
|
|
31
|
+
return m ? m[1] : '';
|
|
32
|
+
}
|
|
33
|
+
/** `TYPE(...)` 实体块捕获:从开括号起做括号配平扫描到闭合(容错 LIST/嵌套)。 */
|
|
34
|
+
function entityBlock(text, type) {
|
|
35
|
+
const re = new RegExp(`${type}\\s*\\(`, 'g');
|
|
36
|
+
let m;
|
|
37
|
+
while ((m = re.exec(text)) !== null) {
|
|
38
|
+
let depth = 0;
|
|
39
|
+
let inQuote = false;
|
|
40
|
+
let i = m.index + m[0].length - 1; // 停在开括号
|
|
41
|
+
for (; i < text.length; i++) {
|
|
42
|
+
const c = text[i];
|
|
43
|
+
if (c === "'")
|
|
44
|
+
inQuote = !inQuote;
|
|
45
|
+
if (inQuote)
|
|
46
|
+
continue;
|
|
47
|
+
if (c === '(')
|
|
48
|
+
depth++;
|
|
49
|
+
else if (c === ')') {
|
|
50
|
+
depth--;
|
|
51
|
+
if (depth === 0)
|
|
52
|
+
return text.slice(m.index, i + 1);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return undefined;
|
|
57
|
+
}
|
|
58
|
+
/** 逗号分隔的顶层简单参数(忽略嵌套括号内容仍按逗号简单切——够用即可)。 */
|
|
59
|
+
function splitTopLevel(body) {
|
|
60
|
+
// 剥离外层括号后,按未被引号包裹的逗号切分(不处理嵌套括号——STEP 伙伴级
|
|
61
|
+
// FILE_NAME/FILE_DESCRIPTION 参数都是简单标量/字符串,不涉及深层嵌套)。
|
|
62
|
+
const s = body.slice(body.indexOf('(') + 1, body.lastIndexOf(')'));
|
|
63
|
+
const parts = [];
|
|
64
|
+
let cur = '';
|
|
65
|
+
let inQuote = false;
|
|
66
|
+
for (let i = 0; i < s.length; i++) {
|
|
67
|
+
const c = s[i];
|
|
68
|
+
if (c === "'")
|
|
69
|
+
inQuote = !inQuote;
|
|
70
|
+
if (c === ',' && !inQuote) {
|
|
71
|
+
parts.push(cur);
|
|
72
|
+
cur = '';
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
cur += c;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
parts.push(cur);
|
|
79
|
+
return parts.map((p) => p.trim());
|
|
80
|
+
}
|
|
81
|
+
/** Header 段整块(FILE_NAME / FILE_DESCRIPTION / FILE_SCHEMA)→ FileMeta。 */
|
|
82
|
+
export function parseStepHeaderMeta(text) {
|
|
83
|
+
const meta = {};
|
|
84
|
+
const header = headerLines(text);
|
|
85
|
+
if (!header)
|
|
86
|
+
return meta;
|
|
87
|
+
const fileBlock = entityBlock(header, 'FILE_NAME');
|
|
88
|
+
if (fileBlock) {
|
|
89
|
+
const parts = splitTopLevel(fileBlock);
|
|
90
|
+
// FILE_NAME(name, time_stamp, author(list), organization(list), preprocessor, originator)
|
|
91
|
+
// 引号数组形如 `('x')`,去首尾括号后 unquote;author/organization 可能为列表。
|
|
92
|
+
const inline = (p) => {
|
|
93
|
+
if (!p)
|
|
94
|
+
return undefined;
|
|
95
|
+
const v = unquote(p.replace(/^\(|\)$/g, ''));
|
|
96
|
+
return v === '' ? undefined : v;
|
|
97
|
+
};
|
|
98
|
+
const title = inline(parts[0]);
|
|
99
|
+
if (title)
|
|
100
|
+
meta.title = title;
|
|
101
|
+
const cdate = inline(parts[1]);
|
|
102
|
+
if (cdate)
|
|
103
|
+
meta.creationDate = cdate;
|
|
104
|
+
const author = inline(parts[2] ?? '');
|
|
105
|
+
if (author)
|
|
106
|
+
meta.author = author;
|
|
107
|
+
const org = inline(parts[3] ?? '');
|
|
108
|
+
if (org)
|
|
109
|
+
meta.organization = org;
|
|
110
|
+
// preprocessor → application(编辑器导入后端把 preprocessor 视为 APP);
|
|
111
|
+
// originator → designer。
|
|
112
|
+
const pre = inline(parts[4] ?? '');
|
|
113
|
+
if (pre)
|
|
114
|
+
meta.application = pre;
|
|
115
|
+
const origin = inline(parts[5] ?? '');
|
|
116
|
+
if (origin)
|
|
117
|
+
meta.designer = origin;
|
|
118
|
+
}
|
|
119
|
+
const descBlock = entityBlock(header, 'FILE_DESCRIPTION');
|
|
120
|
+
if (descBlock) {
|
|
121
|
+
// FILE_DESCRIPTION(description_list, implementation_context):描述只取第一个
|
|
122
|
+
// 顶层参数(描述串列表,`('a','b')` 形态含内层逗号);实现上下文不算。
|
|
123
|
+
// 直接取 `FILE_DESCRIPTION((…),` 里第一层括号内的引号字符串列表。
|
|
124
|
+
const m = /FILE_DESCRIPTION\s*\(\s*\((.*?)\)\s*,\s*/.exec(descBlock);
|
|
125
|
+
if (m) {
|
|
126
|
+
const joined = m[1]
|
|
127
|
+
.split(',')
|
|
128
|
+
.map((p) => unquote(p.trim()))
|
|
129
|
+
.filter((v) => v !== '');
|
|
130
|
+
if (joined.length > 0)
|
|
131
|
+
meta.description = joined.join(', ');
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
return meta;
|
|
135
|
+
}
|
|
136
|
+
/** 伙伴层 PRODUCT 描述 + 根相关字段解析(简化:只取第一个 PRODUCT)。 */
|
|
137
|
+
export function parseStepPartMeta(text) {
|
|
138
|
+
const out = {};
|
|
139
|
+
// 逐 PRODUCT 取 description(第 2 个参数)。
|
|
140
|
+
const dataRe = /PRODUCT\s*\(/g;
|
|
141
|
+
let m;
|
|
142
|
+
while ((m = dataRe.exec(text)) !== null) {
|
|
143
|
+
const close = text.indexOf(')', m.index);
|
|
144
|
+
if (close < 0)
|
|
145
|
+
break;
|
|
146
|
+
const inner = text.slice(m.index, close + 1);
|
|
147
|
+
const descM = /,\s*'([^']*)'/.exec(inner);
|
|
148
|
+
if (descM) {
|
|
149
|
+
const d = descM[1];
|
|
150
|
+
if (d !== '')
|
|
151
|
+
out.description = d;
|
|
152
|
+
break; // 只取第一个
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
// 属性笼(UDA:GENERAL_PROPERTY('name', value?) 挂在 PROPERTY_DEFINITION 上)。
|
|
156
|
+
const props = {};
|
|
157
|
+
const gpRe = /GENERAL_PROPERTY\s*\(\s*'([^']*)'\s*,\s*([^,)]+)/g;
|
|
158
|
+
let gm;
|
|
159
|
+
while ((gm = gpRe.exec(text)) !== null) {
|
|
160
|
+
props[gm[1]] = unquote(gm[2]);
|
|
161
|
+
}
|
|
162
|
+
if (Object.keys(props).length > 0)
|
|
163
|
+
out.metadata = props;
|
|
164
|
+
return out;
|
|
165
|
+
}
|
|
166
|
+
//# sourceMappingURL=stepMetaParser.js.map
|