@faicad/faijs 0.14.1 → 0.16.1
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/dist/api/api-namespace.d.ts +7 -0
- package/dist/api/api-namespace.d.ts.map +1 -1
- package/dist/api/api-namespace.js +23 -22
- package/dist/api/api-namespace.js.map +1 -1
- package/dist/api/boolean.d.ts.map +1 -1
- package/dist/api/boolean.js +26 -8
- package/dist/api/boolean.js.map +1 -1
- package/dist/api/chamfer.d.ts.map +1 -1
- package/dist/api/chamfer.js +4 -1
- package/dist/api/chamfer.js.map +1 -1
- package/dist/api/generated/cad/script-face.d.ts +1 -1
- package/dist/api/generated/cad/script-face.d.ts.map +1 -1
- package/dist/api/generated/cad/script-face.js +1 -2
- package/dist/api/generated/cad/script-face.js.map +1 -1
- package/dist/api/generated/operations.js +16 -16
- package/dist/api/generated/operations.js.map +1 -1
- package/dist/api/generated/script-face-manifest.d.ts.map +1 -1
- package/dist/api/generated/script-face-manifest.js +0 -1
- package/dist/api/generated/script-face-manifest.js.map +1 -1
- package/dist/api/generated/script-face.d.ts +1 -4
- package/dist/api/generated/script-face.d.ts.map +1 -1
- package/dist/api/generated/script-face.js +2 -3
- package/dist/api/generated/script-face.js.map +1 -1
- package/dist/api/generated/sketching.js +1 -1
- package/dist/api/generated/sketching.js.map +1 -1
- package/dist/api/generated/topology.d.ts +0 -8
- package/dist/api/generated/topology.d.ts.map +1 -1
- package/dist/api/generated/topology.js +19 -26
- package/dist/api/generated/topology.js.map +1 -1
- package/dist/api/index.d.ts +1 -10
- package/dist/api/index.d.ts.map +1 -1
- package/dist/api/index.js +10 -18
- package/dist/api/index.js.map +1 -1
- package/dist/api/internal/compat-projection.d.ts +3 -1
- package/dist/api/internal/compat-projection.d.ts.map +1 -1
- package/dist/api/internal/compat-projection.js +8 -5
- package/dist/api/internal/compat-projection.js.map +1 -1
- package/dist/api/internal/replica-role-table.d.ts +36 -0
- package/dist/api/internal/replica-role-table.d.ts.map +1 -0
- package/dist/api/internal/replica-role-table.js +73 -0
- package/dist/api/internal/replica-role-table.js.map +1 -0
- package/dist/api/internal/result-unwrap.d.ts +3 -1
- package/dist/api/internal/result-unwrap.d.ts.map +1 -1
- package/dist/api/internal/result-unwrap.js +2 -2
- package/dist/api/internal/result-unwrap.js.map +1 -1
- package/dist/api/occt-kernel-bridge.d.ts +105 -27
- package/dist/api/occt-kernel-bridge.d.ts.map +1 -1
- package/dist/api/occt-kernel-bridge.js +255 -41
- package/dist/api/occt-kernel-bridge.js.map +1 -1
- package/dist/api/pattern.d.ts.map +1 -1
- package/dist/api/pattern.js +25 -61
- package/dist/api/pattern.js.map +1 -1
- package/dist/api/replicate.d.ts +145 -0
- package/dist/api/replicate.d.ts.map +1 -0
- package/dist/api/replicate.js +351 -0
- package/dist/api/replicate.js.map +1 -0
- package/dist/api/revolve.d.ts +36 -0
- package/dist/api/revolve.d.ts.map +1 -0
- package/dist/api/revolve.js +165 -0
- package/dist/api/revolve.js.map +1 -0
- package/dist/api/surface/arg-spec.d.ts +8 -0
- package/dist/api/surface/arg-spec.d.ts.map +1 -1
- package/dist/api/surface/arg-spec.js +37 -36
- package/dist/api/surface/arg-spec.js.map +1 -1
- package/dist/api/surface/projection-overrides.d.ts.map +1 -1
- package/dist/api/surface/projection-overrides.js +6 -0
- package/dist/api/surface/projection-overrides.js.map +1 -1
- package/dist/boolean/deriveNormals.d.ts +5 -4
- package/dist/boolean/deriveNormals.d.ts.map +1 -1
- package/dist/boolean/deriveNormals.js +24 -7
- package/dist/boolean/deriveNormals.js.map +1 -1
- package/dist/brep/engine/adapters/brep-mock.d.ts.map +1 -1
- package/dist/brep/engine/adapters/brep-mock.js +58 -0
- package/dist/brep/engine/adapters/brep-mock.js.map +1 -1
- package/dist/brep/engine/adapters/brepkit.d.ts.map +1 -1
- package/dist/brep/engine/adapters/brepkit.js +39 -1
- package/dist/brep/engine/adapters/brepkit.js.map +1 -1
- package/dist/brep/engine/adapters/occt.d.ts +1 -5
- package/dist/brep/engine/adapters/occt.d.ts.map +1 -1
- package/dist/brep/engine/adapters/occt.js +232 -18
- package/dist/brep/engine/adapters/occt.js.map +1 -1
- package/dist/brep/engine/primitives.d.ts +79 -0
- package/dist/brep/engine/primitives.d.ts.map +1 -1
- package/dist/brep/engine/primitives.js.map +1 -1
- package/dist/brep/engine/types.d.ts +18 -1
- package/dist/brep/engine/types.d.ts.map +1 -1
- package/dist/brep/engine/types.js.map +1 -1
- package/dist/brepkit-kernel/brepkitKernel.d.ts.map +1 -1
- package/dist/brepkit-kernel/brepkitKernel.js +81 -11
- package/dist/brepkit-kernel/brepkitKernel.js.map +1 -1
- package/dist/browser.d.ts +6 -28
- package/dist/browser.d.ts.map +1 -1
- package/dist/browser.js +6 -17
- package/dist/browser.js.map +1 -1
- package/dist/cad-runtime/admit-compat-lib.d.ts +13 -18
- package/dist/cad-runtime/admit-compat-lib.d.ts.map +1 -1
- package/dist/cad-runtime/admit-compat-lib.js +25 -18
- package/dist/cad-runtime/admit-compat-lib.js.map +1 -1
- package/dist/cad-runtime/backend-dispatch.d.ts +4 -2
- package/dist/cad-runtime/backend-dispatch.d.ts.map +1 -1
- package/dist/cad-runtime/backend-dispatch.js +2 -0
- package/dist/cad-runtime/backend-dispatch.js.map +1 -1
- package/dist/cad-runtime/browser-lib-loader.d.ts +4 -6
- package/dist/cad-runtime/browser-lib-loader.d.ts.map +1 -1
- package/dist/cad-runtime/browser-lib-loader.js +4 -9
- package/dist/cad-runtime/browser-lib-loader.js.map +1 -1
- package/dist/cad-runtime/ports.d.ts +0 -7
- package/dist/cad-runtime/ports.d.ts.map +1 -1
- package/dist/cad-runtime/ports.js.map +1 -1
- package/dist/cad-runtime/runtime.d.ts +1 -3
- package/dist/cad-runtime/runtime.d.ts.map +1 -1
- package/dist/cad-runtime/runtime.js +13 -18
- package/dist/cad-runtime/runtime.js.map +1 -1
- package/dist/env-agnostic.d.ts +38 -0
- package/dist/env-agnostic.d.ts.map +1 -0
- package/dist/env-agnostic.js +29 -0
- package/dist/env-agnostic.js.map +1 -0
- package/dist/fcstd/codegen.d.ts.map +1 -1
- package/dist/fcstd/codegen.js +8 -1
- package/dist/fcstd/codegen.js.map +1 -1
- package/dist/fcstd/expressions.d.ts +24 -0
- package/dist/fcstd/expressions.d.ts.map +1 -1
- package/dist/fcstd/expressions.js +91 -0
- package/dist/fcstd/expressions.js.map +1 -1
- package/dist/fcstd/feature-translate.d.ts.map +1 -1
- package/dist/fcstd/feature-translate.js +16 -2
- package/dist/fcstd/feature-translate.js.map +1 -1
- package/dist/fcstd/structural-types.d.ts.map +1 -1
- package/dist/fcstd/structural-types.js +5 -0
- package/dist/fcstd/structural-types.js.map +1 -1
- package/dist/index.d.ts +7 -24
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +10 -16
- package/dist/index.js.map +1 -1
- package/dist/lang/determinism-scanner.d.ts +9 -0
- package/dist/lang/determinism-scanner.d.ts.map +1 -1
- package/dist/lang/determinism-scanner.js +7 -1
- package/dist/lang/determinism-scanner.js.map +1 -1
- package/dist/lang/symbol-table.d.ts +31 -0
- package/dist/lang/symbol-table.d.ts.map +1 -1
- package/dist/lang/symbol-table.generated.d.ts +6 -16
- package/dist/lang/symbol-table.generated.d.ts.map +1 -1
- package/dist/lang/symbol-table.generated.js +6 -16
- package/dist/lang/symbol-table.generated.js.map +1 -1
- package/dist/lang/symbol-table.js +50 -1
- package/dist/lang/symbol-table.js.map +1 -1
- package/dist/mesh/creased-normals.d.ts +50 -0
- package/dist/mesh/creased-normals.d.ts.map +1 -0
- package/dist/mesh/creased-normals.js +114 -0
- package/dist/mesh/creased-normals.js.map +1 -0
- package/dist/mesh/decoration-provider.d.ts +53 -0
- package/dist/mesh/decoration-provider.d.ts.map +1 -0
- package/dist/mesh/decoration-provider.js +21 -0
- package/dist/mesh/decoration-provider.js.map +1 -0
- package/dist/mesh/engrave.d.ts +4 -0
- package/dist/mesh/engrave.d.ts.map +1 -1
- package/dist/mesh/engrave.js +22 -31
- package/dist/mesh/engrave.js.map +1 -1
- package/dist/mesh/index.d.ts +5 -14
- package/dist/mesh/index.d.ts.map +1 -1
- package/dist/mesh/index.js +7 -19
- package/dist/mesh/index.js.map +1 -1
- package/dist/mesh/io.d.ts +2 -1
- package/dist/mesh/io.d.ts.map +1 -1
- package/dist/mesh/io.js +5 -7
- package/dist/mesh/io.js.map +1 -1
- package/dist/mesh/primitives.d.ts +5 -18
- package/dist/mesh/primitives.d.ts.map +1 -1
- package/dist/mesh/primitives.js +4 -48
- package/dist/mesh/primitives.js.map +1 -1
- package/dist/mesh/stl-loader.d.ts +23 -0
- package/dist/mesh/stl-loader.d.ts.map +1 -0
- package/dist/mesh/stl-loader.js +139 -0
- package/dist/mesh/stl-loader.js.map +1 -0
- package/dist/module-resolver/parse-imports.d.ts +37 -0
- package/dist/module-resolver/parse-imports.d.ts.map +1 -0
- package/dist/module-resolver/parse-imports.js +39 -0
- package/dist/module-resolver/parse-imports.js.map +1 -0
- package/dist/module-resolver/resolver.d.ts +1 -1
- package/dist/module-resolver/resolver.js +2 -2
- package/dist/module-resolver/resolver.js.map +1 -1
- package/dist/node-host/cli.d.ts.map +1 -1
- package/dist/node-host/cli.js +1 -22
- package/dist/node-host/cli.js.map +1 -1
- package/dist/primitives/text/cjk-font.d.ts +42 -0
- package/dist/primitives/text/cjk-font.d.ts.map +1 -0
- package/dist/primitives/text/cjk-font.js +86 -0
- package/dist/primitives/text/cjk-font.js.map +1 -0
- package/dist/sdk.d.ts +2 -2
- package/dist/sdk.js +2 -2
- package/dist/sdk.js.map +1 -1
- package/dist/symbol-table.d.ts +15 -0
- package/dist/symbol-table.d.ts.map +1 -0
- package/dist/symbol-table.js +14 -0
- package/dist/symbol-table.js.map +1 -0
- package/dist/topology/naming/lineage-resolve.js +1 -1
- package/dist/topology/naming/lineage-resolve.js.map +1 -1
- package/dist/vendored/brepjs/kernel/index.d.ts +5 -0
- package/dist/vendored/brepjs/kernel/index.d.ts.map +1 -1
- package/dist/vendored/brepjs/kernel/index.js +11 -0
- package/dist/vendored/brepjs/kernel/index.js.map +1 -1
- package/dist/weapp.d.ts +3 -3
- package/dist/weapp.d.ts.map +1 -1
- package/dist/weapp.js +6 -3
- package/dist/weapp.js.map +1 -1
- package/package.json +16 -14
- package/dist/api/compat/index.d.ts +0 -173
- package/dist/api/compat/index.d.ts.map +0 -1
- package/dist/api/compat/index.js +0 -222
- package/dist/api/compat/index.js.map +0 -1
- package/dist/api/compound.d.ts +0 -110
- package/dist/api/compound.d.ts.map +0 -1
- package/dist/api/compound.js +0 -164
- package/dist/api/compound.js.map +0 -1
- package/dist/api/copy.d.ts +0 -40
- package/dist/api/copy.d.ts.map +0 -1
- package/dist/api/copy.js +0 -83
- package/dist/api/copy.js.map +0 -1
- package/dist/api/fai_drill.d.ts +0 -46
- package/dist/api/fai_drill.d.ts.map +0 -1
- package/dist/api/fai_drill.js +0 -243
- package/dist/api/fai_drill.js.map +0 -1
- package/dist/api/fai_extrude.d.ts +0 -36
- package/dist/api/fai_extrude.d.ts.map +0 -1
- package/dist/api/fai_extrude.js +0 -79
- package/dist/api/fai_extrude.js.map +0 -1
- package/dist/api/fai_split.d.ts +0 -46
- package/dist/api/fai_split.d.ts.map +0 -1
- package/dist/api/fai_split.js +0 -254
- package/dist/api/fai_split.js.map +0 -1
- package/dist/api/load.d.ts +0 -41
- package/dist/api/load.d.ts.map +0 -1
- package/dist/api/load.js +0 -84
- package/dist/api/load.js.map +0 -1
- package/dist/api/svgExtrude.d.ts +0 -32
- package/dist/api/svgExtrude.d.ts.map +0 -1
- package/dist/api/svgExtrude.js +0 -74
- package/dist/api/svgExtrude.js.map +0 -1
- package/dist/api/text.d.ts +0 -34
- package/dist/api/text.d.ts.map +0 -1
- package/dist/api/text.js +0 -101
- package/dist/api/text.js.map +0 -1
- package/dist/brep/text/fontTestHelper.d.ts +0 -30
- package/dist/brep/text/fontTestHelper.d.ts.map +0 -1
- package/dist/brep/text/fontTestHelper.js +0 -57
- package/dist/brep/text/fontTestHelper.js.map +0 -1
- package/dist/cad-runtime/module-executor.d.ts +0 -271
- package/dist/cad-runtime/module-executor.d.ts.map +0 -1
- package/dist/cad-runtime/module-executor.js +0 -630
- package/dist/cad-runtime/module-executor.js.map +0 -1
- package/dist/cad-runtime/terminal-dag.d.ts +0 -65
- package/dist/cad-runtime/terminal-dag.d.ts.map +0 -1
- package/dist/cad-runtime/terminal-dag.js +0 -167
- package/dist/cad-runtime/terminal-dag.js.map +0 -1
- package/dist/faqts/browser.d.ts +0 -16
- package/dist/faqts/browser.d.ts.map +0 -1
- package/dist/faqts/browser.js +0 -13
- package/dist/faqts/browser.js.map +0 -1
- package/dist/faqts/exec-blob.d.ts +0 -14
- package/dist/faqts/exec-blob.d.ts.map +0 -1
- package/dist/faqts/exec-blob.js +0 -22
- package/dist/faqts/exec-blob.js.map +0 -1
- package/dist/faqts/exec-node.d.ts +0 -15
- package/dist/faqts/exec-node.d.ts.map +0 -1
- package/dist/faqts/exec-node.js +0 -29
- package/dist/faqts/exec-node.js.map +0 -1
- package/dist/faqts/imports.d.ts +0 -74
- package/dist/faqts/imports.d.ts.map +0 -1
- package/dist/faqts/imports.js +0 -95
- package/dist/faqts/imports.js.map +0 -1
- package/dist/faqts/index.d.ts +0 -22
- package/dist/faqts/index.d.ts.map +0 -1
- package/dist/faqts/index.js +0 -21
- package/dist/faqts/index.js.map +0 -1
- package/dist/faqts/node.d.ts +0 -23
- package/dist/faqts/node.d.ts.map +0 -1
- package/dist/faqts/node.js +0 -23
- package/dist/faqts/node.js.map +0 -1
- package/dist/faqts/run.d.ts +0 -62
- package/dist/faqts/run.d.ts.map +0 -1
- package/dist/faqts/run.js +0 -62
- package/dist/faqts/run.js.map +0 -1
- package/dist/faqts/transform.d.ts +0 -43
- package/dist/faqts/transform.d.ts.map +0 -1
- package/dist/faqts/transform.js +0 -35
- package/dist/faqts/transform.js.map +0 -1
- package/dist/lang/compile.d.ts +0 -50
- package/dist/lang/compile.d.ts.map +0 -1
- package/dist/lang/compile.js +0 -368
- package/dist/lang/compile.js.map +0 -1
- package/dist/lang/keep.d.ts +0 -109
- package/dist/lang/keep.d.ts.map +0 -1
- package/dist/lang/keep.js +0 -226
- package/dist/lang/keep.js.map +0 -1
- package/dist/lang/parser.d.ts +0 -91
- package/dist/lang/parser.d.ts.map +0 -1
- package/dist/lang/parser.js +0 -1594
- package/dist/lang/parser.js.map +0 -1
- package/dist/mesh/drill-hole/DrillHoleCore.d.ts +0 -90
- package/dist/mesh/drill-hole/DrillHoleCore.d.ts.map +0 -1
- package/dist/mesh/drill-hole/DrillHoleCore.js +0 -287
- package/dist/mesh/drill-hole/DrillHoleCore.js.map +0 -1
- package/dist/mesh/drill-hole/drill-types.d.ts +0 -34
- package/dist/mesh/drill-hole/drill-types.d.ts.map +0 -1
- package/dist/mesh/drill-hole/drill-types.js +0 -7
- package/dist/mesh/drill-hole/drill-types.js.map +0 -1
- package/dist/mesh/fai_drill.d.ts +0 -21
- package/dist/mesh/fai_drill.d.ts.map +0 -1
- package/dist/mesh/fai_drill.js +0 -92
- package/dist/mesh/fai_drill.js.map +0 -1
- package/dist/mesh/fai_extrude.d.ts +0 -24
- package/dist/mesh/fai_extrude.d.ts.map +0 -1
- package/dist/mesh/fai_extrude.js +0 -42
- package/dist/mesh/fai_extrude.js.map +0 -1
- package/dist/mesh/fai_split.d.ts +0 -164
- package/dist/mesh/fai_split.d.ts.map +0 -1
- package/dist/mesh/fai_split.js +0 -269
- package/dist/mesh/fai_split.js.map +0 -1
- package/dist/primitives/svg-extrude.d.ts +0 -43
- package/dist/primitives/svg-extrude.d.ts.map +0 -1
- package/dist/primitives/svg-extrude.js +0 -78
- package/dist/primitives/svg-extrude.js.map +0 -1
- package/dist/primitives/text/cjk.d.ts +0 -61
- package/dist/primitives/text/cjk.d.ts.map +0 -1
- package/dist/primitives/text/cjk.js +0 -215
- package/dist/primitives/text/cjk.js.map +0 -1
- package/dist/primitives/text-geometry.d.ts +0 -47
- package/dist/primitives/text-geometry.d.ts.map +0 -1
- package/dist/primitives/text-geometry.js +0 -127
- package/dist/primitives/text-geometry.js.map +0 -1
- package/dist/test-helpers.d.ts +0 -31
- package/dist/test-helpers.d.ts.map +0 -1
- package/dist/test-helpers.js +0 -55
- package/dist/test-helpers.js.map +0 -1
- package/dist/vendored/brepjs/core/kernelReentrancy.d.ts +0 -41
- package/dist/vendored/brepjs/core/kernelReentrancy.d.ts.map +0 -1
- package/dist/vendored/brepjs/core/kernelReentrancy.js +0 -68
- package/dist/vendored/brepjs/core/kernelReentrancy.js.map +0 -1
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* CJK (Chinese/Japanese/Korean) text geometry generation.
|
|
3
|
-
*
|
|
4
|
-
* Uses the Local Font Access API (window.queryLocalFonts) to load system CJK
|
|
5
|
-
* fonts, then parses glyph paths with opentype.js to create THREE.Shape →
|
|
6
|
-
* ExtrudeGeometry.
|
|
7
|
-
*
|
|
8
|
-
* When a CJK font is available, it is used for ALL characters (including Latin).
|
|
9
|
-
* When no CJK font is available, the default OpenSans Regular font (from
|
|
10
|
-
* fontRegistry) is used for all characters via opentype.js.
|
|
11
|
-
*/
|
|
12
|
-
import * as THREE from 'three';
|
|
13
|
-
import * as opentype from 'opentype.js';
|
|
14
|
-
import type { Font } from 'opentype.js';
|
|
15
|
-
/**
|
|
16
|
-
* Check if a character is CJK (CJK Unified Ideographs + extensions).
|
|
17
|
-
*
|
|
18
|
-
* @param ch - the single character to test.
|
|
19
|
-
* @returns true when the character falls in a CJK code point range.
|
|
20
|
-
*/
|
|
21
|
-
export declare function isCjkChar(ch: string): boolean;
|
|
22
|
-
/**
|
|
23
|
-
* Check if a text string contains any CJK characters.
|
|
24
|
-
*
|
|
25
|
-
* @param text - the text to scan.
|
|
26
|
-
* @returns true when at least one character is CJK.
|
|
27
|
-
*/
|
|
28
|
-
export declare function containsCjk(text: string): boolean;
|
|
29
|
-
/** Result of loading a system CJK font. */
|
|
30
|
-
export interface CjkFontResult {
|
|
31
|
-
font: opentype.Font;
|
|
32
|
-
family: string;
|
|
33
|
-
}
|
|
34
|
-
/**
|
|
35
|
-
* Load a CJK font from the system using the Local Font Access API.
|
|
36
|
-
* Returns null if unavailable (no permission, unsupported browser, or no CJK font found).
|
|
37
|
-
*
|
|
38
|
-
* @returns a promise resolving to the parsed CJK font and its family name,
|
|
39
|
-
* or null when no usable system CJK font is available.
|
|
40
|
-
*/
|
|
41
|
-
export declare function loadSystemCjkFont(): Promise<CjkFontResult | null>;
|
|
42
|
-
/**
|
|
43
|
-
* Generate geometry for mixed text (CJK + Latin).
|
|
44
|
-
*
|
|
45
|
-
* When cjkFont is available, it is used for ALL characters (including Latin),
|
|
46
|
-
* since CJK fonts typically contain Latin glyphs.
|
|
47
|
-
*
|
|
48
|
-
* When cjkFont is null, the default OpenSans Regular font (from fontRegistry)
|
|
49
|
-
* is used for all characters via opentype.js — this is the same font used by
|
|
50
|
-
* the BREP path, ensuring glyph consistency.
|
|
51
|
-
*
|
|
52
|
-
* @param text Text string to render
|
|
53
|
-
* @param size Font size in mm
|
|
54
|
-
* @param depth Extrusion depth in mm
|
|
55
|
-
* @param cjkFont CJK font from system (null = use default font only)
|
|
56
|
-
* @param defaultFont Default opentype.js Font (OpenSans Regular from fontRegistry).
|
|
57
|
-
* If not provided, will be loaded via getOpentypeFont().
|
|
58
|
-
* @returns a promise resolving to the merged, centred geometry for the whole text.
|
|
59
|
-
*/
|
|
60
|
-
export declare function createMixedTextGeometry(text: string, size: number, depth: number, cjkFont: Font | null, defaultFont?: Font): Promise<THREE.BufferGeometry>;
|
|
61
|
-
//# sourceMappingURL=cjk.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"cjk.d.ts","sourceRoot":"","sources":["../../../src/primitives/text/cjk.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAC9B,OAAO,KAAK,QAAQ,MAAM,aAAa,CAAA;AACvC,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,aAAa,CAAA;AAIvC;;;;;GAKG;AACH,wBAAgB,SAAS,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAS7C;AAED;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAKjD;AAED,2CAA2C;AAC3C,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,QAAQ,CAAC,IAAI,CAAA;IACnB,MAAM,EAAE,MAAM,CAAA;CACf;AAED;;;;;;GAMG;AACH,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC,CAwCvE;AAsED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAsB,uBAAuB,CAC3C,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,IAAI,GAAG,IAAI,EACpB,WAAW,CAAC,EAAE,IAAI,GACjB,OAAO,CAAC,KAAK,CAAC,cAAc,CAAC,CA4D/B"}
|
|
@@ -1,215 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* CJK (Chinese/Japanese/Korean) text geometry generation.
|
|
3
|
-
*
|
|
4
|
-
* Uses the Local Font Access API (window.queryLocalFonts) to load system CJK
|
|
5
|
-
* fonts, then parses glyph paths with opentype.js to create THREE.Shape →
|
|
6
|
-
* ExtrudeGeometry.
|
|
7
|
-
*
|
|
8
|
-
* When a CJK font is available, it is used for ALL characters (including Latin).
|
|
9
|
-
* When no CJK font is available, the default OpenSans Regular font (from
|
|
10
|
-
* fontRegistry) is used for all characters via opentype.js.
|
|
11
|
-
*/
|
|
12
|
-
import * as THREE from 'three';
|
|
13
|
-
import * as opentype from 'opentype.js';
|
|
14
|
-
import { mergeBufferGeometries } from '../../primitives/mesh-primitives.js';
|
|
15
|
-
import { getOpentypeFont } from '../text-geometry.js';
|
|
16
|
-
/**
|
|
17
|
-
* Check if a character is CJK (CJK Unified Ideographs + extensions).
|
|
18
|
-
*
|
|
19
|
-
* @param ch - the single character to test.
|
|
20
|
-
* @returns true when the character falls in a CJK code point range.
|
|
21
|
-
*/
|
|
22
|
-
export function isCjkChar(ch) {
|
|
23
|
-
const code = ch.charCodeAt(0);
|
|
24
|
-
return ((code >= 0x4E00 && code <= 0x9FFF) || // CJK Unified Ideographs
|
|
25
|
-
(code >= 0x3400 && code <= 0x4DBF) || // CJK Extension A
|
|
26
|
-
(code >= 0x2F800 && code <= 0x2FA1F) || // CJK Compatibility Ideographs Supplement
|
|
27
|
-
(code >= 0x3000 && code <= 0x303F) || // CJK Symbols and Punctuation
|
|
28
|
-
(code >= 0xFF00 && code <= 0xFFEF) // Fullwidth Forms
|
|
29
|
-
);
|
|
30
|
-
}
|
|
31
|
-
/**
|
|
32
|
-
* Check if a text string contains any CJK characters.
|
|
33
|
-
*
|
|
34
|
-
* @param text - the text to scan.
|
|
35
|
-
* @returns true when at least one character is CJK.
|
|
36
|
-
*/
|
|
37
|
-
export function containsCjk(text) {
|
|
38
|
-
for (const ch of text) {
|
|
39
|
-
if (isCjkChar(ch))
|
|
40
|
-
return true;
|
|
41
|
-
}
|
|
42
|
-
return false;
|
|
43
|
-
}
|
|
44
|
-
/**
|
|
45
|
-
* Load a CJK font from the system using the Local Font Access API.
|
|
46
|
-
* Returns null if unavailable (no permission, unsupported browser, or no CJK font found).
|
|
47
|
-
*
|
|
48
|
-
* @returns a promise resolving to the parsed CJK font and its family name,
|
|
49
|
-
* or null when no usable system CJK font is available.
|
|
50
|
-
*/
|
|
51
|
-
export async function loadSystemCjkFont() {
|
|
52
|
-
const w = typeof window !== 'undefined' ? window : undefined;
|
|
53
|
-
if (!w || typeof w.queryLocalFonts !== 'function') {
|
|
54
|
-
return null;
|
|
55
|
-
}
|
|
56
|
-
try {
|
|
57
|
-
const fonts = await w.queryLocalFonts();
|
|
58
|
-
// Find a font that supports CJK
|
|
59
|
-
const cjkFont = fonts.find((f) => f.family.includes('Microsoft YaHei') ||
|
|
60
|
-
f.family.includes('SimSun') ||
|
|
61
|
-
f.family.includes('Noto Sans') ||
|
|
62
|
-
f.family.includes('Noto Serif') ||
|
|
63
|
-
f.fullName.includes('CJK') ||
|
|
64
|
-
f.fullName.includes('SC') ||
|
|
65
|
-
f.fullName.includes('CN') ||
|
|
66
|
-
f.fullName.includes('JP') ||
|
|
67
|
-
f.fullName.includes('KR') ||
|
|
68
|
-
f.family.includes('Source Han') ||
|
|
69
|
-
f.family.includes('思源') ||
|
|
70
|
-
f.family.includes('微软雅黑') ||
|
|
71
|
-
f.family.includes('宋体') ||
|
|
72
|
-
f.family.includes('黑体') ||
|
|
73
|
-
f.family.includes('楷体') ||
|
|
74
|
-
f.family.includes('仿宋'));
|
|
75
|
-
if (!cjkFont)
|
|
76
|
-
return null;
|
|
77
|
-
const fontData = await cjkFont.blob();
|
|
78
|
-
const buf = await fontData.arrayBuffer();
|
|
79
|
-
const font = opentype.parse(buf);
|
|
80
|
-
return { font, family: cjkFont.family };
|
|
81
|
-
}
|
|
82
|
-
catch {
|
|
83
|
-
// User denied permission or other error
|
|
84
|
-
return null;
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
/**
|
|
88
|
-
* Generate geometry for a single character using opentype.js.
|
|
89
|
-
* Uses the shared opentypePathToGeometry() from text-geometry.ts.
|
|
90
|
-
*/
|
|
91
|
-
function charGeometry(char, size, depth, font, xOffset) {
|
|
92
|
-
const glyph = font.charToGlyph(char);
|
|
93
|
-
if (!glyph || !glyph.path)
|
|
94
|
-
return null;
|
|
95
|
-
const path = glyph.getPath(xOffset, 0, size);
|
|
96
|
-
if (!path || !path.commands || path.commands.length === 0)
|
|
97
|
-
return null;
|
|
98
|
-
// Use the shared opentypePathToGeometry, but without centering (we handle offset manually)
|
|
99
|
-
const commands = path.commands;
|
|
100
|
-
if (commands.length === 0)
|
|
101
|
-
return null;
|
|
102
|
-
const shapes = [];
|
|
103
|
-
let currentShape = null;
|
|
104
|
-
for (const cmd of commands) {
|
|
105
|
-
switch (cmd.type) {
|
|
106
|
-
case 'M':
|
|
107
|
-
// Implicit closure: opentype.js doesn't always emit 'Z' before a new 'M'.
|
|
108
|
-
if (currentShape) {
|
|
109
|
-
shapes.push(currentShape);
|
|
110
|
-
}
|
|
111
|
-
currentShape = new THREE.Shape();
|
|
112
|
-
currentShape.moveTo(cmd.x, cmd.y);
|
|
113
|
-
break;
|
|
114
|
-
case 'L':
|
|
115
|
-
currentShape?.lineTo(cmd.x, cmd.y);
|
|
116
|
-
break;
|
|
117
|
-
case 'C':
|
|
118
|
-
currentShape?.bezierCurveTo(cmd.x1, cmd.y1, cmd.x2, cmd.y2, cmd.x, cmd.y);
|
|
119
|
-
break;
|
|
120
|
-
case 'Q':
|
|
121
|
-
currentShape?.quadraticCurveTo(cmd.x1, cmd.y1, cmd.x, cmd.y);
|
|
122
|
-
break;
|
|
123
|
-
case 'Z':
|
|
124
|
-
if (currentShape) {
|
|
125
|
-
shapes.push(currentShape);
|
|
126
|
-
currentShape = null;
|
|
127
|
-
}
|
|
128
|
-
break;
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
// Handle final unclosed subpath (opentype.js doesn't always emit 'Z')
|
|
132
|
-
if (currentShape) {
|
|
133
|
-
shapes.push(currentShape);
|
|
134
|
-
}
|
|
135
|
-
if (shapes.length === 0)
|
|
136
|
-
return null;
|
|
137
|
-
const geo = new THREE.ExtrudeGeometry(shapes, {
|
|
138
|
-
depth,
|
|
139
|
-
bevelEnabled: false,
|
|
140
|
-
curveSegments: 6,
|
|
141
|
-
});
|
|
142
|
-
return geo;
|
|
143
|
-
}
|
|
144
|
-
/**
|
|
145
|
-
* Generate geometry for mixed text (CJK + Latin).
|
|
146
|
-
*
|
|
147
|
-
* When cjkFont is available, it is used for ALL characters (including Latin),
|
|
148
|
-
* since CJK fonts typically contain Latin glyphs.
|
|
149
|
-
*
|
|
150
|
-
* When cjkFont is null, the default OpenSans Regular font (from fontRegistry)
|
|
151
|
-
* is used for all characters via opentype.js — this is the same font used by
|
|
152
|
-
* the BREP path, ensuring glyph consistency.
|
|
153
|
-
*
|
|
154
|
-
* @param text Text string to render
|
|
155
|
-
* @param size Font size in mm
|
|
156
|
-
* @param depth Extrusion depth in mm
|
|
157
|
-
* @param cjkFont CJK font from system (null = use default font only)
|
|
158
|
-
* @param defaultFont Default opentype.js Font (OpenSans Regular from fontRegistry).
|
|
159
|
-
* If not provided, will be loaded via getOpentypeFont().
|
|
160
|
-
* @returns a promise resolving to the merged, centred geometry for the whole text.
|
|
161
|
-
*/
|
|
162
|
-
export async function createMixedTextGeometry(text, size, depth, cjkFont, defaultFont) {
|
|
163
|
-
// Use CJK font for all chars if available, otherwise use default font
|
|
164
|
-
const font = cjkFont ?? defaultFont ?? (await getOpentypeFont());
|
|
165
|
-
// All characters individually
|
|
166
|
-
const charGeos = [];
|
|
167
|
-
let cursorX = 0;
|
|
168
|
-
for (const char of text) {
|
|
169
|
-
if (char === ' ' || char === '\t' || char === '\n' || char === '\r') {
|
|
170
|
-
// Space: advance by approximate width
|
|
171
|
-
const spaceAdv = font.charToGlyph(' ').advanceWidth ?? size / 3;
|
|
172
|
-
cursorX += spaceAdv * (size / font.unitsPerEm);
|
|
173
|
-
continue;
|
|
174
|
-
}
|
|
175
|
-
const glyph = font.charToGlyph(char);
|
|
176
|
-
if (glyph.index === 0) {
|
|
177
|
-
// Skip notdef glyphs (should not happen if font check was done upstream)
|
|
178
|
-
continue;
|
|
179
|
-
}
|
|
180
|
-
const geo = charGeometry(char, size, depth, font, cursorX);
|
|
181
|
-
if (geo) {
|
|
182
|
-
geo.computeBoundingBox();
|
|
183
|
-
const bb = geo.boundingBox;
|
|
184
|
-
const charWidth = bb.max.x - bb.min.x;
|
|
185
|
-
const adv = (glyph.advanceWidth ?? 0) * (size / font.unitsPerEm);
|
|
186
|
-
// Use advance width for cursor, but ensure minimum advance
|
|
187
|
-
const effectiveAdv = adv > 0 ? adv : charWidth + size * 0.1;
|
|
188
|
-
charGeos.push({ geo, advance: effectiveAdv });
|
|
189
|
-
cursorX += effectiveAdv;
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
// Merge all character geometries into one
|
|
193
|
-
if (charGeos.length === 0) {
|
|
194
|
-
// Fallback: create a minimal geometry from a question mark
|
|
195
|
-
const geo = charGeometry('?', size, depth, font, 0);
|
|
196
|
-
if (geo)
|
|
197
|
-
return geo;
|
|
198
|
-
return new THREE.BufferGeometry();
|
|
199
|
-
}
|
|
200
|
-
// Merge via BufferGeometryUtils or manual merge
|
|
201
|
-
const merged = mergeBufferGeometries(charGeos.map((cg) => cg.geo));
|
|
202
|
-
// Center the whole text in X/Z
|
|
203
|
-
merged.computeBoundingBox();
|
|
204
|
-
if (merged.boundingBox) {
|
|
205
|
-
const cx = (merged.boundingBox.max.x + merged.boundingBox.min.x) / 2;
|
|
206
|
-
const cz = (merged.boundingBox.max.z + merged.boundingBox.min.z) / 2;
|
|
207
|
-
merged.translate(-cx, -merged.boundingBox.min.y, -cz);
|
|
208
|
-
}
|
|
209
|
-
// Dispose individual geometries
|
|
210
|
-
for (const cg of charGeos) {
|
|
211
|
-
cg.geo.dispose();
|
|
212
|
-
}
|
|
213
|
-
return merged;
|
|
214
|
-
}
|
|
215
|
-
//# sourceMappingURL=cjk.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"cjk.js","sourceRoot":"","sources":["../../../src/primitives/text/cjk.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * CJK (Chinese/Japanese/Korean) text geometry generation.\n *\n * Uses the Local Font Access API (window.queryLocalFonts) to load system CJK\n * fonts, then parses glyph paths with opentype.js to create THREE.Shape →\n * ExtrudeGeometry.\n *\n * When a CJK font is available, it is used for ALL characters (including Latin).\n * When no CJK font is available, the default OpenSans Regular font (from\n * fontRegistry) is used for all characters via opentype.js.\n */\nimport * as THREE from 'three'\nimport * as opentype from 'opentype.js'\nimport type { Font } from 'opentype.js'\nimport { mergeBufferGeometries } from '../../primitives/mesh-primitives'\nimport { getOpentypeFont } from '../text-geometry'\n\n/**\n * Check if a character is CJK (CJK Unified Ideographs + extensions).\n *\n * @param ch - the single character to test.\n * @returns true when the character falls in a CJK code point range.\n */\nexport function isCjkChar(ch: string): boolean {\n const code = ch.charCodeAt(0)\n return (\n (code >= 0x4E00 && code <= 0x9FFF) || // CJK Unified Ideographs\n (code >= 0x3400 && code <= 0x4DBF) || // CJK Extension A\n (code >= 0x2F800 && code <= 0x2FA1F) || // CJK Compatibility Ideographs Supplement\n (code >= 0x3000 && code <= 0x303F) || // CJK Symbols and Punctuation\n (code >= 0xFF00 && code <= 0xFFEF) // Fullwidth Forms\n )\n}\n\n/**\n * Check if a text string contains any CJK characters.\n *\n * @param text - the text to scan.\n * @returns true when at least one character is CJK.\n */\nexport function containsCjk(text: string): boolean {\n for (const ch of text) {\n if (isCjkChar(ch)) return true\n }\n return false\n}\n\n/** Result of loading a system CJK font. */\nexport interface CjkFontResult {\n font: opentype.Font\n family: string\n}\n\n/**\n * Load a CJK font from the system using the Local Font Access API.\n * Returns null if unavailable (no permission, unsupported browser, or no CJK font found).\n *\n * @returns a promise resolving to the parsed CJK font and its family name,\n * or null when no usable system CJK font is available.\n */\nexport async function loadSystemCjkFont(): Promise<CjkFontResult | null> {\n const w = typeof window !== 'undefined' ? (window as any) : undefined\n if (!w || typeof w.queryLocalFonts !== 'function') {\n return null\n }\n\n try {\n const fonts: Array<{ family: string; fullName: string; style: string; postscriptName: string; blob: () => Promise<Blob> }> = await w.queryLocalFonts()\n\n // Find a font that supports CJK\n const cjkFont = fonts.find((f) =>\n f.family.includes('Microsoft YaHei') ||\n f.family.includes('SimSun') ||\n f.family.includes('Noto Sans') ||\n f.family.includes('Noto Serif') ||\n f.fullName.includes('CJK') ||\n f.fullName.includes('SC') ||\n f.fullName.includes('CN') ||\n f.fullName.includes('JP') ||\n f.fullName.includes('KR') ||\n f.family.includes('Source Han') ||\n f.family.includes('思源') ||\n f.family.includes('微软雅黑') ||\n f.family.includes('宋体') ||\n f.family.includes('黑体') ||\n f.family.includes('楷体') ||\n f.family.includes('仿宋')\n )\n\n if (!cjkFont) return null\n\n const fontData = await cjkFont.blob()\n const buf = await fontData.arrayBuffer()\n const font = opentype.parse(buf)\n\n return { font, family: cjkFont.family }\n } catch {\n // User denied permission or other error\n return null\n }\n}\n\n/**\n * Generate geometry for a single character using opentype.js.\n * Uses the shared opentypePathToGeometry() from text-geometry.ts.\n */\nfunction charGeometry(\n char: string,\n size: number,\n depth: number,\n font: Font,\n xOffset: number,\n): THREE.BufferGeometry | null {\n const glyph = font.charToGlyph(char)\n if (!glyph || !glyph.path) return null\n\n const path = glyph.getPath(xOffset, 0, size)\n if (!path || !path.commands || path.commands.length === 0) return null\n\n // Use the shared opentypePathToGeometry, but without centering (we handle offset manually)\n const commands = path.commands as opentype.PathCommand[]\n if (commands.length === 0) return null\n\n const shapes: THREE.Shape[] = []\n let currentShape: THREE.Shape | null = null\n\n for (const cmd of commands) {\n switch (cmd.type) {\n case 'M':\n // Implicit closure: opentype.js doesn't always emit 'Z' before a new 'M'.\n if (currentShape) {\n shapes.push(currentShape)\n }\n currentShape = new THREE.Shape()\n currentShape.moveTo(cmd.x!, cmd.y!)\n break\n case 'L':\n currentShape?.lineTo(cmd.x!, cmd.y!)\n break\n case 'C':\n currentShape?.bezierCurveTo(cmd.x1!, cmd.y1!, cmd.x2!, cmd.y2!, cmd.x!, cmd.y!)\n break\n case 'Q':\n currentShape?.quadraticCurveTo(cmd.x1!, cmd.y1!, cmd.x!, cmd.y!)\n break\n case 'Z':\n if (currentShape) {\n shapes.push(currentShape)\n currentShape = null\n }\n break\n }\n }\n\n // Handle final unclosed subpath (opentype.js doesn't always emit 'Z')\n if (currentShape) {\n shapes.push(currentShape)\n }\n\n if (shapes.length === 0) return null\n\n const geo = new THREE.ExtrudeGeometry(shapes, {\n depth,\n bevelEnabled: false,\n curveSegments: 6,\n })\n return geo\n}\n\n\n/**\n * Generate geometry for mixed text (CJK + Latin).\n *\n * When cjkFont is available, it is used for ALL characters (including Latin),\n * since CJK fonts typically contain Latin glyphs.\n *\n * When cjkFont is null, the default OpenSans Regular font (from fontRegistry)\n * is used for all characters via opentype.js — this is the same font used by\n * the BREP path, ensuring glyph consistency.\n *\n * @param text Text string to render\n * @param size Font size in mm\n * @param depth Extrusion depth in mm\n * @param cjkFont CJK font from system (null = use default font only)\n * @param defaultFont Default opentype.js Font (OpenSans Regular from fontRegistry).\n * If not provided, will be loaded via getOpentypeFont().\n * @returns a promise resolving to the merged, centred geometry for the whole text.\n */\nexport async function createMixedTextGeometry(\n text: string,\n size: number,\n depth: number,\n cjkFont: Font | null,\n defaultFont?: Font,\n): Promise<THREE.BufferGeometry> {\n // Use CJK font for all chars if available, otherwise use default font\n const font = cjkFont ?? defaultFont ?? (await getOpentypeFont())\n\n // All characters individually\n const charGeos: { geo: THREE.BufferGeometry; advance: number }[] = []\n let cursorX = 0\n\n for (const char of text) {\n if (char === ' ' || char === '\\t' || char === '\\n' || char === '\\r') {\n // Space: advance by approximate width\n const spaceAdv = font.charToGlyph(' ').advanceWidth ?? size / 3\n cursorX += spaceAdv * (size / font.unitsPerEm)\n continue\n }\n\n const glyph = font.charToGlyph(char)\n if (glyph.index === 0) {\n // Skip notdef glyphs (should not happen if font check was done upstream)\n continue\n }\n\n const geo = charGeometry(char, size, depth, font, cursorX)\n if (geo) {\n geo.computeBoundingBox()\n const bb = geo.boundingBox!\n const charWidth = bb.max.x - bb.min.x\n const adv = (glyph.advanceWidth ?? 0) * (size / font.unitsPerEm)\n // Use advance width for cursor, but ensure minimum advance\n const effectiveAdv = adv > 0 ? adv : charWidth + size * 0.1\n charGeos.push({ geo, advance: effectiveAdv })\n cursorX += effectiveAdv\n }\n }\n\n // Merge all character geometries into one\n if (charGeos.length === 0) {\n // Fallback: create a minimal geometry from a question mark\n const geo = charGeometry('?', size, depth, font, 0)\n if (geo) return geo\n return new THREE.BufferGeometry()\n }\n\n // Merge via BufferGeometryUtils or manual merge\n const merged = mergeBufferGeometries(charGeos.map((cg) => cg.geo))\n\n // Center the whole text in X/Z\n merged.computeBoundingBox()\n if (merged.boundingBox) {\n const cx = (merged.boundingBox.max.x + merged.boundingBox.min.x) / 2\n const cz = (merged.boundingBox.max.z + merged.boundingBox.min.z) / 2\n merged.translate(-cx, -merged.boundingBox.min.y, -cz)\n }\n\n // Dispose individual geometries\n for (const cg of charGeos) {\n cg.geo.dispose()\n }\n\n return merged\n}\n"]}
|
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* text-geometry — 文字几何创建(mesh 路径)
|
|
3
|
-
*
|
|
4
|
-
* 使用 opentype.js + OpenSans Regular 字体(与 BREP 路径统一)。
|
|
5
|
-
* 字体来源:fontRegistry(通过依赖注入的 FontLoader 加载)。
|
|
6
|
-
*
|
|
7
|
-
* 过渡期仍用 THREE.Shape/ExtrudeGeometry,R6 时再替换为 manifold。
|
|
8
|
-
*/
|
|
9
|
-
import * as THREE from 'three';
|
|
10
|
-
import type { Font, Path } from 'opentype.js';
|
|
11
|
-
/**
|
|
12
|
-
* Get the default opentype.js font (OpenSans Regular).
|
|
13
|
-
*
|
|
14
|
-
* Fetched from fontRegistry — the same font used by the BREP path
|
|
15
|
-
* (text-to-solid). The first call triggers a lazy ensureDefaultFont() load.
|
|
16
|
-
*
|
|
17
|
-
* @returns a promise resolving to the default opentype.js Font.
|
|
18
|
-
*/
|
|
19
|
-
export declare function getOpentypeFont(): Promise<Font>;
|
|
20
|
-
/**
|
|
21
|
-
* Create text geometry centered in X/Z, extruded along +Z.
|
|
22
|
-
*
|
|
23
|
-
* Uses opentype.js font.getPath() → THREE.Shape → ExtrudeGeometry.
|
|
24
|
-
* This is the same font source as the BREP path (text-to-solid),
|
|
25
|
-
* ensuring glyph consistency between mesh and BREP paths.
|
|
26
|
-
*
|
|
27
|
-
* @param text Text string to render
|
|
28
|
-
* @param size Font size in mm
|
|
29
|
-
* @param depth Extrusion depth in mm
|
|
30
|
-
* @param font opentype.js Font object (from fontRegistry)
|
|
31
|
-
* @returns a promise resolving to the extruded text geometry.
|
|
32
|
-
*/
|
|
33
|
-
export declare function createTextGeometry(text: string, size: number, depth: number, font: Font): Promise<THREE.BufferGeometry>;
|
|
34
|
-
/**
|
|
35
|
-
* Convert an opentype.js Path to THREE.BufferGeometry.
|
|
36
|
-
*
|
|
37
|
-
* Path commands → THREE.Shape → ExtrudeGeometry.
|
|
38
|
-
* The result is centered in X and Z (bounding box center → origin).
|
|
39
|
-
*
|
|
40
|
-
* Exported for reuse by the CJK text path and 3d_editor preview layer.
|
|
41
|
-
*
|
|
42
|
-
* @param path - the opentype.js path to convert.
|
|
43
|
-
* @param depth - extrusion depth in mm.
|
|
44
|
-
* @returns the resulting BufferGeometry, or null when the path is empty.
|
|
45
|
-
*/
|
|
46
|
-
export declare function opentypePathToGeometry(path: Path, depth: number): THREE.BufferGeometry | null;
|
|
47
|
-
//# sourceMappingURL=text-geometry.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"text-geometry.d.ts","sourceRoot":"","sources":["../../src/primitives/text-geometry.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAC9B,OAAO,KAAK,EAAE,IAAI,EAAE,IAAI,EAAe,MAAM,aAAa,CAAA;AAK1D;;;;;;;GAOG;AACH,wBAAsB,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC,CAUrD;AAID;;;;;;;;;;;;GAYG;AACH,wBAAsB,kBAAkB,CACtC,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,IAAI,GACT,OAAO,CAAC,KAAK,CAAC,cAAc,CAAC,CAmB/B;AAID;;;;;;;;;;;GAWG;AACH,wBAAgB,sBAAsB,CACpC,IAAI,EAAE,IAAI,EACV,KAAK,EAAE,MAAM,GACZ,KAAK,CAAC,cAAc,GAAG,IAAI,CAuD7B"}
|
|
@@ -1,127 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* text-geometry — 文字几何创建(mesh 路径)
|
|
3
|
-
*
|
|
4
|
-
* 使用 opentype.js + OpenSans Regular 字体(与 BREP 路径统一)。
|
|
5
|
-
* 字体来源:fontRegistry(通过依赖注入的 FontLoader 加载)。
|
|
6
|
-
*
|
|
7
|
-
* 过渡期仍用 THREE.Shape/ExtrudeGeometry,R6 时再替换为 manifold。
|
|
8
|
-
*/
|
|
9
|
-
import * as THREE from 'three';
|
|
10
|
-
import { ensureDefaultFont, getFont as getRegisteredFont } from '../brep/text/fontRegistry.js';
|
|
11
|
-
// ── Font loading ──
|
|
12
|
-
/**
|
|
13
|
-
* Get the default opentype.js font (OpenSans Regular).
|
|
14
|
-
*
|
|
15
|
-
* Fetched from fontRegistry — the same font used by the BREP path
|
|
16
|
-
* (text-to-solid). The first call triggers a lazy ensureDefaultFont() load.
|
|
17
|
-
*
|
|
18
|
-
* @returns a promise resolving to the default opentype.js Font.
|
|
19
|
-
*/
|
|
20
|
-
export async function getOpentypeFont() {
|
|
21
|
-
await ensureDefaultFont();
|
|
22
|
-
const font = getRegisteredFont('default');
|
|
23
|
-
if (!font) {
|
|
24
|
-
throw new Error('[text-geometry] Default font not loaded. ' +
|
|
25
|
-
'Call setFontLoader() before using text functions.');
|
|
26
|
-
}
|
|
27
|
-
return font;
|
|
28
|
-
}
|
|
29
|
-
// ── Text geometry ──
|
|
30
|
-
/**
|
|
31
|
-
* Create text geometry centered in X/Z, extruded along +Z.
|
|
32
|
-
*
|
|
33
|
-
* Uses opentype.js font.getPath() → THREE.Shape → ExtrudeGeometry.
|
|
34
|
-
* This is the same font source as the BREP path (text-to-solid),
|
|
35
|
-
* ensuring glyph consistency between mesh and BREP paths.
|
|
36
|
-
*
|
|
37
|
-
* @param text Text string to render
|
|
38
|
-
* @param size Font size in mm
|
|
39
|
-
* @param depth Extrusion depth in mm
|
|
40
|
-
* @param font opentype.js Font object (from fontRegistry)
|
|
41
|
-
* @returns a promise resolving to the extruded text geometry.
|
|
42
|
-
*/
|
|
43
|
-
export async function createTextGeometry(text, size, depth, font) {
|
|
44
|
-
// Check for notdef glyphs (missing characters)
|
|
45
|
-
for (const ch of text) {
|
|
46
|
-
if (ch === ' ' || ch === '\t' || ch === '\n' || ch === '\r')
|
|
47
|
-
continue;
|
|
48
|
-
const glyph = font.charToGlyph(ch);
|
|
49
|
-
if (glyph.index === 0) {
|
|
50
|
-
throw new Error(`[text-geometry] Character "${ch}" (U+${ch.codePointAt(0).toString(16).toUpperCase()}) ` +
|
|
51
|
-
`not found in font. If it is a CJK character, a CJK font must be loaded.`);
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
const path = font.getPath(text, 0, 0, size);
|
|
55
|
-
const geo = opentypePathToGeometry(path, depth);
|
|
56
|
-
if (!geo) {
|
|
57
|
-
throw new Error(`[text-geometry] Failed to create geometry from text: "${text}"`);
|
|
58
|
-
}
|
|
59
|
-
return geo;
|
|
60
|
-
}
|
|
61
|
-
// ── opentype path → THREE geometry ──
|
|
62
|
-
/**
|
|
63
|
-
* Convert an opentype.js Path to THREE.BufferGeometry.
|
|
64
|
-
*
|
|
65
|
-
* Path commands → THREE.Shape → ExtrudeGeometry.
|
|
66
|
-
* The result is centered in X and Z (bounding box center → origin).
|
|
67
|
-
*
|
|
68
|
-
* Exported for reuse by the CJK text path and 3d_editor preview layer.
|
|
69
|
-
*
|
|
70
|
-
* @param path - the opentype.js path to convert.
|
|
71
|
-
* @param depth - extrusion depth in mm.
|
|
72
|
-
* @returns the resulting BufferGeometry, or null when the path is empty.
|
|
73
|
-
*/
|
|
74
|
-
export function opentypePathToGeometry(path, depth) {
|
|
75
|
-
const commands = path.commands;
|
|
76
|
-
if (commands.length === 0)
|
|
77
|
-
return null;
|
|
78
|
-
const shapes = [];
|
|
79
|
-
let currentShape = null;
|
|
80
|
-
for (const cmd of commands) {
|
|
81
|
-
switch (cmd.type) {
|
|
82
|
-
case 'M':
|
|
83
|
-
// Implicit closure: opentype.js doesn't always emit 'Z' before a new 'M'.
|
|
84
|
-
// Push the current shape before starting a new subpath.
|
|
85
|
-
if (currentShape) {
|
|
86
|
-
shapes.push(currentShape);
|
|
87
|
-
}
|
|
88
|
-
currentShape = new THREE.Shape();
|
|
89
|
-
currentShape.moveTo(cmd.x, cmd.y);
|
|
90
|
-
break;
|
|
91
|
-
case 'L':
|
|
92
|
-
currentShape?.lineTo(cmd.x, cmd.y);
|
|
93
|
-
break;
|
|
94
|
-
case 'C':
|
|
95
|
-
currentShape?.bezierCurveTo(cmd.x1, cmd.y1, cmd.x2, cmd.y2, cmd.x, cmd.y);
|
|
96
|
-
break;
|
|
97
|
-
case 'Q':
|
|
98
|
-
currentShape?.quadraticCurveTo(cmd.x1, cmd.y1, cmd.x, cmd.y);
|
|
99
|
-
break;
|
|
100
|
-
case 'Z':
|
|
101
|
-
if (currentShape) {
|
|
102
|
-
shapes.push(currentShape);
|
|
103
|
-
currentShape = null;
|
|
104
|
-
}
|
|
105
|
-
break;
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
// Handle final unclosed subpath (opentype.js doesn't always emit 'Z')
|
|
109
|
-
if (currentShape) {
|
|
110
|
-
shapes.push(currentShape);
|
|
111
|
-
}
|
|
112
|
-
if (shapes.length === 0)
|
|
113
|
-
return null;
|
|
114
|
-
const geo = new THREE.ExtrudeGeometry(shapes, {
|
|
115
|
-
depth,
|
|
116
|
-
bevelEnabled: false,
|
|
117
|
-
curveSegments: 6,
|
|
118
|
-
});
|
|
119
|
-
geo.computeBoundingBox();
|
|
120
|
-
if (geo.boundingBox) {
|
|
121
|
-
const cx = (geo.boundingBox.max.x + geo.boundingBox.min.x) / 2;
|
|
122
|
-
const cz = (geo.boundingBox.max.z + geo.boundingBox.min.z) / 2;
|
|
123
|
-
geo.translate(-cx, -geo.boundingBox.min.y, -cz);
|
|
124
|
-
}
|
|
125
|
-
return geo;
|
|
126
|
-
}
|
|
127
|
-
//# sourceMappingURL=text-geometry.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"text-geometry.js","sourceRoot":"","sources":["../../src/primitives/text-geometry.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * text-geometry — 文字几何创建(mesh 路径)\n *\n * 使用 opentype.js + OpenSans Regular 字体(与 BREP 路径统一)。\n * 字体来源:fontRegistry(通过依赖注入的 FontLoader 加载)。\n *\n * 过渡期仍用 THREE.Shape/ExtrudeGeometry,R6 时再替换为 manifold。\n */\n\nimport * as THREE from 'three'\nimport type { Font, Path, PathCommand } from 'opentype.js'\nimport { ensureDefaultFont, getFont as getRegisteredFont } from '../brep/text/fontRegistry'\n\n// ── Font loading ──\n\n/**\n * Get the default opentype.js font (OpenSans Regular).\n *\n * Fetched from fontRegistry — the same font used by the BREP path\n * (text-to-solid). The first call triggers a lazy ensureDefaultFont() load.\n *\n * @returns a promise resolving to the default opentype.js Font.\n */\nexport async function getOpentypeFont(): Promise<Font> {\n await ensureDefaultFont()\n const font = getRegisteredFont('default')\n if (!font) {\n throw new Error(\n '[text-geometry] Default font not loaded. ' +\n 'Call setFontLoader() before using text functions.',\n )\n }\n return font\n}\n\n// ── Text geometry ──\n\n/**\n * Create text geometry centered in X/Z, extruded along +Z.\n *\n * Uses opentype.js font.getPath() → THREE.Shape → ExtrudeGeometry.\n * This is the same font source as the BREP path (text-to-solid),\n * ensuring glyph consistency between mesh and BREP paths.\n *\n * @param text Text string to render\n * @param size Font size in mm\n * @param depth Extrusion depth in mm\n * @param font opentype.js Font object (from fontRegistry)\n * @returns a promise resolving to the extruded text geometry.\n */\nexport async function createTextGeometry(\n text: string,\n size: number,\n depth: number,\n font: Font,\n): Promise<THREE.BufferGeometry> {\n // Check for notdef glyphs (missing characters)\n for (const ch of text) {\n if (ch === ' ' || ch === '\\t' || ch === '\\n' || ch === '\\r') continue\n const glyph = font.charToGlyph(ch)\n if (glyph.index === 0) {\n throw new Error(\n `[text-geometry] Character \"${ch}\" (U+${ch.codePointAt(0)!.toString(16).toUpperCase()}) ` +\n `not found in font. If it is a CJK character, a CJK font must be loaded.`,\n )\n }\n }\n\n const path = font.getPath(text, 0, 0, size)\n const geo = opentypePathToGeometry(path, depth)\n if (!geo) {\n throw new Error(`[text-geometry] Failed to create geometry from text: \"${text}\"`)\n }\n return geo\n}\n\n// ── opentype path → THREE geometry ──\n\n/**\n * Convert an opentype.js Path to THREE.BufferGeometry.\n *\n * Path commands → THREE.Shape → ExtrudeGeometry.\n * The result is centered in X and Z (bounding box center → origin).\n *\n * Exported for reuse by the CJK text path and 3d_editor preview layer.\n *\n * @param path - the opentype.js path to convert.\n * @param depth - extrusion depth in mm.\n * @returns the resulting BufferGeometry, or null when the path is empty.\n */\nexport function opentypePathToGeometry(\n path: Path,\n depth: number,\n): THREE.BufferGeometry | null {\n const commands = path.commands as PathCommand[]\n if (commands.length === 0) return null\n\n const shapes: THREE.Shape[] = []\n let currentShape: THREE.Shape | null = null\n\n for (const cmd of commands) {\n switch (cmd.type) {\n case 'M':\n // Implicit closure: opentype.js doesn't always emit 'Z' before a new 'M'.\n // Push the current shape before starting a new subpath.\n if (currentShape) {\n shapes.push(currentShape)\n }\n currentShape = new THREE.Shape()\n currentShape.moveTo(cmd.x!, cmd.y!)\n break\n case 'L':\n currentShape?.lineTo(cmd.x!, cmd.y!)\n break\n case 'C':\n currentShape?.bezierCurveTo(cmd.x1!, cmd.y1!, cmd.x2!, cmd.y2!, cmd.x!, cmd.y!)\n break\n case 'Q':\n currentShape?.quadraticCurveTo(cmd.x1!, cmd.y1!, cmd.x!, cmd.y!)\n break\n case 'Z':\n if (currentShape) {\n shapes.push(currentShape)\n currentShape = null\n }\n break\n }\n }\n\n // Handle final unclosed subpath (opentype.js doesn't always emit 'Z')\n if (currentShape) {\n shapes.push(currentShape)\n }\n\n if (shapes.length === 0) return null\n\n const geo = new THREE.ExtrudeGeometry(shapes, {\n depth,\n bevelEnabled: false,\n curveSegments: 6,\n })\n geo.computeBoundingBox()\n if (geo.boundingBox) {\n const cx = (geo.boundingBox.max.x + geo.boundingBox.min.x) / 2\n const cz = (geo.boundingBox.max.z + geo.boundingBox.min.z) / 2\n geo.translate(-cx, -geo.boundingBox.min.y, -cz)\n }\n return geo\n}\n"]}
|
package/dist/test-helpers.d.ts
DELETED
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* test-helpers — 测试辅助函数
|
|
3
|
-
*
|
|
4
|
-
* 提供 executeScript 等便利函数,供测试使用。
|
|
5
|
-
* 从 script-engine/replay-validator.ts 迁移(原名 replayScript,已改名对齐 roadmap §3.6)。
|
|
6
|
-
*
|
|
7
|
-
* Phase 2.5:executeScript 改用 CadRuntime(VM 执行),不再依赖 src/ops/dispatcher 的 executeStatement。
|
|
8
|
-
* executeScript 接受代码文本,走 CadRuntime.execute(无 IR 中间层)。
|
|
9
|
-
*/
|
|
10
|
-
import type { Shape } from './mesh/types.js';
|
|
11
|
-
import type { BrepChainState } from './brep/brep-chain.js';
|
|
12
|
-
import type { HostPorts, ExecutionMode } from './cad-runtime/ports.js';
|
|
13
|
-
/** Result of executing a script via the test helper. */
|
|
14
|
-
export interface ExecuteOutput {
|
|
15
|
-
contentKey: string;
|
|
16
|
-
shape: Shape;
|
|
17
|
-
brepChain: BrepChainState;
|
|
18
|
-
}
|
|
19
|
-
/**
|
|
20
|
-
* Execute a script through the CadRuntime (direct path) and return the final
|
|
21
|
-
* shape, its content key, and the resulting BREP chain state.
|
|
22
|
-
*
|
|
23
|
-
* @param code - the .fai.js source text to execute.
|
|
24
|
-
* @param params - optional execution parameters.
|
|
25
|
-
* @param ports - optional host ports (defaults to a no-op events sink).
|
|
26
|
-
* @param mode - optional execution mode.
|
|
27
|
-
* @param _brepChain - optional pre-existing BREP chain state (reserved).
|
|
28
|
-
* @returns the final shape, content key, and BREP chain state.
|
|
29
|
-
*/
|
|
30
|
-
export declare function executeScript(code: string, params?: Record<string, unknown>, ports?: HostPorts, mode?: ExecutionMode, _brepChain?: BrepChainState): Promise<ExecuteOutput>;
|
|
31
|
-
//# sourceMappingURL=test-helpers.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"test-helpers.d.ts","sourceRoot":"","sources":["../src/test-helpers.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,cAAc,CAAA;AACzC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAA;AAIvD,OAAO,KAAK,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAA;AAWnE,wDAAwD;AACxD,MAAM,WAAW,aAAa;IAC5B,UAAU,EAAE,MAAM,CAAA;IAClB,KAAK,EAAE,KAAK,CAAA;IACZ,SAAS,EAAE,cAAc,CAAA;CAC1B;AAOD;;;;;;;;;;GAUG;AACH,wBAAsB,aAAa,CACjC,IAAI,EAAE,MAAM,EACZ,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAChC,KAAK,CAAC,EAAE,SAAS,EACjB,IAAI,CAAC,EAAE,aAAa,EACpB,UAAU,CAAC,EAAE,cAAc,GAC1B,OAAO,CAAC,aAAa,CAAC,CAsBxB"}
|
package/dist/test-helpers.js
DELETED
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* test-helpers — 测试辅助函数
|
|
3
|
-
*
|
|
4
|
-
* 提供 executeScript 等便利函数,供测试使用。
|
|
5
|
-
* 从 script-engine/replay-validator.ts 迁移(原名 replayScript,已改名对齐 roadmap §3.6)。
|
|
6
|
-
*
|
|
7
|
-
* Phase 2.5:executeScript 改用 CadRuntime(VM 执行),不再依赖 src/ops/dispatcher 的 executeStatement。
|
|
8
|
-
* executeScript 接受代码文本,走 CadRuntime.execute(无 IR 中间层)。
|
|
9
|
-
*/
|
|
10
|
-
import { createRuntime } from './cad-runtime/runtime.js';
|
|
11
|
-
import { computeContentKey } from './cad-runtime/runtime.js';
|
|
12
|
-
// P6/D1:库函数已并入 core 的 api/ 层(原 packages/stdlib 取消)。
|
|
13
|
-
// 用「变量动态 import」——tsc 不解析非字面量 specifier,vitest 经 alias 解析到 api 源码。
|
|
14
|
-
const API_NAMESPACE_MODULE = '@faicad/faijs-core/api/api-namespace';
|
|
15
|
-
async function getCadLib() {
|
|
16
|
-
const mod = (await import(API_NAMESPACE_MODULE));
|
|
17
|
-
return mod.createApiNamespace();
|
|
18
|
-
}
|
|
19
|
-
/** 最小 ports(events no-op),供未传 ports 的测试使用。 */
|
|
20
|
-
function defaultPorts() {
|
|
21
|
-
return { events: { emit: () => { } } };
|
|
22
|
-
}
|
|
23
|
-
/**
|
|
24
|
-
* Execute a script through the CadRuntime (direct path) and return the final
|
|
25
|
-
* shape, its content key, and the resulting BREP chain state.
|
|
26
|
-
*
|
|
27
|
-
* @param code - the .fai.js source text to execute.
|
|
28
|
-
* @param params - optional execution parameters.
|
|
29
|
-
* @param ports - optional host ports (defaults to a no-op events sink).
|
|
30
|
-
* @param mode - optional execution mode.
|
|
31
|
-
* @param _brepChain - optional pre-existing BREP chain state (reserved).
|
|
32
|
-
* @returns the final shape, content key, and BREP chain state.
|
|
33
|
-
*/
|
|
34
|
-
export async function executeScript(code, params, ports, mode, _brepChain) {
|
|
35
|
-
// P5/E-a-1:测试辅助注入 cad 命名空间(core 不默认装配;test-helpers 只被测试消费)
|
|
36
|
-
const runtime = createRuntime(ports ?? defaultPorts(), mode, { cad: await getCadLib() });
|
|
37
|
-
const result = await runtime.execute(code, { params });
|
|
38
|
-
// 从 outputs 中取最后一个 shape(与原逻辑一致)
|
|
39
|
-
const shapeNames = [...result.outputs.keys()];
|
|
40
|
-
if (shapeNames.length === 0) {
|
|
41
|
-
throw new Error(`[executeScript] empty result — no geometry outputs`);
|
|
42
|
-
}
|
|
43
|
-
const finalName = shapeNames[shapeNames.length - 1];
|
|
44
|
-
const finalShape = result.outputs.get(finalName);
|
|
45
|
-
if (!('positions' in finalShape) || !('indices' in finalShape)) {
|
|
46
|
-
throw new Error(`[executeScript] final output "${finalName}" is not a mesh shape`);
|
|
47
|
-
}
|
|
48
|
-
const contentKey = computeContentKey(finalShape.positions, finalShape.indices);
|
|
49
|
-
return {
|
|
50
|
-
contentKey,
|
|
51
|
-
shape: finalShape,
|
|
52
|
-
brepChain: result.brepChain,
|
|
53
|
-
};
|
|
54
|
-
}
|
|
55
|
-
//# sourceMappingURL=test-helpers.js.map
|
package/dist/test-helpers.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"test-helpers.js","sourceRoot":"","sources":["../src/test-helpers.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAIH,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAA;AACrD,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAA;AAIzD,oDAAoD;AACpD,mEAAmE;AACnE,MAAM,oBAAoB,GAAG,sCAAsC,CAAA;AAEnE,KAAK,UAAU,SAAS;IACtB,MAAM,GAAG,GAAG,CAAC,MAAM,MAAM,CAAC,oBAAoB,CAAC,CAAkD,CAAA;IACjG,OAAO,GAAG,CAAC,kBAAkB,EAAE,CAAA;AACjC,CAAC;AASD,8CAA8C;AAC9C,SAAS,YAAY;IACnB,OAAO,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE,GAAE,CAAC,EAAE,EAAe,CAAA;AACpD,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,IAAY,EACZ,MAAgC,EAChC,KAAiB,EACjB,IAAoB,EACpB,UAA2B;IAE3B,2DAA2D;IAC3D,MAAM,OAAO,GAAG,aAAa,CAAC,KAAK,IAAI,YAAY,EAAE,EAAE,IAAI,EAAE,EAAE,GAAG,EAAE,MAAM,SAAS,EAAE,EAAE,CAAC,CAAA;IACxF,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,MAAM,EAAE,CAAC,CAAA;IAEtD,iCAAiC;IACjC,MAAM,UAAU,GAAG,CAAC,GAAG,MAAM,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,CAAA;IAC7C,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC5B,MAAM,IAAI,KAAK,CAAC,oDAAoD,CAAC,CAAA;IACvE,CAAC;IACD,MAAM,SAAS,GAAG,UAAU,CAAC,UAAU,CAAC,MAAM,GAAG,CAAC,CAAC,CAAA;IACnD,MAAM,UAAU,GAAG,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,SAAS,CAAE,CAAA;IACjD,IAAI,CAAC,CAAC,WAAW,IAAI,UAAU,CAAC,IAAI,CAAC,CAAC,SAAS,IAAI,UAAU,CAAC,EAAE,CAAC;QAC/D,MAAM,IAAI,KAAK,CAAC,iCAAiC,SAAS,uBAAuB,CAAC,CAAA;IACpF,CAAC;IACD,MAAM,UAAU,GAAG,iBAAiB,CAAC,UAAU,CAAC,SAAS,EAAE,UAAU,CAAC,OAAO,CAAC,CAAA;IAE9E,OAAO;QACL,UAAU;QACV,KAAK,EAAE,UAAU;QACjB,SAAS,EAAE,MAAM,CAAC,SAAS;KAC5B,CAAA;AACH,CAAC","sourcesContent":["/**\n * test-helpers — 测试辅助函数\n *\n * 提供 executeScript 等便利函数,供测试使用。\n * 从 script-engine/replay-validator.ts 迁移(原名 replayScript,已改名对齐 roadmap §3.6)。\n *\n * Phase 2.5:executeScript 改用 CadRuntime(VM 执行),不再依赖 src/ops/dispatcher 的 executeStatement。\n * executeScript 接受代码文本,走 CadRuntime.execute(无 IR 中间层)。\n */\n\nimport type { Shape } from './mesh/types'\nimport type { BrepChainState } from './brep/brep-chain'\nimport { createRuntime } from './cad-runtime/runtime'\nimport { computeContentKey } from './cad-runtime/runtime'\nimport type { StdlibNamespace } from './runtime-state'\nimport type { HostPorts, ExecutionMode } from './cad-runtime/ports'\n\n// P6/D1:库函数已并入 core 的 api/ 层(原 packages/stdlib 取消)。\n// 用「变量动态 import」——tsc 不解析非字面量 specifier,vitest 经 alias 解析到 api 源码。\nconst API_NAMESPACE_MODULE = '@faicad/faijs-core/api/api-namespace'\n\nasync function getCadLib(): Promise<StdlibNamespace> {\n const mod = (await import(API_NAMESPACE_MODULE)) as { createApiNamespace: () => StdlibNamespace }\n return mod.createApiNamespace()\n}\n\n/** Result of executing a script via the test helper. */\nexport interface ExecuteOutput {\n contentKey: string\n shape: Shape\n brepChain: BrepChainState\n}\n\n/** 最小 ports(events no-op),供未传 ports 的测试使用。 */\nfunction defaultPorts(): HostPorts {\n return { events: { emit: () => {} } } as HostPorts\n}\n\n/**\n * Execute a script through the CadRuntime (direct path) and return the final\n * shape, its content key, and the resulting BREP chain state.\n *\n * @param code - the .fai.js source text to execute.\n * @param params - optional execution parameters.\n * @param ports - optional host ports (defaults to a no-op events sink).\n * @param mode - optional execution mode.\n * @param _brepChain - optional pre-existing BREP chain state (reserved).\n * @returns the final shape, content key, and BREP chain state.\n */\nexport async function executeScript(\n code: string,\n params?: Record<string, unknown>,\n ports?: HostPorts,\n mode?: ExecutionMode,\n _brepChain?: BrepChainState,\n): Promise<ExecuteOutput> {\n // P5/E-a-1:测试辅助注入 cad 命名空间(core 不默认装配;test-helpers 只被测试消费)\n const runtime = createRuntime(ports ?? defaultPorts(), mode, { cad: await getCadLib() })\n const result = await runtime.execute(code, { params })\n\n // 从 outputs 中取最后一个 shape(与原逻辑一致)\n const shapeNames = [...result.outputs.keys()]\n if (shapeNames.length === 0) {\n throw new Error(`[executeScript] empty result — no geometry outputs`)\n }\n const finalName = shapeNames[shapeNames.length - 1]\n const finalShape = result.outputs.get(finalName)!\n if (!('positions' in finalShape) || !('indices' in finalShape)) {\n throw new Error(`[executeScript] final output \"${finalName}\" is not a mesh shape`)\n }\n const contentKey = computeContentKey(finalShape.positions, finalShape.indices)\n\n return {\n contentKey,\n shape: finalShape,\n brepChain: result.brepChain,\n }\n}\n"]}
|