@faicad/faijs 0.29.3 → 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.
Files changed (80) hide show
  1. package/dist/api/appearance.d.ts +138 -0
  2. package/dist/api/appearance.d.ts.map +1 -0
  3. package/dist/api/appearance.js +230 -0
  4. package/dist/api/appearance.js.map +1 -0
  5. package/dist/api/import-step.d.ts.map +1 -1
  6. package/dist/api/import-step.js +28 -0
  7. package/dist/api/import-step.js.map +1 -1
  8. package/dist/api/index.d.ts +4 -0
  9. package/dist/api/index.d.ts.map +1 -1
  10. package/dist/api/index.js +2 -0
  11. package/dist/api/index.js.map +1 -1
  12. package/dist/api/meta.d.ts +93 -0
  13. package/dist/api/meta.d.ts.map +1 -0
  14. package/dist/api/meta.js +99 -0
  15. package/dist/api/meta.js.map +1 -0
  16. package/dist/api/primitives.d.ts.map +1 -1
  17. package/dist/api/primitives.js +117 -2
  18. package/dist/api/primitives.js.map +1 -1
  19. package/dist/brep/brep-ops.d.ts.map +1 -1
  20. package/dist/brep/brep-ops.js +28 -3
  21. package/dist/brep/brep-ops.js.map +1 -1
  22. package/dist/brep/engine/adapters/occt.js +1 -1
  23. package/dist/brep/engine/adapters/occt.js.map +1 -1
  24. package/dist/brep/export/export-model.d.ts +40 -0
  25. package/dist/brep/export/export-model.d.ts.map +1 -1
  26. package/dist/brep/export/export-model.js +268 -25
  27. package/dist/brep/export/export-model.js.map +1 -1
  28. package/dist/brep/export/step-meta-header.d.ts +102 -0
  29. package/dist/brep/export/step-meta-header.d.ts.map +1 -0
  30. package/dist/brep/export/step-meta-header.js +225 -0
  31. package/dist/brep/export/step-meta-header.js.map +1 -0
  32. package/dist/brep/export/step.d.ts +5 -1
  33. package/dist/brep/export/step.d.ts.map +1 -1
  34. package/dist/brep/export/step.js +11 -2
  35. package/dist/brep/export/step.js.map +1 -1
  36. package/dist/define-op.d.ts.map +1 -1
  37. package/dist/define-op.js +63 -1
  38. package/dist/define-op.js.map +1 -1
  39. package/dist/lang/metadata-extractor.d.ts.map +1 -1
  40. package/dist/lang/metadata-extractor.js +2 -21
  41. package/dist/lang/metadata-extractor.js.map +1 -1
  42. package/dist/lang/types.d.ts +5 -6
  43. package/dist/lang/types.d.ts.map +1 -1
  44. package/dist/lang/types.js.map +1 -1
  45. package/dist/mesh/io.d.ts +6 -0
  46. package/dist/mesh/io.d.ts.map +1 -1
  47. package/dist/mesh/io.js +25 -1
  48. package/dist/mesh/io.js.map +1 -1
  49. package/dist/mesh/primitives.d.ts.map +1 -1
  50. package/dist/mesh/primitives.js +41 -6
  51. package/dist/mesh/primitives.js.map +1 -1
  52. package/dist/mesh/threemf-loader.d.ts +23 -0
  53. package/dist/mesh/threemf-loader.d.ts.map +1 -1
  54. package/dist/mesh/threemf-loader.js +182 -8
  55. package/dist/mesh/threemf-loader.js.map +1 -1
  56. package/dist/mesh/types.d.ts +38 -0
  57. package/dist/mesh/types.d.ts.map +1 -1
  58. package/dist/mesh/types.js.map +1 -1
  59. package/dist/occt-kernel/highLevelApi.d.ts +4 -1
  60. package/dist/occt-kernel/highLevelApi.d.ts.map +1 -1
  61. package/dist/occt-kernel/highLevelApi.js +4 -2
  62. package/dist/occt-kernel/highLevelApi.js.map +1 -1
  63. package/dist/occt-kernel/occt-primitives.js +1 -1
  64. package/dist/occt-kernel/occt-primitives.js.map +1 -1
  65. package/dist/occt-kernel/occtKernel.d.ts +1 -1
  66. package/dist/occt-kernel/occtKernel.js +1 -1
  67. package/dist/occt-kernel/occtKernel.js.map +1 -1
  68. package/dist/occt-kernel/stepMetaParser.d.ts +44 -0
  69. package/dist/occt-kernel/stepMetaParser.d.ts.map +1 -0
  70. package/dist/occt-kernel/stepMetaParser.js +166 -0
  71. package/dist/occt-kernel/stepMetaParser.js.map +1 -0
  72. package/dist/shape.d.ts +11 -3
  73. package/dist/shape.d.ts.map +1 -1
  74. package/dist/shape.js +4 -2
  75. package/dist/shape.js.map +1 -1
  76. package/dist/step/stepMetaParser.d.ts +55 -0
  77. package/dist/step/stepMetaParser.d.ts.map +1 -0
  78. package/dist/step/stepMetaParser.js +177 -0
  79. package/dist/step/stepMetaParser.js.map +1 -0
  80. package/package.json +2 -2
@@ -0,0 +1,93 @@
1
+ /**
2
+ * api/meta — faijs 零件名称/描述/料号 与 整体文件元数据 权威类型与 Shape 方法
3
+ *
4
+ * 设计文档:docs/plans/2026-10-05-faijs-meta-name-note-api-design.md
5
+ *
6
+ * 定位(与 api/appearance.ts 同款方法模式):
7
+ * - 名称/描述设置**不是 op**(不进 defineOp/api-namespace/args-schema),是 Shape
8
+ * 实例方法(`box1.setName('…')`,复用 `asm1.solve()` 的成员调用语句形态)。
9
+ * - `ShapeMeta`(零件级)与 `FileMeta`(整体级)引擎无关、JSON 可序列化;
10
+ * `Shape.meta` 随 Shape 走 mesh/brep 双链路,编辑器/查看器只读字段。
11
+ * - 本文件零依赖(不 import THREE / occt / store);唯一 import 是 mesh/types
12
+ * 的 `Shape` 类型(type-only),mesh/types 亦只 type-import 本文件的类型,
13
+ * 两者为类型环、无运行时环(值依赖单向:shape.ts → api/meta.ts)。
14
+ *
15
+ * 命名约定(camelCase,faijs 全 TS/JS 生态):
16
+ * - 零件级:`name` / `description` / `partNumber` / `metadata`(键值)。
17
+ * - 方法:`setName` / `setDescription` / `setPartNumber` / `setMetaField` /
18
+ * `setMeta` / `getMeta`。字段名与 3MF/STEP 规范一致(不用 note)。
19
+ * 空串 = 清除:`setName('')` 删除 name(与「undefined 不覆盖」互补,用户可
20
+ * 显式去掉继承来的名称)。
21
+ */
22
+ import type { Shape } from '../mesh/types.js';
23
+ /** 零件级说明性元数据 —— 引擎无关、JSON 可序列化、随 Shape 走双链路。 */
24
+ export interface ShapeMeta {
25
+ /** 零件名:3MF `<object name>` / STEP `PRODUCT().name`。 */
26
+ name?: string;
27
+ /** 描述:STEP `PRODUCT.description`;3MF 写 `faijs:description` metadatagroup。 */
28
+ description?: string;
29
+ /** 料号:3MF `<object partnumber>`;STEP `PRODUCT_IDENTIFICATION` 或 UDA。 */
30
+ partNumber?: string;
31
+ /**
32
+ * 自定义键值:3MF `<object><metadatagroup>`(vendor 前缀);STEP UDA。
33
+ * 键为规范/厂商原始名(3MF 含命名空间前缀);faijs 不解释值语义,
34
+ * 读入保留、写出回写。
35
+ */
36
+ metadata?: Record<string, string>;
37
+ }
38
+ /**
39
+ * 整体/文档级说明性元数据 —— 导入结果 / 导出选项,不挂 Shape。
40
+ *
41
+ * 不叫 `ModelMeta`:CAD 直觉里 "model" 偏单个零件(那是 `ShapeMeta` 的活);
42
+ * 本类型承载整个交换文件(3MF `<model>` / STEP P21 header)的元数据,故用
43
+ * `FileMeta`。
44
+ */
45
+ export interface FileMeta {
46
+ title?: string;
47
+ description?: string;
48
+ designer?: string;
49
+ author?: string;
50
+ organization?: string;
51
+ copyright?: string;
52
+ licenseTerms?: string;
53
+ rating?: string;
54
+ creationDate?: string;
55
+ modificationDate?: string;
56
+ application?: string;
57
+ /** 未知/厂商自定义 metadata 兜底(3MF model 级带前缀名;STEP header 其余字段)。 */
58
+ metadata?: Record<string, string>;
59
+ }
60
+ /** Shape 元数据方法签名(运行时由 attachMetaMethods 挂载;纯数据判定不受影响)。 */
61
+ export interface ShapeMetaMethods {
62
+ /** 合并 meta:`{...cur, ...spec}`,spec 中 undefined 字段保留旧值。 */
63
+ setMeta(spec: ShapeMeta): this;
64
+ /** 便捷:等价 setMeta({ name })(空串视为清除)。 */
65
+ setName(name: string): this;
66
+ /** 便捷:等价 setMeta({ description })(空串视为清除)。 */
67
+ setDescription(description: string): this;
68
+ /** 便捷:等价 setMeta({ partNumber })。 */
69
+ setPartNumber(partNumber: string): this;
70
+ /** 便捷:等价 setMeta({ metadata: {...cur.metadata, ...kv} });值为空串的键删除。 */
71
+ setMetaField(key: string, value: string): this;
72
+ /** 读取当前 meta(可能 undefined)。 */
73
+ getMeta(): Readonly<ShapeMeta> | undefined;
74
+ }
75
+ /**
76
+ * 合并零件级元数据:spec 中 undefined 字段不覆盖旧值;空串覆盖为清除。
77
+ * @param cur 当前 meta(可为 undefined)
78
+ * @param spec 待合并字段(undefined 字段跳过;'' 显式清除)
79
+ * @returns 合并后的 meta(新对象;cur 为 undefined 时仅含 spec 非空字段)
80
+ */
81
+ export declare function mergeMeta(cur: ShapeMeta | undefined, spec: ShapeMeta): ShapeMeta;
82
+ /**
83
+ * 给 Shape 实例挂载元数据方法(幂等:已有 setMeta 则跳过)。
84
+ *
85
+ * 所有产物构造点(solid/curve → fromBrep/fromMeshSolid/fromBrepCurve)统一
86
+ * 调用本函数,保证 mesh/brep 双支路产物都可用 `box1.setName(...)`。
87
+ * 方法**不序列化**(JSON 丢弃函数);`meta` 字段随产物跨打印,编辑器/
88
+ * 查看器只读字段即可,不依赖方法。
89
+ * @param shape 产物 Shape 实例(solid/curve 产物)
90
+ * @returns 挂载后的 shape(类型提升为 `Shape & ShapeMetaMethods`;同一实例原地挂载)
91
+ */
92
+ export declare function attachMetaMethods(shape: Shape): Shape & ShapeMetaMethods;
93
+ //# sourceMappingURL=meta.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"meta.d.ts","sourceRoot":"","sources":["../../src/api/meta.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,eAAe,CAAA;AAI1C,gDAAgD;AAChD,MAAM,WAAW,SAAS;IACxB,uDAAuD;IACvD,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,6EAA6E;IAC7E,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,wEAAwE;IACxE,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAClC;AAED;;;;;;GAMG;AACH,MAAM,WAAW,QAAQ;IACvB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,8DAA8D;IAC9D,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAClC;AAED,0DAA0D;AAC1D,MAAM,WAAW,gBAAgB;IAC/B,2DAA2D;IAC3D,OAAO,CAAC,IAAI,EAAE,SAAS,GAAG,IAAI,CAAA;IAC9B,uCAAuC;IACvC,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;IAC3B,8CAA8C;IAC9C,cAAc,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAA;IACzC,qCAAqC;IACrC,aAAa,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;IACvC,sEAAsE;IACtE,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;IAC9C,+BAA+B;IAC/B,OAAO,IAAI,QAAQ,CAAC,SAAS,CAAC,GAAG,SAAS,CAAA;CAC3C;AAID;;;;;GAKG;AACH,wBAAgB,SAAS,CAAC,GAAG,EAAE,SAAS,GAAG,SAAS,EAAE,IAAI,EAAE,SAAS,GAAG,SAAS,CAuBhF;AAID;;;;;;;;;GASG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,KAAK,GAAG,KAAK,GAAG,gBAAgB,CA2BxE"}
@@ -0,0 +1,99 @@
1
+ /**
2
+ * api/meta — faijs 零件名称/描述/料号 与 整体文件元数据 权威类型与 Shape 方法
3
+ *
4
+ * 设计文档:docs/plans/2026-10-05-faijs-meta-name-note-api-design.md
5
+ *
6
+ * 定位(与 api/appearance.ts 同款方法模式):
7
+ * - 名称/描述设置**不是 op**(不进 defineOp/api-namespace/args-schema),是 Shape
8
+ * 实例方法(`box1.setName('…')`,复用 `asm1.solve()` 的成员调用语句形态)。
9
+ * - `ShapeMeta`(零件级)与 `FileMeta`(整体级)引擎无关、JSON 可序列化;
10
+ * `Shape.meta` 随 Shape 走 mesh/brep 双链路,编辑器/查看器只读字段。
11
+ * - 本文件零依赖(不 import THREE / occt / store);唯一 import 是 mesh/types
12
+ * 的 `Shape` 类型(type-only),mesh/types 亦只 type-import 本文件的类型,
13
+ * 两者为类型环、无运行时环(值依赖单向:shape.ts → api/meta.ts)。
14
+ *
15
+ * 命名约定(camelCase,faijs 全 TS/JS 生态):
16
+ * - 零件级:`name` / `description` / `partNumber` / `metadata`(键值)。
17
+ * - 方法:`setName` / `setDescription` / `setPartNumber` / `setMetaField` /
18
+ * `setMeta` / `getMeta`。字段名与 3MF/STEP 规范一致(不用 note)。
19
+ * 空串 = 清除:`setName('')` 删除 name(与「undefined 不覆盖」互补,用户可
20
+ * 显式去掉继承来的名称)。
21
+ */
22
+ // ── 合并 ──
23
+ /**
24
+ * 合并零件级元数据:spec 中 undefined 字段不覆盖旧值;空串覆盖为清除。
25
+ * @param cur 当前 meta(可为 undefined)
26
+ * @param spec 待合并字段(undefined 字段跳过;'' 显式清除)
27
+ * @returns 合并后的 meta(新对象;cur 为 undefined 时仅含 spec 非空字段)
28
+ */
29
+ export function mergeMeta(cur, spec) {
30
+ const clean = {};
31
+ for (const [k, v] of Object.entries(spec)) {
32
+ if (v === undefined)
33
+ continue;
34
+ if (k === 'metadata' && v && typeof v === 'object') {
35
+ // 键值子合并:保留旧 metadata 的未覆盖键。
36
+ const base = { ...(cur?.metadata ?? {}) };
37
+ for (const [kk, vv] of Object.entries(v)) {
38
+ if (vv === '')
39
+ delete base[kk]; // 空串清除该键
40
+ else
41
+ base[kk] = vv;
42
+ }
43
+ clean[k] = base;
44
+ continue;
45
+ }
46
+ if (v === '')
47
+ clean[k] = undefined; // 空串清除顶层字段
48
+ else
49
+ clean[k] = v;
50
+ }
51
+ const merged = { ...(cur ?? {}), ...clean };
52
+ // 清理合并后为 undefined 的顶层键(空串清除写入 undefined)。
53
+ for (const k of Object.keys(merged)) {
54
+ if (merged[k] === undefined)
55
+ delete merged[k];
56
+ }
57
+ return merged;
58
+ }
59
+ // ── Shape 方法挂载 ──
60
+ /**
61
+ * 给 Shape 实例挂载元数据方法(幂等:已有 setMeta 则跳过)。
62
+ *
63
+ * 所有产物构造点(solid/curve → fromBrep/fromMeshSolid/fromBrepCurve)统一
64
+ * 调用本函数,保证 mesh/brep 双支路产物都可用 `box1.setName(...)`。
65
+ * 方法**不序列化**(JSON 丢弃函数);`meta` 字段随产物跨打印,编辑器/
66
+ * 查看器只读字段即可,不依赖方法。
67
+ * @param shape 产物 Shape 实例(solid/curve 产物)
68
+ * @returns 挂载后的 shape(类型提升为 `Shape & ShapeMetaMethods`;同一实例原地挂载)
69
+ */
70
+ export function attachMetaMethods(shape) {
71
+ const s = shape;
72
+ if (typeof s.setMeta === 'function')
73
+ return s;
74
+ s.setMeta = function setMeta(spec) {
75
+ this.meta = mergeMeta(this.meta, spec);
76
+ return this;
77
+ };
78
+ s.setName = function setName(name) {
79
+ this.meta = mergeMeta(this.meta, { name });
80
+ return this;
81
+ };
82
+ s.setDescription = function setDescription(description) {
83
+ this.meta = mergeMeta(this.meta, { description });
84
+ return this;
85
+ };
86
+ s.setPartNumber = function setPartNumber(partNumber) {
87
+ this.meta = mergeMeta(this.meta, { partNumber });
88
+ return this;
89
+ };
90
+ s.setMetaField = function setMetaField(key, value) {
91
+ this.meta = mergeMeta(this.meta, { metadata: { [key]: value } });
92
+ return this;
93
+ };
94
+ s.getMeta = function getMeta() {
95
+ return this.meta;
96
+ };
97
+ return s;
98
+ }
99
+ //# sourceMappingURL=meta.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"meta.js","sourceRoot":"","sources":["../../src/api/meta.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * api/meta — faijs 零件名称/描述/料号 与 整体文件元数据 权威类型与 Shape 方法\n *\n * 设计文档:docs/plans/2026-10-05-faijs-meta-name-note-api-design.md\n *\n * 定位(与 api/appearance.ts 同款方法模式):\n * - 名称/描述设置**不是 op**(不进 defineOp/api-namespace/args-schema),是 Shape\n * 实例方法(`box1.setName('…')`,复用 `asm1.solve()` 的成员调用语句形态)。\n * - `ShapeMeta`(零件级)与 `FileMeta`(整体级)引擎无关、JSON 可序列化;\n * `Shape.meta` 随 Shape 走 mesh/brep 双链路,编辑器/查看器只读字段。\n * - 本文件零依赖(不 import THREE / occt / store);唯一 import 是 mesh/types\n * 的 `Shape` 类型(type-only),mesh/types 亦只 type-import 本文件的类型,\n * 两者为类型环、无运行时环(值依赖单向:shape.ts → api/meta.ts)。\n *\n * 命名约定(camelCase,faijs 全 TS/JS 生态):\n * - 零件级:`name` / `description` / `partNumber` / `metadata`(键值)。\n * - 方法:`setName` / `setDescription` / `setPartNumber` / `setMetaField` /\n * `setMeta` / `getMeta`。字段名与 3MF/STEP 规范一致(不用 note)。\n * 空串 = 清除:`setName('')` 删除 name(与「undefined 不覆盖」互补,用户可\n * 显式去掉继承来的名称)。\n */\n\nimport type { Shape } from '../mesh/types'\n\n// ── 类型 ──\n\n/** 零件级说明性元数据 —— 引擎无关、JSON 可序列化、随 Shape 走双链路。 */\nexport interface ShapeMeta {\n /** 零件名:3MF `<object name>` / STEP `PRODUCT().name`。 */\n name?: string\n /** 描述:STEP `PRODUCT.description`;3MF 写 `faijs:description` metadatagroup。 */\n description?: string\n /** 料号:3MF `<object partnumber>`;STEP `PRODUCT_IDENTIFICATION` 或 UDA。 */\n partNumber?: string\n /**\n * 自定义键值:3MF `<object><metadatagroup>`(vendor 前缀);STEP UDA。\n * 键为规范/厂商原始名(3MF 含命名空间前缀);faijs 不解释值语义,\n * 读入保留、写出回写。\n */\n metadata?: Record<string, string>\n}\n\n/**\n * 整体/文档级说明性元数据 —— 导入结果 / 导出选项,不挂 Shape。\n *\n * 不叫 `ModelMeta`:CAD 直觉里 \"model\" 偏单个零件(那是 `ShapeMeta` 的活);\n * 本类型承载整个交换文件(3MF `<model>` / STEP P21 header)的元数据,故用\n * `FileMeta`。\n */\nexport interface FileMeta {\n title?: string // 3MF Title / STEP FILE_NAME.name\n description?: string // 3MF Description / STEP FILE_DESCRIPTION.description\n designer?: string // 3MF Designer / STEP FILE_NAME.originator\n author?: string // STEP FILE_NAME.author(3MF 无对应;跨格式不互转)\n organization?: string // STEP FILE_NAME.organization(3MF 无对应)\n copyright?: string // 3MF Copyright(STEP 无标准位置)\n licenseTerms?: string // 3MF LicenseTerms(STEP 无标准位置)\n rating?: string // 3MF Rating(STEP 无标准位置)\n creationDate?: string // 3MF CreationDate / STEP FILE_NAME.timestamp\n modificationDate?: string // 3MF ModificationDate(STEP 无标准位置)\n application?: string // 3MF Application / STEP FILE_NAME.preprocessor\n /** 未知/厂商自定义 metadata 兜底(3MF model 级带前缀名;STEP header 其余字段)。 */\n metadata?: Record<string, string>\n}\n\n/** Shape 元数据方法签名(运行时由 attachMetaMethods 挂载;纯数据判定不受影响)。 */\nexport interface ShapeMetaMethods {\n /** 合并 meta:`{...cur, ...spec}`,spec 中 undefined 字段保留旧值。 */\n setMeta(spec: ShapeMeta): this\n /** 便捷:等价 setMeta({ name })(空串视为清除)。 */\n setName(name: string): this\n /** 便捷:等价 setMeta({ description })(空串视为清除)。 */\n setDescription(description: string): this\n /** 便捷:等价 setMeta({ partNumber })。 */\n setPartNumber(partNumber: string): this\n /** 便捷:等价 setMeta({ metadata: {...cur.metadata, ...kv} });值为空串的键删除。 */\n setMetaField(key: string, value: string): this\n /** 读取当前 meta(可能 undefined)。 */\n getMeta(): Readonly<ShapeMeta> | undefined\n}\n\n// ── 合并 ──\n\n/**\n * 合并零件级元数据:spec 中 undefined 字段不覆盖旧值;空串覆盖为清除。\n * @param cur 当前 meta(可为 undefined)\n * @param spec 待合并字段(undefined 字段跳过;'' 显式清除)\n * @returns 合并后的 meta(新对象;cur 为 undefined 时仅含 spec 非空字段)\n */\nexport function mergeMeta(cur: ShapeMeta | undefined, spec: ShapeMeta): ShapeMeta {\n const clean: Record<string, unknown> = {}\n for (const [k, v] of Object.entries(spec)) {\n if (v === undefined) continue\n if (k === 'metadata' && v && typeof v === 'object') {\n // 键值子合并:保留旧 metadata 的未覆盖键。\n const base: Record<string, string> = { ...((cur?.metadata as Record<string, string> | undefined) ?? {}) }\n for (const [kk, vv] of Object.entries(v as Record<string, string>)) {\n if (vv === '') delete base[kk] // 空串清除该键\n else base[kk] = vv\n }\n clean[k] = base\n continue\n }\n if (v === '') clean[k] = undefined as unknown as string // 空串清除顶层字段\n else clean[k] = v\n }\n const merged = { ...(cur ?? {}), ...clean } as ShapeMeta\n // 清理合并后为 undefined 的顶层键(空串清除写入 undefined)。\n for (const k of Object.keys(merged)) {\n if ((merged as Record<string, unknown>)[k] === undefined) delete (merged as Record<string, unknown>)[k]\n }\n return merged\n}\n\n// ── Shape 方法挂载 ──\n\n/**\n * 给 Shape 实例挂载元数据方法(幂等:已有 setMeta 则跳过)。\n *\n * 所有产物构造点(solid/curve → fromBrep/fromMeshSolid/fromBrepCurve)统一\n * 调用本函数,保证 mesh/brep 双支路产物都可用 `box1.setName(...)`。\n * 方法**不序列化**(JSON 丢弃函数);`meta` 字段随产物跨打印,编辑器/\n * 查看器只读字段即可,不依赖方法。\n * @param shape 产物 Shape 实例(solid/curve 产物)\n * @returns 挂载后的 shape(类型提升为 `Shape & ShapeMetaMethods`;同一实例原地挂载)\n */\nexport function attachMetaMethods(shape: Shape): Shape & ShapeMetaMethods {\n const s = shape as Shape & ShapeMetaMethods\n if (typeof s.setMeta === 'function') return s\n s.setMeta = function setMeta(this: Shape & ShapeMetaMethods, spec: ShapeMeta) {\n this.meta = mergeMeta(this.meta, spec)\n return this\n }\n s.setName = function setName(this: Shape & ShapeMetaMethods, name: string) {\n this.meta = mergeMeta(this.meta, { name })\n return this\n }\n s.setDescription = function setDescription(this: Shape & ShapeMetaMethods, description: string) {\n this.meta = mergeMeta(this.meta, { description })\n return this\n }\n s.setPartNumber = function setPartNumber(this: Shape & ShapeMetaMethods, partNumber: string) {\n this.meta = mergeMeta(this.meta, { partNumber })\n return this\n }\n s.setMetaField = function setMetaField(this: Shape & ShapeMetaMethods, key: string, value: string) {\n this.meta = mergeMeta(this.meta, { metadata: { [key]: value } })\n return this\n }\n s.getMeta = function getMeta(this: Shape) {\n return this.meta\n }\n return s\n}"]}
@@ -1 +1 @@
1
- {"version":3,"file":"primitives.d.ts","sourceRoot":"","sources":["../../src/api/primitives.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,eAAe,CAAA;AAgB1C;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAUrE;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAExE;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAS1E;AAED;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAUtE;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAKvE;AAmBD;;;;;;;;;;;;;;;;;;;;;;KAsBK;AACL,eAAO,MAAM,GAAG;;CAwBd,CAAA;AAEF;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,MAAM;;CAgBjB,CAAA;AAWF;;;;;;;;;;;;;;;;;;;;;;IAsBI;AACJ,eAAO,MAAM,QAAQ;;CAgBnB,CAAA;AAEF;;;;;;;;;;;;;;;;;;;;;;IAsBI;AACJ,eAAO,MAAM,IAAI;;CAuBf,CAAA;AAEF;;;;;;;;;;;;;;;;IAgBI;AACJ,eAAO,MAAM,KAAK;;CAchB,CAAA"}
1
+ {"version":3,"file":"primitives.d.ts","sourceRoot":"","sources":["../../src/api/primitives.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,eAAe,CAAA;AAmB1C;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAUrE;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAExE;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAS1E;AAED;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAUtE;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAKvE;AAyHD;;;;;;;;;;;;;;;;;;;;;;KAsBK;AACL,eAAO,MAAM,GAAG;;CAwBd,CAAA;AAEF;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,MAAM;;CAgBjB,CAAA;AAWF;;;;;;;;;;;;;;;;;;;;;;IAsBI;AACJ,eAAO,MAAM,QAAQ;;CAgBnB,CAAA;AAEF;;;;;;;;;;;;;;;;;;;;;;IAsBI;AACJ,eAAO,MAAM,IAAI;;CAuBf,CAAA;AAEF;;;;;;;;;;;;;;;;IAgBI;AACJ,eAAO,MAAM,KAAK;;CAchB,CAAA"}
@@ -7,7 +7,6 @@
7
7
  import { clampNRad } from '../mesh/types.js';
8
8
  import { cad } from '../mesh/index.js';
9
9
  import { primitiveToBrepSolid } from '../primitives/brep-primitives.js';
10
- import { solidToShape } from '../brep/brep-ops.js';
11
10
  import { getCurrentStmt } from '../runtime-state.js';
12
11
  import { getBrepApi } from '../brep/handle-bridge.js';
13
12
  import { fromBrep } from '../shape.js';
@@ -15,6 +14,8 @@ import { assignRoles } from '../topology/naming/roles.js';
15
14
  import { asPartName } from '../identity.js';
16
15
  import { defineOp } from '../sdk.js';
17
16
  import { assertPositiveNumber, assertNonNegativeNumber } from './assert.js';
17
+ import { DEFAULT_LINEAR_DEFLECTION } from '../tolerance.js';
18
+ import { mm } from '../units.js';
18
19
  // ── per-op 参数自校验(Phase 2.2;api 层被直接 import 时的防御层) ──
19
20
  /**
20
21
  * Validate box parameters (brepjs contract, §4.1 A 决策): `width`, `depth` and
@@ -93,7 +94,121 @@ function primitiveBrep(op, params) {
93
94
  // 改名/复用,StmtId 全局唯一,保证多个同类型 primitive 不撞 origin。
94
95
  const origin = String(getCurrentStmt()?.id ?? op);
95
96
  const roles = assignRoles(kernel, result.solid, op);
96
- return fromBrep(solidToShape(kernel, result.solid, clampNRad((params.nRad ?? params.segments))), { solid: result.solid, roleTable: new Map([[asPartName(origin), roles]]) });
97
+ const segments = clampNRad((params.nRad ?? params.segments));
98
+ // P4 面级:brep 链基本体也挂契约序 faceRanges(编辑器默认 brep 链——
99
+ // setFaceColor 必须可用)。box 的 OCCT 面枚举序(实测 0=−X,1=+Y,…)与契约
100
+ // (+X/−X/+Y/−Y/+Z/−Z)不一致,按面法线重排 indices;cylinder/cone 的
101
+ // OCCT 序与契约一致(实测锁定:cylinder 0=侧面,1=顶,2=底;cone radiusTop=0
102
+ // 0=侧面,1=底),直接透传。
103
+ const { shape, faceRanges } = brepPrimitiveMesh(kernel, result.solid, op, segments);
104
+ if (faceRanges)
105
+ shape.faceRanges = faceRanges;
106
+ return fromBrep(shape, { solid: result.solid, roleTable: new Map([[asPartName(origin), roles]]) });
107
+ }
108
+ /** 面法线主轴向:用该面非退化三角形的法线和定轴与符号(OCCT 统一 outward 绕向)。 */
109
+ function faceNormalAxis(mesh, triStart, triCount) {
110
+ let sx = 0;
111
+ let sy = 0;
112
+ let sz = 0;
113
+ for (let t = 0; t < triCount; t++) {
114
+ const i0 = mesh.indices[(triStart + t) * 3];
115
+ const i1 = mesh.indices[(triStart + t) * 3 + 1];
116
+ const i2 = mesh.indices[(triStart + t) * 3 + 2];
117
+ const p0x = mesh.positions[i0 * 3];
118
+ const p0y = mesh.positions[i0 * 3 + 1];
119
+ const p0z = mesh.positions[i0 * 3 + 2];
120
+ const p1x = mesh.positions[i1 * 3];
121
+ const p1y = mesh.positions[i1 * 3 + 1];
122
+ const p1z = mesh.positions[i1 * 3 + 2];
123
+ const p2x = mesh.positions[i2 * 3];
124
+ const p2y = mesh.positions[i2 * 3 + 1];
125
+ const p2z = mesh.positions[i2 * 3 + 2];
126
+ const ux = p1x - p0x;
127
+ const uy = p1y - p0y;
128
+ const uz = p1z - p0z;
129
+ const vx = p2x - p0x;
130
+ const vy = p2y - p0y;
131
+ const vz = p2z - p0z;
132
+ const nx = uy * vz - uz * vy;
133
+ const ny = uz * vx - ux * vz;
134
+ const nz = ux * vy - uy * vx;
135
+ const len = Math.hypot(nx, ny, nz);
136
+ if (!Number.isFinite(len) || len < 1e-12)
137
+ continue;
138
+ sx += nx;
139
+ sy += ny;
140
+ sz += nz;
141
+ }
142
+ const ax = Math.abs(sx);
143
+ const ay = Math.abs(sy);
144
+ const az = Math.abs(sz);
145
+ if (!Number.isFinite(ax + ay + az) || ax + ay + az < 1e-12)
146
+ return null;
147
+ if (ax >= ay && ax >= az)
148
+ return { axis: 0, sign: sx > 0 ? 1 : -1 };
149
+ if (ay >= ax && ay >= az)
150
+ return { axis: 1, sign: sy > 0 ? 1 : -1 };
151
+ return { axis: 2, sign: sz > 0 ? 1 : -1 };
152
+ }
153
+ /**
154
+ * 三角化基本体并附 P4 契约序 faceRanges。
155
+ * faceGroups 三元组 = [triStart, triCount, faceHash],前两元是索引单位
156
+ * (brep-ops.ts 注释)→ 三角形单位 = 索引/3。
157
+ * - box:6 面 → 按面法线重排 indices 到契约序(0=+X,1=−X,2=+Y,3=−Y,4=+Z,5=−Z)。
158
+ * - cylinder/cone:OCCT 枚举序与契约一致(探针实测锁定),直接透传,不重排。
159
+ * - wedge/sphere 及其它:无契约,不挂 faceRanges(setFaceColor 抛 E_FACE_UNAVAILABLE)。
160
+ */
161
+ function brepPrimitiveMesh(kernel, solid, op, segments) {
162
+ const angularDeflection = (2 * Math.PI) / Math.max(3, segments);
163
+ const mesh = kernel.meshShape(solid, {
164
+ linearDeflection: DEFAULT_LINEAR_DEFLECTION.as(mm),
165
+ angularDeflection,
166
+ });
167
+ const shape = {
168
+ positions: new Float32Array(mesh.positions),
169
+ indices: new Uint32Array(mesh.indices),
170
+ };
171
+ const fg = mesh.faceGroups;
172
+ if (!fg)
173
+ return { shape };
174
+ const faces = [];
175
+ for (let f = 0; f < fg.length / 3; f++) {
176
+ faces.push({ triStart: fg[f * 3] / 3, triCount: fg[f * 3 + 1] / 3 });
177
+ }
178
+ if (op === 'box' && faces.length === 6) {
179
+ // 契约序重排:每面判向 → 契约 idx(+X=0,−X=1,+Y=2,−Y=3,+Z=4,−Z=5)
180
+ const byContract = new Array(6).fill(undefined);
181
+ for (const f of faces) {
182
+ const na = faceNormalAxis(mesh, f.triStart, f.triCount);
183
+ if (!na)
184
+ return { shape };
185
+ const idx = na.axis === 0 ? (na.sign > 0 ? 0 : 1) : na.axis === 1 ? (na.sign > 0 ? 2 : 3) : (na.sign > 0 ? 4 : 5);
186
+ if (byContract[idx] !== undefined)
187
+ return { shape }; // 法线判向歧义 → 不挂
188
+ byContract[idx] = f;
189
+ }
190
+ if (byContract.some((f) => f === undefined))
191
+ return { shape };
192
+ const newIndices = new Uint32Array(mesh.indices.length);
193
+ const faceRanges = [];
194
+ let outTri = 0;
195
+ for (let c = 0; c < 6; c++) {
196
+ const f = byContract[c];
197
+ faceRanges.push({ start: outTri, count: f.triCount });
198
+ for (let t = 0; t < f.triCount; t++) {
199
+ newIndices[(outTri + t) * 3] = mesh.indices[(f.triStart + t) * 3];
200
+ newIndices[(outTri + t) * 3 + 1] = mesh.indices[(f.triStart + t) * 3 + 1];
201
+ newIndices[(outTri + t) * 3 + 2] = mesh.indices[(f.triStart + t) * 3 + 2];
202
+ }
203
+ outTri += f.triCount;
204
+ }
205
+ return { shape: { ...shape, indices: newIndices }, faceRanges };
206
+ }
207
+ if ((op === 'cylinder' || op === 'cone') && faces.length >= 2) {
208
+ // OCCT 枚举序 = P4a 契约序(探针实测):0=侧面, 1=顶, 2=底(cone 无顶盖时 0=侧面,1=底)
209
+ return { shape, faceRanges: faces.map((f) => ({ start: f.triStart, count: f.triCount })) };
210
+ }
211
+ return { shape };
97
212
  }
98
213
  /**
99
214
  * 创建长方体(brepjs 契约,§4.1 A 决策)。
@@ -1 +1 @@
1
- {"version":3,"file":"primitives.js","sourceRoot":"","sources":["../../src/api/primitives.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * api primitives — 基本体创建库函数(box/sphere/cylinder/cone/wedge)\n *\n *\n * dispatchPath 静态判定 brep/mesh,产物经 solid()/fromBrep() 构造器创建。\n */\n\nimport type { Shape } from '../mesh/types'\nimport { clampNRad } from '../mesh/types'\nimport { cad } from '../mesh'\nimport { primitiveToBrepSolid } from '../primitives/brep-primitives'\nimport { solidToShape } from '../brep/brep-ops'\nimport { getCurrentStmt } from '../runtime-state'\nimport { getBrepApi } from '../brep/handle-bridge'\nimport { fromBrep } from '../shape'\nimport { assignRoles } from '../topology/naming/roles'\nimport type { Provenance } from '../topology/naming/lineage'\nimport { asPartName } from '../identity'\nimport { defineOp } from '../sdk'\nimport { assertPositiveNumber, assertNonNegativeNumber } from './assert'\n\n// ── per-op 参数自校验(Phase 2.2;api 层被直接 import 时的防御层) ──\n\n/**\n * Validate box parameters (brepjs contract, §4.1 A 决策): `width`, `depth` and\n * `height` must be positive numbers. The legacy `{ size }` object form is\n * removed — any call still passing `size` throws an explicit `E_ARGS_FORM`\n * error pointing at the new signature (error hint ≠ compatibility).\n * @param params - the raw box operation parameters.\n */\nexport function assertBoxParams(params: Record<string, unknown>): void {\n if (params.size !== undefined) {\n throw new Error(\n '[faijs/args] box: E_ARGS_FORM: the `box({ size })` object form is removed. ' +\n 'box now uses `box(width, depth, height, { at?, centered?, segments? })`.',\n )\n }\n assertPositiveNumber(params.width, 'box.width')\n assertPositiveNumber(params.depth, 'box.depth')\n assertPositiveNumber(params.height, 'box.height')\n}\n\n/**\n * Validate sphere parameters: `radius` must be a positive number.\n * @param params - the raw sphere operation parameters.\n */\nexport function assertSphereParams(params: Record<string, unknown>): void {\n assertPositiveNumber(params.radius, 'sphere.radius')\n}\n\n/**\n * Validate cylinder parameters (brepjs contract, §4.3 A 决策): `radius` and\n * `height` must be positive. The legacy `{ center }` object key is removed — any\n * call still passing `center` throws an explicit `E_ARGS_FORM` error pointing at\n * the new signature (error hint ≠ compatibility, 裁决 3).\n * @param params - the raw cylinder operation parameters.\n */\nexport function assertCylinderParams(params: Record<string, unknown>): void {\n if (params.center !== undefined || params.size !== undefined) {\n throw new Error(\n '[faijs/args] cylinder: E_ARGS_FORM: the legacy object form is removed. ' +\n 'cylinder now uses `cylinder(radius, height, { at?, centered?, segments? })`.',\n )\n }\n assertPositiveNumber(params.radius, 'cylinder.radius')\n assertPositiveNumber(params.height, 'cylinder.height')\n}\n\n/**\n * Validate cone parameters (brepjs contract, §4.1 P 决策): `radiusBottom` and\n * `height` must be positive, `radiusTop` must be non-negative. The legacy\n * `{ center }` object key is removed — any call still passing `center` throws an\n * explicit `E_ARGS_FORM` error pointing at the new signature (error hint ≠\n * compatibility, 裁决 3).\n * @param params - the raw cone operation parameters.\n */\nexport function assertConeParams(params: Record<string, unknown>): void {\n if (params.center !== undefined || params.size !== undefined) {\n throw new Error(\n '[faijs/args] cone: E_ARGS_FORM: the legacy object form is removed. ' +\n 'cone now uses `cone(bottomRadius, topRadius, height, { at?, centered?, segments? })`.',\n )\n }\n assertPositiveNumber(params.radiusBottom, 'cone.radiusBottom')\n assertNonNegativeNumber(params.radiusTop, 'cone.radiusTop')\n assertPositiveNumber(params.height, 'cone.height')\n}\n\n/**\n * Validate wedge parameters: `width`, `height`, `angle`, and `length` must be\n * positive numbers.\n * @param params - the raw wedge operation parameters.\n */\nexport function assertWedgeParams(params: Record<string, unknown>): void {\n assertPositiveNumber(params.width, 'wedge.width')\n assertPositiveNumber(params.height, 'wedge.height')\n assertPositiveNumber(params.angle, 'wedge.angle')\n assertPositiveNumber(params.length, 'wedge.length')\n}\n\n/** BREP 路径:OCCT 精确构造 + 三角化 + fromBrep 登记(基本体无面演化;链根建 roleTable)。 */\nfunction primitiveBrep(op: string, params: Record<string, unknown>): Shape {\n const kernel = getBrepApi()\n const type = op === 'box' ? 'cube' : op\n const result = primitiveToBrepSolid(kernel, type as 'cube' | 'sphere' | 'cylinder' | 'cone' | 'wedge', params as never)\n // §3.2:链根建表——语义命名器按 op 类型给面命名(semantic 'top'/'lateral' 等,\n // Phase 1.7 已删 'box:' 前缀与位置兜底)。\n // Phase 1.6:origin 用链根语句的 StmtId(当前语句 id,§2.2/§4.1)——变量名会被\n // 改名/复用,StmtId 全局唯一,保证多个同类型 primitive 不撞 origin。\n const origin = String(getCurrentStmt()?.id ?? op)\n const roles = assignRoles(kernel, result.solid, op)\n return fromBrep(\n solidToShape(kernel, result.solid, clampNRad((params.nRad ?? params.segments) as number)),\n { solid: result.solid, roleTable: new Map([[asPartName(origin), roles]]) },\n )\n}\n\n/**\n * 创建长方体(brepjs 契约,§4.1 A 决策)。\n * @group 创建\n * @inputs 0\n * @async false\n * @qual ok\n * @name box\n * @returns Shape 长方体几何,可作为后续 op 的输入。\n * @param params.width - X 方向边长(mm)。type:number required:true\n * @param params.depth - Y 方向边长(mm)。type:number required:true\n * @param params.height - Z 方向边长(mm)。type:number required:true\n * @param params.at - 中心点(CENTER 语义,优先于 centered)。type:[x,y,z] 可选\n * @param params.centered - 无 at 时是否居中到原点(type:boolean 默认 false,角点在原点)。\n * @param params.segments - 细分度(影响三角化)。type:number 默认 64(= brepjs standard 等效,P0 §5.0/§5.1)\n * @example\n * const part0 = cad.box(10 * MM, 20 * MM, 30 * MM)\n * const part1 = cad.box(30 * MM, 20 * MM, 10 * MM, { centered: true, at: [1, 2, 3], segments: 64 })\n *\n * 位置原生(§4.1/§6.2):`box(width, depth, height)` 与 `box(10 * MM, 20 * MM, 30 * MM, {centered:true})`\n * 有量纲位必须写单位字面量(基准单位亦然,`10` 裸数字被 D8 R2 拒)。\n * 归一到同一对象(D11 位置→对象 + 尾参 options 合并)。旧 `{ size }` 对象形态已废弃(裁决 3),\n * 传入会抛 `E_ARGS_FORM`(错误提示 ≠ 兼容,§4.1)。\n */\nexport const box = defineOp({\n name: 'box',\n mesh: (params: Record<string, unknown>) => {\n assertBoxParams(params)\n return cad.box(params as never)\n },\n brep: (params: Record<string, unknown>) => {\n assertBoxParams(params)\n return primitiveBrep('box', params)\n },\n // schema feeds codegen/UI parameter panels.\n schema: {\n width: 'number',\n depth: 'number',\n height: 'number',\n at: 'vec3?',\n centered: 'boolean?',\n segments: 'number?',\n },\n // D11 位置→对象(§4.1/§6.2):三个标量装箱成 { width, depth, height },尾参\n // options 经 dual-form-args 的尾参合并(§6.2)并入。\n slotMap: { keys: ['width', 'depth', 'height'] },\n paramDims: { width: 'length', depth: 'length', height: 'length' },\n naming: { kind: 'construct', newFaces: { via: 'explicit', vocab: [{ kind: 'semantic', name: 'top' }, { kind: 'semantic', name: 'bottom' }, { kind: 'semantic', name: 'front' }, { kind: 'semantic', name: 'back' }, { kind: 'semantic', name: 'left' }, { kind: 'semantic', name: 'right' }] } } as Provenance,\n})\n\n/**\n * 创建球体。\n * @group 创建\n * @inputs 0\n * @async false\n * @qual ok\n * @name sphere\n * @returns Shape 球体几何,可作为后续 op 的输入。\n * @param params.radius - 半径(mm)。type:number required:true\n * @param params.segments - 细分度(影响面数)。type:number 默认 64(= brepjs standard 等效,P0 §5.0/§5.1)\n * @param params.center - 球心位置(at 的同义别名)。type:[x,y,z] 默认 [0,0,0](原点)。\n * @param params.at - 球心位置(center 的同义别名,brepjs 契约;裁决 4 双形态合法)。\n * @example\n * const r = cad.sphere({ radius: 10 })\n * const r = cad.sphere(10, { at: [0, 0, 10], segments: 64 })\n * const r = cad.sphere({ radius: 10, segments: 64, center: [0,0,10] })\n */\nexport const sphere = defineOp({\n name: 'sphere',\n mesh: (params: Record<string, unknown>) => {\n assertSphereParams(params)\n return cad.sphere(centerParams(params) as never)\n },\n brep: (params: Record<string, unknown>) => {\n assertSphereParams(params)\n return primitiveBrep('sphere', centerParams(params))\n },\n schema: { radius: 'number', segments: 'number?', center: 'vec3?', at: 'vec3?' },\n // D11: `sphere(10)` == `sphere({ radius: 10 })`; 尾参 options({at, segments})\n // 经 dual-form-args 的尾参合并规则归一(裁决 4,§6.2)。\n slotMap: { keys: ['radius'] },\n paramDims: { radius: 'length' },\n naming: { kind: 'unmodeled', reason: 'sphere face vocabulary pending Phase 3' } as Provenance,\n})\n\n/**\n * 位置归一:把 brepjs 契约的 `at`(= faijs 的 `center`,球心语义)归一为一个\n * `center` 输入,mesh/brep 两条消费路径共用(裁决 1/4,§4.2)。\n */\nfunction centerParams(params: Record<string, unknown>): Record<string, unknown> {\n if (params.at !== undefined) return { ...params, center: params.at }\n return params\n}\n\n/**\n * 创建圆柱体(brepjs 契约,§4.3 A 决策)。\n * 锚点:`at` 是**底面轴心**(BASE 语义,默认 [0,0,0],底面在原点、+Z 延伸);`centered:true`\n * 指底面落到 −h/2(无 at 时居中到原点;与 `at` 同给时以 `at` 为中心)。\n * @group 创建\n * @inputs 0\n * @async false\n * @qual ok\n * @name cylinder\n * @returns Shape 圆柱体几何,可作为后续 op 的输入。\n * @param params.radius - 底面半径(mm)。type:number required:true\n * @param params.height - 高度(mm),沿 +Z 轴。type:number required:true\n * @param params.at - 底面中心(BASE 语义)。type:[x,y,z] 可选\n * @param params.centered - 是否居中(底面 −h/2;与 at 同给时以 at 为中心)。type:boolean 默认 false\n * @param params.segments - 细分度(影响三角化)。type:number 默认 64(= brepjs standard 等效,P0 §5.0/§5.1)\n * @example\n * const c = cad.cylinder(5, 40)\n * const c = cad.cylinder(5, 40, { centered: true, at: [0, 0, 20], segments: 64 })\n *\n * 位置原生(§4.1/§6.2):`cylinder(5, 40)` 与 `cylinder(5, 40, {centered:true})`\n * 归一到同一对象(D11 位置→装箱 + 尾参 options 合并)。旧 `{ center }` 对象形态已废弃\n * (裁决 3),传入会抛 `E_ARGS_FORM`(错误提示 ≠ 兼容,§4.3)。\n */\nexport const cylinder = defineOp({\n name: 'cylinder',\n mesh: (params: Record<string, unknown>) => {\n assertCylinderParams(params)\n return cad.cylinder(params as never)\n },\n brep: (params: Record<string, unknown>) => {\n assertCylinderParams(params)\n return primitiveBrep('cylinder', params)\n },\n schema: { radius: 'number', height: 'number', at: 'vec3?', centered: 'boolean?', segments: 'number?' },\n // D11(§4.1/§6.2):`cylinder(5, 40)` 两个标量装箱成 { radius, height };尾参 options\n // 经 dual-form-args 尾参合并并入。\n slotMap: { keys: ['radius', 'height'] },\n paramDims: { radius: 'length', height: 'length' },\n naming: { kind: 'construct', newFaces: { via: 'explicit', vocab: [{ kind: 'semantic', name: 'top' }, { kind: 'semantic', name: 'bottom' }, { kind: 'semantic', name: 'lateral' }] } } as Provenance,\n})\n\n/**\n * 创建圆锥体(brepjs 契约,§4.1 P 决策)。radiusTop 等于 radiusBottom 时即圆柱,0 为尖锥。\n * 锚点:`at` 是**底面轴心**(BASE 语义,默认 [0,0,0],底面在原点、+Z 延伸);`centered:true`\n * 指底面落到 −h/2(无 at 时居中到原点;与 `at` 同给时以 `at` 为中心)。\n * @group 创建\n * @inputs 0\n * @async false\n * @qual ok\n * @name cone\n * @returns Shape 圆锥体几何,可作为后续 op 的输入。\n * @param params.radiusBottom - 底半径(mm)。type:number required:true\n * @param params.radiusTop - 顶半径(mm),0 为尖锥,非负,等于 radiusBottom 得圆柱。type:number required:true\n * @param params.height - 高度(mm),沿 +Z 轴。type:number required:true\n * @param params.at - 底面轴心(BASE 语义)。type:[x,y,z] 可选\n * @param params.centered - 是否居中(底面 −h/2;与 at 同给时以 at 为中心)。type:boolean 默认 false\n * @param params.segments - 细分度(影响三角化)。type:number 默认 64(= brepjs standard 等效,P0 §5.0/§5.1)\n * @example\n * const c = cad.cone(10, 4, 30)\n * const c = cad.cone(10, 0, 30, { centered: true, at: [0, 0, 20], segments: 64 })\n * 位置原生(§4.1/§6.2):`cone(10, 4, 30)` 与 `cone(10, 4, 30, { centered: true })`\n * 归一到同一对象(D11 位置→装箱 + 尾参 options 合并)。旧 `{ center }`/`{ size }` 对象形态\n * 已废弃(裁决 3),传入会抛 E_ARGS_FORM(错误提示 ≠ 兼容)。\n */\nexport const cone = defineOp({\n name: 'cone',\n mesh: (params: Record<string, unknown>) => {\n assertConeParams(params)\n return cad.cone(params as never)\n },\n brep: (params: Record<string, unknown>) => {\n assertConeParams(params)\n return primitiveBrep('cone', params)\n },\n schema: {\n radiusBottom: 'number',\n radiusTop: 'number',\n height: 'number',\n at: 'vec3?',\n centered: 'boolean?',\n segments: 'number?',\n },\n // D11(§4.1/§6.2): `cone(10, 4, 30)` 三个标量装箱成 { radiusBottom, radiusTop, height }。\n // 尾参 options({at, centered, segments})经 dual-form-args 尾参合并并入。\n slotMap: { keys: ['radiusBottom', 'radiusTop', 'height'] },\n paramDims: { radiusBottom: 'length', radiusTop: 'length', height: 'length' },\n naming: { kind: 'construct', newFaces: { via: 'explicit', vocab: [{ kind: 'semantic', name: 'top' }, { kind: 'semantic', name: 'bottom' }, { kind: 'semantic', name: 'lateral' }] } } as Provenance,\n})\n\n/**\n * 创建楔形体。唯一契约是 width/height/angle/length(width/height/angle 为正数,length 沿切割方向),\n * 旧文档的 size 形态已废弃,传 { size } 会抛错。\n * @group 创建\n * @inputs 0\n * @async false\n * @qual ok\n * @name wedge\n * @note 曾与 UI 面板的 `size` 形态并存并写入文档,但断言层确认唯一合法契约是 width/height/angle/length;传 `{ size }` 直接抛错。已按真源收敛。\n * @returns Shape 楔形体几何,可作为后续 op 的输入。\n * @param params.width - 底面宽度(mm)。type:number required:true\n * @param params.height - 高度(mm)。type:number required:true\n * @param params.angle - 楔形角度(度)。type:number required:true\n * @param params.length - 沿切割方向的长度(mm)。type:number required:true\n * @example\n * const w = cad.wedge({ width: 30, height: 20, angle: 45, length: 10 })\n */\nexport const wedge = defineOp({\n name: 'wedge',\n mesh: (params: Record<string, unknown>) => {\n assertWedgeParams(params)\n return cad.wedge(params as never)\n },\n brep: (params: Record<string, unknown>) => {\n assertWedgeParams(params)\n return primitiveBrep('wedge', params)\n },\n // D11: `wedge(30, 20, 45, 10)` == `wedge({ width: 30, height: 20, angle: 45, length: 10 })`.\n slotMap: { keys: ['width', 'height', 'angle', 'length'] },\n paramDims: { width: 'length', height: 'length', angle: 'angle', length: 'length' },\n naming: { kind: 'unmodeled', reason: 'wedge face vocabulary pending Phase 3' } as Provenance,\n})\n"]}
1
+ {"version":3,"file":"primitives.js","sourceRoot":"","sources":["../../src/api/primitives.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * api primitives — 基本体创建库函数(box/sphere/cylinder/cone/wedge)\n *\n *\n * dispatchPath 静态判定 brep/mesh,产物经 solid()/fromBrep() 构造器创建。\n */\n\nimport type { Shape } from '../mesh/types'\nimport { clampNRad } from '../mesh/types'\nimport { cad } from '../mesh'\nimport { primitiveToBrepSolid } from '../primitives/brep-primitives'\nimport { getCurrentStmt } from '../runtime-state'\nimport { getBrepApi } from '../brep/handle-bridge'\nimport { fromBrep } from '../shape'\nimport { assignRoles } from '../topology/naming/roles'\nimport type { Provenance } from '../topology/naming/lineage'\nimport { asPartName } from '../identity'\nimport { defineOp } from '../sdk'\nimport { assertPositiveNumber, assertNonNegativeNumber } from './assert'\nimport type { BrepMeshResult, BrepHandle } from '../brep/engine/types'\nimport type { BrepEngineApi } from '../brep/engine/primitives'\nimport { DEFAULT_LINEAR_DEFLECTION } from '../tolerance'\nimport { mm } from '../units'\n\n// ── per-op 参数自校验(Phase 2.2;api 层被直接 import 时的防御层) ──\n\n/**\n * Validate box parameters (brepjs contract, §4.1 A 决策): `width`, `depth` and\n * `height` must be positive numbers. The legacy `{ size }` object form is\n * removed — any call still passing `size` throws an explicit `E_ARGS_FORM`\n * error pointing at the new signature (error hint ≠ compatibility).\n * @param params - the raw box operation parameters.\n */\nexport function assertBoxParams(params: Record<string, unknown>): void {\n if (params.size !== undefined) {\n throw new Error(\n '[faijs/args] box: E_ARGS_FORM: the `box({ size })` object form is removed. ' +\n 'box now uses `box(width, depth, height, { at?, centered?, segments? })`.',\n )\n }\n assertPositiveNumber(params.width, 'box.width')\n assertPositiveNumber(params.depth, 'box.depth')\n assertPositiveNumber(params.height, 'box.height')\n}\n\n/**\n * Validate sphere parameters: `radius` must be a positive number.\n * @param params - the raw sphere operation parameters.\n */\nexport function assertSphereParams(params: Record<string, unknown>): void {\n assertPositiveNumber(params.radius, 'sphere.radius')\n}\n\n/**\n * Validate cylinder parameters (brepjs contract, §4.3 A 决策): `radius` and\n * `height` must be positive. The legacy `{ center }` object key is removed — any\n * call still passing `center` throws an explicit `E_ARGS_FORM` error pointing at\n * the new signature (error hint ≠ compatibility, 裁决 3).\n * @param params - the raw cylinder operation parameters.\n */\nexport function assertCylinderParams(params: Record<string, unknown>): void {\n if (params.center !== undefined || params.size !== undefined) {\n throw new Error(\n '[faijs/args] cylinder: E_ARGS_FORM: the legacy object form is removed. ' +\n 'cylinder now uses `cylinder(radius, height, { at?, centered?, segments? })`.',\n )\n }\n assertPositiveNumber(params.radius, 'cylinder.radius')\n assertPositiveNumber(params.height, 'cylinder.height')\n}\n\n/**\n * Validate cone parameters (brepjs contract, §4.1 P 决策): `radiusBottom` and\n * `height` must be positive, `radiusTop` must be non-negative. The legacy\n * `{ center }` object key is removed — any call still passing `center` throws an\n * explicit `E_ARGS_FORM` error pointing at the new signature (error hint ≠\n * compatibility, 裁决 3).\n * @param params - the raw cone operation parameters.\n */\nexport function assertConeParams(params: Record<string, unknown>): void {\n if (params.center !== undefined || params.size !== undefined) {\n throw new Error(\n '[faijs/args] cone: E_ARGS_FORM: the legacy object form is removed. ' +\n 'cone now uses `cone(bottomRadius, topRadius, height, { at?, centered?, segments? })`.',\n )\n }\n assertPositiveNumber(params.radiusBottom, 'cone.radiusBottom')\n assertNonNegativeNumber(params.radiusTop, 'cone.radiusTop')\n assertPositiveNumber(params.height, 'cone.height')\n}\n\n/**\n * Validate wedge parameters: `width`, `height`, `angle`, and `length` must be\n * positive numbers.\n * @param params - the raw wedge operation parameters.\n */\nexport function assertWedgeParams(params: Record<string, unknown>): void {\n assertPositiveNumber(params.width, 'wedge.width')\n assertPositiveNumber(params.height, 'wedge.height')\n assertPositiveNumber(params.angle, 'wedge.angle')\n assertPositiveNumber(params.length, 'wedge.length')\n}\n\n/** BREP 路径:OCCT 精确构造 + 三角化 + fromBrep 登记(基本体无面演化;链根建 roleTable)。 */\nfunction primitiveBrep(op: string, params: Record<string, unknown>): Shape {\n const kernel = getBrepApi()\n const type = op === 'box' ? 'cube' : op\n const result = primitiveToBrepSolid(kernel, type as 'cube' | 'sphere' | 'cylinder' | 'cone' | 'wedge', params as never)\n // §3.2:链根建表——语义命名器按 op 类型给面命名(semantic 'top'/'lateral' 等,\n // Phase 1.7 已删 'box:' 前缀与位置兜底)。\n // Phase 1.6:origin 用链根语句的 StmtId(当前语句 id,§2.2/§4.1)——变量名会被\n // 改名/复用,StmtId 全局唯一,保证多个同类型 primitive 不撞 origin。\n const origin = String(getCurrentStmt()?.id ?? op)\n const roles = assignRoles(kernel, result.solid, op)\n const segments = clampNRad((params.nRad ?? params.segments) as number)\n // P4 面级:brep 链基本体也挂契约序 faceRanges(编辑器默认 brep 链——\n // setFaceColor 必须可用)。box 的 OCCT 面枚举序(实测 0=−X,1=+Y,…)与契约\n // (+X/−X/+Y/−Y/+Z/−Z)不一致,按面法线重排 indices;cylinder/cone 的\n // OCCT 序与契约一致(实测锁定:cylinder 0=侧面,1=顶,2=底;cone radiusTop=0\n // 0=侧面,1=底),直接透传。\n const { shape, faceRanges } = brepPrimitiveMesh(kernel, result.solid, op, segments)\n if (faceRanges) shape.faceRanges = faceRanges\n return fromBrep(\n shape,\n { solid: result.solid, roleTable: new Map([[asPartName(origin), roles]]) },\n )\n}\n\n/** 面法线主轴向:用该面非退化三角形的法线和定轴与符号(OCCT 统一 outward 绕向)。 */\nfunction faceNormalAxis(\n mesh: BrepMeshResult,\n triStart: number,\n triCount: number,\n): { axis: 0 | 1 | 2; sign: 1 | -1 } | null {\n let sx = 0\n let sy = 0\n let sz = 0\n for (let t = 0; t < triCount; t++) {\n const i0 = mesh.indices[(triStart + t) * 3]\n const i1 = mesh.indices[(triStart + t) * 3 + 1]\n const i2 = mesh.indices[(triStart + t) * 3 + 2]\n const p0x = mesh.positions[i0 * 3]; const p0y = mesh.positions[i0 * 3 + 1]; const p0z = mesh.positions[i0 * 3 + 2]\n const p1x = mesh.positions[i1 * 3]; const p1y = mesh.positions[i1 * 3 + 1]; const p1z = mesh.positions[i1 * 3 + 2]\n const p2x = mesh.positions[i2 * 3]; const p2y = mesh.positions[i2 * 3 + 1]; const p2z = mesh.positions[i2 * 3 + 2]\n const ux = p1x - p0x; const uy = p1y - p0y; const uz = p1z - p0z\n const vx = p2x - p0x; const vy = p2y - p0y; const vz = p2z - p0z\n const nx = uy * vz - uz * vy\n const ny = uz * vx - ux * vz\n const nz = ux * vy - uy * vx\n const len = Math.hypot(nx, ny, nz)\n if (!Number.isFinite(len) || len < 1e-12) continue\n sx += nx; sy += ny; sz += nz\n }\n const ax = Math.abs(sx); const ay = Math.abs(sy); const az = Math.abs(sz)\n if (!Number.isFinite(ax + ay + az) || ax + ay + az < 1e-12) return null\n if (ax >= ay && ax >= az) return { axis: 0, sign: sx > 0 ? 1 : -1 }\n if (ay >= ax && ay >= az) return { axis: 1, sign: sy > 0 ? 1 : -1 }\n return { axis: 2, sign: sz > 0 ? 1 : -1 }\n}\n\n/**\n * 三角化基本体并附 P4 契约序 faceRanges。\n * faceGroups 三元组 = [triStart, triCount, faceHash],前两元是索引单位\n * (brep-ops.ts 注释)→ 三角形单位 = 索引/3。\n * - box:6 面 → 按面法线重排 indices 到契约序(0=+X,1=−X,2=+Y,3=−Y,4=+Z,5=−Z)。\n * - cylinder/cone:OCCT 枚举序与契约一致(探针实测锁定),直接透传,不重排。\n * - wedge/sphere 及其它:无契约,不挂 faceRanges(setFaceColor 抛 E_FACE_UNAVAILABLE)。\n */\nfunction brepPrimitiveMesh(\n kernel: BrepEngineApi,\n solid: BrepHandle,\n op: string,\n segments: number,\n): { shape: Shape; faceRanges?: Shape['faceRanges'] } {\n const angularDeflection = (2 * Math.PI) / Math.max(3, segments)\n const mesh = kernel.meshShape(solid, {\n linearDeflection: DEFAULT_LINEAR_DEFLECTION.as(mm),\n angularDeflection,\n })\n const shape: Shape = {\n positions: new Float32Array(mesh.positions),\n indices: new Uint32Array(mesh.indices),\n }\n const fg = mesh.faceGroups\n if (!fg) return { shape }\n const faces: Array<{ triStart: number; triCount: number }> = []\n for (let f = 0; f < fg.length / 3; f++) {\n faces.push({ triStart: fg[f * 3] / 3, triCount: fg[f * 3 + 1] / 3 })\n }\n if (op === 'box' && faces.length === 6) {\n // 契约序重排:每面判向 → 契约 idx(+X=0,−X=1,+Y=2,−Y=3,+Z=4,−Z=5)\n const byContract: Array<(typeof faces)[number] | undefined> = new Array(6).fill(undefined)\n for (const f of faces) {\n const na = faceNormalAxis(mesh, f.triStart, f.triCount)\n if (!na) return { shape }\n const idx = na.axis === 0 ? (na.sign > 0 ? 0 : 1) : na.axis === 1 ? (na.sign > 0 ? 2 : 3) : (na.sign > 0 ? 4 : 5)\n if (byContract[idx] !== undefined) return { shape } // 法线判向歧义 → 不挂\n byContract[idx] = f\n }\n if (byContract.some((f) => f === undefined)) return { shape }\n const newIndices = new Uint32Array(mesh.indices.length)\n const faceRanges: NonNullable<Shape['faceRanges']> = []\n let outTri = 0\n for (let c = 0; c < 6; c++) {\n const f = byContract[c]!\n faceRanges.push({ start: outTri, count: f.triCount })\n for (let t = 0; t < f.triCount; t++) {\n newIndices[(outTri + t) * 3] = mesh.indices[(f.triStart + t) * 3]\n newIndices[(outTri + t) * 3 + 1] = mesh.indices[(f.triStart + t) * 3 + 1]\n newIndices[(outTri + t) * 3 + 2] = mesh.indices[(f.triStart + t) * 3 + 2]\n }\n outTri += f.triCount\n }\n return { shape: { ...shape, indices: newIndices }, faceRanges }\n }\n if ((op === 'cylinder' || op === 'cone') && faces.length >= 2) {\n // OCCT 枚举序 = P4a 契约序(探针实测):0=侧面, 1=顶, 2=底(cone 无顶盖时 0=侧面,1=底)\n return { shape, faceRanges: faces.map((f) => ({ start: f.triStart, count: f.triCount })) }\n }\n return { shape }\n}\n\n/**\n * 创建长方体(brepjs 契约,§4.1 A 决策)。\n * @group 创建\n * @inputs 0\n * @async false\n * @qual ok\n * @name box\n * @returns Shape 长方体几何,可作为后续 op 的输入。\n * @param params.width - X 方向边长(mm)。type:number required:true\n * @param params.depth - Y 方向边长(mm)。type:number required:true\n * @param params.height - Z 方向边长(mm)。type:number required:true\n * @param params.at - 中心点(CENTER 语义,优先于 centered)。type:[x,y,z] 可选\n * @param params.centered - 无 at 时是否居中到原点(type:boolean 默认 false,角点在原点)。\n * @param params.segments - 细分度(影响三角化)。type:number 默认 64(= brepjs standard 等效,P0 §5.0/§5.1)\n * @example\n * const part0 = cad.box(10 * MM, 20 * MM, 30 * MM)\n * const part1 = cad.box(30 * MM, 20 * MM, 10 * MM, { centered: true, at: [1, 2, 3], segments: 64 })\n *\n * 位置原生(§4.1/§6.2):`box(width, depth, height)` 与 `box(10 * MM, 20 * MM, 30 * MM, {centered:true})`\n * 有量纲位必须写单位字面量(基准单位亦然,`10` 裸数字被 D8 R2 拒)。\n * 归一到同一对象(D11 位置→对象 + 尾参 options 合并)。旧 `{ size }` 对象形态已废弃(裁决 3),\n * 传入会抛 `E_ARGS_FORM`(错误提示 ≠ 兼容,§4.1)。\n */\nexport const box = defineOp({\n name: 'box',\n mesh: (params: Record<string, unknown>) => {\n assertBoxParams(params)\n return cad.box(params as never)\n },\n brep: (params: Record<string, unknown>) => {\n assertBoxParams(params)\n return primitiveBrep('box', params)\n },\n // schema feeds codegen/UI parameter panels.\n schema: {\n width: 'number',\n depth: 'number',\n height: 'number',\n at: 'vec3?',\n centered: 'boolean?',\n segments: 'number?',\n },\n // D11 位置→对象(§4.1/§6.2):三个标量装箱成 { width, depth, height },尾参\n // options 经 dual-form-args 的尾参合并(§6.2)并入。\n slotMap: { keys: ['width', 'depth', 'height'] },\n paramDims: { width: 'length', depth: 'length', height: 'length' },\n naming: { kind: 'construct', newFaces: { via: 'explicit', vocab: [{ kind: 'semantic', name: 'top' }, { kind: 'semantic', name: 'bottom' }, { kind: 'semantic', name: 'front' }, { kind: 'semantic', name: 'back' }, { kind: 'semantic', name: 'left' }, { kind: 'semantic', name: 'right' }] } } as Provenance,\n})\n\n/**\n * 创建球体。\n * @group 创建\n * @inputs 0\n * @async false\n * @qual ok\n * @name sphere\n * @returns Shape 球体几何,可作为后续 op 的输入。\n * @param params.radius - 半径(mm)。type:number required:true\n * @param params.segments - 细分度(影响面数)。type:number 默认 64(= brepjs standard 等效,P0 §5.0/§5.1)\n * @param params.center - 球心位置(at 的同义别名)。type:[x,y,z] 默认 [0,0,0](原点)。\n * @param params.at - 球心位置(center 的同义别名,brepjs 契约;裁决 4 双形态合法)。\n * @example\n * const r = cad.sphere({ radius: 10 })\n * const r = cad.sphere(10, { at: [0, 0, 10], segments: 64 })\n * const r = cad.sphere({ radius: 10, segments: 64, center: [0,0,10] })\n */\nexport const sphere = defineOp({\n name: 'sphere',\n mesh: (params: Record<string, unknown>) => {\n assertSphereParams(params)\n return cad.sphere(centerParams(params) as never)\n },\n brep: (params: Record<string, unknown>) => {\n assertSphereParams(params)\n return primitiveBrep('sphere', centerParams(params))\n },\n schema: { radius: 'number', segments: 'number?', center: 'vec3?', at: 'vec3?' },\n // D11: `sphere(10)` == `sphere({ radius: 10 })`; 尾参 options({at, segments})\n // 经 dual-form-args 的尾参合并规则归一(裁决 4,§6.2)。\n slotMap: { keys: ['radius'] },\n paramDims: { radius: 'length' },\n naming: { kind: 'unmodeled', reason: 'sphere face vocabulary pending Phase 3' } as Provenance,\n})\n\n/**\n * 位置归一:把 brepjs 契约的 `at`(= faijs 的 `center`,球心语义)归一为一个\n * `center` 输入,mesh/brep 两条消费路径共用(裁决 1/4,§4.2)。\n */\nfunction centerParams(params: Record<string, unknown>): Record<string, unknown> {\n if (params.at !== undefined) return { ...params, center: params.at }\n return params\n}\n\n/**\n * 创建圆柱体(brepjs 契约,§4.3 A 决策)。\n * 锚点:`at` 是**底面轴心**(BASE 语义,默认 [0,0,0],底面在原点、+Z 延伸);`centered:true`\n * 指底面落到 −h/2(无 at 时居中到原点;与 `at` 同给时以 `at` 为中心)。\n * @group 创建\n * @inputs 0\n * @async false\n * @qual ok\n * @name cylinder\n * @returns Shape 圆柱体几何,可作为后续 op 的输入。\n * @param params.radius - 底面半径(mm)。type:number required:true\n * @param params.height - 高度(mm),沿 +Z 轴。type:number required:true\n * @param params.at - 底面中心(BASE 语义)。type:[x,y,z] 可选\n * @param params.centered - 是否居中(底面 −h/2;与 at 同给时以 at 为中心)。type:boolean 默认 false\n * @param params.segments - 细分度(影响三角化)。type:number 默认 64(= brepjs standard 等效,P0 §5.0/§5.1)\n * @example\n * const c = cad.cylinder(5, 40)\n * const c = cad.cylinder(5, 40, { centered: true, at: [0, 0, 20], segments: 64 })\n *\n * 位置原生(§4.1/§6.2):`cylinder(5, 40)` 与 `cylinder(5, 40, {centered:true})`\n * 归一到同一对象(D11 位置→装箱 + 尾参 options 合并)。旧 `{ center }` 对象形态已废弃\n * (裁决 3),传入会抛 `E_ARGS_FORM`(错误提示 ≠ 兼容,§4.3)。\n */\nexport const cylinder = defineOp({\n name: 'cylinder',\n mesh: (params: Record<string, unknown>) => {\n assertCylinderParams(params)\n return cad.cylinder(params as never)\n },\n brep: (params: Record<string, unknown>) => {\n assertCylinderParams(params)\n return primitiveBrep('cylinder', params)\n },\n schema: { radius: 'number', height: 'number', at: 'vec3?', centered: 'boolean?', segments: 'number?' },\n // D11(§4.1/§6.2):`cylinder(5, 40)` 两个标量装箱成 { radius, height };尾参 options\n // 经 dual-form-args 尾参合并并入。\n slotMap: { keys: ['radius', 'height'] },\n paramDims: { radius: 'length', height: 'length' },\n naming: { kind: 'construct', newFaces: { via: 'explicit', vocab: [{ kind: 'semantic', name: 'top' }, { kind: 'semantic', name: 'bottom' }, { kind: 'semantic', name: 'lateral' }] } } as Provenance,\n})\n\n/**\n * 创建圆锥体(brepjs 契约,§4.1 P 决策)。radiusTop 等于 radiusBottom 时即圆柱,0 为尖锥。\n * 锚点:`at` 是**底面轴心**(BASE 语义,默认 [0,0,0],底面在原点、+Z 延伸);`centered:true`\n * 指底面落到 −h/2(无 at 时居中到原点;与 `at` 同给时以 `at` 为中心)。\n * @group 创建\n * @inputs 0\n * @async false\n * @qual ok\n * @name cone\n * @returns Shape 圆锥体几何,可作为后续 op 的输入。\n * @param params.radiusBottom - 底半径(mm)。type:number required:true\n * @param params.radiusTop - 顶半径(mm),0 为尖锥,非负,等于 radiusBottom 得圆柱。type:number required:true\n * @param params.height - 高度(mm),沿 +Z 轴。type:number required:true\n * @param params.at - 底面轴心(BASE 语义)。type:[x,y,z] 可选\n * @param params.centered - 是否居中(底面 −h/2;与 at 同给时以 at 为中心)。type:boolean 默认 false\n * @param params.segments - 细分度(影响三角化)。type:number 默认 64(= brepjs standard 等效,P0 §5.0/§5.1)\n * @example\n * const c = cad.cone(10, 4, 30)\n * const c = cad.cone(10, 0, 30, { centered: true, at: [0, 0, 20], segments: 64 })\n * 位置原生(§4.1/§6.2):`cone(10, 4, 30)` 与 `cone(10, 4, 30, { centered: true })`\n * 归一到同一对象(D11 位置→装箱 + 尾参 options 合并)。旧 `{ center }`/`{ size }` 对象形态\n * 已废弃(裁决 3),传入会抛 E_ARGS_FORM(错误提示 ≠ 兼容)。\n */\nexport const cone = defineOp({\n name: 'cone',\n mesh: (params: Record<string, unknown>) => {\n assertConeParams(params)\n return cad.cone(params as never)\n },\n brep: (params: Record<string, unknown>) => {\n assertConeParams(params)\n return primitiveBrep('cone', params)\n },\n schema: {\n radiusBottom: 'number',\n radiusTop: 'number',\n height: 'number',\n at: 'vec3?',\n centered: 'boolean?',\n segments: 'number?',\n },\n // D11(§4.1/§6.2): `cone(10, 4, 30)` 三个标量装箱成 { radiusBottom, radiusTop, height }。\n // 尾参 options({at, centered, segments})经 dual-form-args 尾参合并并入。\n slotMap: { keys: ['radiusBottom', 'radiusTop', 'height'] },\n paramDims: { radiusBottom: 'length', radiusTop: 'length', height: 'length' },\n naming: { kind: 'construct', newFaces: { via: 'explicit', vocab: [{ kind: 'semantic', name: 'top' }, { kind: 'semantic', name: 'bottom' }, { kind: 'semantic', name: 'lateral' }] } } as Provenance,\n})\n\n/**\n * 创建楔形体。唯一契约是 width/height/angle/length(width/height/angle 为正数,length 沿切割方向),\n * 旧文档的 size 形态已废弃,传 { size } 会抛错。\n * @group 创建\n * @inputs 0\n * @async false\n * @qual ok\n * @name wedge\n * @note 曾与 UI 面板的 `size` 形态并存并写入文档,但断言层确认唯一合法契约是 width/height/angle/length;传 `{ size }` 直接抛错。已按真源收敛。\n * @returns Shape 楔形体几何,可作为后续 op 的输入。\n * @param params.width - 底面宽度(mm)。type:number required:true\n * @param params.height - 高度(mm)。type:number required:true\n * @param params.angle - 楔形角度(度)。type:number required:true\n * @param params.length - 沿切割方向的长度(mm)。type:number required:true\n * @example\n * const w = cad.wedge({ width: 30, height: 20, angle: 45, length: 10 })\n */\nexport const wedge = defineOp({\n name: 'wedge',\n mesh: (params: Record<string, unknown>) => {\n assertWedgeParams(params)\n return cad.wedge(params as never)\n },\n brep: (params: Record<string, unknown>) => {\n assertWedgeParams(params)\n return primitiveBrep('wedge', params)\n },\n // D11: `wedge(30, 20, 45, 10)` == `wedge({ width: 30, height: 20, angle: 45, length: 10 })`.\n slotMap: { keys: ['width', 'height', 'angle', 'length'] },\n paramDims: { width: 'length', height: 'length', angle: 'angle', length: 'length' },\n naming: { kind: 'unmodeled', reason: 'wedge face vocabulary pending Phase 3' } as Provenance,\n})\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"brep-ops.d.ts","sourceRoot":"","sources":["../../src/brep/brep-ops.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"brep-ops.d.ts","sourceRoot":"","sources":["../../src/brep/brep-ops.ts"],"names":[],"mappings":"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"}
@@ -20,6 +20,7 @@
20
20
  */
21
21
  import * as THREE from 'three';
22
22
  import { getOcctKernel } from '../occt-kernel/occtKernel.js';
23
+ import { getSolidColorsOrdered } from '../occt-kernel/stepColorParser.js';
23
24
  import { getSolidBoundingBox } from './brep-utils.js';
24
25
  import { DEFAULT_LINEAR_DEFLECTION } from '../tolerance.js';
25
26
  import { mm } from '../units.js';
@@ -495,6 +496,30 @@ export function extrudeBrep(kernel, solid, params) {
495
496
  return result;
496
497
  }
497
498
  // ─── STEP/BREP 导入操作 ───
499
+ /**
500
+ * 单零件导入的 STEP 颜色挂载(P2,方案 §5 STEP 行)。
501
+ *
502
+ * `getSolidColorsOrdered`(stepColorParser)把 STYLED_ITEM → COLOUR_RGB 引用链
503
+ * 解析为按 MANIFOLD_SOLID_BREP 文件序的颜色数组;该序与 OCCT
504
+ * `getSubShapes(compound,'solid')` 一致(stepColorParser 注释),因此取 `[0]`
505
+ * 即「loadBrep 单零件收敛取第一个 solid」的颜色,语义对齐。
506
+ *
507
+ * 宽容兼容外部数据:BREP(CASCADE Topology 文本)无颜色概念直接跳过;STEP
508
+ * 文本无 `STYLED_ITEM` 早退(零额外开销);引用链缺失/未知预定义色返回 null,
509
+ * 一律不挂外观、不抛错(AGENTS.md 全局铁律:不得以内部严格性拒收正常文件)。
510
+ */
511
+ function applyFirstStepColor(shape, buffer) {
512
+ const head = new TextDecoder('utf-8').decode(buffer.slice(0, 64));
513
+ if (head.includes('CASCADE Topology'))
514
+ return shape;
515
+ const text = new TextDecoder('utf-8').decode(buffer);
516
+ if (!text.includes('STYLED_ITEM'))
517
+ return shape;
518
+ const c0 = getSolidColorsOrdered(text)[0];
519
+ if (c0)
520
+ shape.appearance = { color: [c0[0], c0[1], c0[2]] };
521
+ return shape;
522
+ }
498
523
  /**
499
524
  * BREP-native STEP 导入:使用 OCCT kernel.importStep 导入 STEP 文件为精确实体。
500
525
  *
@@ -548,7 +573,7 @@ export function loadBrep(kernel, buffer, brepChain, stmtId, opts) {
548
573
  // failed"),调用方必须自己保证它只流向变换/聚合。
549
574
  if (opts?.allowNonSolid && hasAnyTopology(kernel, top)) {
550
575
  const shape = solidToShape(kernel, top, undefined, brepChain, stmtId);
551
- return { solid: top, shape };
576
+ return { solid: top, shape: applyFirstStepColor(shape, buffer) };
552
577
  }
553
578
  kernel.release(top);
554
579
  throw new Error(`[loadBrep] imported shape contains no solid sub-shapes ` +
@@ -560,7 +585,7 @@ export function loadBrep(kernel, buffer, brepChain, stmtId, opts) {
560
585
  const realSolid = solids[0];
561
586
  kernel.release(top); // 释放 Compound 包裹,realSolid 独立持有
562
587
  const shape = solidToShape(kernel, realSolid, undefined, brepChain, stmtId);
563
- return { solid: realSolid, shape };
588
+ return { solid: realSolid, shape: applyFirstStepColor(shape, buffer) };
564
589
  }
565
590
  // 多 solid(§5.4 单零件收敛):只支持单零件 —— 降级取**第一个** solid,
566
591
  // 返回单一非复合 Shape,并回传 multiSolidCount(≥2 表示本文件被降级取件,
@@ -582,7 +607,7 @@ export function loadBrep(kernel, buffer, brepChain, stmtId, opts) {
582
607
  }
583
608
  kernel.release(top); // 释放 Compound 包裹,first 独立持有(同单 solid 模式)
584
609
  const shape = solidToShape(kernel, first, undefined, brepChain, stmtId);
585
- return { solid: first, shape, multiSolidCount: solids.length };
610
+ return { solid: first, shape: applyFirstStepColor(shape, buffer), multiSolidCount: solids.length };
586
611
  }
587
612
  /** Sub-shape kinds that make an imported shape "addressable but not a solid". */
588
613
  const NON_SOLID_KINDS = ['vertex', 'edge', 'wire', 'face', 'shell'];