@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.
- package/dist/api/appearance.d.ts +138 -0
- package/dist/api/appearance.d.ts.map +1 -0
- package/dist/api/appearance.js +230 -0
- package/dist/api/appearance.js.map +1 -0
- package/dist/api/import-step.d.ts.map +1 -1
- package/dist/api/import-step.js +28 -0
- package/dist/api/import-step.js.map +1 -1
- package/dist/api/index.d.ts +4 -0
- package/dist/api/index.d.ts.map +1 -1
- package/dist/api/index.js +2 -0
- package/dist/api/index.js.map +1 -1
- package/dist/api/meta.d.ts +93 -0
- package/dist/api/meta.d.ts.map +1 -0
- package/dist/api/meta.js +99 -0
- package/dist/api/meta.js.map +1 -0
- package/dist/api/primitives.d.ts.map +1 -1
- package/dist/api/primitives.js +117 -2
- package/dist/api/primitives.js.map +1 -1
- package/dist/brep/brep-ops.d.ts.map +1 -1
- package/dist/brep/brep-ops.js +28 -3
- package/dist/brep/brep-ops.js.map +1 -1
- package/dist/brep/engine/adapters/occt.js +1 -1
- package/dist/brep/engine/adapters/occt.js.map +1 -1
- package/dist/brep/export/export-model.d.ts +40 -0
- package/dist/brep/export/export-model.d.ts.map +1 -1
- package/dist/brep/export/export-model.js +268 -25
- package/dist/brep/export/export-model.js.map +1 -1
- package/dist/brep/export/step-meta-header.d.ts +102 -0
- package/dist/brep/export/step-meta-header.d.ts.map +1 -0
- package/dist/brep/export/step-meta-header.js +225 -0
- package/dist/brep/export/step-meta-header.js.map +1 -0
- package/dist/brep/export/step.d.ts +5 -1
- package/dist/brep/export/step.d.ts.map +1 -1
- package/dist/brep/export/step.js +11 -2
- package/dist/brep/export/step.js.map +1 -1
- package/dist/define-op.d.ts.map +1 -1
- package/dist/define-op.js +63 -1
- package/dist/define-op.js.map +1 -1
- package/dist/lang/metadata-extractor.d.ts.map +1 -1
- package/dist/lang/metadata-extractor.js +2 -21
- package/dist/lang/metadata-extractor.js.map +1 -1
- package/dist/lang/types.d.ts +5 -6
- package/dist/lang/types.d.ts.map +1 -1
- package/dist/lang/types.js.map +1 -1
- package/dist/mesh/io.d.ts +6 -0
- package/dist/mesh/io.d.ts.map +1 -1
- package/dist/mesh/io.js +25 -1
- package/dist/mesh/io.js.map +1 -1
- package/dist/mesh/primitives.d.ts.map +1 -1
- package/dist/mesh/primitives.js +41 -6
- package/dist/mesh/primitives.js.map +1 -1
- package/dist/mesh/threemf-loader.d.ts +23 -0
- package/dist/mesh/threemf-loader.d.ts.map +1 -1
- package/dist/mesh/threemf-loader.js +182 -8
- package/dist/mesh/threemf-loader.js.map +1 -1
- package/dist/mesh/types.d.ts +38 -0
- package/dist/mesh/types.d.ts.map +1 -1
- package/dist/mesh/types.js.map +1 -1
- package/dist/occt-kernel/highLevelApi.d.ts +4 -1
- package/dist/occt-kernel/highLevelApi.d.ts.map +1 -1
- package/dist/occt-kernel/highLevelApi.js +4 -2
- package/dist/occt-kernel/highLevelApi.js.map +1 -1
- package/dist/occt-kernel/occt-primitives.js +1 -1
- package/dist/occt-kernel/occt-primitives.js.map +1 -1
- package/dist/occt-kernel/occtKernel.d.ts +1 -1
- package/dist/occt-kernel/occtKernel.js +1 -1
- package/dist/occt-kernel/occtKernel.js.map +1 -1
- package/dist/occt-kernel/stepMetaParser.d.ts +44 -0
- package/dist/occt-kernel/stepMetaParser.d.ts.map +1 -0
- package/dist/occt-kernel/stepMetaParser.js +166 -0
- package/dist/occt-kernel/stepMetaParser.js.map +1 -0
- package/dist/shape.d.ts +11 -3
- package/dist/shape.d.ts.map +1 -1
- package/dist/shape.js +4 -2
- package/dist/shape.js.map +1 -1
- package/dist/step/stepMetaParser.d.ts +55 -0
- package/dist/step/stepMetaParser.d.ts.map +1 -0
- package/dist/step/stepMetaParser.js +177 -0
- package/dist/step/stepMetaParser.js.map +1 -0
- package/package.json +2 -2
package/dist/lang/types.d.ts
CHANGED
|
@@ -31,15 +31,14 @@ export interface ParamDef {
|
|
|
31
31
|
label?: string;
|
|
32
32
|
}
|
|
33
33
|
/**
|
|
34
|
-
* Scene-level model metadata (name
|
|
34
|
+
* Scene-level model metadata (name) carried by a script.
|
|
35
|
+
*
|
|
36
|
+
* 外观不再经 meta 传递(2026-10-05 v2:`appearance` 死特性已删除)——
|
|
37
|
+
* 外观是 Shape 实例方法/字段(`box1.setColor(...)` → `shape.appearance`),
|
|
38
|
+
* 编辑器消费端读执行结果的 `shape.appearance`,而非脚本元数据。
|
|
35
39
|
*/
|
|
36
40
|
export interface ScriptMetaIR {
|
|
37
41
|
name?: string;
|
|
38
|
-
appearance?: {
|
|
39
|
-
color?: string;
|
|
40
|
-
metalness?: number;
|
|
41
|
-
roughness?: number;
|
|
42
|
-
};
|
|
43
42
|
}
|
|
44
43
|
/** 终端变量类型(keep-syntax 设计 §6:运行时登记,缺省 'shape')。 */
|
|
45
44
|
export type VarKind = 'shape' | 'compound' | 'value';
|
package/dist/lang/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/lang/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,aAAa,CAAA;AAI3C,4BAA4B;AAC5B,MAAM,MAAM,IAAI,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAA;AAE3C,mFAAmF;AACnF,MAAM,MAAM,SAAS,GACjB,MAAM,GACN,MAAM,GACN,OAAO,GACP,IAAI,GACJ,SAAS,EAAE,GACX;IAAE,CAAC,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;CAAE,CAAA;AAI9B;;;GAGG;AACH,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,QAAQ,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,CAAA;IACzC,KAAK,EAAE,SAAS,CAAA;IAChB,OAAO,EAAE,SAAS,CAAA;IAClB,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,OAAO,CAAC,EAAE,MAAM,EAAE,CAAA;IAClB,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AAID
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/lang/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,aAAa,CAAA;AAI3C,4BAA4B;AAC5B,MAAM,MAAM,IAAI,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAA;AAE3C,mFAAmF;AACnF,MAAM,MAAM,SAAS,GACjB,MAAM,GACN,MAAM,GACN,OAAO,GACP,IAAI,GACJ,SAAS,EAAE,GACX;IAAE,CAAC,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;CAAE,CAAA;AAI9B;;;GAGG;AACH,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,QAAQ,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,CAAA;IACzC,KAAK,EAAE,SAAS,CAAA;IAChB,OAAO,EAAE,SAAS,CAAA;IAClB,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,OAAO,CAAC,EAAE,MAAM,EAAE,CAAA;IAClB,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AAID;;;;;;GAMG;AACH,MAAM,WAAW,YAAY;IAC3B,IAAI,CAAC,EAAE,MAAM,CAAA;CACd;AAED,kDAAkD;AAClD,MAAM,MAAM,OAAO,GAAG,OAAO,GAAG,UAAU,GAAG,OAAO,CAAA;AAEpD,2DAA2D;AAC3D,MAAM,WAAW,aAAa;IAC5B,4DAA4D;IAC5D,EAAE,EAAE,QAAQ,CAAA;IACZ,yCAAyC;IACzC,IAAI,CAAC,EAAE,YAAY,CAAA;IACnB,4DAA4D;IAC5D,IAAI,CAAC,EAAE,OAAO,CAAA;IACd,0DAA0D;IAC1D,MAAM,CAAC,EAAE,OAAO,CAAA;CACjB"}
|
package/dist/lang/types.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/lang/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG","sourcesContent":["/**\n * faijs 文本层类型定义 — 保留类型(L0 零依赖)\n *\n * 设计文档:docs/language-design.md §3.1\n *\n * 代码文本是唯一事实源。IR 已删除(T5),本文件只保留宿主消费的\n * 保留类型(ParamDef / TerminalShape / ScriptMetaIR / VarKind)和\n * 基础值类型(Vec3 / JsonValue)。\n *\n * L0 边界:此文件仅依赖 TypeScript 内置类型 + identity(零依赖品牌模块)。\n */\n\nimport { type PartName } from '../identity'\n\n// ── 值与引用 ──\n\n/** A 3-component vector. */\nexport type Vec3 = [number, number, number]\n\n/** A JSON-serializable value, used for parameter literals and wire-shaped args. */\nexport type JsonValue =\n | string\n | number\n | boolean\n | null\n | JsonValue[]\n | { [k: string]: JsonValue }\n\n// ── 参数表 ──\n\n/**\n * A parameter declaration (`const name = <literal>`), with its value and\n * optional schema metadata.\n */\nexport interface ParamDef {\n name: string\n type: 'number' | 'vec3' | 'bool' | 'enum'\n value: JsonValue\n default: JsonValue\n min?: number\n max?: number\n options?: string[]\n label?: string\n}\n\n// ── Part 脚本 ──\n\n/**\n * Scene-level model metadata (name
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/lang/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG","sourcesContent":["/**\n * faijs 文本层类型定义 — 保留类型(L0 零依赖)\n *\n * 设计文档:docs/language-design.md §3.1\n *\n * 代码文本是唯一事实源。IR 已删除(T5),本文件只保留宿主消费的\n * 保留类型(ParamDef / TerminalShape / ScriptMetaIR / VarKind)和\n * 基础值类型(Vec3 / JsonValue)。\n *\n * L0 边界:此文件仅依赖 TypeScript 内置类型 + identity(零依赖品牌模块)。\n */\n\nimport { type PartName } from '../identity'\n\n// ── 值与引用 ──\n\n/** A 3-component vector. */\nexport type Vec3 = [number, number, number]\n\n/** A JSON-serializable value, used for parameter literals and wire-shaped args. */\nexport type JsonValue =\n | string\n | number\n | boolean\n | null\n | JsonValue[]\n | { [k: string]: JsonValue }\n\n// ── 参数表 ──\n\n/**\n * A parameter declaration (`const name = <literal>`), with its value and\n * optional schema metadata.\n */\nexport interface ParamDef {\n name: string\n type: 'number' | 'vec3' | 'bool' | 'enum'\n value: JsonValue\n default: JsonValue\n min?: number\n max?: number\n options?: string[]\n label?: string\n}\n\n// ── Part 脚本 ──\n\n/**\n * Scene-level model metadata (name) carried by a script.\n *\n * 外观不再经 meta 传递(2026-10-05 v2:`appearance` 死特性已删除)——\n * 外观是 Shape 实例方法/字段(`box1.setColor(...)` → `shape.appearance`),\n * 编辑器消费端读执行结果的 `shape.appearance`,而非脚本元数据。\n */\nexport interface ScriptMetaIR {\n name?: string\n}\n\n/** 终端变量类型(keep-syntax 设计 §6:运行时登记,缺省 'shape')。 */\nexport type VarKind = 'shape' | 'compound' | 'value'\n\n/** 终端 shape:return 数组/DAG 叶子判定列出的最终输出(设计文档 §2.2 / §4.1) */\nexport interface TerminalShape {\n /** 终端左值变量名(PartName,如 'part0')——终端按变量名(outputs)标识,非语句 id */\n id: PartName\n /** 该终端 mesh 的独立 meta(name/appearance) */\n meta?: ScriptMetaIR\n /** 变量类型('shape' | 'compound' | 'value'),运行时登记,缺省 'shape' */\n kind?: VarKind\n /** 保留但 canvas 不渲染(keep-syntax 设计 §6),缺省 undefined → 可见 */\n hidden?: boolean\n}\n"]}
|
package/dist/mesh/io.d.ts
CHANGED
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
*/
|
|
18
18
|
import { type UnitName, type ValueWithUnits } from '../units.js';
|
|
19
19
|
import type { Shape } from './types.js';
|
|
20
|
+
import type { FileMeta } from '../api/meta.js';
|
|
20
21
|
/** Result of a unit-aware file import. */
|
|
21
22
|
export interface ImportFileResult {
|
|
22
23
|
shape: Shape;
|
|
@@ -32,6 +33,11 @@ export interface ImportFileResult {
|
|
|
32
33
|
* single-part; the file was downgraded to its first part — §5.4).
|
|
33
34
|
*/
|
|
34
35
|
multiPartCount?: number;
|
|
36
|
+
/**
|
|
37
|
+
* 整体级元数据(文件级;方案 §5.1 3MF `<model><metadata>`)。STL/STEP 视实现
|
|
38
|
+
* 是否解析;无声明则省略。仅随导入结果上抛,不挂 Shape。
|
|
39
|
+
*/
|
|
40
|
+
fileMeta?: FileMeta;
|
|
35
41
|
}
|
|
36
42
|
/**
|
|
37
43
|
* Bounded scan window for `detectStepUnit`. Unit entities sit at the front of
|
package/dist/mesh/io.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"io.d.ts","sourceRoot":"","sources":["../../src/mesh/io.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAMH,OAAO,EAAM,KAAK,QAAQ,EAAE,KAAK,cAAc,EAAE,MAAM,UAAU,CAAA;AACjE,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,SAAS,CAAA;AAEpC,0CAA0C;AAC1C,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,KAAK,CAAA;IACZ;;;OAGG;IACH,IAAI,EAAE,QAAQ,GAAG,IAAI,CAAA;IACrB;;;;;OAKG;IACH,cAAc,CAAC,EAAE,MAAM,CAAA;
|
|
1
|
+
{"version":3,"file":"io.d.ts","sourceRoot":"","sources":["../../src/mesh/io.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAMH,OAAO,EAAM,KAAK,QAAQ,EAAE,KAAK,cAAc,EAAE,MAAM,UAAU,CAAA;AACjE,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,SAAS,CAAA;AAEpC,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAA;AAE3C,0CAA0C;AAC1C,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,KAAK,CAAA;IACZ;;;OAGG;IACH,IAAI,EAAE,QAAQ,GAAG,IAAI,CAAA;IACrB;;;;;OAKG;IACH,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB;;;OAGG;IACH,QAAQ,CAAC,EAAE,QAAQ,CAAA;CACpB;AAuBD;;;;;GAKG;AACH,eAAO,MAAM,qBAAqB,QAAa,CAAA;AAE/C;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,QAAQ,GAAG,IAAI,CAqBhE;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,UAAU,CAC9B,MAAM,EAAE,WAAW,EACnB,MAAM,CAAC,EAAE,MAAM,EACf,IAAI,CAAC,EAAE;IAAE,IAAI,CAAC,EAAE,cAAc,CAAA;CAAE,GAC/B,OAAO,CAAC,gBAAgB,CAAC,CA2D3B"}
|
package/dist/mesh/io.js
CHANGED
|
@@ -113,8 +113,32 @@ export async function importFile(buffer, format, opts) {
|
|
|
113
113
|
const shape = {
|
|
114
114
|
positions: first.positions,
|
|
115
115
|
indices: first.indices,
|
|
116
|
+
// P2(方案 §5 3MF 行):对象级 baseColor → appearance.color(sRGB 原值,
|
|
117
|
+
// 宽容兼容:无 baseColor 不带 appearance)。colorgroup(vertexColors)与
|
|
118
|
+
// 逐三角形材质属 Phase 2(materialGroups / vertexColors),P2 不映射。
|
|
119
|
+
...(first.baseColor ? { appearance: { color: [first.baseColor[0], first.baseColor[1], first.baseColor[2]] } } : {}),
|
|
120
|
+
// P4(方案 §5 3MF 行):逐三角形 basematerials(p1=p2=p3)→ materialGroups
|
|
121
|
+
// (三角形区间 + appearance.color);无则不带。vertexColors(colorgroup)
|
|
122
|
+
// 由上层(编辑器导入路径)消费,io 单零件收敛不展开为材质分组。
|
|
123
|
+
...(first.materialGroups && first.materialGroups.length > 0
|
|
124
|
+
? {
|
|
125
|
+
materialGroups: first.materialGroups.map((g) => ({
|
|
126
|
+
start: g.start,
|
|
127
|
+
count: g.count,
|
|
128
|
+
appearance: { color: [g.color[0], g.color[1], g.color[2]] },
|
|
129
|
+
})),
|
|
130
|
+
}
|
|
131
|
+
: {}),
|
|
132
|
+
// 零件级元数据(方案 §5.1 3MF 行):对象 name/partnumber/metadatagroup → meta。
|
|
133
|
+
...(first.meta ? { meta: first.meta } : {}),
|
|
134
|
+
};
|
|
135
|
+
return {
|
|
136
|
+
shape,
|
|
137
|
+
unit: archive.unit,
|
|
138
|
+
multiPartCount,
|
|
139
|
+
// 整体级元数据(`<model><metadata>`)随导入结果上抛(方案 §5.1)。
|
|
140
|
+
...(archive.fileMeta ? { fileMeta: archive.fileMeta } : {}),
|
|
116
141
|
};
|
|
117
|
-
return { shape, unit: archive.unit, multiPartCount };
|
|
118
142
|
}
|
|
119
143
|
if (fmt === 'stl') {
|
|
120
144
|
const scale = (opts?.unit ?? mm).as(mm);
|
package/dist/mesh/io.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"io.js","sourceRoot":"","sources":["../../src/mesh/io.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * mesh IO API — headless 文件加载\n *\n * STL 由 core 自持的 `mesh/stl-loader.ts` 解析(零 three addons);3MF 由\n * `mesh/threemf-loader.ts` 解析(ZIP 解压 + XML,单位换算到 mm 基准)。\n * 坐标永远以 faijs 基准长度单位(mm)存储 — Shape 不贴 unit 标签(D3)。\n *\n * 单位换算边界(unit-system §5.2):\n * - STL 无单位元数据 → 由 `opts.unit` 显式声明,缺省 mm,不做启发式猜测。\n * - 3MF `<model unit>` 由解析器读取并换算(micron/mm/cm/inch/foot/meter)。\n *\n * 返回契约(unit-system §10.6):`importFile` 返回 `{ shape, unit }` — `unit`\n * 是文件**自己声明的单位**(3MF `<model unit>`、STEP 单位实体),无声明格式\n * (STL)为 null(此时 `opts.unit` 决定刻度)。坐标恒为基准值 — `unit` 只作\n * 元数据(sourceUnit 记录、导出目标判定),绝不参与几何缩放(读入折算已由\n * 内核/解析器完成,二次缩放 = 双重换算)。\n */\n\nimport * as THREE from 'three'\nimport { geoToManifoldMesh } from '../boolean/geo-convert'\nimport { parseStl } from './stl-loader'\nimport { parseThreemf } from './threemf-loader'\nimport { mm, type UnitName, type ValueWithUnits } from '../units'\nimport type { Shape } from './types'\n\n/** Result of a unit-aware file import. */\nexport interface ImportFileResult {\n shape: Shape\n /**\n * The unit the file itself declares (3MF `<model unit>`, STEP unit entities).\n * null for declaration-less formats (STL) — the caller's opts.unit decided.\n */\n unit: UnitName | null\n /**\n * Total parts the single file declared (e.g. 3MF `<build>` object count),\n * present only when > 1. Single-part mesh (STL, single-object 3MF) omits it.\n * When set, `shape` is only the FIRST part's geometry (feijs `load` op is\n * single-part; the file was downgraded to its first part — §5.4).\n */\n multiPartCount?: number\n}\n\n/** SI prefixes that may precede .METRE. in a STEP SI_UNIT, → faijs UnitName. */\nconst SI_PREFIX_TO_UNIT: Record<string, UnitName> = {\n '.MILLI.': 'mm',\n '.CENTI.': 'cm',\n '$': 'm',\n}\n\n/** CONVERSION_BASED_UNIT names (uppercased) found in real-world STEP files. */\nconst CONVERSION_NAME_TO_UNIT: Record<string, UnitName> = {\n 'METRE': 'm',\n 'METER': 'm',\n 'MILLIMETRE': 'mm',\n 'MILLIMETER': 'mm',\n 'CENTIMETRE': 'cm',\n 'CENTIMETER': 'cm',\n 'MICROMETRE': 'micron',\n 'MICROMETER': 'micron',\n 'INCH': 'inch',\n 'FOOT': 'foot',\n}\n\n/**\n * Bounded scan window for `detectStepUnit`. Unit entities sit at the front of\n * the DATA section (right after the product/context blocks); 256 KiB covers\n * every real-world header+context preamble observed so far. Recomputable\n * constant — raise if a fixture ever misses.\n */\nexport const STEP_UNIT_SCAN_PREFIX = 256 * 1024\n\n/**\n * Parse the declared length unit from STEP text (unit-system §10.4).\n *\n * Unit entities live in the DATA section (not HEADER — ISO 10303-21 reserves\n * HEADER for FILE_DESCRIPTION/FILE_NAME/FILE_SCHEMA), near its start. We scan\n * a bounded prefix; the justification is \"unit entities sit at the front of\n * the DATA section\", not \"top of file\".\n *\n * Recognized forms, both attached to a LENGTH_UNIT():\n * - `SI_UNIT(<prefix>, .METRE.)` — prefix `.MILLI.`/`.CENTI.`/`.MICRO.` or `$`.\n * - `CONVERSION_BASED_UNIT('<NAME>', #n)` — inch/foot/etc.\n *\n * Metadata only — NEVER used to scale geometry (OCCT already normalizes on\n * read; re-scaling = double conversion).\n *\n * @param stepText - the full STEP file text to scan (only a bounded prefix is read).\n * @returns the faijs UnitName, or null when no length-unit declaration is found\n * (STEP permits omitting it; caller falls back to the base unit).\n */\nexport function detectStepUnit(stepText: string): UnitName | null {\n const head = stepText.slice(0, STEP_UNIT_SCAN_PREFIX)\n\n // 1) CONVERSION_BASED_UNIT('<NAME>', #n) — non-SI units (inch/foot/…).\n const conv = head.match(/CONVERSION_BASED_UNIT\\s*\\(\\s*'([^']+)'/i)\n if (conv) {\n const mapped = CONVERSION_NAME_TO_UNIT[conv[1].toUpperCase()]\n if (mapped) return mapped\n }\n\n // 2) SI_UNIT(<prefix>, .METRE.) — the .METRE. guard excludes angle entities\n // (they carry .RADIAN./.STERADIAN., never .METRE.).\n const si = head.match(/SI_UNIT\\s*\\(\\s*([^)]*?)\\s*,\\s*\\.METRE\\.\\s*\\)/i)\n if (si) {\n const prefix = si[1].trim().toUpperCase()\n if (prefix === '.MICRO.') return 'micron'\n const mapped = SI_PREFIX_TO_UNIT[prefix]\n if (mapped) return mapped\n }\n\n return null\n}\n\n/**\n * Load geometry from raw file bytes (headless variant).\n *\n * @param buffer - the raw file bytes to parse (already decompressed; stpz\n * unzipping is the caller's job — faijs never unzips implicitly).\n * @param format - format identifier such as 'stl', '3mf'/'threemf' or 'step'\n * (defaults to 'stl').\n * @param opts - optional settings; `unit` declares the source unit for\n * formats without unit metadata (e.g. STL). Defaults to mm.\n * @returns the shape with base-unit coordinates plus the file's own declared\n * unit (`unit`, metadata only; null when the format has no declaration).\n */\nexport async function importFile(\n buffer: ArrayBuffer,\n format?: string,\n opts?: { unit?: ValueWithUnits },\n): Promise<ImportFileResult> {\n const fmt = (format ?? 'stl').toLowerCase()\n\n if (fmt === '3mf' || fmt === 'threemf') {\n const archive = await parseThreemf(buffer)\n // §5.4 单零件收敛:只取**第一个**对象实例(declaration order — `<build><item>`\n // 序,见 threemf-loader)构造成单一 part;多对象文件记 multiPartCount 供上层\n // 登记\"多零件降级\"警告。坐标已在 parseThreemf 里折算为 faijs 基准单位。\n const first = archive.objects[0]\n if (!first) {\n throw new Error('[mesh/io] 3MF contains no objects')\n }\n const multiPartCount = archive.objects.length > 1 ? archive.objects.length : undefined\n const shape: Shape = {\n positions: first.positions as Float32Array,\n indices: first.indices as Uint32Array,\n }\n return { shape, unit: archive.unit, multiPartCount }\n }\n\n if (fmt === 'stl') {\n const scale = (opts?.unit ?? mm).as(mm)\n const geo = parseStl(buffer)\n if (scale !== 1) {\n const attr = geo.getAttribute('position') as THREE.BufferAttribute\n const arr = attr.array as Float32Array\n for (let i = 0; i < arr.length; i++) arr[i] *= scale\n }\n return { shape: geoToManifoldMesh(geo), unit: null }\n }\n\n // STEP goes through the BREP chain (loadBrep → OCCT, which normalizes to the\n // base unit on read). The mesh io path has no kernel-independent STEP parser\n // and must not fake one — a missing path is an error, not a fallback.\n throw new Error(`[mesh/io] unsupported format: ${fmt}`)\n}\n"]}
|
|
1
|
+
{"version":3,"file":"io.js","sourceRoot":"","sources":["../../src/mesh/io.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * mesh IO API — headless 文件加载\n *\n * STL 由 core 自持的 `mesh/stl-loader.ts` 解析(零 three addons);3MF 由\n * `mesh/threemf-loader.ts` 解析(ZIP 解压 + XML,单位换算到 mm 基准)。\n * 坐标永远以 faijs 基准长度单位(mm)存储 — Shape 不贴 unit 标签(D3)。\n *\n * 单位换算边界(unit-system §5.2):\n * - STL 无单位元数据 → 由 `opts.unit` 显式声明,缺省 mm,不做启发式猜测。\n * - 3MF `<model unit>` 由解析器读取并换算(micron/mm/cm/inch/foot/meter)。\n *\n * 返回契约(unit-system §10.6):`importFile` 返回 `{ shape, unit }` — `unit`\n * 是文件**自己声明的单位**(3MF `<model unit>`、STEP 单位实体),无声明格式\n * (STL)为 null(此时 `opts.unit` 决定刻度)。坐标恒为基准值 — `unit` 只作\n * 元数据(sourceUnit 记录、导出目标判定),绝不参与几何缩放(读入折算已由\n * 内核/解析器完成,二次缩放 = 双重换算)。\n */\n\nimport * as THREE from 'three'\nimport { geoToManifoldMesh } from '../boolean/geo-convert'\nimport { parseStl } from './stl-loader'\nimport { parseThreemf } from './threemf-loader'\nimport { mm, type UnitName, type ValueWithUnits } from '../units'\nimport type { Shape } from './types'\nimport type { PbrAppearance } from '../api/appearance'\nimport type { FileMeta } from '../api/meta'\n\n/** Result of a unit-aware file import. */\nexport interface ImportFileResult {\n shape: Shape\n /**\n * The unit the file itself declares (3MF `<model unit>`, STEP unit entities).\n * null for declaration-less formats (STL) — the caller's opts.unit decided.\n */\n unit: UnitName | null\n /**\n * Total parts the single file declared (e.g. 3MF `<build>` object count),\n * present only when > 1. Single-part mesh (STL, single-object 3MF) omits it.\n * When set, `shape` is only the FIRST part's geometry (feijs `load` op is\n * single-part; the file was downgraded to its first part — §5.4).\n */\n multiPartCount?: number\n /**\n * 整体级元数据(文件级;方案 §5.1 3MF `<model><metadata>`)。STL/STEP 视实现\n * 是否解析;无声明则省略。仅随导入结果上抛,不挂 Shape。\n */\n fileMeta?: FileMeta\n}\n\n/** SI prefixes that may precede .METRE. in a STEP SI_UNIT, → faijs UnitName. */\nconst SI_PREFIX_TO_UNIT: Record<string, UnitName> = {\n '.MILLI.': 'mm',\n '.CENTI.': 'cm',\n '$': 'm',\n}\n\n/** CONVERSION_BASED_UNIT names (uppercased) found in real-world STEP files. */\nconst CONVERSION_NAME_TO_UNIT: Record<string, UnitName> = {\n 'METRE': 'm',\n 'METER': 'm',\n 'MILLIMETRE': 'mm',\n 'MILLIMETER': 'mm',\n 'CENTIMETRE': 'cm',\n 'CENTIMETER': 'cm',\n 'MICROMETRE': 'micron',\n 'MICROMETER': 'micron',\n 'INCH': 'inch',\n 'FOOT': 'foot',\n}\n\n/**\n * Bounded scan window for `detectStepUnit`. Unit entities sit at the front of\n * the DATA section (right after the product/context blocks); 256 KiB covers\n * every real-world header+context preamble observed so far. Recomputable\n * constant — raise if a fixture ever misses.\n */\nexport const STEP_UNIT_SCAN_PREFIX = 256 * 1024\n\n/**\n * Parse the declared length unit from STEP text (unit-system §10.4).\n *\n * Unit entities live in the DATA section (not HEADER — ISO 10303-21 reserves\n * HEADER for FILE_DESCRIPTION/FILE_NAME/FILE_SCHEMA), near its start. We scan\n * a bounded prefix; the justification is \"unit entities sit at the front of\n * the DATA section\", not \"top of file\".\n *\n * Recognized forms, both attached to a LENGTH_UNIT():\n * - `SI_UNIT(<prefix>, .METRE.)` — prefix `.MILLI.`/`.CENTI.`/`.MICRO.` or `$`.\n * - `CONVERSION_BASED_UNIT('<NAME>', #n)` — inch/foot/etc.\n *\n * Metadata only — NEVER used to scale geometry (OCCT already normalizes on\n * read; re-scaling = double conversion).\n *\n * @param stepText - the full STEP file text to scan (only a bounded prefix is read).\n * @returns the faijs UnitName, or null when no length-unit declaration is found\n * (STEP permits omitting it; caller falls back to the base unit).\n */\nexport function detectStepUnit(stepText: string): UnitName | null {\n const head = stepText.slice(0, STEP_UNIT_SCAN_PREFIX)\n\n // 1) CONVERSION_BASED_UNIT('<NAME>', #n) — non-SI units (inch/foot/…).\n const conv = head.match(/CONVERSION_BASED_UNIT\\s*\\(\\s*'([^']+)'/i)\n if (conv) {\n const mapped = CONVERSION_NAME_TO_UNIT[conv[1].toUpperCase()]\n if (mapped) return mapped\n }\n\n // 2) SI_UNIT(<prefix>, .METRE.) — the .METRE. guard excludes angle entities\n // (they carry .RADIAN./.STERADIAN., never .METRE.).\n const si = head.match(/SI_UNIT\\s*\\(\\s*([^)]*?)\\s*,\\s*\\.METRE\\.\\s*\\)/i)\n if (si) {\n const prefix = si[1].trim().toUpperCase()\n if (prefix === '.MICRO.') return 'micron'\n const mapped = SI_PREFIX_TO_UNIT[prefix]\n if (mapped) return mapped\n }\n\n return null\n}\n\n/**\n * Load geometry from raw file bytes (headless variant).\n *\n * @param buffer - the raw file bytes to parse (already decompressed; stpz\n * unzipping is the caller's job — faijs never unzips implicitly).\n * @param format - format identifier such as 'stl', '3mf'/'threemf' or 'step'\n * (defaults to 'stl').\n * @param opts - optional settings; `unit` declares the source unit for\n * formats without unit metadata (e.g. STL). Defaults to mm.\n * @returns the shape with base-unit coordinates plus the file's own declared\n * unit (`unit`, metadata only; null when the format has no declaration).\n */\nexport async function importFile(\n buffer: ArrayBuffer,\n format?: string,\n opts?: { unit?: ValueWithUnits },\n): Promise<ImportFileResult> {\n const fmt = (format ?? 'stl').toLowerCase()\n\n if (fmt === '3mf' || fmt === 'threemf') {\n const archive = await parseThreemf(buffer)\n // §5.4 单零件收敛:只取**第一个**对象实例(declaration order — `<build><item>`\n // 序,见 threemf-loader)构造成单一 part;多对象文件记 multiPartCount 供上层\n // 登记\"多零件降级\"警告。坐标已在 parseThreemf 里折算为 faijs 基准单位。\n const first = archive.objects[0]\n if (!first) {\n throw new Error('[mesh/io] 3MF contains no objects')\n }\n const multiPartCount = archive.objects.length > 1 ? archive.objects.length : undefined\n const shape: Shape = {\n positions: first.positions as Float32Array,\n indices: first.indices as Uint32Array,\n // P2(方案 §5 3MF 行):对象级 baseColor → appearance.color(sRGB 原值,\n // 宽容兼容:无 baseColor 不带 appearance)。colorgroup(vertexColors)与\n // 逐三角形材质属 Phase 2(materialGroups / vertexColors),P2 不映射。\n ...(first.baseColor ? { appearance: { color: [first.baseColor[0], first.baseColor[1], first.baseColor[2]] } } : {}),\n // P4(方案 §5 3MF 行):逐三角形 basematerials(p1=p2=p3)→ materialGroups\n // (三角形区间 + appearance.color);无则不带。vertexColors(colorgroup)\n // 由上层(编辑器导入路径)消费,io 单零件收敛不展开为材质分组。\n ...(first.materialGroups && first.materialGroups.length > 0\n ? {\n materialGroups: first.materialGroups.map((g) => ({\n start: g.start,\n count: g.count,\n appearance: { color: [g.color[0], g.color[1], g.color[2]] } as PbrAppearance,\n })),\n }\n : {}),\n // 零件级元数据(方案 §5.1 3MF 行):对象 name/partnumber/metadatagroup → meta。\n ...(first.meta ? { meta: first.meta } : {}),\n }\n return {\n shape,\n unit: archive.unit,\n multiPartCount,\n // 整体级元数据(`<model><metadata>`)随导入结果上抛(方案 §5.1)。\n ...(archive.fileMeta ? { fileMeta: archive.fileMeta } : {}),\n }\n }\n\n if (fmt === 'stl') {\n const scale = (opts?.unit ?? mm).as(mm)\n const geo = parseStl(buffer)\n if (scale !== 1) {\n const attr = geo.getAttribute('position') as THREE.BufferAttribute\n const arr = attr.array as Float32Array\n for (let i = 0; i < arr.length; i++) arr[i] *= scale\n }\n return { shape: geoToManifoldMesh(geo), unit: null }\n }\n\n // STEP goes through the BREP chain (loadBrep → OCCT, which normalizes to the\n // base unit on read). The mesh io path has no kernel-independent STEP parser\n // and must not fake one — a missing path is an error, not a fallback.\n throw new Error(`[mesh/io] unsupported format: ${fmt}`)\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"primitives.d.ts","sourceRoot":"","sources":["../../src/mesh/primitives.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAKH,OAAO,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,YAAY,EAAE,cAAc,EAAE,UAAU,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,SAAS,CAAA;
|
|
1
|
+
{"version":3,"file":"primitives.d.ts","sourceRoot":"","sources":["../../src/mesh/primitives.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAKH,OAAO,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,YAAY,EAAE,cAAc,EAAE,UAAU,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,SAAS,CAAA;AAcjH;;;;;;;;;;;GAWG;AACH,wBAAgB,GAAG,CAAC,MAAM,EAAE,SAAS,GAAG,KAAK,CAiC5C;AAED;;;;;GAKG;AACH,wBAAgB,MAAM,CAAC,MAAM,EAAE,YAAY,GAAG,KAAK,CAOlD;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,QAAQ,CAAC,MAAM,EAAE,cAAc,GAAG,KAAK,CAkBtD;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,IAAI,CAAC,MAAM,EAAE,UAAU,GAAG,KAAK,CA6C9C;AAED;;;;;GAKG;AACH,wBAAgB,KAAK,CAAC,MAAM,EAAE,WAAW,GAAG,KAAK,CA0DhD;AAED;;;;;GAKG;AACH,wBAAsB,KAAK,CAAC,MAAM,EAAE;IAClC,MAAM,EAAE,QAAQ,GAAG,UAAU,CAAA;IAC7B,OAAO,EAAE,MAAM,CAAA;IACf,MAAM,EAAE,QAAQ,GAAG,MAAM,GAAG,QAAQ,GAAG,MAAM,CAAA;IAC7C,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,MAAM,EAAE,MAAM,CAAA;IACd,IAAI,EAAE,KAAK,GAAG,KAAK,GAAG,MAAM,CAAA;IAC5B,IAAI,CAAC,EAAE,MAAM,CAAA;CACd,GAAG,OAAO,CAAC,KAAK,CAAC,CAYjB;AAED;;;;;;GAMG;AACH,wBAAsB,GAAG,CAAC,MAAM,EAAE,SAAS,GAAG,OAAO,CAAC,KAAK,CAAC,CAc3D"}
|
package/dist/mesh/primitives.js
CHANGED
|
@@ -17,9 +17,12 @@ import { makePrimitiveGeo } from '../primitives/mesh-primitives.js';
|
|
|
17
17
|
import { geoToManifoldMesh } from '../boolean/csg-backend.js';
|
|
18
18
|
import { clampNRad } from './types.js';
|
|
19
19
|
// ── 内部工具 ──
|
|
20
|
-
/** THREE.BufferGeometry → Shape (ManifoldMeshData) */
|
|
21
|
-
function geoToShape(geo) {
|
|
22
|
-
|
|
20
|
+
/** THREE.BufferGeometry → Shape (ManifoldMeshData);可选携带面结构元数据。 */
|
|
21
|
+
function geoToShape(geo, faceRanges) {
|
|
22
|
+
const shape = geoToManifoldMesh(geo);
|
|
23
|
+
if (faceRanges !== undefined)
|
|
24
|
+
shape.faceRanges = faceRanges;
|
|
25
|
+
return shape;
|
|
23
26
|
}
|
|
24
27
|
// ── 创建 API ──
|
|
25
28
|
/**
|
|
@@ -58,7 +61,18 @@ export function box(params) {
|
|
|
58
61
|
}
|
|
59
62
|
if (tx !== 0 || ty !== 0 || tz !== 0)
|
|
60
63
|
geo.translate(tx, ty, tz);
|
|
61
|
-
|
|
64
|
+
// 面结构(P4 面级):BoxGeometry 12 三角形 = 6 面 × 2,顺序固定
|
|
65
|
+
// (+X, −X, +Y, −Y, +Z, −Z);geoToManifoldMesh 焊接顶点保三角形序,故面序契约成立。
|
|
66
|
+
// 面序号契约(setFaceColor 的 faceIds 即此序号):0=+X, 1=−X, 2=+Y, 3=−Y, 4=+Z, 5=−Z。
|
|
67
|
+
const faceRanges = [
|
|
68
|
+
{ start: 0, count: 2 },
|
|
69
|
+
{ start: 2, count: 2 },
|
|
70
|
+
{ start: 4, count: 2 },
|
|
71
|
+
{ start: 6, count: 2 },
|
|
72
|
+
{ start: 8, count: 2 },
|
|
73
|
+
{ start: 10, count: 2 },
|
|
74
|
+
];
|
|
75
|
+
return geoToShape(geo, faceRanges);
|
|
62
76
|
}
|
|
63
77
|
/**
|
|
64
78
|
* Create a sphere centered at the origin (or the optional `center`).
|
|
@@ -95,7 +109,14 @@ export function cylinder(params) {
|
|
|
95
109
|
const baseY = params.at?.[1] ?? 0;
|
|
96
110
|
const baseZ = (params.at?.[2] ?? 0) - (params.centered === true ? params.height / 2 : 0);
|
|
97
111
|
geo.translate(baseX, baseY, baseZ + params.height / 2);
|
|
98
|
-
|
|
112
|
+
// 面结构(P4 面级):CylinderGeometry 三角形布局稳定——侧面 2*segs(tri 0..2segs-1)、
|
|
113
|
+
// 顶盖 segs、底盖 segs。面序号契约:0=侧面, 1=顶, 2=底。
|
|
114
|
+
const faceRanges = [
|
|
115
|
+
{ start: 0, count: 2 * segs },
|
|
116
|
+
{ start: 2 * segs, count: segs },
|
|
117
|
+
{ start: 3 * segs, count: segs },
|
|
118
|
+
];
|
|
119
|
+
return geoToShape(geo, faceRanges);
|
|
99
120
|
}
|
|
100
121
|
/**
|
|
101
122
|
* Create a cone, or a frustum when the top and bottom radii differ
|
|
@@ -130,7 +151,21 @@ export function cone(params) {
|
|
|
130
151
|
const baseY = params.at?.[1] ?? 0;
|
|
131
152
|
const baseZ = (params.at?.[2] ?? 0) - (params.centered === true ? params.height / 2 : 0);
|
|
132
153
|
resultGeo.translate(baseX, baseY, baseZ + params.height / 2);
|
|
133
|
-
|
|
154
|
+
// 面结构(P4 面级):radiusTop=0 的 ConeGeometry 只有 2 面——侧面(segs 个
|
|
155
|
+
// 三角扇)+ 底盖(segs 个);radiusTop>0 的圆台 CylinderGeometry 3 面
|
|
156
|
+
// (侧面 2*segs、顶、底,同 cylinder 布局)。面序号契约:0=侧面, 1=底
|
|
157
|
+
// (尖锥);0=侧面, 1=顶, 2=底(圆台)。
|
|
158
|
+
const faceRanges = params.radiusTop === 0
|
|
159
|
+
? [
|
|
160
|
+
{ start: 0, count: segs },
|
|
161
|
+
{ start: segs, count: segs },
|
|
162
|
+
]
|
|
163
|
+
: [
|
|
164
|
+
{ start: 0, count: 2 * segs },
|
|
165
|
+
{ start: 2 * segs, count: segs },
|
|
166
|
+
{ start: 3 * segs, count: segs },
|
|
167
|
+
];
|
|
168
|
+
return geoToShape(resultGeo, faceRanges);
|
|
134
169
|
}
|
|
135
170
|
/**
|
|
136
171
|
* Create a wedge (ramp) solid, fully parameterized and Z-up.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"primitives.js","sourceRoot":"","sources":["../../src/mesh/primitives.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * mesh 基本体 API — 从现有纯函数提取的统一接口\n *\n * 提取来源(§5.7):\n * - box/sphere/cylinder/cone/wedge ← engine/primitives/mesh-primitives.ts (makePrimitiveGeo)\n * - screw ← engine/primitives/screw/screw.ts (makeScrew)\n *\n * `text` / `svgExtrude`(three 的 Shape / ExtrudeGeometry / SVGLoader 链)已随\n * B 组迁到 `@faicad/faijs-extra` 的 `mesh/primitives.ts`,core 的 mesh 面不再\n * 承载 three 的非基础几何生成链。\n *\n * 所有函数返回 Shape (ManifoldMeshData):THREE.BufferGeometry → geoToManifoldMesh 转换。\n * 坐标系:Z-up、毫米。\n */\n\nimport * as THREE from 'three'\nimport { makePrimitiveGeo } from '../primitives/mesh-primitives'\nimport { geoToManifoldMesh } from '../boolean/csg-backend'\nimport type { Shape, BoxParams, SphereParams, CylinderParams, ConeParams, WedgeParams, SdfParams } from './types'\nimport { clampNRad } from './types'\n\n// ── 内部工具 ──\n\n/** THREE.BufferGeometry → Shape (ManifoldMeshData) */\nfunction geoToShape(geo: THREE.BufferGeometry): Shape {\n return geoToManifoldMesh(geo)\n}\n\n// ── 创建 API ──\n\n/**\n * Create a box solid (brepjs contract, §4.1 A 决策).\n *\n * `box(width, depth, height)` — X=width, Y=depth, Z=height — places the\n * min-corner at the origin by default (`centered:false`). `centered: true`\n * centers the box at the origin; `at` is CENTER semantics and takes precedence\n * over `centered`. The `segments` option is consumed by the tessellation\n * caller (this mesh builder keeps it via clampNRad when present).\n *\n * @param params - box parameters (width/depth/height, optional at/centered/segments).\n * @returns the box shape.\n */\nexport function box(params: BoxParams): Shape {\n const { width, depth, height } = params\n // THREE.BoxGeometry(a, b, c) is Y-up (X=a, Y=b, Z=c); after the +90° rotateX\n // the dims map to X=a, Y=c, Z=b. To reach X=width, Y=depth, Z=height the\n // pre-rotation sizes must be (width, height, depth) — 裁决 7 xyz contract.\n const geo = new THREE.BoxGeometry(width, height, depth)\n geo.applyMatrix4(new THREE.Matrix4().makeRotationX(Math.PI / 2))\n // brepjs box semantics: corner at origin by default; centered at origin when\n // `centered` (no `at`); `at` (CENTER semantics) takes precedence.\n const at = params.at\n let tx = 0\n let ty = 0\n let tz = 0\n if (at !== undefined) {\n ;[tx, ty, tz] = at\n } else if (!params.centered) {\n tx = width / 2\n ty = depth / 2\n tz = height / 2\n }\n if (tx !== 0 || ty !== 0 || tz !== 0) geo.translate(tx, ty, tz)\n return geoToShape(geo)\n}\n\n/**\n * Create a sphere centered at the origin (or the optional `center`).\n *\n * @param params - sphere parameters (radius, optional segments, optional center).\n * @returns the sphere shape.\n */\nexport function sphere(params: SphereParams): Shape {\n const segs = clampNRad(params.nRad ?? params.segments)\n const geo = makePrimitiveGeo('sphere', params.radius * 2, segs)\n if (params.center) {\n geo.translate(params.center[0], params.center[1], params.center[2])\n }\n return geoToShape(geo)\n}\n\n/**\n * Create a cylinder along +Z (`cylinder(radius, height, { at?, centered?,\n * segments? })` brepjs 契约,§4.3 A 决策;与 brep 路径逐点对齐)。\n *\n * 锚点:`at` 是**底面轴心**(BASE)语义(默认 [0,0,0],底面在原点、+Z 延伸);\n * `centered:true` 指底面落到 −h/2(无 at 时居中到原点)——与 `at` 同给时以\n * `at` 为中心。`segments` 经 clampNRad 消费(P0 §5)。\n *\n * @param params - cylinder parameters (radius, height, optional at/centered/segments).\n * @returns the cylinder shape.\n */\nexport function cylinder(params: CylinderParams): Shape {\n const segs = clampNRad(params.nRad ?? params.segments)\n const geo = new THREE.CylinderGeometry(params.radius, params.radius, params.height, segs)\n geo.applyMatrix4(new THREE.Matrix4().makeRotationX(Math.PI / 2))\n // geometry(rotateX 后)沿 z ∈ [-h/2, +h/2](three 默认 Y-up 居中):\n // 目标底面中心 in baseZ = (at?.[2] ?? 0) - (centered ? h/2 : 0) → 平移到 baseZ + h/2。\n const baseX = params.at?.[0] ?? 0\n const baseY = params.at?.[1] ?? 0\n const baseZ = (params.at?.[2] ?? 0) - (params.centered === true ? params.height / 2 : 0)\n geo.translate(baseX, baseY, baseZ + params.height / 2)\n return geoToShape(geo)\n}\n\n/**\n * Create a cone, or a frustum when the top and bottom radii differ\n * (`cone(bottomRadius, topRadius, height, { at?, centered?, segments? })` brepjs\n * 契约,§4.1 P 决策;与 brep 路径逐点对齐)。\n *\n * 锚点:`at` 是**底面轴心**(BASE)语义(默认 [0,0,0],底面在原点、+Z 延伸);\n * `centered:true` 指底面落到 −h/2(无 at 时居中到原点)——与 `at` 同给时以\n * `at` 为中心。`segments` 经 clampNRad 消费(P0 §5)。\n *\n * @param params - cone parameters (radiusBottom, radiusTop, height, optional at/centered/segments).\n * @returns the cone shape.\n */\nexport function cone(params: ConeParams): Shape {\n const segs = clampNRad(params.nRad ?? params.segments)\n const geo = new THREE.ConeGeometry(\n Math.max(params.radiusBottom, params.radiusTop),\n params.height,\n segs,\n )\n geo.applyMatrix4(new THREE.Matrix4().makeRotationX(Math.PI / 2))\n // radiusTop === 0 → 尖锥(ConeGeometry 顶点在顶);其余(含 radiusTop ===\n // radiusBottom 的等径圆柱/圆台)用 CylinderGeometry(radiusTop/bottom 各就各位)。\n let resultGeo: THREE.BufferGeometry\n if (params.radiusTop === 0) {\n resultGeo = geo\n } else {\n const geo2 = new THREE.CylinderGeometry(\n params.radiusTop,\n params.radiusBottom,\n params.height,\n segs,\n )\n geo2.applyMatrix4(new THREE.Matrix4().makeRotationX(Math.PI / 2))\n resultGeo = geo2\n }\n // geometry(rotateX 后)沿 z ∈ [-h/2, +h/2](three 默认 Y-up 居中):\n // 目标底面中心 in baseZ = (at?.[2] ?? 0) - (centered ? h/2 : 0) → 平坦平移 baseZ + h/2。\n const baseX = params.at?.[0] ?? 0\n const baseY = params.at?.[1] ?? 0\n const baseZ = (params.at?.[2] ?? 0) - (params.centered === true ? params.height / 2 : 0)\n resultGeo.translate(baseX, baseY, baseZ + params.height / 2)\n return geoToShape(resultGeo)\n}\n\n/**\n * Create a wedge (ramp) solid, fully parameterized and Z-up.\n *\n * @param params - wedge parameters (width, height, angle, length, optional center).\n * @returns the wedge shape.\n */\nexport function wedge(params: WedgeParams): Shape {\n const width = params.width\n const height = params.height\n const angle = params.angle\n const length = params.length\n\n const angleRad = (angle * Math.PI) / 180\n const halfExtrude = length / 2\n const hw = width / 2\n const halfTopWidth = Math.max(0, hw - height / Math.tan(angleRad))\n // 顶边塌缩(斜坡已在宽度内到顶)→ 三角棱柱(与 brep wedge 的退化处理一致,\n // 保证 mesh/brep 同参数 bbox 一致;零面积三角形会破坏 manifold)。\n const degenerate = halfTopWidth <= 1e-12\n\n const positions = degenerate\n ? new Float32Array([\n -halfExtrude, -hw, 0,\n -halfExtrude, hw, 0,\n -halfExtrude, 0, height,\n halfExtrude, -hw, 0,\n halfExtrude, hw, 0,\n halfExtrude, 0, height,\n ])\n : new Float32Array([\n -halfExtrude, -hw, 0,\n -halfExtrude, hw, 0,\n -halfExtrude, halfTopWidth, height,\n -halfExtrude, -halfTopWidth, height,\n halfExtrude, -hw, 0,\n halfExtrude, hw, 0,\n halfExtrude, halfTopWidth, height,\n halfExtrude, -halfTopWidth, height,\n ])\n\n const indices = degenerate\n ? new Uint32Array([\n 0, 1, 2, 3, 5, 4,\n 0, 3, 4, 0, 4, 1,\n 0, 2, 5, 0, 5, 3,\n 1, 4, 5, 1, 5, 2,\n ])\n : new Uint32Array([\n 0, 1, 2, 0, 2, 3,\n 4, 6, 5, 4, 7, 6,\n 0, 4, 5, 0, 5, 1,\n 3, 2, 6, 3, 6, 7,\n 0, 3, 7, 0, 7, 4,\n 1, 5, 6, 1, 6, 2,\n ])\n\n const geo = new THREE.BufferGeometry()\n geo.setAttribute('position', new THREE.BufferAttribute(positions, 3))\n geo.setIndex(new THREE.BufferAttribute(indices, 1))\n\n if (params.center) {\n geo.translate(params.center[0], params.center[1], params.center[2])\n }\n return geoToShape(geo)\n}\n\n/**\n * Create a screw (threaded) geometry.\n *\n * @param params - screw parameters (system, specIdx, thread, length, head, optional pitchCustom and nRad).\n * @returns the screw shape.\n */\nexport async function screw(params: {\n system: 'metric' | 'imperial'\n specIdx: number\n thread: 'coarse' | 'fine' | 'custom' | 'none'\n pitchCustom?: number\n length: number\n head: 'hex' | 'chc' | 'none'\n nRad?: number\n}): Promise<Shape> {\n const { makeScrew } = await import('../primitives/screw/screw')\n const geo = makeScrew({\n system: params.system,\n specIdx: params.specIdx,\n thread: params.thread,\n pitchCustom: params.pitchCustom ?? 0,\n length: params.length,\n head: params.head,\n nRad: clampNRad(params.nRad),\n })\n return geoToShape(geo)\n}\n\n/**\n * Create a mesh from SDF (signed distance field) code, sampling the field with\n * marching cubes.\n *\n * @param params - SDF parameters (code, optional bounds, params, resolution).\n * @returns the sampled shape.\n */\nexport async function sdf(params: SdfParams): Promise<Shape> {\n const { runSdf } = await import('../sdf/sdf-runner')\n const box = params.box ?? [[-10, -10, -10], [10, 10, 10]]\n const bounds: [number, number, number, number, number, number] = [\n box[0][0], box[0][1], box[0][2],\n box[1][0], box[1][1], box[1][2],\n ]\n const mesh = await runSdf(\n params.code,\n params.params ?? {},\n bounds,\n params.resolution ?? 1.0,\n )\n return { positions: mesh.positions, indices: mesh.indices }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"primitives.js","sourceRoot":"","sources":["../../src/mesh/primitives.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * mesh 基本体 API — 从现有纯函数提取的统一接口\n *\n * 提取来源(§5.7):\n * - box/sphere/cylinder/cone/wedge ← engine/primitives/mesh-primitives.ts (makePrimitiveGeo)\n * - screw ← engine/primitives/screw/screw.ts (makeScrew)\n *\n * `text` / `svgExtrude`(three 的 Shape / ExtrudeGeometry / SVGLoader 链)已随\n * B 组迁到 `@faicad/faijs-extra` 的 `mesh/primitives.ts`,core 的 mesh 面不再\n * 承载 three 的非基础几何生成链。\n *\n * 所有函数返回 Shape (ManifoldMeshData):THREE.BufferGeometry → geoToManifoldMesh 转换。\n * 坐标系:Z-up、毫米。\n */\n\nimport * as THREE from 'three'\nimport { makePrimitiveGeo } from '../primitives/mesh-primitives'\nimport { geoToManifoldMesh } from '../boolean/csg-backend'\nimport type { Shape, BoxParams, SphereParams, CylinderParams, ConeParams, WedgeParams, SdfParams } from './types'\nimport { clampNRad } from './types'\n\n// ── 内部工具 ──\n\n/** THREE.BufferGeometry → Shape (ManifoldMeshData);可选携带面结构元数据。 */\nfunction geoToShape(geo: THREE.BufferGeometry, faceRanges?: Shape['faceRanges']): Shape {\n const shape = geoToManifoldMesh(geo) as Shape\n if (faceRanges !== undefined) shape.faceRanges = faceRanges\n return shape\n}\n\n// ── 创建 API ──\n\n/**\n * Create a box solid (brepjs contract, §4.1 A 决策).\n *\n * `box(width, depth, height)` — X=width, Y=depth, Z=height — places the\n * min-corner at the origin by default (`centered:false`). `centered: true`\n * centers the box at the origin; `at` is CENTER semantics and takes precedence\n * over `centered`. The `segments` option is consumed by the tessellation\n * caller (this mesh builder keeps it via clampNRad when present).\n *\n * @param params - box parameters (width/depth/height, optional at/centered/segments).\n * @returns the box shape.\n */\nexport function box(params: BoxParams): Shape {\n const { width, depth, height } = params\n // THREE.BoxGeometry(a, b, c) is Y-up (X=a, Y=b, Z=c); after the +90° rotateX\n // the dims map to X=a, Y=c, Z=b. To reach X=width, Y=depth, Z=height the\n // pre-rotation sizes must be (width, height, depth) — 裁决 7 xyz contract.\n const geo = new THREE.BoxGeometry(width, height, depth)\n geo.applyMatrix4(new THREE.Matrix4().makeRotationX(Math.PI / 2))\n // brepjs box semantics: corner at origin by default; centered at origin when\n // `centered` (no `at`); `at` (CENTER semantics) takes precedence.\n const at = params.at\n let tx = 0\n let ty = 0\n let tz = 0\n if (at !== undefined) {\n ;[tx, ty, tz] = at\n } else if (!params.centered) {\n tx = width / 2\n ty = depth / 2\n tz = height / 2\n }\n if (tx !== 0 || ty !== 0 || tz !== 0) geo.translate(tx, ty, tz)\n // 面结构(P4 面级):BoxGeometry 12 三角形 = 6 面 × 2,顺序固定\n // (+X, −X, +Y, −Y, +Z, −Z);geoToManifoldMesh 焊接顶点保三角形序,故面序契约成立。\n // 面序号契约(setFaceColor 的 faceIds 即此序号):0=+X, 1=−X, 2=+Y, 3=−Y, 4=+Z, 5=−Z。\n const faceRanges: Shape['faceRanges'] = [\n { start: 0, count: 2 },\n { start: 2, count: 2 },\n { start: 4, count: 2 },\n { start: 6, count: 2 },\n { start: 8, count: 2 },\n { start: 10, count: 2 },\n ]\n return geoToShape(geo, faceRanges)\n}\n\n/**\n * Create a sphere centered at the origin (or the optional `center`).\n *\n * @param params - sphere parameters (radius, optional segments, optional center).\n * @returns the sphere shape.\n */\nexport function sphere(params: SphereParams): Shape {\n const segs = clampNRad(params.nRad ?? params.segments)\n const geo = makePrimitiveGeo('sphere', params.radius * 2, segs)\n if (params.center) {\n geo.translate(params.center[0], params.center[1], params.center[2])\n }\n return geoToShape(geo)\n}\n\n/**\n * Create a cylinder along +Z (`cylinder(radius, height, { at?, centered?,\n * segments? })` brepjs 契约,§4.3 A 决策;与 brep 路径逐点对齐)。\n *\n * 锚点:`at` 是**底面轴心**(BASE)语义(默认 [0,0,0],底面在原点、+Z 延伸);\n * `centered:true` 指底面落到 −h/2(无 at 时居中到原点)——与 `at` 同给时以\n * `at` 为中心。`segments` 经 clampNRad 消费(P0 §5)。\n *\n * @param params - cylinder parameters (radius, height, optional at/centered/segments).\n * @returns the cylinder shape.\n */\nexport function cylinder(params: CylinderParams): Shape {\n const segs = clampNRad(params.nRad ?? params.segments)\n const geo = new THREE.CylinderGeometry(params.radius, params.radius, params.height, segs)\n geo.applyMatrix4(new THREE.Matrix4().makeRotationX(Math.PI / 2))\n // geometry(rotateX 后)沿 z ∈ [-h/2, +h/2](three 默认 Y-up 居中):\n // 目标底面中心 in baseZ = (at?.[2] ?? 0) - (centered ? h/2 : 0) → 平移到 baseZ + h/2。\n const baseX = params.at?.[0] ?? 0\n const baseY = params.at?.[1] ?? 0\n const baseZ = (params.at?.[2] ?? 0) - (params.centered === true ? params.height / 2 : 0)\n geo.translate(baseX, baseY, baseZ + params.height / 2)\n // 面结构(P4 面级):CylinderGeometry 三角形布局稳定——侧面 2*segs(tri 0..2segs-1)、\n // 顶盖 segs、底盖 segs。面序号契约:0=侧面, 1=顶, 2=底。\n const faceRanges: Shape['faceRanges'] = [\n { start: 0, count: 2 * segs },\n { start: 2 * segs, count: segs },\n { start: 3 * segs, count: segs },\n ]\n return geoToShape(geo, faceRanges)\n}\n\n/**\n * Create a cone, or a frustum when the top and bottom radii differ\n * (`cone(bottomRadius, topRadius, height, { at?, centered?, segments? })` brepjs\n * 契约,§4.1 P 决策;与 brep 路径逐点对齐)。\n *\n * 锚点:`at` 是**底面轴心**(BASE)语义(默认 [0,0,0],底面在原点、+Z 延伸);\n * `centered:true` 指底面落到 −h/2(无 at 时居中到原点)——与 `at` 同给时以\n * `at` 为中心。`segments` 经 clampNRad 消费(P0 §5)。\n *\n * @param params - cone parameters (radiusBottom, radiusTop, height, optional at/centered/segments).\n * @returns the cone shape.\n */\nexport function cone(params: ConeParams): Shape {\n const segs = clampNRad(params.nRad ?? params.segments)\n const geo = new THREE.ConeGeometry(\n Math.max(params.radiusBottom, params.radiusTop),\n params.height,\n segs,\n )\n geo.applyMatrix4(new THREE.Matrix4().makeRotationX(Math.PI / 2))\n // radiusTop === 0 → 尖锥(ConeGeometry 顶点在顶);其余(含 radiusTop ===\n // radiusBottom 的等径圆柱/圆台)用 CylinderGeometry(radiusTop/bottom 各就各位)。\n let resultGeo: THREE.BufferGeometry\n if (params.radiusTop === 0) {\n resultGeo = geo\n } else {\n const geo2 = new THREE.CylinderGeometry(\n params.radiusTop,\n params.radiusBottom,\n params.height,\n segs,\n )\n geo2.applyMatrix4(new THREE.Matrix4().makeRotationX(Math.PI / 2))\n resultGeo = geo2\n }\n // geometry(rotateX 后)沿 z ∈ [-h/2, +h/2](three 默认 Y-up 居中):\n // 目标底面中心 in baseZ = (at?.[2] ?? 0) - (centered ? h/2 : 0) → 平坦平移 baseZ + h/2。\n const baseX = params.at?.[0] ?? 0\n const baseY = params.at?.[1] ?? 0\n const baseZ = (params.at?.[2] ?? 0) - (params.centered === true ? params.height / 2 : 0)\n resultGeo.translate(baseX, baseY, baseZ + params.height / 2)\n // 面结构(P4 面级):radiusTop=0 的 ConeGeometry 只有 2 面——侧面(segs 个\n // 三角扇)+ 底盖(segs 个);radiusTop>0 的圆台 CylinderGeometry 3 面\n // (侧面 2*segs、顶、底,同 cylinder 布局)。面序号契约:0=侧面, 1=底\n // (尖锥);0=侧面, 1=顶, 2=底(圆台)。\n const faceRanges: Shape['faceRanges'] =\n params.radiusTop === 0\n ? [\n { start: 0, count: segs },\n { start: segs, count: segs },\n ]\n : [\n { start: 0, count: 2 * segs },\n { start: 2 * segs, count: segs },\n { start: 3 * segs, count: segs },\n ]\n return geoToShape(resultGeo, faceRanges)\n}\n\n/**\n * Create a wedge (ramp) solid, fully parameterized and Z-up.\n *\n * @param params - wedge parameters (width, height, angle, length, optional center).\n * @returns the wedge shape.\n */\nexport function wedge(params: WedgeParams): Shape {\n const width = params.width\n const height = params.height\n const angle = params.angle\n const length = params.length\n\n const angleRad = (angle * Math.PI) / 180\n const halfExtrude = length / 2\n const hw = width / 2\n const halfTopWidth = Math.max(0, hw - height / Math.tan(angleRad))\n // 顶边塌缩(斜坡已在宽度内到顶)→ 三角棱柱(与 brep wedge 的退化处理一致,\n // 保证 mesh/brep 同参数 bbox 一致;零面积三角形会破坏 manifold)。\n const degenerate = halfTopWidth <= 1e-12\n\n const positions = degenerate\n ? new Float32Array([\n -halfExtrude, -hw, 0,\n -halfExtrude, hw, 0,\n -halfExtrude, 0, height,\n halfExtrude, -hw, 0,\n halfExtrude, hw, 0,\n halfExtrude, 0, height,\n ])\n : new Float32Array([\n -halfExtrude, -hw, 0,\n -halfExtrude, hw, 0,\n -halfExtrude, halfTopWidth, height,\n -halfExtrude, -halfTopWidth, height,\n halfExtrude, -hw, 0,\n halfExtrude, hw, 0,\n halfExtrude, halfTopWidth, height,\n halfExtrude, -halfTopWidth, height,\n ])\n\n const indices = degenerate\n ? new Uint32Array([\n 0, 1, 2, 3, 5, 4,\n 0, 3, 4, 0, 4, 1,\n 0, 2, 5, 0, 5, 3,\n 1, 4, 5, 1, 5, 2,\n ])\n : new Uint32Array([\n 0, 1, 2, 0, 2, 3,\n 4, 6, 5, 4, 7, 6,\n 0, 4, 5, 0, 5, 1,\n 3, 2, 6, 3, 6, 7,\n 0, 3, 7, 0, 7, 4,\n 1, 5, 6, 1, 6, 2,\n ])\n\n const geo = new THREE.BufferGeometry()\n geo.setAttribute('position', new THREE.BufferAttribute(positions, 3))\n geo.setIndex(new THREE.BufferAttribute(indices, 1))\n\n if (params.center) {\n geo.translate(params.center[0], params.center[1], params.center[2])\n }\n return geoToShape(geo)\n}\n\n/**\n * Create a screw (threaded) geometry.\n *\n * @param params - screw parameters (system, specIdx, thread, length, head, optional pitchCustom and nRad).\n * @returns the screw shape.\n */\nexport async function screw(params: {\n system: 'metric' | 'imperial'\n specIdx: number\n thread: 'coarse' | 'fine' | 'custom' | 'none'\n pitchCustom?: number\n length: number\n head: 'hex' | 'chc' | 'none'\n nRad?: number\n}): Promise<Shape> {\n const { makeScrew } = await import('../primitives/screw/screw')\n const geo = makeScrew({\n system: params.system,\n specIdx: params.specIdx,\n thread: params.thread,\n pitchCustom: params.pitchCustom ?? 0,\n length: params.length,\n head: params.head,\n nRad: clampNRad(params.nRad),\n })\n return geoToShape(geo)\n}\n\n/**\n * Create a mesh from SDF (signed distance field) code, sampling the field with\n * marching cubes.\n *\n * @param params - SDF parameters (code, optional bounds, params, resolution).\n * @returns the sampled shape.\n */\nexport async function sdf(params: SdfParams): Promise<Shape> {\n const { runSdf } = await import('../sdf/sdf-runner')\n const box = params.box ?? [[-10, -10, -10], [10, 10, 10]]\n const bounds: [number, number, number, number, number, number] = [\n box[0][0], box[0][1], box[0][2],\n box[1][0], box[1][1], box[1][2],\n ]\n const mesh = await runSdf(\n params.code,\n params.params ?? {},\n bounds,\n params.resolution ?? 1.0,\n )\n return { positions: mesh.positions, indices: mesh.indices }\n}\n"]}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { type UnitName } from '../units.js';
|
|
2
|
+
import type { ShapeMeta, FileMeta } from '../api/meta.js';
|
|
2
3
|
/** One parsed 3MF object instance: triangle soup in mm base (unit-scaled). */
|
|
3
4
|
export interface ThreemfObject {
|
|
4
5
|
/** The `<object id>` this instance instantiates. */
|
|
@@ -23,6 +24,26 @@ export interface ThreemfObject {
|
|
|
23
24
|
* `positions.length`.
|
|
24
25
|
*/
|
|
25
26
|
vertexColors?: Float32Array;
|
|
27
|
+
/**
|
|
28
|
+
* Per-triangle base-material groups (P4, 3MF Core `<triangle pid p1..p3>`
|
|
29
|
+
* with p1=p2=p3 referencing a `<basematerials>` base): maximal runs of
|
|
30
|
+
* consecutive triangles sharing one base index, each with that base's
|
|
31
|
+
* display color. Triangles with mixed p1/p2/p3 (vertex-attribute
|
|
32
|
+
* interpolation) are skipped. Multi-base objects surface here instead of a
|
|
33
|
+
* single `baseColor`.
|
|
34
|
+
*/
|
|
35
|
+
materialGroups?: Array<{
|
|
36
|
+
start: number;
|
|
37
|
+
count: number;
|
|
38
|
+
color: [number, number, number];
|
|
39
|
+
}>;
|
|
40
|
+
/**
|
|
41
|
+
* 零件级说明性元数据(设计文档 2026-10-05-meta §5.1):`name` 来自
|
|
42
|
+
* `<object name>`;`partNumber` 来自 `<object partnumber>`;`metadata` 来自
|
|
43
|
+
* `<object><metadatagroup><metadata name>…`(键保留命名空间前缀)。组件实例
|
|
44
|
+
* (component 容器)只带对所引用对象的 meta 拷贝。
|
|
45
|
+
*/
|
|
46
|
+
meta?: ShapeMeta;
|
|
26
47
|
}
|
|
27
48
|
/** Structured 3MF parse result. */
|
|
28
49
|
export interface ThreemfArchive {
|
|
@@ -32,6 +53,8 @@ export interface ThreemfArchive {
|
|
|
32
53
|
objects: ThreemfObject[];
|
|
33
54
|
/** Every non-model archive entry (key → raw bytes) for downstream consumers. */
|
|
34
55
|
extraEntries: Map<string, Uint8Array>;
|
|
56
|
+
/** 整体级元数据(设计文档 2026-10-meta 表中的 3MF model context;`<model><metadata>`)。 */
|
|
57
|
+
fileMeta?: FileMeta;
|
|
35
58
|
}
|
|
36
59
|
/**
|
|
37
60
|
* Parse 3MF bytes into a structured archive.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"threemf-loader.d.ts","sourceRoot":"","sources":["../../src/mesh/threemf-loader.ts"],"names":[],"mappings":"AA4BA,OAAO,EAAc,KAAK,QAAQ,EAAE,MAAM,UAAU,CAAA;
|
|
1
|
+
{"version":3,"file":"threemf-loader.d.ts","sourceRoot":"","sources":["../../src/mesh/threemf-loader.ts"],"names":[],"mappings":"AA4BA,OAAO,EAAc,KAAK,QAAQ,EAAE,MAAM,UAAU,CAAA;AACpD,OAAO,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAA;AAyHtD,8EAA8E;AAC9E,MAAM,WAAW,aAAa;IAC5B,oDAAoD;IACpD,EAAE,EAAE,MAAM,CAAA;IACV,uEAAuE;IACvE,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,SAAS,EAAE,YAAY,CAAA;IACvB,OAAO,EAAE,WAAW,CAAA;IACpB;;;;;;OAMG;IACH,SAAS,CAAC,EAAE,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAA;IAC7C;;;;;;OAMG;IACH,YAAY,CAAC,EAAE,YAAY,CAAA;IAC3B;;;;;;;OAOG;IACH,cAAc,CAAC,EAAE,KAAK,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAA;KAAE,CAAC,CAAA;IACzF;;;;;OAKG;IACH,IAAI,CAAC,EAAE,SAAS,CAAA;CACjB;AAED,mCAAmC;AACnC,MAAM,WAAW,cAAc;IAC7B,8DAA8D;IAC9D,IAAI,EAAE,QAAQ,CAAA;IACd,oFAAoF;IACpF,OAAO,EAAE,aAAa,EAAE,CAAA;IACxB,gFAAgF;IAChF,YAAY,EAAE,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,CAAA;IACrC,2EAA2E;IAC3E,QAAQ,CAAC,EAAE,QAAQ,CAAA;CACpB;AAwoBD;;;;;;;;;;;;GAYG;AACH,wBAAsB,YAAY,CAAC,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,cAAc,CAAC,CAgC/E"}
|