@faicad/faijs 0.35.2 → 0.35.8
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/assembly/entities.js +14 -4
- package/dist/api/assembly/entities.js.map +1 -1
- package/dist/api/extrude.d.ts.map +1 -1
- package/dist/api/extrude.js +4 -1
- package/dist/api/extrude.js.map +1 -1
- package/dist/api/fillet.d.ts.map +1 -1
- package/dist/api/fillet.js +47 -0
- package/dist/api/fillet.js.map +1 -1
- package/dist/api/generated/script-face-manifest.js +1 -1
- package/dist/api/generated/script-face-manifest.js.map +1 -1
- package/dist/api/generated/topology.js +1 -1
- package/dist/api/generated/topology.js.map +1 -1
- package/dist/api/primitives.d.ts +3 -2
- package/dist/api/primitives.d.ts.map +1 -1
- package/dist/api/primitives.js +3 -2
- package/dist/api/primitives.js.map +1 -1
- package/dist/api/surface/arg-spec.d.ts.map +1 -1
- package/dist/api/surface/arg-spec.js +5 -6
- package/dist/api/surface/arg-spec.js.map +1 -1
- package/dist/api/topo-resolve.d.ts.map +1 -1
- package/dist/api/topo-resolve.js +24 -5
- package/dist/api/topo-resolve.js.map +1 -1
- package/dist/brepkit-kernel/brepkitKernel.d.ts.map +1 -1
- package/dist/brepkit-kernel/brepkitKernel.js +13 -2
- package/dist/brepkit-kernel/brepkitKernel.js.map +1 -1
- package/dist/brepkit-kernel/brepkitWasm.d.ts +3 -1
- package/dist/brepkit-kernel/brepkitWasm.d.ts.map +1 -1
- package/dist/brepkit-kernel/brepkitWasm.js +6 -2
- package/dist/brepkit-kernel/brepkitWasm.js.map +1 -1
- package/dist/cad-runtime/runtime.d.ts.map +1 -1
- package/dist/cad-runtime/runtime.js +15 -2
- package/dist/cad-runtime/runtime.js.map +1 -1
- package/dist/extra/ops/load.d.ts.map +1 -1
- package/dist/extra/ops/load.js +40 -2
- package/dist/extra/ops/load.js.map +1 -1
- package/dist/mesh/primitives.d.ts +6 -4
- package/dist/mesh/primitives.d.ts.map +1 -1
- package/dist/mesh/primitives.js +15 -8
- package/dist/mesh/primitives.js.map +1 -1
- package/dist/mesh/types.d.ts +4 -3
- package/dist/mesh/types.d.ts.map +1 -1
- package/dist/mesh/types.js.map +1 -1
- package/dist/primitives/brep-primitives.d.ts.map +1 -1
- package/dist/primitives/brep-primitives.js +39 -12
- package/dist/primitives/brep-primitives.js.map +1 -1
- package/dist/topology/naming/geom-hint.d.ts +12 -0
- package/dist/topology/naming/geom-hint.d.ts.map +1 -1
- package/dist/topology/naming/geom-hint.js +1 -1
- package/dist/topology/naming/geom-hint.js.map +1 -1
- package/dist/topology/naming/lineage.d.ts +1 -0
- package/dist/topology/naming/lineage.d.ts.map +1 -1
- package/dist/topology/naming/lineage.js +37 -1
- package/dist/topology/naming/lineage.js.map +1 -1
- package/dist/topology/naming/resolve-face.d.ts +13 -2
- package/dist/topology/naming/resolve-face.d.ts.map +1 -1
- package/dist/topology/naming/resolve-face.js +18 -2
- package/dist/topology/naming/resolve-face.js.map +1 -1
- package/package.json +1 -1
|
@@ -48,23 +48,50 @@ function applyCenter(kernel, solid, center) {
|
|
|
48
48
|
* 用 OCCT 直接构造一个长方体 Solid(原 brepjs `box(width, depth, height,
|
|
49
49
|
* {at?, centered?})` 契约,§4.1 A 决策;与 mesh 路径逐点对齐)。
|
|
50
50
|
*
|
|
51
|
-
*
|
|
52
|
-
*
|
|
53
|
-
*
|
|
51
|
+
* 锚点(2026-10-16 与 cylinder/cone 统一为 BASE 语义):
|
|
52
|
+
* - 默认(无 at、无 centered):角点在原点,底面贴地(z∈[0,h]);
|
|
53
|
+
* - `centered:true`(无 at):居中到原点;
|
|
54
|
+
* - `at`:底面中心落在 at(BASE 语义,与 cylinder/cone 一致);
|
|
55
|
+
* 与 `centered:true` 同给时以 at 为中心。
|
|
56
|
+
* 等价写法:`box(w, d, h)` ≡ `box(w, d, h, { at: [w/2, d/2, 0] })`。
|
|
54
57
|
*/
|
|
55
58
|
function cubeToCadSolid(kernel, params) {
|
|
56
59
|
const w = params.width;
|
|
57
60
|
const d = params.depth;
|
|
58
61
|
const h = params.height;
|
|
59
|
-
//
|
|
60
|
-
//
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
62
|
+
// 底面中心的目标位置(BASE 锚点):
|
|
63
|
+
// - at 给定:at(at + centered 时再下移 h/2,使 at 成为中心);
|
|
64
|
+
// - 仅 centered:原点居中 → 底面中心 (0, 0, -h/2);
|
|
65
|
+
// - 默认:角点在原点 → 底面中心 (w/2, d/2, 0)。
|
|
66
|
+
let baseX;
|
|
67
|
+
let baseY;
|
|
68
|
+
let baseZ;
|
|
69
|
+
if (params.at !== undefined) {
|
|
70
|
+
baseX = params.at[0];
|
|
71
|
+
baseY = params.at[1];
|
|
72
|
+
baseZ = params.at[2] - (params.centered === true ? h / 2 : 0);
|
|
73
|
+
}
|
|
74
|
+
else if (params.centered === true) {
|
|
75
|
+
baseX = 0;
|
|
76
|
+
baseY = 0;
|
|
77
|
+
baseZ = -h / 2;
|
|
78
|
+
}
|
|
79
|
+
else {
|
|
80
|
+
baseX = w / 2;
|
|
81
|
+
baseY = d / 2;
|
|
82
|
+
baseZ = 0;
|
|
83
|
+
}
|
|
84
|
+
// 角点实体 (0,0,0)-(w,d,h),平移到「底面中心落在 (baseX, baseY, baseZ)」。
|
|
85
|
+
const solid = kernel.makeBoxFromCorners({ x: 0, y: 0, z: 0 }, { x: w, y: d, z: h });
|
|
86
|
+
const dx = baseX - w / 2;
|
|
87
|
+
const dy = baseY - d / 2;
|
|
88
|
+
const dz = baseZ;
|
|
89
|
+
if (dx !== 0 || dy !== 0 || dz !== 0) {
|
|
90
|
+
const translated = kernel.translate(solid, dx, dy, dz);
|
|
91
|
+
kernel.release(solid);
|
|
92
|
+
return translated;
|
|
93
|
+
}
|
|
94
|
+
return solid;
|
|
68
95
|
}
|
|
69
96
|
/**
|
|
70
97
|
* 用 OCCT 直接构造一个球体 Solid。
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"brep-primitives.js","sourceRoot":"","sources":["../../src/primitives/brep-primitives.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Primitive → CAD 实体转换。\n *\n * @platform occt — 本文件 import occt-kernel(meshReconstruct):primitive 直接\n * 构造路径绑定 occt 构造函数(makeBox/makeSphere/...),平台原生面调用;\n * 守卫 R1 豁免、R2 无 defineOp 不适用。\n *\n * 将本项目的各种 primitive(cube, sphere, cylinder, cone, wedge, screw)\n * 转换为 OCCT CAD 实体(Solid),并支持导出为 BREP 格式的 STEP 文件。\n *\n * 两条路径:\n *\n * 1. **直接构造路径**(primitive path):\n * 对于有 OCCT 直接对应的基本体(cube, sphere, cylinder, cone, wedge),\n * 直接调用 OCCT 构造函数(makeBox, makeSphere, makeCylinder, makeCone)\n * 或用 extrude 从 2D 轮廓构造(wedge)。\n * 产出精确 BREP——平面是 PLANE,圆柱面是 CYLINDRICAL_SURFACE,等。\n *\n * 2. **Mesh 重建路径**(mesh path):\n * 对于无 OCCT 直接对应的复杂形状(screw, text),从 mesh Shape\n * 提取三角网格,经 meshReconstruct.ts 的多阶段愈合管线重建为 Solid。\n * 产出仍为 BREP,但曲面由多个小三角平面近似(faceted)。在本项目里,默认brep模型不包含此类近似的到的模型。\n *\n * 坐标系:本项目 primitive 为 Z-up(经过 ROT_Y_TO_Z 旋转),\n * OCCT 默认也是 Z-up,因此直接对应,无需额外轴转换。\n */\n\n\nimport type { BrepHandle } from '../brep/engine/types'\nimport type { BrepEngineApi } from '../brep/engine/primitives'\nimport type { PrimitiveType } from './types'\nimport { reconstructSolidFromMesh } from '../occt-kernel/meshReconstruct'\nimport type {\n BoxParams,\n SphereParams,\n CylinderParams,\n ConeParams,\n WedgeParams,\n Shape,\n} from '../mesh/types'\n\n// ─── 辅助:从 Shape 提取网格数据 ───\n\n/**\n * Extract positions + indices from a Shape for the mesh reconstruction path.\n *\n * @param shape - the source Shape.\n * @returns the extracted positions and indices arrays.\n */\nexport function extractMeshData(shape: Shape): {\n positions: Float32Array\n indices: Uint32Array\n} {\n return { positions: new Float32Array(shape.positions), indices: new Uint32Array(shape.indices) }\n}\n\n// ─── 直接构造路径 ───\n\n/** 应用 center 偏移到 OCCT solid(如果有 center 参数)。 */\nfunction applyCenter(kernel: BrepEngineApi, solid: BrepHandle, center?: [number, number, number]): BrepHandle {\n if (!center) return solid\n const translated = kernel.translate(solid, center[0], center[1], center[2])\n kernel.release(solid)\n return translated\n}\n\n/**\n * 用 OCCT 直接构造一个长方体 Solid(原 brepjs `box(width, depth, height,\n * {at?, centered?})` 契约,§4.1 A 决策;与 mesh 路径逐点对齐)。\n *\n * 几何语义与旧 `primitiveFns.box` 完全一致:\n * 默认 min 角点在原点;`centered:true`(无 at 时)居中到原点;`at` 为中心\n * 语义且优先于 `centered`。\n */\nfunction cubeToCadSolid(kernel: BrepEngineApi, params: BoxParams): BrepHandle {\n const w = params.width\n const d = params.depth\n const h = params.height\n // 原 brepjs box: center = at ?? (centered ? [0,0,0] : undefined);未给 center →\n // 构造角点实体不平移(这里统一中心构造 + 平移量,等价)。\n const center = params.at !== undefined\n ? params.at\n : params.centered\n ? ([0, 0, 0] as [number, number, number])\n : ([w / 2, d / 2, h / 2] as [number, number, number])\n const solid = kernel.makeBoxFromCorners(\n { x: -w / 2, y: -d / 2, z: -h / 2 },\n { x: w / 2, y: d / 2, z: h / 2 },\n )\n return applyCenter(kernel, solid, center)\n}\n\n/**\n * 用 OCCT 直接构造一个球体 Solid。\n *\n * 接收完整 SphereParams:radius 是球体半径,segments 不影响 BREP(仅影响 mesh 离散化)。\n */\nfunction sphereToCadSolid(kernel: BrepEngineApi, params: SphereParams): BrepHandle {\n const solid = kernel.makeSphere(params.radius)\n return applyCenter(kernel, solid, params.center)\n}\n\n/**\n * 用 OCCT 直接构造一个圆柱体 Solid(原 brepjs `cylinder(radius, height, {\n * at, centered })` 契约,§4.3 A 决策;与 mesh 路径逐点对齐)。\n *\n * 锚点同旧 `primitiveFns.cylinder`:`at` 是底面轴心(BASE)语义(默认\n * [0,0,0]),OCCT makeCylinder 原生从 z=0 沿 +Z 建高 → 无需重居中;`centered:true`\n * 指底面沿轴下移 −h/2(无 at 时居中到原点;与 `at` 同给时以 `at` 为中心)。\n */\nfunction cylinderToCadSolid(kernel: BrepEngineApi, params: CylinderParams): BrepHandle {\n const solid = kernel.makeCylinder(params.radius, params.height)\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 if (baseX !== 0 || baseY !== 0 || baseZ !== 0) {\n const translated = kernel.translate(solid, baseX, baseY, baseZ)\n kernel.release(solid)\n return translated\n }\n return solid\n}\n\n/**\n * 用 OCCT 直接构造一个圆锥体 Solid(原 brepjs `cone(bottomRadius, topRadius,\n * height, { at, centered })` 契约,§4.1 P 决策;与 mesh 路径逐点对齐)。\n *\n * 锚点同旧 `primitiveFns.cone`:`at` 是底面轴心(BASE)语义(默认\n * [0,0,0]),OCCT makeCone 原生从 z=0 沿 +Z 建高 → 无需重居中;`centered:true`\n * 指底面沿轴下移 −h/2(无 at 时居中到原点;与 `at` 同给时以 `at` 为中心)。\n */\nfunction coneToCadSolid(kernel: BrepEngineApi, params: ConeParams): BrepHandle {\n const solid = kernel.makeCone(params.radiusBottom, params.radiusTop, params.height)\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 if (baseX !== 0 || baseY !== 0 || baseZ !== 0) {\n const translated = kernel.translate(solid, baseX, baseY, baseZ)\n kernel.release(solid)\n return translated\n }\n return solid\n}\n\n/**\n * 用 OCCT 从 2D 梯形轮廓拉伸构造楔形体 Solid。\n *\n * 支持全参数(width/height/angle/length),向后兼容旧式 { size: number }。\n *\n * 参数(来自 WedgePanel.buildWedgeGeometry):\n * - 底边宽度 width(沿 Y)\n * - 高度 height(沿 Z)\n * - 底边与斜边的夹角 angleDeg\n * - 拉伸总长 length(沿 X,从 -length/2 到 +length/2)\n *\n * 构造步骤:\n * 1. 在 YZ 平面创建梯形 wire(4 个顶点,4 条边)\n * 2. 从 wire 创建 planar face\n * 3. 沿 X 轴拉伸\n * 4. 平移使 X 方向居中\n */\nfunction wedgeToCadSolid(kernel: BrepEngineApi, params: WedgeParams): BrepHandle {\n const width = params.width // 底边长度(沿 Y)\n const height = params.height // 梯形高(沿 Z)\n const angleDeg = params.angle // 底边与斜边的夹角\n const length = params.length // 拉伸总长(沿 X)\n const angleRad = (angleDeg * Math.PI) / 180\n const halfExtrude = length / 2\n const hw = width / 2\n\n // 上边半宽 = 底边半宽 - 高 / tan(角度)\n const halfTopWidth = Math.max(0, hw - height / Math.tan(angleRad))\n\n // 在 YZ 平面创建梯形 wire(X=0)。顶边塌缩(halfTopWidth≈0,斜坡已在宽度内到顶)\n // 时退化为三角棱柱——不能再保留零长顶边(两个重合顶点会让 OCCT makeLineEdge\n // 报 CONSTRUCTION_FAILED,即 P23 实测的 wedge 退化参数失败)。\n const edges: BrepHandle[] = []\n if (halfTopWidth > 1e-12) {\n // 梯形:底边 (±hw,0) + 上边 (±halfTopWidth,height)\n edges.push(\n kernel.makeLineEdge({ x: 0, y: -hw, z: 0 }, { x: 0, y: hw, z: 0 }),\n kernel.makeLineEdge({ x: 0, y: hw, z: 0 }, { x: 0, y: halfTopWidth, z: height }),\n kernel.makeLineEdge({ x: 0, y: halfTopWidth, z: height }, { x: 0, y: -halfTopWidth, z: height }),\n kernel.makeLineEdge({ x: 0, y: -halfTopWidth, z: height }, { x: 0, y: -hw, z: 0 }),\n )\n } else {\n // 三角棱柱:(−hw,0) → (hw,0) → (0,height)\n edges.push(\n kernel.makeLineEdge({ x: 0, y: -hw, z: 0 }, { x: 0, y: hw, z: 0 }),\n kernel.makeLineEdge({ x: 0, y: hw, z: 0 }, { x: 0, y: 0, z: height }),\n kernel.makeLineEdge({ x: 0, y: 0, z: height }, { x: 0, y: -hw, z: 0 }),\n )\n }\n\n const wire = kernel.makeWire(edges)\n const face = kernel.makeFace(wire)\n const extruded = kernel.extrude(face, 2 * halfExtrude, 0, 0)\n // 平移使 X 方向居中\n const centered = kernel.translate(extruded, -halfExtrude, 0, 0)\n\n // 释放中间句柄\n for (const e of edges) kernel.release(e)\n kernel.release(wire)\n kernel.release(face)\n kernel.release(extruded)\n\n return applyCenter(kernel, centered, params.center)\n}\n\n// ─── 统一入口 ───\n\n/**\n * Conversion result: the CAD solid handle and the construction path used.\n */\nexport interface PrimitiveToBrepResult {\n /** CAD solid handle (the caller is responsible for releasing it). */\n solid: BrepHandle\n /** The construction path used. */\n path: 'primitive' | 'mesh'\n /** The primitive type. */\n type: PrimitiveType | 'screw' | 'text'\n}\n\n/** Union type of the primitive parameter objects. */\nexport type PrimitiveParams = BoxParams | SphereParams | CylinderParams | ConeParams | WedgeParams\n\n/**\n * 将旧的 size 数字转换为对应类型的完整 params(向后兼容)。\n *\n * - cube: { size: size }\n * - wedge: { width: size, height: size/2, angle: 60, length: 50 }\n * - sphere: { radius: size / 2 }\n * - cylinder: { radius: size / 2, height: size }\n * - cone: { radiusBottom: size / 2, radiusTop: 0, height: size }\n */\nfunction sizeToParams(type: PrimitiveType | 'screw' | 'text', size: number): PrimitiveParams {\n switch (type) {\n case 'cube':\n case 'box':\n return { width: size, depth: size, height: size }\n case 'sphere':\n return { radius: size / 2 }\n case 'cylinder':\n return { radius: size / 2, height: size }\n case 'cone':\n return { radiusBottom: size / 2, radiusTop: 0, height: size }\n case 'wedge':\n return { width: size, height: size / 2, angle: 60, length: 50 }\n default:\n throw new Error(`sizeToParams does not support primitive type \"${type}\" (use geometry data)`)\n }\n}\n\n/**\n * Convert a project primitive to an OCCT CAD solid.\n *\n * - cube, sphere, cylinder, cone, wedge: constructed directly with OCCT (exact BREP)\n * - screw, text: use the mesh reconstruction path (faceted BREP)\n *\n * @param kernel - the initialized OCCT kernel.\n * @param type - the primitive type.\n * @param params - a full parameter object (BoxParams etc.), or a size number (backwards-compatible, default 20mm).\n * @returns the CAD solid plus path information.\n */\nexport function primitiveToBrepSolid(\n kernel: BrepEngineApi,\n type: PrimitiveType | 'screw' | 'text',\n params?: PrimitiveParams | number,\n): PrimitiveToBrepResult {\n const fullParams = typeof params === 'number' || params === undefined\n ? sizeToParams(type, params ?? 20)\n : params\n\n switch (type) {\n case 'cube':\n case 'box':\n return { solid: cubeToCadSolid(kernel, fullParams as BoxParams), path: 'primitive', type }\n\n case 'sphere':\n return { solid: sphereToCadSolid(kernel, fullParams as SphereParams), path: 'primitive', type }\n\n case 'cylinder':\n return { solid: cylinderToCadSolid(kernel, fullParams as CylinderParams), path: 'primitive', type }\n\n case 'cone':\n return { solid: coneToCadSolid(kernel, fullParams as ConeParams), path: 'primitive', type }\n\n case 'wedge':\n return { solid: wedgeToCadSolid(kernel, fullParams as WedgeParams), path: 'primitive', type }\n\n case 'screw':\n case 'text': {\n // Mesh 重建路径:从 THREE.js 几何体提取网格数据\n // 对于 screw/text,调用方应使用 geometryToBrepSolid\n throw new Error(\n `${type} requires geometry data — use geometryToBrepSolid() instead`,\n )\n }\n\n default:\n throw new Error(`Unsupported primitive type: ${type}`)\n }\n}\n\n/**\n * Create a CAD solid from a Shape via the mesh reconstruction path.\n *\n * Suitable for complex shapes that cannot be constructed directly\n * (screw, text, SVG extrusion, etc.).\n *\n * @param kernel - the initialized OCCT kernel.\n * @param shape - the mesh Shape.\n * @returns the CAD solid plus path information.\n */\nexport function geometryToBrepSolid(\n kernel: BrepEngineApi,\n shape: Shape,\n): PrimitiveToBrepResult {\n const { positions, indices } = extractMeshData(shape)\n const solid = reconstructSolidFromMesh(kernel, positions, indices)\n return { solid, path: 'mesh', type: 'screw' }\n}\n\n/**\n * Export a CAD solid as a BREP-format STEP string.\n *\n * OCCT's exportStep produces a standard ISO-10303-21 STEP file using\n * ADVANCED_FACE with exact surfaces (PLANE, CYLINDRICAL_SURFACE, etc.)\n * rather than a faceted representation (POLYGONAL_FACE).\n *\n * @param kernel - the initialized OCCT kernel.\n * @param solid - the CAD solid handle.\n * @returns the STEP file content as a string.\n */\nexport function brepSolidToStep(kernel: BrepEngineApi, solid: BrepHandle): string {\n return kernel.exportStep(solid)\n}\n\n/**\n * Convenience method: convert a primitive directly to a STEP string.\n *\n * Internally calls primitiveToBrepSolid + brepSolidToStep and manages the\n * handle lifecycle automatically.\n *\n * @param kernel - the initialized OCCT kernel.\n * @param type - the primitive type.\n * @param params - a full parameter object, or a size number (backwards-compatible, default 20mm).\n * @returns the STEP file content string plus the path used.\n */\nexport function primitiveToBrepStep(\n kernel: BrepEngineApi,\n type: PrimitiveType,\n params?: PrimitiveParams | number,\n): { step: string; path: 'primitive' | 'mesh' } {\n const result = primitiveToBrepSolid(kernel, type, params)\n try {\n const step = brepSolidToStep(kernel, result.solid)\n return { step, path: result.path }\n } finally {\n kernel.release(result.solid)\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"brep-primitives.js","sourceRoot":"","sources":["../../src/primitives/brep-primitives.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Primitive → CAD 实体转换。\n *\n * @platform occt — 本文件 import occt-kernel(meshReconstruct):primitive 直接\n * 构造路径绑定 occt 构造函数(makeBox/makeSphere/...),平台原生面调用;\n * 守卫 R1 豁免、R2 无 defineOp 不适用。\n *\n * 将本项目的各种 primitive(cube, sphere, cylinder, cone, wedge, screw)\n * 转换为 OCCT CAD 实体(Solid),并支持导出为 BREP 格式的 STEP 文件。\n *\n * 两条路径:\n *\n * 1. **直接构造路径**(primitive path):\n * 对于有 OCCT 直接对应的基本体(cube, sphere, cylinder, cone, wedge),\n * 直接调用 OCCT 构造函数(makeBox, makeSphere, makeCylinder, makeCone)\n * 或用 extrude 从 2D 轮廓构造(wedge)。\n * 产出精确 BREP——平面是 PLANE,圆柱面是 CYLINDRICAL_SURFACE,等。\n *\n * 2. **Mesh 重建路径**(mesh path):\n * 对于无 OCCT 直接对应的复杂形状(screw, text),从 mesh Shape\n * 提取三角网格,经 meshReconstruct.ts 的多阶段愈合管线重建为 Solid。\n * 产出仍为 BREP,但曲面由多个小三角平面近似(faceted)。在本项目里,默认brep模型不包含此类近似的到的模型。\n *\n * 坐标系:本项目 primitive 为 Z-up(经过 ROT_Y_TO_Z 旋转),\n * OCCT 默认也是 Z-up,因此直接对应,无需额外轴转换。\n */\n\n\nimport type { BrepHandle } from '../brep/engine/types'\nimport type { BrepEngineApi } from '../brep/engine/primitives'\nimport type { PrimitiveType } from './types'\nimport { reconstructSolidFromMesh } from '../occt-kernel/meshReconstruct'\nimport type {\n BoxParams,\n SphereParams,\n CylinderParams,\n ConeParams,\n WedgeParams,\n Shape,\n} from '../mesh/types'\n\n// ─── 辅助:从 Shape 提取网格数据 ───\n\n/**\n * Extract positions + indices from a Shape for the mesh reconstruction path.\n *\n * @param shape - the source Shape.\n * @returns the extracted positions and indices arrays.\n */\nexport function extractMeshData(shape: Shape): {\n positions: Float32Array\n indices: Uint32Array\n} {\n return { positions: new Float32Array(shape.positions), indices: new Uint32Array(shape.indices) }\n}\n\n// ─── 直接构造路径 ───\n\n/** 应用 center 偏移到 OCCT solid(如果有 center 参数)。 */\nfunction applyCenter(kernel: BrepEngineApi, solid: BrepHandle, center?: [number, number, number]): BrepHandle {\n if (!center) return solid\n const translated = kernel.translate(solid, center[0], center[1], center[2])\n kernel.release(solid)\n return translated\n}\n\n/**\n * 用 OCCT 直接构造一个长方体 Solid(原 brepjs `box(width, depth, height,\n * {at?, centered?})` 契约,§4.1 A 决策;与 mesh 路径逐点对齐)。\n *\n * 锚点(2026-10-16 与 cylinder/cone 统一为 BASE 语义):\n * - 默认(无 at、无 centered):角点在原点,底面贴地(z∈[0,h]);\n * - `centered:true`(无 at):居中到原点;\n * - `at`:底面中心落在 at(BASE 语义,与 cylinder/cone 一致);\n * 与 `centered:true` 同给时以 at 为中心。\n * 等价写法:`box(w, d, h)` ≡ `box(w, d, h, { at: [w/2, d/2, 0] })`。\n */\nfunction cubeToCadSolid(kernel: BrepEngineApi, params: BoxParams): BrepHandle {\n const w = params.width\n const d = params.depth\n const h = params.height\n // 底面中心的目标位置(BASE 锚点):\n // - at 给定:at(at + centered 时再下移 h/2,使 at 成为中心);\n // - 仅 centered:原点居中 → 底面中心 (0, 0, -h/2);\n // - 默认:角点在原点 → 底面中心 (w/2, d/2, 0)。\n let baseX: number\n let baseY: number\n let baseZ: number\n if (params.at !== undefined) {\n baseX = params.at[0]\n baseY = params.at[1]\n baseZ = params.at[2] - (params.centered === true ? h / 2 : 0)\n } else if (params.centered === true) {\n baseX = 0\n baseY = 0\n baseZ = -h / 2\n } else {\n baseX = w / 2\n baseY = d / 2\n baseZ = 0\n }\n // 角点实体 (0,0,0)-(w,d,h),平移到「底面中心落在 (baseX, baseY, baseZ)」。\n const solid = kernel.makeBoxFromCorners(\n { x: 0, y: 0, z: 0 },\n { x: w, y: d, z: h },\n )\n const dx = baseX - w / 2\n const dy = baseY - d / 2\n const dz = baseZ\n if (dx !== 0 || dy !== 0 || dz !== 0) {\n const translated = kernel.translate(solid, dx, dy, dz)\n kernel.release(solid)\n return translated\n }\n return solid\n}\n\n/**\n * 用 OCCT 直接构造一个球体 Solid。\n *\n * 接收完整 SphereParams:radius 是球体半径,segments 不影响 BREP(仅影响 mesh 离散化)。\n */\nfunction sphereToCadSolid(kernel: BrepEngineApi, params: SphereParams): BrepHandle {\n const solid = kernel.makeSphere(params.radius)\n return applyCenter(kernel, solid, params.center)\n}\n\n/**\n * 用 OCCT 直接构造一个圆柱体 Solid(原 brepjs `cylinder(radius, height, {\n * at, centered })` 契约,§4.3 A 决策;与 mesh 路径逐点对齐)。\n *\n * 锚点同旧 `primitiveFns.cylinder`:`at` 是底面轴心(BASE)语义(默认\n * [0,0,0]),OCCT makeCylinder 原生从 z=0 沿 +Z 建高 → 无需重居中;`centered:true`\n * 指底面沿轴下移 −h/2(无 at 时居中到原点;与 `at` 同给时以 `at` 为中心)。\n */\nfunction cylinderToCadSolid(kernel: BrepEngineApi, params: CylinderParams): BrepHandle {\n const solid = kernel.makeCylinder(params.radius, params.height)\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 if (baseX !== 0 || baseY !== 0 || baseZ !== 0) {\n const translated = kernel.translate(solid, baseX, baseY, baseZ)\n kernel.release(solid)\n return translated\n }\n return solid\n}\n\n/**\n * 用 OCCT 直接构造一个圆锥体 Solid(原 brepjs `cone(bottomRadius, topRadius,\n * height, { at, centered })` 契约,§4.1 P 决策;与 mesh 路径逐点对齐)。\n *\n * 锚点同旧 `primitiveFns.cone`:`at` 是底面轴心(BASE)语义(默认\n * [0,0,0]),OCCT makeCone 原生从 z=0 沿 +Z 建高 → 无需重居中;`centered:true`\n * 指底面沿轴下移 −h/2(无 at 时居中到原点;与 `at` 同给时以 `at` 为中心)。\n */\nfunction coneToCadSolid(kernel: BrepEngineApi, params: ConeParams): BrepHandle {\n const solid = kernel.makeCone(params.radiusBottom, params.radiusTop, params.height)\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 if (baseX !== 0 || baseY !== 0 || baseZ !== 0) {\n const translated = kernel.translate(solid, baseX, baseY, baseZ)\n kernel.release(solid)\n return translated\n }\n return solid\n}\n\n/**\n * 用 OCCT 从 2D 梯形轮廓拉伸构造楔形体 Solid。\n *\n * 支持全参数(width/height/angle/length),向后兼容旧式 { size: number }。\n *\n * 参数(来自 WedgePanel.buildWedgeGeometry):\n * - 底边宽度 width(沿 Y)\n * - 高度 height(沿 Z)\n * - 底边与斜边的夹角 angleDeg\n * - 拉伸总长 length(沿 X,从 -length/2 到 +length/2)\n *\n * 构造步骤:\n * 1. 在 YZ 平面创建梯形 wire(4 个顶点,4 条边)\n * 2. 从 wire 创建 planar face\n * 3. 沿 X 轴拉伸\n * 4. 平移使 X 方向居中\n */\nfunction wedgeToCadSolid(kernel: BrepEngineApi, params: WedgeParams): BrepHandle {\n const width = params.width // 底边长度(沿 Y)\n const height = params.height // 梯形高(沿 Z)\n const angleDeg = params.angle // 底边与斜边的夹角\n const length = params.length // 拉伸总长(沿 X)\n const angleRad = (angleDeg * Math.PI) / 180\n const halfExtrude = length / 2\n const hw = width / 2\n\n // 上边半宽 = 底边半宽 - 高 / tan(角度)\n const halfTopWidth = Math.max(0, hw - height / Math.tan(angleRad))\n\n // 在 YZ 平面创建梯形 wire(X=0)。顶边塌缩(halfTopWidth≈0,斜坡已在宽度内到顶)\n // 时退化为三角棱柱——不能再保留零长顶边(两个重合顶点会让 OCCT makeLineEdge\n // 报 CONSTRUCTION_FAILED,即 P23 实测的 wedge 退化参数失败)。\n const edges: BrepHandle[] = []\n if (halfTopWidth > 1e-12) {\n // 梯形:底边 (±hw,0) + 上边 (±halfTopWidth,height)\n edges.push(\n kernel.makeLineEdge({ x: 0, y: -hw, z: 0 }, { x: 0, y: hw, z: 0 }),\n kernel.makeLineEdge({ x: 0, y: hw, z: 0 }, { x: 0, y: halfTopWidth, z: height }),\n kernel.makeLineEdge({ x: 0, y: halfTopWidth, z: height }, { x: 0, y: -halfTopWidth, z: height }),\n kernel.makeLineEdge({ x: 0, y: -halfTopWidth, z: height }, { x: 0, y: -hw, z: 0 }),\n )\n } else {\n // 三角棱柱:(−hw,0) → (hw,0) → (0,height)\n edges.push(\n kernel.makeLineEdge({ x: 0, y: -hw, z: 0 }, { x: 0, y: hw, z: 0 }),\n kernel.makeLineEdge({ x: 0, y: hw, z: 0 }, { x: 0, y: 0, z: height }),\n kernel.makeLineEdge({ x: 0, y: 0, z: height }, { x: 0, y: -hw, z: 0 }),\n )\n }\n\n const wire = kernel.makeWire(edges)\n const face = kernel.makeFace(wire)\n const extruded = kernel.extrude(face, 2 * halfExtrude, 0, 0)\n // 平移使 X 方向居中\n const centered = kernel.translate(extruded, -halfExtrude, 0, 0)\n\n // 释放中间句柄\n for (const e of edges) kernel.release(e)\n kernel.release(wire)\n kernel.release(face)\n kernel.release(extruded)\n\n return applyCenter(kernel, centered, params.center)\n}\n\n// ─── 统一入口 ───\n\n/**\n * Conversion result: the CAD solid handle and the construction path used.\n */\nexport interface PrimitiveToBrepResult {\n /** CAD solid handle (the caller is responsible for releasing it). */\n solid: BrepHandle\n /** The construction path used. */\n path: 'primitive' | 'mesh'\n /** The primitive type. */\n type: PrimitiveType | 'screw' | 'text'\n}\n\n/** Union type of the primitive parameter objects. */\nexport type PrimitiveParams = BoxParams | SphereParams | CylinderParams | ConeParams | WedgeParams\n\n/**\n * 将旧的 size 数字转换为对应类型的完整 params(向后兼容)。\n *\n * - cube: { size: size }\n * - wedge: { width: size, height: size/2, angle: 60, length: 50 }\n * - sphere: { radius: size / 2 }\n * - cylinder: { radius: size / 2, height: size }\n * - cone: { radiusBottom: size / 2, radiusTop: 0, height: size }\n */\nfunction sizeToParams(type: PrimitiveType | 'screw' | 'text', size: number): PrimitiveParams {\n switch (type) {\n case 'cube':\n case 'box':\n return { width: size, depth: size, height: size }\n case 'sphere':\n return { radius: size / 2 }\n case 'cylinder':\n return { radius: size / 2, height: size }\n case 'cone':\n return { radiusBottom: size / 2, radiusTop: 0, height: size }\n case 'wedge':\n return { width: size, height: size / 2, angle: 60, length: 50 }\n default:\n throw new Error(`sizeToParams does not support primitive type \"${type}\" (use geometry data)`)\n }\n}\n\n/**\n * Convert a project primitive to an OCCT CAD solid.\n *\n * - cube, sphere, cylinder, cone, wedge: constructed directly with OCCT (exact BREP)\n * - screw, text: use the mesh reconstruction path (faceted BREP)\n *\n * @param kernel - the initialized OCCT kernel.\n * @param type - the primitive type.\n * @param params - a full parameter object (BoxParams etc.), or a size number (backwards-compatible, default 20mm).\n * @returns the CAD solid plus path information.\n */\nexport function primitiveToBrepSolid(\n kernel: BrepEngineApi,\n type: PrimitiveType | 'screw' | 'text',\n params?: PrimitiveParams | number,\n): PrimitiveToBrepResult {\n const fullParams = typeof params === 'number' || params === undefined\n ? sizeToParams(type, params ?? 20)\n : params\n\n switch (type) {\n case 'cube':\n case 'box':\n return { solid: cubeToCadSolid(kernel, fullParams as BoxParams), path: 'primitive', type }\n\n case 'sphere':\n return { solid: sphereToCadSolid(kernel, fullParams as SphereParams), path: 'primitive', type }\n\n case 'cylinder':\n return { solid: cylinderToCadSolid(kernel, fullParams as CylinderParams), path: 'primitive', type }\n\n case 'cone':\n return { solid: coneToCadSolid(kernel, fullParams as ConeParams), path: 'primitive', type }\n\n case 'wedge':\n return { solid: wedgeToCadSolid(kernel, fullParams as WedgeParams), path: 'primitive', type }\n\n case 'screw':\n case 'text': {\n // Mesh 重建路径:从 THREE.js 几何体提取网格数据\n // 对于 screw/text,调用方应使用 geometryToBrepSolid\n throw new Error(\n `${type} requires geometry data — use geometryToBrepSolid() instead`,\n )\n }\n\n default:\n throw new Error(`Unsupported primitive type: ${type}`)\n }\n}\n\n/**\n * Create a CAD solid from a Shape via the mesh reconstruction path.\n *\n * Suitable for complex shapes that cannot be constructed directly\n * (screw, text, SVG extrusion, etc.).\n *\n * @param kernel - the initialized OCCT kernel.\n * @param shape - the mesh Shape.\n * @returns the CAD solid plus path information.\n */\nexport function geometryToBrepSolid(\n kernel: BrepEngineApi,\n shape: Shape,\n): PrimitiveToBrepResult {\n const { positions, indices } = extractMeshData(shape)\n const solid = reconstructSolidFromMesh(kernel, positions, indices)\n return { solid, path: 'mesh', type: 'screw' }\n}\n\n/**\n * Export a CAD solid as a BREP-format STEP string.\n *\n * OCCT's exportStep produces a standard ISO-10303-21 STEP file using\n * ADVANCED_FACE with exact surfaces (PLANE, CYLINDRICAL_SURFACE, etc.)\n * rather than a faceted representation (POLYGONAL_FACE).\n *\n * @param kernel - the initialized OCCT kernel.\n * @param solid - the CAD solid handle.\n * @returns the STEP file content as a string.\n */\nexport function brepSolidToStep(kernel: BrepEngineApi, solid: BrepHandle): string {\n return kernel.exportStep(solid)\n}\n\n/**\n * Convenience method: convert a primitive directly to a STEP string.\n *\n * Internally calls primitiveToBrepSolid + brepSolidToStep and manages the\n * handle lifecycle automatically.\n *\n * @param kernel - the initialized OCCT kernel.\n * @param type - the primitive type.\n * @param params - a full parameter object, or a size number (backwards-compatible, default 20mm).\n * @returns the STEP file content string plus the path used.\n */\nexport function primitiveToBrepStep(\n kernel: BrepEngineApi,\n type: PrimitiveType,\n params?: PrimitiveParams | number,\n): { step: string; path: 'primitive' | 'mesh' } {\n const result = primitiveToBrepSolid(kernel, type, params)\n try {\n const step = brepSolidToStep(kernel, result.solid)\n return { step, path: result.path }\n } finally {\n kernel.release(result.solid)\n }\n}\n"]}
|
|
@@ -11,6 +11,18 @@
|
|
|
11
11
|
import type { BrepEngineApi } from '../../brep/engine/primitives.js';
|
|
12
12
|
import type { BrepHandle } from '../../brep/engine/types.js';
|
|
13
13
|
import type { FaceHint, EdgeHint, AxisHint } from './types.js';
|
|
14
|
+
/**
|
|
15
|
+
* BREP 现场圆柱面 → 轴 hint(P0 装配前置)。
|
|
16
|
+
*
|
|
17
|
+
* 算法与 occt-kernel/topologyExt.ts getSurfaceParams 的 cylinder 分支同源:
|
|
18
|
+
* direction = normalize(S(u,v+1) − S(u,v))(V 向即轴向);origin = P − R·外法向
|
|
19
|
+
*(surfaceNormal 含朝向,reversed 面先取反修正)。
|
|
20
|
+
*
|
|
21
|
+
* @param kernel - the OCCT kernel.
|
|
22
|
+
* @param face - the cylindrical face handle.
|
|
23
|
+
* @returns the axis hint, or undefined when the axis cannot be derived.
|
|
24
|
+
*/
|
|
25
|
+
export declare function captureCylinderFaceAxis(kernel: BrepEngineApi, face: BrepHandle): AxisHint | undefined;
|
|
14
26
|
/**
|
|
15
27
|
* BREP 现场面 → FaceHint。
|
|
16
28
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"geom-hint.d.ts","sourceRoot":"","sources":["../../../src/topology/naming/geom-hint.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAA;AACjE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAA;AACzD,OAAO,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAA;
|
|
1
|
+
{"version":3,"file":"geom-hint.d.ts","sourceRoot":"","sources":["../../../src/topology/naming/geom-hint.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAA;AACjE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAA;AACzD,OAAO,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAA;AAS3D;;;;;;;;;;GAUG;AACH,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,aAAa,EAAE,IAAI,EAAE,UAAU,GAAG,QAAQ,GAAG,SAAS,CAqBrG;AAgDD;;;;;;;;;GASG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,aAAa,EAAE,IAAI,EAAE,UAAU,GAAG,QAAQ,CAgBjF;AAED;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE;IACjC,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,MAAM,CAAC,EAAE,SAAS,MAAM,EAAE,GAAG,IAAI,CAAA;IACjC,MAAM,CAAC,EAAE,SAAS,MAAM,EAAE,GAAG,IAAI,CAAA;IACjC,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,IAAI,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,SAAS,MAAM,EAAE,GAAG,IAAI,CAAC;QAAC,SAAS,CAAC,EAAE,SAAS,MAAM,EAAE,GAAG,IAAI,CAAA;KAAE,GAAG,IAAI,CAAA;CAC1F,GAAG,QAAQ,CAiBX;AAED;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE;IACjC,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,MAAM,CAAC,EAAE,SAAS,MAAM,EAAE,GAAG,IAAI,CAAA;IACjC,IAAI,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,SAAS,MAAM,EAAE,GAAG,IAAI,CAAC;QAAC,SAAS,CAAC,EAAE,SAAS,MAAM,EAAE,GAAG,IAAI,CAAA;KAAE,GAAG,IAAI,CAAA;CAC1F,GAAG,QAAQ,CAeX;AAED;;;;;;;;;;GAUG;AACH;;;;;;;;;;GAUG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,aAAa,EAAE,IAAI,EAAE,UAAU,GAAG,QAAQ,GAAG,SAAS,CAkB7F;AAED;;;;;;;;;GASG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,aAAa,EAAE,IAAI,EAAE,UAAU,GAAG,QAAQ,CAmBjF"}
|
|
@@ -26,7 +26,7 @@ function normalizedAxis(v) {
|
|
|
26
26
|
* @param face - the cylindrical face handle.
|
|
27
27
|
* @returns the axis hint, or undefined when the axis cannot be derived.
|
|
28
28
|
*/
|
|
29
|
-
function captureCylinderFaceAxis(kernel, face) {
|
|
29
|
+
export function captureCylinderFaceAxis(kernel, face) {
|
|
30
30
|
try {
|
|
31
31
|
const uv = kernel.uvBounds(face);
|
|
32
32
|
const p0 = kernel.pointOnSurface(face, uv.uMin, uv.vMin);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"geom-hint.js","sourceRoot":"","sources":["../../../src/topology/naming/geom-hint.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAMH,4CAA4C;AAC5C,SAAS,cAAc,CAAC,CAA2B;IACjD,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;IACxC,IAAI,GAAG,GAAG,KAAK,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC;QAAE,OAAO,IAAI,CAAA;IACrD,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,CAAA;AAC7C,CAAC;AAED;;;;;;;;;;GAUG;AACH,SAAS,uBAAuB,CAAC,MAAqB,EAAE,IAAgB;IACtE,IAAI,CAAC;QACH,MAAM,EAAE,GAAG,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAA;QAChC,MAAM,EAAE,GAAG,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,CAAA;QACxD,MAAM,EAAE,GAAG,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,GAAG,CAAC,CAAC,CAAA;QAC5D,MAAM,SAAS,GAAG,cAAc,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,CAAA;QACzE,MAAM,GAAG,GAAG,MAAM,CAAC,mBAAmB,CAAC,IAAI,CAAC,CAAA;QAC5C,IAAI,CAAC,SAAS,IAAI,CAAC,GAAG;YAAE,OAAO,SAAS,CAAA;QACxC,IAAI,EAAE,GAAG,MAAM,CAAC,aAAa,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,CAAA;QACrD,IAAI,MAAM,CAAC,gBAAgB,CAAC,IAAI,CAAC,KAAK,UAAU,EAAE,CAAC;YACjD,EAAE,GAAG,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAA;QACvC,CAAC;QACD,MAAM,MAAM,GAA6B;YACvC,EAAE,CAAC,CAAC,GAAG,GAAG,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC;YACxB,EAAE,CAAC,CAAC,GAAG,GAAG,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC;YACxB,EAAE,CAAC,CAAC,GAAG,GAAG,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC;SACzB,CAAA;QACD,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,CAAA;IAC9B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAA;IAClB,CAAC;AACH,CAAC;AAED;;;;;;;;;;GAUG;AACH,SAAS,qBAAqB,CAAC,MAAqB,EAAE,IAAgB;IACpE,IAAI,CAAC;QACH,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,MAAM,CAAC,eAAe,CAAC,IAAI,CAAC,CAAA;QACpD,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC;YAAE,OAAO,SAAS,CAAA;QACvE,MAAM,CAAC,GAAG,CAAC,IAAI,GAAG,KAAK,CAAC,GAAG,CAAC,CAAA;QAC5B,MAAM,EAAE,GAAG,MAAM,CAAC,iBAAiB,CAAC,IAAI,EAAE,KAAK,CAAC,CAAA;QAChD,MAAM,EAAE,GAAG,MAAM,CAAC,iBAAiB,CAAC,IAAI,EAAE,KAAK,GAAG,CAAC,CAAC,CAAA;QACpD,MAAM,EAAE,GAAG,MAAM,CAAC,iBAAiB,CAAC,IAAI,EAAE,KAAK,GAAG,CAAC,GAAG,CAAC,CAAC,CAAA;QACxD,MAAM,EAAE,GAA6B,CAAC,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAA;QAC5E,MAAM,EAAE,GAA6B,CAAC,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAA;QAC5E,uDAAuD;QACvD,MAAM,GAAG,GAAG,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAA;QACzD,MAAM,GAAG,GAAG,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAA;QACzD,MAAM,GAAG,GAAG,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAA;QACzD,MAAM,KAAK,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,CAAA;QACnC,IAAI,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,KAAK;YAAE,OAAO,SAAS,CAAA;QAC7C,MAAM,KAAK,GAAG,CAAC,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,CAAC,GAAG,CAAC,CAAC,GAAG,KAAK,CAAC,CAAA;QACnD,MAAM,IAAI,GAAG,CAAC,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,CAAC,GAAG,CAAC,CAAC,GAAG,KAAK,CAAC,CAAA;QAClD,MAAM,MAAM,GAA6B;YACvC,EAAE,CAAC,CAAC,GAAG,KAAK,GAAG,EAAE,CAAC,CAAC,CAAC,GAAG,IAAI,GAAG,EAAE,CAAC,CAAC,CAAC;YACnC,EAAE,CAAC,CAAC,GAAG,KAAK,GAAG,EAAE,CAAC,CAAC,CAAC,GAAG,IAAI,GAAG,EAAE,CAAC,CAAC,CAAC;YACnC,EAAE,CAAC,CAAC,GAAG,KAAK,GAAG,EAAE,CAAC,CAAC,CAAC,GAAG,IAAI,GAAG,EAAE,CAAC,CAAC,CAAC;SACpC,CAAA;QACD,MAAM,SAAS,GAAG,cAAc,CAAC;YAC/B,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;YAC7B,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;YAC7B,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;SAC9B,CAAC,CAAA;QACF,IAAI,CAAC,SAAS;YAAE,OAAO,SAAS,CAAA;QAChC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,CAAA;IAC9B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAA;IAClB,CAAC;AACH,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,eAAe,CAAC,MAAqB,EAAE,IAAgB;IACrE,MAAM,WAAW,GAAG,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC,CAAA;IAC5C,MAAM,EAAE,GAAG,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAA;IAChC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,GAAG,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;IACjC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,GAAG,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;IACjC,MAAM,MAAM,GAAG,MAAM,CAAC,aAAa,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC,CAAA;IAC/C,MAAM,MAAM,GAAG,MAAM,CAAC,mBAAmB,CAAC,IAAI,CAAC,CAAA;IAC/C,qDAAqD;IACrD,MAAM,IAAI,GAAG,WAAW,KAAK,UAAU,CAAC,CAAC,CAAC,uBAAuB,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,CAAA;IAC3F,OAAO;QACL,IAAI,EAAE,MAAM;QACZ,WAAW;QACX,MAAM,EAAE,CAAC,MAAM,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC;QACtC,MAAM,EAAE,CAAC,MAAM,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC;QACtC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAC1B,CAAA;AACH,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,aAAa,CAAC,GAM7B;IACC,MAAM,IAAI,GAAa;QACrB,IAAI,EAAE,MAAM;QACZ,GAAG,CAAC,GAAG,CAAC,WAAW,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,GAAG,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC1E,GAAG,CAAC,GAAG,CAAC,MAAM,IAAI,GAAG,CAAC,MAAM,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAA6B,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACvI,GAAG,CAAC,GAAG,CAAC,MAAM,IAAI,GAAG,CAAC,MAAM,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAA6B,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACvI,GAAG,CAAC,GAAG,CAAC,IAAI,KAAK,SAAS,IAAI,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAClF,GAAG,CAAC,GAAG,CAAC,IAAI,EAAE,MAAM,IAAI,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,KAAK,CAAC,IAAI,GAAG,CAAC,IAAI,CAAC,SAAS,IAAI,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,KAAK,CAAC;YAC3G,CAAC,CAAC;gBACE,IAAI,EAAE;oBACJ,MAAM,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAA6B;oBAChG,SAAS,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAA6B;iBAC7G;aACF;YACH,CAAC,CAAC,EAAE,CAAC;KACR,CAAA;IACD,OAAO,IAAI,CAAA;AACb,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,aAAa,CAAC,GAI7B;IACC,MAAM,IAAI,GAAa;QACrB,IAAI,EAAE,MAAM;QACZ,GAAG,CAAC,GAAG,CAAC,MAAM,KAAK,SAAS,IAAI,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC1F,GAAG,CAAC,GAAG,CAAC,MAAM,IAAI,GAAG,CAAC,MAAM,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAA6B,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACzI,GAAG,CAAC,GAAG,CAAC,IAAI,EAAE,MAAM,IAAI,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,KAAK,CAAC,IAAI,GAAG,CAAC,IAAI,CAAC,SAAS,IAAI,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,KAAK,CAAC;YAC3G,CAAC,CAAC;gBACE,IAAI,EAAE;oBACJ,MAAM,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAA6B;oBAChG,SAAS,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAA6B;iBAC7G;aACF;YACH,CAAC,CAAC,EAAE,CAAC;KACR,CAAA;IACD,OAAO,IAAI,CAAA;AACb,CAAC;AAED;;;;;;;;;;GAUG;AACH;;;;;;;;;;GAUG;AACH,MAAM,UAAU,eAAe,CAAC,MAAqB,EAAE,IAAgB;IACrE,IAAI,CAAC;QACH,MAAM,SAAS,GAAG,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,CAAA;QACxC,IAAI,SAAS,KAAK,MAAM,EAAE,CAAC;YACzB,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM,CAAC,eAAe,CAAC,IAAI,CAAC,CAAA;YAC9C,MAAM,MAAM,GAAG,MAAM,CAAC,iBAAiB,CAAC,IAAI,EAAE,KAAK,CAAC,CAAA;YACpD,MAAM,OAAO,GAAG,MAAM,CAAC,YAAY,CAAC,IAAI,EAAE,KAAK,CAAC,CAAA;YAChD,MAAM,SAAS,GAAG,cAAc,CAAC,CAAC,OAAO,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,CAAA;YACnE,IAAI,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,SAAS,EAAE,CAAC;gBACrG,OAAO,EAAE,MAAM,EAAE,CAAC,MAAM,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,CAAA;YAC9D,CAAC;QACH,CAAC;aAAM,IAAI,SAAS,KAAK,QAAQ,EAAE,CAAC;YAClC,OAAO,qBAAqB,CAAC,MAAM,EAAE,IAAI,CAAC,CAAA;QAC5C,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,yCAAyC;IAC3C,CAAC;IACD,OAAO,SAAS,CAAA;AAClB,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,eAAe,CAAC,MAAqB,EAAE,IAAgB;IACrE,MAAM,MAAM,GAAG,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC,CAAA;IACvC,MAAM,IAAI,GAA4F,EAAE,IAAI,EAAE,MAAM,EAAE,CAAA;IACtH,IAAI,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,MAAM,GAAG,CAAC;QAAE,IAAI,CAAC,MAAM,GAAG,MAAM,CAAA;IAC/D,IAAI,CAAC;QACH,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,MAAM,CAAC,eAAe,CAAC,IAAI,CAAC,CAAA;QACpD,IAAI,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;YACpD,MAAM,GAAG,GAAG,MAAM,CAAC,iBAAiB,CAAC,IAAI,EAAE,CAAC,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAA;YAC9D,IAAI,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;gBAC/E,IAAI,CAAC,QAAQ,GAAG,CAAC,GAAG,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,CAAA;YACvC,CAAC;QACH,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,oCAAoC;IACtC,CAAC;IACD,uCAAuC;IACvC,MAAM,IAAI,GAAG,eAAe,CAAC,MAAM,EAAE,IAAI,CAAC,CAAA;IAC1C,IAAI,IAAI;QAAE,IAAI,CAAC,IAAI,GAAG,IAAI,CAAA;IAC1B,OAAO,IAAI,CAAA;AACb,CAAC","sourcesContent":["/**\n * geom-hint.ts — 几何 hint 捕获(§3.1)\n *\n * 两路:\n * - `captureFaceHint(kernel, faceHandle)`:BREP 现场面 → FaceHint(assignRoles 用)。\n * - `faceRowToHint(row)`:面行/FaceRow → FaceHint(primitive/mesh 命名槽快照用)。\n *\n * hint 字段与 SelectorRuntime 的 FaceRow(surfaceType/area/center/normal)同源\n * (§2.2),保证 BREP 现场与面行快照两条打分路径口径一致。\n */\n\nimport type { BrepEngineApi } from '../../brep/engine/primitives'\nimport type { BrepHandle } from '../../brep/engine/types'\nimport type { FaceHint, EdgeHint, AxisHint } from './types'\n\n/** 归一化向量(axis 采集内部用;零向量返回 null,调用方放弃采集)。 */\nfunction normalizedAxis(v: [number, number, number]): [number, number, number] | null {\n const len = Math.hypot(v[0], v[1], v[2])\n if (len < 1e-12 || !Number.isFinite(len)) return null\n return [v[0] / len, v[1] / len, v[2] / len]\n}\n\n/**\n * BREP 现场圆柱面 → 轴 hint(P0 装配前置)。\n *\n * 算法与 occt-kernel/topologyExt.ts getSurfaceParams 的 cylinder 分支同源:\n * direction = normalize(S(u,v+1) − S(u,v))(V 向即轴向);origin = P − R·外法向\n *(surfaceNormal 含朝向,reversed 面先取反修正)。\n *\n * @param kernel - the OCCT kernel.\n * @param face - the cylindrical face handle.\n * @returns the axis hint, or undefined when the axis cannot be derived.\n */\nfunction captureCylinderFaceAxis(kernel: BrepEngineApi, face: BrepHandle): AxisHint | undefined {\n try {\n const uv = kernel.uvBounds(face)\n const p0 = kernel.pointOnSurface(face, uv.uMin, uv.vMin)\n const p1 = kernel.pointOnSurface(face, uv.uMin, uv.vMin + 1)\n const direction = normalizedAxis([p1.x - p0.x, p1.y - p0.y, p1.z - p0.z])\n const cyl = kernel.getFaceCylinderData(face)\n if (!direction || !cyl) return undefined\n let sn = kernel.surfaceNormal(face, uv.uMin, uv.vMin)\n if (kernel.shapeOrientation(face) === 'reversed') {\n sn = { x: -sn.x, y: -sn.y, z: -sn.z }\n }\n const origin: [number, number, number] = [\n p0.x - cyl.radius * sn.x,\n p0.y - cyl.radius * sn.y,\n p0.z - cyl.radius * sn.z,\n ]\n return { origin, direction }\n } catch {\n return undefined\n }\n}\n\n/**\n * BREP 现场圆边 → 轴 hint(origin = 圆心,direction = 所在平面法向;P0 装配前置)。\n *\n * 用曲线上三个不同参数的采样点做外接圆圆心(三点定圆,精确、无弧长近似),\n * 法向取 (p1−p0)×(p2−p0) 归一化。只用 curvePointAtParam/curveParameters 等既有\n * 公开内核 API(与 getCurveParams 的 circle 分支同一能力面),不新增内核方法。\n *\n * @param kernel - the OCCT kernel.\n * @param edge - the circular edge handle.\n * @returns the axis hint, or undefined when sampling fails.\n */\nfunction captureCircleEdgeAxis(kernel: BrepEngineApi, edge: BrepHandle): AxisHint | undefined {\n try {\n const { first, last } = kernel.curveParameters(edge)\n if (!Number.isFinite(first) || !Number.isFinite(last)) return undefined\n const d = (last - first) / 3\n const pa = kernel.curvePointAtParam(edge, first)\n const pb = kernel.curvePointAtParam(edge, first + d)\n const pc = kernel.curvePointAtParam(edge, first + 2 * d)\n const e1: [number, number, number] = [pb.x - pa.x, pb.y - pa.y, pb.z - pa.z]\n const e2: [number, number, number] = [pc.x - pa.x, pc.y - pa.y, pc.z - pa.z]\n // 三点外接圆:解 o = a + α·e1 + β·e2,满足 |o−a| = |o−b| = |o−c|\n const e11 = e1[0] * e1[0] + e1[1] * e1[1] + e1[2] * e1[2]\n const e22 = e2[0] * e2[0] + e2[1] * e2[1] + e2[2] * e2[2]\n const e12 = e1[0] * e2[0] + e1[1] * e2[1] + e1[2] * e2[2]\n const denom = e11 * e22 - e12 * e12\n if (Math.abs(denom) < 1e-18) return undefined\n const alpha = (e11 * e22 - e22 * e12) / (2 * denom)\n const beta = (e22 * e11 - e11 * e12) / (2 * denom)\n const origin: [number, number, number] = [\n pa.x + alpha * e1[0] + beta * e2[0],\n pa.y + alpha * e1[1] + beta * e2[1],\n pa.z + alpha * e1[2] + beta * e2[2],\n ]\n const direction = normalizedAxis([\n e1[1] * e2[2] - e1[2] * e2[1],\n e1[2] * e2[0] - e1[0] * e2[2],\n e1[0] * e2[1] - e1[1] * e2[0],\n ])\n if (!direction) return undefined\n return { origin, direction }\n } catch {\n return undefined\n }\n}\n\n/**\n * BREP 现场面 → FaceHint。\n *\n * 面积在 occt-wasm 无公开 API(queryBatch 仅测试用),故现场路径不填 area——\n * 打分器对缺失 area 不扣分(scorerArea 双 undefined 跳过)。\n *\n * @param kernel - the OCCT kernel.\n * @param face - the face handle to snapshot.\n * @returns the captured FaceHint.\n */\nexport function captureFaceHint(kernel: BrepEngineApi, face: BrepHandle): FaceHint {\n const surfaceType = kernel.surfaceType(face)\n const uv = kernel.uvBounds(face)\n const u = (uv.uMin + uv.uMax) / 2\n const v = (uv.vMin + uv.vMax) / 2\n const normal = kernel.surfaceNormal(face, u, v)\n const center = kernel.surfaceCenterOfMass(face)\n // P0 装配前置:圆柱面采集轴 hint(其余面类型缺省——平面用 center+normal 即可)\n const axis = surfaceType === 'cylinder' ? captureCylinderFaceAxis(kernel, face) : undefined\n return {\n kind: 'face',\n surfaceType,\n normal: [normal.x, normal.y, normal.z],\n center: [center.x, center.y, center.z],\n ...(axis ? { axis } : {}),\n }\n}\n\n/**\n * 面行 → FaceHint(mesh/primitive 命名槽快照路径;§3.6 setTopology 注入用)。\n * 面行的 surfaceType/normal/center/area 与 BREP 现场同口径(§1.1 事实)。\n *\n * @param row - a FaceRow (or shape-compatible object) from the selector manifest.\n * @returns the FaceHint derived from the row.\n */\nexport function faceRowToHint(row: {\n surfaceType?: string\n normal?: readonly number[] | null\n center?: readonly number[] | null\n area?: number\n axis?: { origin?: readonly number[] | null; direction?: readonly number[] | null } | null\n}): FaceHint {\n const hint: FaceHint = {\n kind: 'face',\n ...(row.surfaceType !== undefined ? { surfaceType: row.surfaceType } : {}),\n ...(row.normal && row.normal.length === 3 ? { normal: [row.normal[0], row.normal[1], row.normal[2]] as [number, number, number] } : {}),\n ...(row.center && row.center.length === 3 ? { center: [row.center[0], row.center[1], row.center[2]] as [number, number, number] } : {}),\n ...(row.area !== undefined && Number.isFinite(row.area) ? { area: row.area } : {}),\n ...(row.axis?.origin && row.axis.origin.length === 3 && row.axis.direction && row.axis.direction.length === 3\n ? {\n axis: {\n origin: [row.axis.origin[0], row.axis.origin[1], row.axis.origin[2]] as [number, number, number],\n direction: [row.axis.direction[0], row.axis.direction[1], row.axis.direction[2]] as [number, number, number],\n },\n }\n : {}),\n }\n return hint\n}\n\n/**\n * 边行 → EdgeHint(mesh/primitive 命名槽快照路径;§3.7 edgeNaming 用)。\n * EdgeRow.center 与 EdgeHint.midpoint 同口径(§3.7:边 midpoint 与 EdgeRow.center\n * 同口径,geom-hint.ts 统一采集)。\n *\n * @param row - an EdgeRow (or shape-compatible object) from the selector manifest.\n * @returns the EdgeHint derived from the row.\n */\nexport function edgeRowToHint(row: {\n length?: number\n center?: readonly number[] | null\n axis?: { origin?: readonly number[] | null; direction?: readonly number[] | null } | null\n}): EdgeHint {\n const hint: EdgeHint = {\n kind: 'edge',\n ...(row.length !== undefined && Number.isFinite(row.length) ? { length: row.length } : {}),\n ...(row.center && row.center.length === 3 ? { midpoint: [row.center[0], row.center[1], row.center[2]] as [number, number, number] } : {}),\n ...(row.axis?.origin && row.axis.origin.length === 3 && row.axis.direction && row.axis.direction.length === 3\n ? {\n axis: {\n origin: [row.axis.origin[0], row.axis.origin[1], row.axis.origin[2]] as [number, number, number],\n direction: [row.axis.direction[0], row.axis.direction[1], row.axis.direction[2]] as [number, number, number],\n },\n }\n : {}),\n }\n return hint\n}\n\n/**\n * BREP 现场边 → EdgeHint。\n *\n * hint 是「并列裁决者」而非身份本身(§1.2),只在两邻面多公共边时用于打分。\n * length 用 `kernel.curveLength(edge)`;midpoint 取曲线参数中点的点坐标\n * (与 face 的 curvePointAtParam 同口径;屏蔽封闭/退化边的采样退化)。\n *\n * @param kernel - the OCCT kernel.\n * @param edge - the edge handle to snapshot.\n * @returns the captured EdgeHint.\n */\n/**\n * BREP 现场边 → 轴 hint(装配约束的边实体来源;P0 前置)。\n *\n * 直边:origin = 曲线起点,direction = 起点切向;\n * 圆边:origin = 圆心(三点定圆),direction = 所在平面法向;\n * 其它曲线类型 → undefined(不静默造轴)。\n *\n * @param kernel - the OCCT kernel.\n * @param edge - the edge handle.\n * @returns the axis hint, or undefined for unsupported curves / sampling failure.\n */\nexport function captureEdgeAxis(kernel: BrepEngineApi, edge: BrepHandle): AxisHint | undefined {\n try {\n const curveType = kernel.curveType(edge)\n if (curveType === 'line') {\n const { first } = kernel.curveParameters(edge)\n const origin = kernel.curvePointAtParam(edge, first)\n const tangent = kernel.curveTangent(edge, first)\n const direction = normalizedAxis([tangent.x, tangent.y, tangent.z])\n if (Number.isFinite(origin.x) && Number.isFinite(origin.y) && Number.isFinite(origin.z) && direction) {\n return { origin: [origin.x, origin.y, origin.z], direction }\n }\n } else if (curveType === 'circle') {\n return captureCircleEdgeAxis(kernel, edge)\n }\n } catch {\n // 曲线类型读取失败 → 无 axis hint(调用方按缺省处理,不静默造轴)\n }\n return undefined\n}\n\n/**\n * 采集棱边 hint(长度 / 中点 / 轴)。\n *\n * P0 装配前置:直边(起点 + 切向)与圆边(圆心 + 所在平面法向)产出 axis hint;\n * 退化或非线/圆曲线不产出 axis(调用方按缺省处理,不静默造轴)。\n *\n * @param kernel - the BREP engine API.\n * @param edge - the edge handle.\n * @returns the captured edge hint.\n */\nexport function captureEdgeHint(kernel: BrepEngineApi, edge: BrepHandle): EdgeHint {\n const length = kernel.curveLength(edge)\n const hint: { kind: 'edge'; length?: number; midpoint?: [number, number, number]; axis?: AxisHint } = { kind: 'edge' }\n if (Number.isFinite(length) && length > 0) hint.length = length\n try {\n const { first, last } = kernel.curveParameters(edge)\n if (Number.isFinite(first) && Number.isFinite(last)) {\n const mid = kernel.curvePointAtParam(edge, (first + last) / 2)\n if (Number.isFinite(mid.x) && Number.isFinite(mid.y) && Number.isFinite(mid.z)) {\n hint.midpoint = [mid.x, mid.y, mid.z]\n }\n }\n } catch {\n // 退化边(如长度 0)读曲线参数失败 → 只留 length,不发散\n }\n // P0 装配前置:直边(起点+切向)/ 圆边(圆心+法向)采集轴 hint\n const axis = captureEdgeAxis(kernel, edge)\n if (axis) hint.axis = axis\n return hint\n}\n"]}
|
|
1
|
+
{"version":3,"file":"geom-hint.js","sourceRoot":"","sources":["../../../src/topology/naming/geom-hint.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * geom-hint.ts — 几何 hint 捕获(§3.1)\n *\n * 两路:\n * - `captureFaceHint(kernel, faceHandle)`:BREP 现场面 → FaceHint(assignRoles 用)。\n * - `faceRowToHint(row)`:面行/FaceRow → FaceHint(primitive/mesh 命名槽快照用)。\n *\n * hint 字段与 SelectorRuntime 的 FaceRow(surfaceType/area/center/normal)同源\n * (§2.2),保证 BREP 现场与面行快照两条打分路径口径一致。\n */\n\nimport type { BrepEngineApi } from '../../brep/engine/primitives'\nimport type { BrepHandle } from '../../brep/engine/types'\nimport type { FaceHint, EdgeHint, AxisHint } from './types'\n\n/** 归一化向量(axis 采集内部用;零向量返回 null,调用方放弃采集)。 */\nfunction normalizedAxis(v: [number, number, number]): [number, number, number] | null {\n const len = Math.hypot(v[0], v[1], v[2])\n if (len < 1e-12 || !Number.isFinite(len)) return null\n return [v[0] / len, v[1] / len, v[2] / len]\n}\n\n/**\n * BREP 现场圆柱面 → 轴 hint(P0 装配前置)。\n *\n * 算法与 occt-kernel/topologyExt.ts getSurfaceParams 的 cylinder 分支同源:\n * direction = normalize(S(u,v+1) − S(u,v))(V 向即轴向);origin = P − R·外法向\n *(surfaceNormal 含朝向,reversed 面先取反修正)。\n *\n * @param kernel - the OCCT kernel.\n * @param face - the cylindrical face handle.\n * @returns the axis hint, or undefined when the axis cannot be derived.\n */\nexport function captureCylinderFaceAxis(kernel: BrepEngineApi, face: BrepHandle): AxisHint | undefined {\n try {\n const uv = kernel.uvBounds(face)\n const p0 = kernel.pointOnSurface(face, uv.uMin, uv.vMin)\n const p1 = kernel.pointOnSurface(face, uv.uMin, uv.vMin + 1)\n const direction = normalizedAxis([p1.x - p0.x, p1.y - p0.y, p1.z - p0.z])\n const cyl = kernel.getFaceCylinderData(face)\n if (!direction || !cyl) return undefined\n let sn = kernel.surfaceNormal(face, uv.uMin, uv.vMin)\n if (kernel.shapeOrientation(face) === 'reversed') {\n sn = { x: -sn.x, y: -sn.y, z: -sn.z }\n }\n const origin: [number, number, number] = [\n p0.x - cyl.radius * sn.x,\n p0.y - cyl.radius * sn.y,\n p0.z - cyl.radius * sn.z,\n ]\n return { origin, direction }\n } catch {\n return undefined\n }\n}\n\n/**\n * BREP 现场圆边 → 轴 hint(origin = 圆心,direction = 所在平面法向;P0 装配前置)。\n *\n * 用曲线上三个不同参数的采样点做外接圆圆心(三点定圆,精确、无弧长近似),\n * 法向取 (p1−p0)×(p2−p0) 归一化。只用 curvePointAtParam/curveParameters 等既有\n * 公开内核 API(与 getCurveParams 的 circle 分支同一能力面),不新增内核方法。\n *\n * @param kernel - the OCCT kernel.\n * @param edge - the circular edge handle.\n * @returns the axis hint, or undefined when sampling fails.\n */\nfunction captureCircleEdgeAxis(kernel: BrepEngineApi, edge: BrepHandle): AxisHint | undefined {\n try {\n const { first, last } = kernel.curveParameters(edge)\n if (!Number.isFinite(first) || !Number.isFinite(last)) return undefined\n const d = (last - first) / 3\n const pa = kernel.curvePointAtParam(edge, first)\n const pb = kernel.curvePointAtParam(edge, first + d)\n const pc = kernel.curvePointAtParam(edge, first + 2 * d)\n const e1: [number, number, number] = [pb.x - pa.x, pb.y - pa.y, pb.z - pa.z]\n const e2: [number, number, number] = [pc.x - pa.x, pc.y - pa.y, pc.z - pa.z]\n // 三点外接圆:解 o = a + α·e1 + β·e2,满足 |o−a| = |o−b| = |o−c|\n const e11 = e1[0] * e1[0] + e1[1] * e1[1] + e1[2] * e1[2]\n const e22 = e2[0] * e2[0] + e2[1] * e2[1] + e2[2] * e2[2]\n const e12 = e1[0] * e2[0] + e1[1] * e2[1] + e1[2] * e2[2]\n const denom = e11 * e22 - e12 * e12\n if (Math.abs(denom) < 1e-18) return undefined\n const alpha = (e11 * e22 - e22 * e12) / (2 * denom)\n const beta = (e22 * e11 - e11 * e12) / (2 * denom)\n const origin: [number, number, number] = [\n pa.x + alpha * e1[0] + beta * e2[0],\n pa.y + alpha * e1[1] + beta * e2[1],\n pa.z + alpha * e1[2] + beta * e2[2],\n ]\n const direction = normalizedAxis([\n e1[1] * e2[2] - e1[2] * e2[1],\n e1[2] * e2[0] - e1[0] * e2[2],\n e1[0] * e2[1] - e1[1] * e2[0],\n ])\n if (!direction) return undefined\n return { origin, direction }\n } catch {\n return undefined\n }\n}\n\n/**\n * BREP 现场面 → FaceHint。\n *\n * 面积在 occt-wasm 无公开 API(queryBatch 仅测试用),故现场路径不填 area——\n * 打分器对缺失 area 不扣分(scorerArea 双 undefined 跳过)。\n *\n * @param kernel - the OCCT kernel.\n * @param face - the face handle to snapshot.\n * @returns the captured FaceHint.\n */\nexport function captureFaceHint(kernel: BrepEngineApi, face: BrepHandle): FaceHint {\n const surfaceType = kernel.surfaceType(face)\n const uv = kernel.uvBounds(face)\n const u = (uv.uMin + uv.uMax) / 2\n const v = (uv.vMin + uv.vMax) / 2\n const normal = kernel.surfaceNormal(face, u, v)\n const center = kernel.surfaceCenterOfMass(face)\n // P0 装配前置:圆柱面采集轴 hint(其余面类型缺省——平面用 center+normal 即可)\n const axis = surfaceType === 'cylinder' ? captureCylinderFaceAxis(kernel, face) : undefined\n return {\n kind: 'face',\n surfaceType,\n normal: [normal.x, normal.y, normal.z],\n center: [center.x, center.y, center.z],\n ...(axis ? { axis } : {}),\n }\n}\n\n/**\n * 面行 → FaceHint(mesh/primitive 命名槽快照路径;§3.6 setTopology 注入用)。\n * 面行的 surfaceType/normal/center/area 与 BREP 现场同口径(§1.1 事实)。\n *\n * @param row - a FaceRow (or shape-compatible object) from the selector manifest.\n * @returns the FaceHint derived from the row.\n */\nexport function faceRowToHint(row: {\n surfaceType?: string\n normal?: readonly number[] | null\n center?: readonly number[] | null\n area?: number\n axis?: { origin?: readonly number[] | null; direction?: readonly number[] | null } | null\n}): FaceHint {\n const hint: FaceHint = {\n kind: 'face',\n ...(row.surfaceType !== undefined ? { surfaceType: row.surfaceType } : {}),\n ...(row.normal && row.normal.length === 3 ? { normal: [row.normal[0], row.normal[1], row.normal[2]] as [number, number, number] } : {}),\n ...(row.center && row.center.length === 3 ? { center: [row.center[0], row.center[1], row.center[2]] as [number, number, number] } : {}),\n ...(row.area !== undefined && Number.isFinite(row.area) ? { area: row.area } : {}),\n ...(row.axis?.origin && row.axis.origin.length === 3 && row.axis.direction && row.axis.direction.length === 3\n ? {\n axis: {\n origin: [row.axis.origin[0], row.axis.origin[1], row.axis.origin[2]] as [number, number, number],\n direction: [row.axis.direction[0], row.axis.direction[1], row.axis.direction[2]] as [number, number, number],\n },\n }\n : {}),\n }\n return hint\n}\n\n/**\n * 边行 → EdgeHint(mesh/primitive 命名槽快照路径;§3.7 edgeNaming 用)。\n * EdgeRow.center 与 EdgeHint.midpoint 同口径(§3.7:边 midpoint 与 EdgeRow.center\n * 同口径,geom-hint.ts 统一采集)。\n *\n * @param row - an EdgeRow (or shape-compatible object) from the selector manifest.\n * @returns the EdgeHint derived from the row.\n */\nexport function edgeRowToHint(row: {\n length?: number\n center?: readonly number[] | null\n axis?: { origin?: readonly number[] | null; direction?: readonly number[] | null } | null\n}): EdgeHint {\n const hint: EdgeHint = {\n kind: 'edge',\n ...(row.length !== undefined && Number.isFinite(row.length) ? { length: row.length } : {}),\n ...(row.center && row.center.length === 3 ? { midpoint: [row.center[0], row.center[1], row.center[2]] as [number, number, number] } : {}),\n ...(row.axis?.origin && row.axis.origin.length === 3 && row.axis.direction && row.axis.direction.length === 3\n ? {\n axis: {\n origin: [row.axis.origin[0], row.axis.origin[1], row.axis.origin[2]] as [number, number, number],\n direction: [row.axis.direction[0], row.axis.direction[1], row.axis.direction[2]] as [number, number, number],\n },\n }\n : {}),\n }\n return hint\n}\n\n/**\n * BREP 现场边 → EdgeHint。\n *\n * hint 是「并列裁决者」而非身份本身(§1.2),只在两邻面多公共边时用于打分。\n * length 用 `kernel.curveLength(edge)`;midpoint 取曲线参数中点的点坐标\n * (与 face 的 curvePointAtParam 同口径;屏蔽封闭/退化边的采样退化)。\n *\n * @param kernel - the OCCT kernel.\n * @param edge - the edge handle to snapshot.\n * @returns the captured EdgeHint.\n */\n/**\n * BREP 现场边 → 轴 hint(装配约束的边实体来源;P0 前置)。\n *\n * 直边:origin = 曲线起点,direction = 起点切向;\n * 圆边:origin = 圆心(三点定圆),direction = 所在平面法向;\n * 其它曲线类型 → undefined(不静默造轴)。\n *\n * @param kernel - the OCCT kernel.\n * @param edge - the edge handle.\n * @returns the axis hint, or undefined for unsupported curves / sampling failure.\n */\nexport function captureEdgeAxis(kernel: BrepEngineApi, edge: BrepHandle): AxisHint | undefined {\n try {\n const curveType = kernel.curveType(edge)\n if (curveType === 'line') {\n const { first } = kernel.curveParameters(edge)\n const origin = kernel.curvePointAtParam(edge, first)\n const tangent = kernel.curveTangent(edge, first)\n const direction = normalizedAxis([tangent.x, tangent.y, tangent.z])\n if (Number.isFinite(origin.x) && Number.isFinite(origin.y) && Number.isFinite(origin.z) && direction) {\n return { origin: [origin.x, origin.y, origin.z], direction }\n }\n } else if (curveType === 'circle') {\n return captureCircleEdgeAxis(kernel, edge)\n }\n } catch {\n // 曲线类型读取失败 → 无 axis hint(调用方按缺省处理,不静默造轴)\n }\n return undefined\n}\n\n/**\n * 采集棱边 hint(长度 / 中点 / 轴)。\n *\n * P0 装配前置:直边(起点 + 切向)与圆边(圆心 + 所在平面法向)产出 axis hint;\n * 退化或非线/圆曲线不产出 axis(调用方按缺省处理,不静默造轴)。\n *\n * @param kernel - the BREP engine API.\n * @param edge - the edge handle.\n * @returns the captured edge hint.\n */\nexport function captureEdgeHint(kernel: BrepEngineApi, edge: BrepHandle): EdgeHint {\n const length = kernel.curveLength(edge)\n const hint: { kind: 'edge'; length?: number; midpoint?: [number, number, number]; axis?: AxisHint } = { kind: 'edge' }\n if (Number.isFinite(length) && length > 0) hint.length = length\n try {\n const { first, last } = kernel.curveParameters(edge)\n if (Number.isFinite(first) && Number.isFinite(last)) {\n const mid = kernel.curvePointAtParam(edge, (first + last) / 2)\n if (Number.isFinite(mid.x) && Number.isFinite(mid.y) && Number.isFinite(mid.z)) {\n hint.midpoint = [mid.x, mid.y, mid.z]\n }\n }\n } catch {\n // 退化边(如长度 0)读曲线参数失败 → 只留 length,不发散\n }\n // P0 装配前置:直边(起点+切向)/ 圆边(圆心+法向)采集轴 hint\n const axis = captureEdgeAxis(kernel, edge)\n if (axis) hint.axis = axis\n return hint\n}\n"]}
|
|
@@ -351,6 +351,7 @@ export declare class LineageGraph {
|
|
|
351
351
|
* 执行期共用的血缘图实例。
|
|
352
352
|
*
|
|
353
353
|
* 唯一性由约束 C1(禁止并发多 runtime)保证;测试请自建 `new LineageGraph()`。
|
|
354
|
+
* **跨 faijs 实例共享**(globalThis),见 `sharedLineageGraph`。
|
|
354
355
|
*/
|
|
355
356
|
export declare const runtimeLineage: LineageGraph;
|
|
356
357
|
//# sourceMappingURL=lineage.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lineage.d.ts","sourceRoot":"","sources":["../../../src/topology/naming/lineage.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6CG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAA;AACtD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAA;AAC9D,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,aAAa,CAAA;AAI3C;;;;;;;;;;GAUG;AACH,MAAM,MAAM,WAAW,GACnB;IAAE,QAAQ,CAAC,GAAG,EAAE,aAAa,CAAA;CAAE,GAC/B;IAAE,QAAQ,CAAC,GAAG,EAAE,UAAU,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,SAAS,QAAQ,EAAE,CAAA;CAAE,CAAA;AAErE;;;;;;;;GAQG;AACH,MAAM,MAAM,UAAU;AACpB,+DAA+D;AAC7D;IAAE,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IAAC,QAAQ,CAAC,QAAQ,EAAE,WAAW,CAAA;CAAE;AAC7D,4EAA4E;GAC1E;IAAE,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC;IAAC,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC,WAAW,EAAE;QAAE,GAAG,EAAE,UAAU,CAAA;KAAE,CAAC,CAAA;CAAE;AAC9F,oEAAoE;GAClE;IAAE,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAA;CAAE;AAC/B,iCAAiC;GAC/B;IAAE,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAA;CAAE;AAChC,yGAAyG;GACvG;IAAE,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC;IAAC,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAA;CAAE;AACpD,uCAAuC;GACrC;IAAE,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAA;AAE3D,gCAAgC;AAChC,MAAM,MAAM,cAAc,GAAG,UAAU,CAAC,MAAM,CAAC,CAAA;AAE/C,kCAAkC;AAClC,eAAO,MAAM,gBAAgB,qFAOnB,CAAA;AAEV;;;;;;;;;GASG;AACH,MAAM,MAAM,eAAe,GAAG,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,GAAG,aAAa,CAAA;AAEnE;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,CAAC,EAAE,eAAe,GAAG,CAAC,IAAI,aAAa,CAEtE;AAED;;;;;GAKG;AACH,MAAM,WAAW,WAAW;IAC1B,0CAA0C;IAC1C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,uCAAuC;IACvC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;IACnB,oDAAoD;IACpD,QAAQ,CAAC,MAAM,EAAE,SAAS,QAAQ,EAAE,CAAA;IACpC,uBAAuB;IACvB,QAAQ,CAAC,OAAO,EAAE,SAAS,QAAQ,EAAE,CAAA;IACrC,8BAA8B;IAC9B,QAAQ,CAAC,UAAU,EAAE,UAAU,CAAA;IAC/B,+DAA+D;IAC/D,QAAQ,CAAC,SAAS,CAAC,EAAE,eAAe,CAAA;CACrC;AAED;;;;;;GAMG;AACH,MAAM,WAAW,YAAY;IAC3B,+BAA+B;IAC/B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,YAAY;IACZ,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;IACnB,sCAAsC;IACtC,QAAQ,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAA;IAClC,sCAAsC;IACtC,QAAQ,CAAC,OAAO,EAAE,SAAS,CAAC,QAAQ,EAAE,GAAG,QAAQ,EAAE,CAAC,CAAA;IACpD,0BAA0B;IAC1B,QAAQ,CAAC,UAAU,EAAE,UAAU,CAAA;CAChC;AAED,oCAAoC;AACpC,MAAM,WAAW,WAAW;IAC1B,oDAAoD;IACpD,QAAQ,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,QAAQ,GAAG,SAAS,CAAA;IACxD,oDAAoD;IACpD,QAAQ,CAAC,WAAW,EAAE,MAAM;QAAE,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;KAAE,GAAG,SAAS,CAAA;CAChE;AAID,8BAA8B;AAC9B,MAAM,MAAM,gBAAgB,GAAG,wBAAwB,GAAG,kBAAkB,GAAG,uBAAuB,CAAA;AAEtG,4BAA4B;AAC5B,qBAAa,YAAa,SAAQ,KAAK;IACrC,6BAA6B;IAC7B,QAAQ,CAAC,IAAI,EAAE,gBAAgB,CAAA;IAC/B,sBAAsB;IACtB,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAA;IAEtB;;;;OAIG;gBACS,IAAI,EAAE,gBAAgB,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM;CAMnE;AAID;;;;;;;;;;GAUG;AACH,wBAAgB,cAAc,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,QAAQ,GAAG,OAAO,CAiBhE;AAED;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,WAAW,EAAE,CAAC,EAAE,WAAW,GAAG,OAAO,CAQzE;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,UAAU,GAAG,OAAO,CAetE;AASD;;;;;GAKG;AACH,qBAAa,YAAY;IACvB,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAiC;IACvD,OAAO,CAAC,QAAQ,CAAC,SAAS,CAA8B;IACxD;;;;;;OAMG;IACH,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAiF;IAC9G;;;OAGG;IACH,OAAO,CAAC,QAAQ,CAAC,aAAa,CAA6B;IAC3D;;;;;;;;OAQG;IACH,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAmF;IAEtH;;;;;;;OAOG;IACH,QAAQ,CAAC,KAAK,EAAE,YAAY,EAAE,IAAI,EAAE,WAAW,GAAG,WAAW;IA6E7D;;;;;;;;;OASG;IACH,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,eAAe,GAAG,IAAI;IAY/D;;;;;OAKG;IACH,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,GAAG,SAAS;IAI3C;;;;;OAKG;IACH,MAAM,CAAC,IAAI,EAAE,QAAQ,GAAG,MAAM,GAAG,SAAS;IAI1C;;;;;OAKG;IACH,UAAU,CAAC,IAAI,EAAE,QAAQ,GAAG,WAAW,GAAG,SAAS;IAKnD;;;;;;;;OAQG;IACH,aAAa,CAAC,IAAI,EAAE,QAAQ,GAAG,WAAW,GAAG,SAAS;IAOtD,eAAe;IACf,IAAI,IAAI,IAAI,MAAM,CAEjB;IAED;;;;OAIG;IACH,OAAO,IAAI,MAAM,EAAE;IAInB,wCAAwC;IACxC,KAAK,IAAI,IAAI;IAQb;;;;;;;;;;OAUG;IACH,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,WAAW,CAAC,MAAM,EAAE,WAAW,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC,CAAC,EAAE,KAAK,CAAC,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,QAAQ,GAAG,IAAI;IAM3I;;;;OAIG;IACH,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,CAAC,MAAM,EAAE,WAAW,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC,CAAC,GAAG,SAAS;IAIpG;;;;OAIG;IACH,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,GAAG,SAAS;IAIjD;;;;;;;;;OASG;IACH,WAAW,CAAC,IAAI,EAAE,QAAQ,GAAG,WAAW,CAAC,MAAM,EAAE,WAAW,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC,CAAC,GAAG,SAAS;CAGrG;
|
|
1
|
+
{"version":3,"file":"lineage.d.ts","sourceRoot":"","sources":["../../../src/topology/naming/lineage.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6CG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAA;AACtD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAA;AAC9D,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,aAAa,CAAA;AAI3C;;;;;;;;;;GAUG;AACH,MAAM,MAAM,WAAW,GACnB;IAAE,QAAQ,CAAC,GAAG,EAAE,aAAa,CAAA;CAAE,GAC/B;IAAE,QAAQ,CAAC,GAAG,EAAE,UAAU,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,SAAS,QAAQ,EAAE,CAAA;CAAE,CAAA;AAErE;;;;;;;;GAQG;AACH,MAAM,MAAM,UAAU;AACpB,+DAA+D;AAC7D;IAAE,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IAAC,QAAQ,CAAC,QAAQ,EAAE,WAAW,CAAA;CAAE;AAC7D,4EAA4E;GAC1E;IAAE,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC;IAAC,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC,WAAW,EAAE;QAAE,GAAG,EAAE,UAAU,CAAA;KAAE,CAAC,CAAA;CAAE;AAC9F,oEAAoE;GAClE;IAAE,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAA;CAAE;AAC/B,iCAAiC;GAC/B;IAAE,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAA;CAAE;AAChC,yGAAyG;GACvG;IAAE,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC;IAAC,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAA;CAAE;AACpD,uCAAuC;GACrC;IAAE,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAA;AAE3D,gCAAgC;AAChC,MAAM,MAAM,cAAc,GAAG,UAAU,CAAC,MAAM,CAAC,CAAA;AAE/C,kCAAkC;AAClC,eAAO,MAAM,gBAAgB,qFAOnB,CAAA;AAEV;;;;;;;;;GASG;AACH,MAAM,MAAM,eAAe,GAAG,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,GAAG,aAAa,CAAA;AAEnE;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,CAAC,EAAE,eAAe,GAAG,CAAC,IAAI,aAAa,CAEtE;AAED;;;;;GAKG;AACH,MAAM,WAAW,WAAW;IAC1B,0CAA0C;IAC1C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,uCAAuC;IACvC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;IACnB,oDAAoD;IACpD,QAAQ,CAAC,MAAM,EAAE,SAAS,QAAQ,EAAE,CAAA;IACpC,uBAAuB;IACvB,QAAQ,CAAC,OAAO,EAAE,SAAS,QAAQ,EAAE,CAAA;IACrC,8BAA8B;IAC9B,QAAQ,CAAC,UAAU,EAAE,UAAU,CAAA;IAC/B,+DAA+D;IAC/D,QAAQ,CAAC,SAAS,CAAC,EAAE,eAAe,CAAA;CACrC;AAED;;;;;;GAMG;AACH,MAAM,WAAW,YAAY;IAC3B,+BAA+B;IAC/B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,YAAY;IACZ,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;IACnB,sCAAsC;IACtC,QAAQ,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAA;IAClC,sCAAsC;IACtC,QAAQ,CAAC,OAAO,EAAE,SAAS,CAAC,QAAQ,EAAE,GAAG,QAAQ,EAAE,CAAC,CAAA;IACpD,0BAA0B;IAC1B,QAAQ,CAAC,UAAU,EAAE,UAAU,CAAA;CAChC;AAED,oCAAoC;AACpC,MAAM,WAAW,WAAW;IAC1B,oDAAoD;IACpD,QAAQ,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,QAAQ,GAAG,SAAS,CAAA;IACxD,oDAAoD;IACpD,QAAQ,CAAC,WAAW,EAAE,MAAM;QAAE,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;KAAE,GAAG,SAAS,CAAA;CAChE;AAID,8BAA8B;AAC9B,MAAM,MAAM,gBAAgB,GAAG,wBAAwB,GAAG,kBAAkB,GAAG,uBAAuB,CAAA;AAEtG,4BAA4B;AAC5B,qBAAa,YAAa,SAAQ,KAAK;IACrC,6BAA6B;IAC7B,QAAQ,CAAC,IAAI,EAAE,gBAAgB,CAAA;IAC/B,sBAAsB;IACtB,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAA;IAEtB;;;;OAIG;gBACS,IAAI,EAAE,gBAAgB,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM;CAMnE;AAID;;;;;;;;;;GAUG;AACH,wBAAgB,cAAc,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,QAAQ,GAAG,OAAO,CAiBhE;AAED;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,WAAW,EAAE,CAAC,EAAE,WAAW,GAAG,OAAO,CAQzE;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,UAAU,GAAG,OAAO,CAetE;AASD;;;;;GAKG;AACH,qBAAa,YAAY;IACvB,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAiC;IACvD,OAAO,CAAC,QAAQ,CAAC,SAAS,CAA8B;IACxD;;;;;;OAMG;IACH,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAiF;IAC9G;;;OAGG;IACH,OAAO,CAAC,QAAQ,CAAC,aAAa,CAA6B;IAC3D;;;;;;;;OAQG;IACH,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAmF;IAEtH;;;;;;;OAOG;IACH,QAAQ,CAAC,KAAK,EAAE,YAAY,EAAE,IAAI,EAAE,WAAW,GAAG,WAAW;IA6E7D;;;;;;;;;OASG;IACH,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,eAAe,GAAG,IAAI;IAY/D;;;;;OAKG;IACH,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,GAAG,SAAS;IAI3C;;;;;OAKG;IACH,MAAM,CAAC,IAAI,EAAE,QAAQ,GAAG,MAAM,GAAG,SAAS;IAI1C;;;;;OAKG;IACH,UAAU,CAAC,IAAI,EAAE,QAAQ,GAAG,WAAW,GAAG,SAAS;IAKnD;;;;;;;;OAQG;IACH,aAAa,CAAC,IAAI,EAAE,QAAQ,GAAG,WAAW,GAAG,SAAS;IAOtD,eAAe;IACf,IAAI,IAAI,IAAI,MAAM,CAEjB;IAED;;;;OAIG;IACH,OAAO,IAAI,MAAM,EAAE;IAInB,wCAAwC;IACxC,KAAK,IAAI,IAAI;IAQb;;;;;;;;;;OAUG;IACH,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,WAAW,CAAC,MAAM,EAAE,WAAW,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC,CAAC,EAAE,KAAK,CAAC,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,QAAQ,GAAG,IAAI;IAM3I;;;;OAIG;IACH,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,CAAC,MAAM,EAAE,WAAW,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC,CAAC,GAAG,SAAS;IAIpG;;;;OAIG;IACH,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,GAAG,SAAS;IAIjD;;;;;;;;;OASG;IACH,WAAW,CAAC,IAAI,EAAE,QAAQ,GAAG,WAAW,CAAC,MAAM,EAAE,WAAW,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC,CAAC,GAAG,SAAS;CAGrG;AAyDD;;;;;GAKG;AACH,eAAO,MAAM,cAAc,EAAE,YAAmC,CAAA"}
|
|
@@ -397,10 +397,46 @@ function sameIdentity(a, b) {
|
|
|
397
397
|
sameNames(a.outputs, b.outputs) &&
|
|
398
398
|
provenanceEquals(a.provenance, b.provenance));
|
|
399
399
|
}
|
|
400
|
+
/**
|
|
401
|
+
* globalThis 上的血缘图共享键与版本(见 `sharedLineageGraph`)。
|
|
402
|
+
*/
|
|
403
|
+
const LINEAGE_KEY = '__FAICAD_FAIJS_LINEAGE__';
|
|
404
|
+
const LINEAGE_VERSION = 1;
|
|
405
|
+
/**
|
|
406
|
+
* 取(或建)挂在 globalThis 上的血缘图。
|
|
407
|
+
*
|
|
408
|
+
* **为什么必须挂 globalThis**:宿主 bundle 与第三方库(如 animation)可能各打一份
|
|
409
|
+
* faijs 代码(node_modules 里 animation 内嵌一份、宿主一份)。模块级单例会让
|
|
410
|
+
* 「建命名的一方」与「解析的一方」看到两张不同的表——求解侧 `roleTable` 恒空,
|
|
411
|
+
* exact 路径永不命中,只剩几何兜底;而 brepkit 的 `uvBounds` 对平面返回 ±1e6
|
|
412
|
+
* 哨兵,`surfaceCenterOfMass` 退化成参数原点求值,非居中模型上兜底全拒 →
|
|
413
|
+
* `topo ref (face) not found in the current shape`(2026-10-16 装配选面 bug 实锤)。
|
|
414
|
+
*
|
|
415
|
+
* 与 `runtime-state.ts` 的 `getRuntimeState()` 同一机制——那边早就是 globalThis
|
|
416
|
+
* (注释原话"让两份 faijs 代码共享同一份状态……构建期去重是主手段,这里是兜底"),
|
|
417
|
+
* 血缘图是漏补的那一块。版本不符直接抛错,不静默错乱(与 N1/N2/N3 同精神:
|
|
418
|
+
* 宁可在执行期就炸)。
|
|
419
|
+
*
|
|
420
|
+
* @returns the shared lineage graph singleton.
|
|
421
|
+
*/
|
|
422
|
+
function sharedLineageGraph() {
|
|
423
|
+
const g = globalThis;
|
|
424
|
+
const existing = g[LINEAGE_KEY];
|
|
425
|
+
if (existing) {
|
|
426
|
+
if (existing.version !== LINEAGE_VERSION) {
|
|
427
|
+
throw new Error(`[faijs] lineage version mismatch: loaded=${existing.version}, expected=${LINEAGE_VERSION}`);
|
|
428
|
+
}
|
|
429
|
+
return existing.graph;
|
|
430
|
+
}
|
|
431
|
+
const created = { version: LINEAGE_VERSION, graph: new LineageGraph() };
|
|
432
|
+
g[LINEAGE_KEY] = created;
|
|
433
|
+
return created.graph;
|
|
434
|
+
}
|
|
400
435
|
/**
|
|
401
436
|
* 执行期共用的血缘图实例。
|
|
402
437
|
*
|
|
403
438
|
* 唯一性由约束 C1(禁止并发多 runtime)保证;测试请自建 `new LineageGraph()`。
|
|
439
|
+
* **跨 faijs 实例共享**(globalThis),见 `sharedLineageGraph`。
|
|
404
440
|
*/
|
|
405
|
-
export const runtimeLineage =
|
|
441
|
+
export const runtimeLineage = sharedLineageGraph();
|
|
406
442
|
//# sourceMappingURL=lineage.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lineage.js","sourceRoot":"","sources":["../../../src/topology/naming/lineage.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * lineage.ts — 血缘图登记(计划 §4.3)。\n *\n * 每个 op 执行完登记一条 `LineageNode`:**谁(`StmtId`)用什么 op、吃了哪些\n * part、产出哪些 part、属哪个 provenance 类别**。两张表:\n *\n * | 表 | 键 → 值 | 用途 |\n * |---|---|---|\n * | `lineage` | `StmtId` → `LineageNode` | 从身份原点沿 DAG 前进 |\n * | `partToStmt` | `PartName` → `StmtId` | 从 part 名字反查是哪条语句造的 |\n *\n * ## 为什么这一层必须存在\n *\n * 现状把身份表达成 **hash**(`face-evolution.ts` 的内存指针哈希),于是每次查询都在\n * 付「对齐 hash」的利息:谁改了几何,谁的 hash 就变,身份就断。正确形态是\n * `(StmtId, RoleName)` 的**因果坐标**——`StmtId` 说「哪条语句产生」,`RoleName` 说\n * 「那条语句把它当作什么」。因果坐标不随几何变化,**也不需要知道中间过了几个 op**。\n *\n * ## 登记口只能有一个(但调用点有两个)\n *\n * 手写 op 走 `wrapBrepOne`(`define-op.ts`),生成投影走 `compatOp`\n * (`api/internal/compat-op.ts`)——**两条路径都必须登记**,否则 42 条投影永远无名。\n * 但两条路径共用一个 `register()`,规则才只有一处。\n *\n * ## 三条硬规则(这是「未来漏洞最少」的核心)\n *\n * | # | 规则 | 违反时 |\n * |---|---|---|\n * | **N1** | inputs 里任一 Shape 查不到 `PartName` → 报错 | `E_TOPO_UNTRACKED_INPUT` |\n * | **N2** | 当前语句锚点缺失,或与声明的 `stmt` 不符 → 报错 | `E_TOPO_NO_ANCHOR` |\n * | **N3** | 同一 `StmtId` 重复登记且**身份内容**不同 → 报错 | `E_TOPO_DUPLICATE_STMT` |\n *\n * **N1 为什么必须是错误而不是\"默认成链根\"**:op 内部常临时造 Shape(中间产物、\n * 工具件)。若给它们默认一个 origin,「看起来对但语义错」的身份就诞生了——\n * 引用能解析成功,但解析到**别的面**。这类错误不会在测试里暴露(测试用的参数恰好\n * 让两者重合),只会在用户改参数、改尺寸时暴露。**宁可在执行期就炸。**\n *\n * **N2 为什么现在才敢做**:它依赖 `getCurrentStmt()` 是\"当前语句的权威读法\"。\n * 这一点由约束 **C1(禁止并发多 runtime)** 保证(见 §4.7.1)——不是\"全局态凑合能用\"。\n *\n * ## 依赖注入,不读全局\n *\n * `register()` 收一个 `LineageDeps`(`nameOf` / `currentStmt`)而不是 import\n * `runtime-state`。理由有两条:其一,`topology/` 现有模块(如 `roles.ts`)都是\n * \"把依赖当参数\"的风格,读全局会破坏它;其二,N1/N2/N3 的测试不想去摆弄全局态。\n */\n\nimport type { PartName, StmtId } from '../../identity'\nimport type { HashEvolution } from '../../brep/face-evolution'\nimport { type RoleName } from './role-name'\n\n// ── provenance 类别(封闭,计划 §4.4)──\n\n/**\n * 新造面的获取方式(只有 `kernel` / `construct` 需要)。\n *\n * - `byAdjacency`:靠结果形状与输入的**邻接关系**推出哪个面是新造的\n * (布尔/倒角等:新面必然与已知面相邻,而幸存面有自己的坐标)\n * - `explicit`:op 直接给出词汇表(构造类:底面 = profile、侧面 i = 第 i 条边扫掠)\n *\n * ⚠️ **不能靠内核的 `generated` 桶**(Phase 0.4 实测):它与 `modified` 同构分段、\n * 键集相同,值是各输入面派生的**中间形**——`cut` 里 12 个 hash 结果里 0 存活,\n * `fillet`/`fuse` 里整桶为空。故 `byAdjacency` / `explicit` 是**必填**。\n */\nexport type NewFaceRule =\n | { readonly via: 'byAdjacency' }\n | { readonly via: 'explicit'; readonly vocab: readonly RoleName[] }\n\n/**\n * 六个 provenance 类别(计划 §4.4,封闭集)。\n *\n * **继承面的处置完全由类别决定,op 不写**;只有 `construct` 和 `kernel` 会造新面,\n * 才有词汇这一项 ⇒ `identity` / `subdivide` / `replicate(k)` **零声明**。\n *\n * 本表是**六个类别的定义**;某个 op 实际声明哪一类,以该 op 的 `defineOp` 为准\n * (实测:`sweep`、`loft` 声明 `unmodeled`;`extrude`、`revolve`、`makeBox` 声明 `construct`)。\n */\nexport type Provenance =\n /** 内核给历史:boolean / fillet / chamfer / shell / offset / 刚体变换 */\n | { readonly kind: 'kernel'; readonly newFaces: NewFaceRule }\n /** 输出面 ↔ 输入的构造规则:extrude / revolve / primitives(`via: 'explicit'` 词汇表给出) */\n | { readonly kind: 'construct'; readonly newFaces: Extract<NewFaceRule, { via: 'explicit' }> }\n /** 1:1,第 i 面 → 第 i 面:copy / place / clone / locate / applyMatrix */\n | { readonly kind: 'identity' }\n /** 每输入面 → 若干片:split / section */\n | { readonly kind: 'subdivide' }\n /** 第 k 份第 i 面 ← 第 i 面:linearPattern / circularPattern / gridPattern / rectangularPattern / mirrorJoin */\n | { readonly kind: 'replicate'; readonly k: number }\n /** 显式记账:算不出来。应趋近于 0;审计测试必须列出全部并给出理由 */\n | { readonly kind: 'unmodeled'; readonly reason: string }\n\n/** `Provenance` 的类别标签(封闭六值)。 */\nexport type ProvenanceKind = Provenance['kind']\n\n/** 六个类别标签,供审计测试枚举(新增类别必须同步此处)。 */\nexport const PROVENANCE_KINDS = [\n 'kernel',\n 'construct',\n 'identity',\n 'subdivide',\n 'replicate',\n 'unmodeled',\n] as const\n\n/**\n * 演化记录(`kind='kernel'` 时执行期补挂)。\n *\n * 两种形态并存(1.10 前置①实测):\n * - **序号键**(`slot.faceEvolution` 的实际存储形态,`Map<ordinal, ordinal[]>`):\n * boolean/fillet/chamfer 走 `decodeEvolution`(逐句柄 hashCode),copy/transform/place\n * 走 `identityEvolution`(恒等)。回走推进 identity 类与\"序号不变\"的 kernel 路径用它。\n * - **哈希键**(`HashEvolution`,`decodeHashEvolution` 的输出):只在 booleanWithRoleTable\n * 等组合函数内部瞬时存在,不落 slot。回走按哈希集合推进时用它。\n */\nexport type EvolutionRecord = Map<number, number[]> | HashEvolution\n\n/**\n * 判断演化记录是否为哈希键形态(`HashEvolution` 有 `modified`/`deleted` 字段)。\n *\n * @param e - the evolution record to test.\n * @returns true when the record is the hash-key form (`HashEvolution`).\n */\nexport function isHashEvolution(e: EvolutionRecord): e is HashEvolution {\n return 'modified' in e && 'deleted' in e\n}\n\n/**\n * 血缘图的一个节点 = 一条语句的登记记录。\n *\n * `inputs`/`outputs` 是 `PartName`(不是 Shape):Shape 是执行期的活对象,\n * 身份层必须只留**可序列化、可比较**的东西,否则节点会随 arena 释放而失去意义。\n */\nexport interface LineageNode {\n /** 该语句的 id(`ExecutionAnchor.id`),全局唯一。 */\n readonly stmt: StmtId\n /** op 名(如 `cad.fillet`)——用于报错信息与审计。 */\n readonly op: string\n /** 输入 part 名(`inputs.map(nameOf)` 的结果,已保证全部有名字)。 */\n readonly inputs: readonly PartName[]\n /** 产出 part 名(至少一个)。 */\n readonly outputs: readonly PartName[]\n /** provenance 类别 + 该类别的载荷。 */\n readonly provenance: Provenance\n /** `kind='kernel'` 时执行期记录的 hash 演化(`attachEvolution` 事后补上)。 */\n readonly evolution?: EvolutionRecord\n}\n\n/**\n * 登记入参(尚未解析成 `PartName` 的形态)。\n *\n * `inputs` 故意收 **Shape 句柄**而不是 `PartName`:N1 的判据就是\n * \"这个 Shape 有没有名字\",若调用方先自己 map 成名字,就正好把\n * \"查不到名字\"这一步跳过/默认了——那正是 N1 要防的。\n */\nexport interface LineageDraft {\n /** 声明本条语句的 id(N2 会与当前锚点核对)。 */\n readonly stmt: StmtId\n /** op 名。 */\n readonly op: string\n /** 输入 Shape 句柄(N1 在 register 内解析)。 */\n readonly inputs: readonly object[]\n /** 产出 part 名(非空;调用方从锚点/nameOf 拿到)。 */\n readonly outputs: readonly [PartName, ...PartName[]]\n /** provenance 类别 + 载荷。 */\n readonly provenance: Provenance\n}\n\n/** 登记所需的外部读口(由调用点注入,见文件头「依赖注入」)。 */\nexport interface LineageDeps {\n /** Shape → PartName(`runtime-state` 的 `nameOf`)。 */\n readonly nameOf: (shape: object) => PartName | undefined\n /** 当前执行语句锚点(`runtime-state` 的 `getCurrentStmt`)。 */\n readonly currentStmt: () => { readonly id: string } | undefined\n}\n\n// ── 错误 ──\n\n/** 血缘登记错误码(三条规则 N1/N2/N3)。 */\nexport type LineageErrorCode = 'E_TOPO_UNTRACKED_INPUT' | 'E_TOPO_NO_ANCHOR' | 'E_TOPO_DUPLICATE_STMT'\n\n/** 血缘登记失败。带稳定错误码,禁止静默兜底。 */\nexport class LineageError extends Error {\n /** 稳定错误码(宿主/args 校验按码识别)。 */\n readonly code: LineageErrorCode\n /** 出错的语句 id(若能确定)。 */\n readonly stmt?: string\n\n /**\n * @param code - the stable error code.\n * @param message - what went wrong, with the offending statement named.\n * @param stmt - the statement id, when known.\n */\n constructor(code: LineageErrorCode, message: string, stmt?: string) {\n super(message)\n this.name = 'LineageError'\n this.code = code\n this.stmt = stmt\n }\n}\n\n// ── 结构化比较(不引 node:util——topology/ 要能进浏览器构建)──\n\n/**\n * 两个 `RoleName` 是否相等(按值、递归)。\n *\n * 手写而不是 `JSON.stringify` 比较:键序会随写字面量的顺序变化\n * (`{index, op}` 与 `{op, index}` 是同一个值、不同的 JSON),\n * 而这两个函数是 N3「内容不同才报错」的判据——键序敏感会**误报冲突**。\n *\n * @param a - one role name.\n * @param b - the other role name.\n * @returns true when the two roles are structurally identical.\n */\nexport function roleNameEquals(a: RoleName, b: RoleName): boolean {\n switch (a.kind) {\n case 'semantic':\n return b.kind === 'semantic' && a.name === b.name\n case 'wall':\n return b.kind === 'wall' && a.index === b.index\n case 'imported':\n return b.kind === 'imported' && a.index === b.index\n case 'generated':\n return b.kind === 'generated' && a.op === b.op && a.index === b.index\n case 'hole':\n return b.kind === 'hole' && a.index === b.index && roleNameEquals(a.inner, b.inner)\n case 'replica':\n return b.kind === 'replica' && a.k === b.k && roleNameEquals(a.inner, b.inner)\n case 'splinter':\n return b.kind === 'splinter' && a.index === b.index && roleNameEquals(a.inner, b.inner)\n }\n}\n\n/**\n * 两条新造面规则是否相等(词汇表**逐项按序**比较——顺序是构造语义的一部分:\n * 侧面 i 对应第 i 条 profile 边,重排就是换了一个 role)。\n *\n * @param a - one rule.\n * @param b - the other rule.\n * @returns true when the two rules are structurally identical.\n */\nexport function newFaceRuleEquals(a: NewFaceRule, b: NewFaceRule): boolean {\n if (a.via === 'byAdjacency') return b.via === 'byAdjacency'\n if (b.via !== 'explicit') return false\n if (a.vocab.length !== b.vocab.length) return false\n for (let i = 0; i < a.vocab.length; i++) {\n if (!roleNameEquals(a.vocab[i], b.vocab[i])) return false\n }\n return true\n}\n\n/**\n * 两个 `Provenance` 是否相等(按值)。\n *\n * @param a - one provenance.\n * @param b - the other provenance.\n * @returns true when they are structurally identical.\n */\nexport function provenanceEquals(a: Provenance, b: Provenance): boolean {\n switch (a.kind) {\n case 'identity':\n return b.kind === 'identity'\n case 'subdivide':\n return b.kind === 'subdivide'\n case 'replicate':\n return b.kind === 'replicate' && a.k === b.k\n case 'unmodeled':\n return b.kind === 'unmodeled' && a.reason === b.reason\n case 'kernel':\n return b.kind === 'kernel' && newFaceRuleEquals(a.newFaces, b.newFaces)\n case 'construct':\n return b.kind === 'construct' && newFaceRuleEquals(a.newFaces, b.newFaces)\n }\n}\n\n/** 两个字符串数组是否逐项相等。 */\nfunction sameNames(a: readonly PartName[], b: readonly PartName[]): boolean {\n return a.length === b.length && a.every((x, i) => x === b[i])\n}\n\n// ── 血缘图 ──\n\n/**\n * 血缘图:两张表 + 一个登记函数。\n *\n * 实例化而非全局单例,是为了让 N1/N2/N3 的测试各用各的图、互不污染;\n * 执行期由 `runtime-state` 侧持有唯一实例(C1 保证单 runtime,不存在两图并存)。\n */\nexport class LineageGraph {\n private readonly nodes = new Map<StmtId, LineageNode>()\n private readonly partOwner = new Map<PartName, StmtId>()\n /**\n * 执行期旁挂:语句输出 part 的 roleTable(1.10 前置③)。\n *\n * 回走锚定需要 root 语句的「origin→role→hash[]」表;它本来只存在\n * `slot.roleTable`(解析缓存)里,删字段后唯一落点就是这里。\n * 不进 `LineageNode`(节点是身份数据,N3 比较不含它)。\n */\n private readonly outputTables = new Map<StmtId, ReadonlyMap<string, ReadonlyMap<string, readonly number[]>>>()\n /**\n * 执行期旁挂:语句输出 part 的 BREP 句柄(回走锚定/落地做 ordinal↔hash 换算用)。\n * 句柄是活对象不进节点;随 `clear()` 一起清(句柄生命周期由 solidCache 管)。\n */\n private readonly outputHandles = new Map<StmtId, unknown>()\n /**\n * 执行期旁挂:**part 名键**的 roleTable(1.10 前置③,op 读输入表用)。\n *\n * 为什么有语句键还要 part 键:op 实现读的是「输入 part 的表」。按语句反查\n * (stmtOf(part))在重赋值下会指到**本语句**——register 先于 impl 执行,\n * `part0 = translate(part0)` 的 partOwner 已被 s2 覆盖,impl 读输入表时\n * 拿到的是自己的输出。part 键表只在 `recordOutput`(impl 内 fromBrep 时)\n * 才覆盖 ⇒ impl 读表时看到的仍是上一条语句记录的旧表——时序天然正确。\n */\n private readonly outputTablesByPart = new Map<PartName, ReadonlyMap<string, ReadonlyMap<string, readonly number[]>>>()\n\n /**\n * 登记一条语句(N1/N2/N3 全在这里校验)。\n *\n * @param draft - the statement's lineage facts (inputs still as Shape handles).\n * @param deps - the injected readers (`nameOf` / `currentStmt`).\n * @returns the stored node.\n * @throws LineageError on N1 (untracked input), N2 (anchor mismatch), or N3 (conflicting re-register).\n */\n register(draft: LineageDraft, deps: LineageDeps): LineageNode {\n const stmt = draft.stmt\n\n // N2:当前锚点必须是本条语句,否则说明\"我拿到的 stmt 不是正在跑的那条\"。\n const anchor = deps.currentStmt()\n if (!anchor) {\n throw new LineageError(\n 'E_TOPO_NO_ANCHOR',\n `${draft.op} 登记血缘时无当前语句锚点(getCurrentStmt() 为空)`,\n stmt,\n )\n }\n if (anchor.id !== stmt) {\n throw new LineageError(\n 'E_TOPO_NO_ANCHOR',\n `${draft.op} 声明的语句 ${stmt} 与当前锚点 ${anchor.id} 不符`,\n stmt,\n )\n }\n\n // N1:输入 Shape 必须都有 PartName——**不许默认成链根**。\n const inputs: PartName[] = []\n for (let i = 0; i < draft.inputs.length; i++) {\n const name = deps.nameOf(draft.inputs[i])\n if (name === undefined) {\n throw new LineageError(\n 'E_TOPO_UNTRACKED_INPUT',\n `${draft.op} 的第 ${i} 个输入 Shape 没有 PartName(op 内部临时造的件?)。` +\n `不允许默认成链根——那会产生\"能解析但解析错面\"的假身份。`,\n stmt,\n )\n }\n inputs.push(name)\n }\n\n const node: LineageNode = {\n stmt,\n op: draft.op,\n inputs,\n outputs: [...draft.outputs],\n provenance: draft.provenance,\n }\n\n // N3:同一语句重复登记,若**身份内容**不同即为冲突。\n // 注意比较范围刻意**不含 evolution**:它在执行期事后补(`attachEvolution`),\n // 若纳入比较,第二次登记会因\"上次还没补 evolution\"而误报冲突。\n const existing = this.nodes.get(stmt)\n if (existing && !sameIdentity(existing, node)) {\n throw new LineageError(\n 'E_TOPO_DUPLICATE_STMT',\n `${stmt} 被重复登记且内容不同:` +\n `已登记 ${existing.op}(${existing.inputs.join(',')} → ${existing.outputs.join(',')}, ${existing.provenance.kind}),` +\n `本次为 ${node.op}(${node.inputs.join(',')} → ${node.outputs.join(',')}, ${node.provenance.kind})`,\n stmt,\n )\n }\n\n // PartName → StmtId:反查索引(名字 → 语句)。**最后写者胜**。\n //\n // 重赋值(`part0 = cad.translate(part0, …)`)是 faijs 的合法惯用法:后一条语句\n // 重新绑定同名 PartName,旧绑定随之失效。身份载体是 `(StmtId, RoleName)`,\n // PartName 只是反查索引,故覆盖更新即可——不报错。\n //\n // ⚠️ 曾经这里有一条 `E_TOPO_PART_REDEFINED` 守卫(把\"两名同出\"一律判为\n // \"反查歧义\")。§1.4/1.5 接线后它当场误杀了重赋值(8 例回退,见\n // `api/dual-form-contract.test.ts`),已废除:线性程序里\"两名同出\"就是重赋值,\n // 是合法的;而当两条语句真的同时存活并引用时,\"当前绑定\"语义本就该取最新。\n\n // ⚠️ 幂等重登记必须**保留已补挂的 evolution**:既然 N3 刻意不比较它,\n // 那它就不是\"本次登记的输入\",重登记时用不带 evolution 的新对象覆盖\n // 等于把先前记录的 hash 演化**静默丢掉**——而丢掉的正是 kernel 类推进 role\n // 所需的全部信息(重新算一遍几何也补不回来,因为演化只在执行那一刻可得)。\n this.nodes.set(stmt, existing?.evolution ? { ...node, evolution: existing.evolution } : node)\n for (const out of node.outputs) this.partOwner.set(out, stmt)\n return this.nodes.get(stmt)!\n }\n\n /**\n * 事后补挂 hash 演化(`kind='kernel'` 用)。\n *\n * 与 `register` 分开是因为演化记录发生在几何算完之后,而登记发生在调用边界;\n * 合成一个操作会让 N3 的\"内容比较\"必须处理\"evolution 可能晚到\"的时序问题。\n *\n * @param stmt - the statement whose evolution to attach.\n * @param evolution - the hash evolution produced by this statement.\n * @throws LineageError when the statement was never registered.\n */\n attachEvolution(stmt: StmtId, evolution: EvolutionRecord): void {\n const node = this.nodes.get(stmt)\n if (!node) {\n throw new LineageError(\n 'E_TOPO_NO_ANCHOR',\n `为未登记的语句 ${stmt} 挂 hash 演化——必须先 register`,\n stmt,\n )\n }\n this.nodes.set(stmt, { ...node, evolution })\n }\n\n /**\n * 按语句 id 取节点。\n *\n * @param stmt - the statement id to look up.\n * @returns the statement's LineageNode, or undefined when not registered.\n */\n node(stmt: StmtId): LineageNode | undefined {\n return this.nodes.get(stmt)\n }\n\n /**\n * 按 part 名反查产出它的语句 id。\n *\n * @param part - the part name to look up.\n * @returns the producing statement id, or undefined when unowned.\n */\n stmtOf(part: PartName): StmtId | undefined {\n return this.partOwner.get(part)\n }\n\n /**\n * 按 part 名反查产出它的节点。\n *\n * @param part - the part name to look up.\n * @returns the producing node, or undefined when unowned.\n */\n nodeOfPart(part: PartName): LineageNode | undefined {\n const stmt = this.partOwner.get(part)\n return stmt === undefined ? undefined : this.nodes.get(stmt)\n }\n\n /**\n * 找把 `part` 作为输入的下游节点(回走推进用,1.10 前置②)。\n *\n * 链行走的方向是「origin → 消费者 → 消费者的消费者」:中间 part 的产出方\n * 是 origin 自己(`stmtOf` 指回原点),不能用产出方找下一步。\n *\n * @param part - the part name consumed by the wanted node.\n * @returns the first (registration-order) node whose inputs contain the part.\n */\n nodeConsuming(part: PartName): LineageNode | undefined {\n for (const node of this.nodes.values()) {\n if (node.inputs.includes(part)) return node\n }\n return undefined\n }\n\n /** 已登记的语句数。 */\n get size(): number {\n return this.nodes.size\n }\n\n /**\n * 全部已登记语句 id(回走恢复需遍历候选 origin 时用)。\n *\n * @returns the registered statement ids.\n */\n stmtIds(): StmtId[] {\n return [...this.nodes.keys()]\n }\n\n /** 清空(每次执行开始时调用——一次执行内 `StmtId` 稳定)。 */\n clear(): void {\n this.nodes.clear()\n this.partOwner.clear()\n this.outputTables.clear()\n this.outputHandles.clear()\n this.outputTablesByPart.clear()\n }\n\n /**\n * 记录语句输出 part 的 roleTable 与句柄(1.10 前置③,执行期旁挂)。\n *\n * 调用点:`define-op.wrapped` 的 brep 分支——登记血缘时(或补挂演化时)\n * 顺手记录,读口是 `getSlot(outShape)`。表/句柄都可选(构造类 op 可能两者皆无)。\n *\n * @param stmt - the statement whose output is recorded.\n * @param roleTable - the output part's role table (origin→role→hash[]), if any.\n * @param solid - the output part's BREP handle, if any.\n * @param part - the output part name to also key the table under (part-key authority), if any.\n */\n recordOutput(stmt: StmtId, roleTable?: ReadonlyMap<string, ReadonlyMap<string, readonly number[]>>, solid?: unknown, part?: PartName): void {\n if (roleTable) this.outputTables.set(stmt, roleTable)\n if (solid !== undefined) this.outputHandles.set(stmt, solid)\n if (roleTable && part !== undefined) this.outputTablesByPart.set(part, roleTable)\n }\n\n /** 读语句输出 part 的 roleTable(回走锚定用)。\n *\n * @param stmt - the statement whose output table to read.\n * @returns the statement-keyed role table, or undefined when none was recorded.\n */\n outputTableOf(stmt: StmtId): ReadonlyMap<string, ReadonlyMap<string, readonly number[]>> | undefined {\n return this.outputTables.get(stmt)\n }\n\n /** 读语句输出 part 的 BREP 句柄(回走 ordinal↔hash 换算用)。\n *\n * @param stmt - the statement whose output handle to read.\n * @returns the statement-keyed BREP handle, or undefined when none was recorded.\n */\n outputHandleOf(stmt: StmtId): unknown | undefined {\n return this.outputHandles.get(stmt)\n }\n\n /**\n * 读 part 名键的 roleTable(op 实现读**输入**表用,1.10 前置③)。\n *\n * 语义 = 旧 `getSlot(input)?.roleTable`:impl 执行时刻,该 part 的表是\n * 上一条语句 `recordOutput` 记录的那份(本语句的覆盖发生在 impl 内\n * fromBrep 时,晚于任何输入读)。未记录(mesh 产物 / 未接血缘)→ undefined。\n *\n * @param part - the output part name whose role table to read.\n * @returns the part-keyed role table, or undefined when not recorded.\n */\n tableOfPart(part: PartName): ReadonlyMap<string, ReadonlyMap<string, readonly number[]>> | undefined {\n return this.outputTablesByPart.get(part)\n }\n}\n\n/**\n * 判断两节点是否\"身份内容\"相同(N3 用;刻意不含 `evolution`)。\n *\n * @param a - the stored node.\n * @param b - the incoming node.\n * @returns true when op / inputs / outputs / provenance all match.\n */\nfunction sameIdentity(a: LineageNode, b: LineageNode): boolean {\n return (\n a.op === b.op &&\n sameNames(a.inputs, b.inputs) &&\n sameNames(a.outputs, b.outputs) &&\n provenanceEquals(a.provenance, b.provenance)\n )\n}\n\n/**\n * 执行期共用的血缘图实例。\n *\n * 唯一性由约束 C1(禁止并发多 runtime)保证;测试请自建 `new LineageGraph()`。\n */\nexport const runtimeLineage = new LineageGraph()\n"]}
|
|
1
|
+
{"version":3,"file":"lineage.js","sourceRoot":"","sources":["../../../src/topology/naming/lineage.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * lineage.ts — 血缘图登记(计划 §4.3)。\n *\n * 每个 op 执行完登记一条 `LineageNode`:**谁(`StmtId`)用什么 op、吃了哪些\n * part、产出哪些 part、属哪个 provenance 类别**。两张表:\n *\n * | 表 | 键 → 值 | 用途 |\n * |---|---|---|\n * | `lineage` | `StmtId` → `LineageNode` | 从身份原点沿 DAG 前进 |\n * | `partToStmt` | `PartName` → `StmtId` | 从 part 名字反查是哪条语句造的 |\n *\n * ## 为什么这一层必须存在\n *\n * 现状把身份表达成 **hash**(`face-evolution.ts` 的内存指针哈希),于是每次查询都在\n * 付「对齐 hash」的利息:谁改了几何,谁的 hash 就变,身份就断。正确形态是\n * `(StmtId, RoleName)` 的**因果坐标**——`StmtId` 说「哪条语句产生」,`RoleName` 说\n * 「那条语句把它当作什么」。因果坐标不随几何变化,**也不需要知道中间过了几个 op**。\n *\n * ## 登记口只能有一个(但调用点有两个)\n *\n * 手写 op 走 `wrapBrepOne`(`define-op.ts`),生成投影走 `compatOp`\n * (`api/internal/compat-op.ts`)——**两条路径都必须登记**,否则 42 条投影永远无名。\n * 但两条路径共用一个 `register()`,规则才只有一处。\n *\n * ## 三条硬规则(这是「未来漏洞最少」的核心)\n *\n * | # | 规则 | 违反时 |\n * |---|---|---|\n * | **N1** | inputs 里任一 Shape 查不到 `PartName` → 报错 | `E_TOPO_UNTRACKED_INPUT` |\n * | **N2** | 当前语句锚点缺失,或与声明的 `stmt` 不符 → 报错 | `E_TOPO_NO_ANCHOR` |\n * | **N3** | 同一 `StmtId` 重复登记且**身份内容**不同 → 报错 | `E_TOPO_DUPLICATE_STMT` |\n *\n * **N1 为什么必须是错误而不是\"默认成链根\"**:op 内部常临时造 Shape(中间产物、\n * 工具件)。若给它们默认一个 origin,「看起来对但语义错」的身份就诞生了——\n * 引用能解析成功,但解析到**别的面**。这类错误不会在测试里暴露(测试用的参数恰好\n * 让两者重合),只会在用户改参数、改尺寸时暴露。**宁可在执行期就炸。**\n *\n * **N2 为什么现在才敢做**:它依赖 `getCurrentStmt()` 是\"当前语句的权威读法\"。\n * 这一点由约束 **C1(禁止并发多 runtime)** 保证(见 §4.7.1)——不是\"全局态凑合能用\"。\n *\n * ## 依赖注入,不读全局\n *\n * `register()` 收一个 `LineageDeps`(`nameOf` / `currentStmt`)而不是 import\n * `runtime-state`。理由有两条:其一,`topology/` 现有模块(如 `roles.ts`)都是\n * \"把依赖当参数\"的风格,读全局会破坏它;其二,N1/N2/N3 的测试不想去摆弄全局态。\n */\n\nimport type { PartName, StmtId } from '../../identity'\nimport type { HashEvolution } from '../../brep/face-evolution'\nimport { type RoleName } from './role-name'\n\n// ── provenance 类别(封闭,计划 §4.4)──\n\n/**\n * 新造面的获取方式(只有 `kernel` / `construct` 需要)。\n *\n * - `byAdjacency`:靠结果形状与输入的**邻接关系**推出哪个面是新造的\n * (布尔/倒角等:新面必然与已知面相邻,而幸存面有自己的坐标)\n * - `explicit`:op 直接给出词汇表(构造类:底面 = profile、侧面 i = 第 i 条边扫掠)\n *\n * ⚠️ **不能靠内核的 `generated` 桶**(Phase 0.4 实测):它与 `modified` 同构分段、\n * 键集相同,值是各输入面派生的**中间形**——`cut` 里 12 个 hash 结果里 0 存活,\n * `fillet`/`fuse` 里整桶为空。故 `byAdjacency` / `explicit` 是**必填**。\n */\nexport type NewFaceRule =\n | { readonly via: 'byAdjacency' }\n | { readonly via: 'explicit'; readonly vocab: readonly RoleName[] }\n\n/**\n * 六个 provenance 类别(计划 §4.4,封闭集)。\n *\n * **继承面的处置完全由类别决定,op 不写**;只有 `construct` 和 `kernel` 会造新面,\n * 才有词汇这一项 ⇒ `identity` / `subdivide` / `replicate(k)` **零声明**。\n *\n * 本表是**六个类别的定义**;某个 op 实际声明哪一类,以该 op 的 `defineOp` 为准\n * (实测:`sweep`、`loft` 声明 `unmodeled`;`extrude`、`revolve`、`makeBox` 声明 `construct`)。\n */\nexport type Provenance =\n /** 内核给历史:boolean / fillet / chamfer / shell / offset / 刚体变换 */\n | { readonly kind: 'kernel'; readonly newFaces: NewFaceRule }\n /** 输出面 ↔ 输入的构造规则:extrude / revolve / primitives(`via: 'explicit'` 词汇表给出) */\n | { readonly kind: 'construct'; readonly newFaces: Extract<NewFaceRule, { via: 'explicit' }> }\n /** 1:1,第 i 面 → 第 i 面:copy / place / clone / locate / applyMatrix */\n | { readonly kind: 'identity' }\n /** 每输入面 → 若干片:split / section */\n | { readonly kind: 'subdivide' }\n /** 第 k 份第 i 面 ← 第 i 面:linearPattern / circularPattern / gridPattern / rectangularPattern / mirrorJoin */\n | { readonly kind: 'replicate'; readonly k: number }\n /** 显式记账:算不出来。应趋近于 0;审计测试必须列出全部并给出理由 */\n | { readonly kind: 'unmodeled'; readonly reason: string }\n\n/** `Provenance` 的类别标签(封闭六值)。 */\nexport type ProvenanceKind = Provenance['kind']\n\n/** 六个类别标签,供审计测试枚举(新增类别必须同步此处)。 */\nexport const PROVENANCE_KINDS = [\n 'kernel',\n 'construct',\n 'identity',\n 'subdivide',\n 'replicate',\n 'unmodeled',\n] as const\n\n/**\n * 演化记录(`kind='kernel'` 时执行期补挂)。\n *\n * 两种形态并存(1.10 前置①实测):\n * - **序号键**(`slot.faceEvolution` 的实际存储形态,`Map<ordinal, ordinal[]>`):\n * boolean/fillet/chamfer 走 `decodeEvolution`(逐句柄 hashCode),copy/transform/place\n * 走 `identityEvolution`(恒等)。回走推进 identity 类与\"序号不变\"的 kernel 路径用它。\n * - **哈希键**(`HashEvolution`,`decodeHashEvolution` 的输出):只在 booleanWithRoleTable\n * 等组合函数内部瞬时存在,不落 slot。回走按哈希集合推进时用它。\n */\nexport type EvolutionRecord = Map<number, number[]> | HashEvolution\n\n/**\n * 判断演化记录是否为哈希键形态(`HashEvolution` 有 `modified`/`deleted` 字段)。\n *\n * @param e - the evolution record to test.\n * @returns true when the record is the hash-key form (`HashEvolution`).\n */\nexport function isHashEvolution(e: EvolutionRecord): e is HashEvolution {\n return 'modified' in e && 'deleted' in e\n}\n\n/**\n * 血缘图的一个节点 = 一条语句的登记记录。\n *\n * `inputs`/`outputs` 是 `PartName`(不是 Shape):Shape 是执行期的活对象,\n * 身份层必须只留**可序列化、可比较**的东西,否则节点会随 arena 释放而失去意义。\n */\nexport interface LineageNode {\n /** 该语句的 id(`ExecutionAnchor.id`),全局唯一。 */\n readonly stmt: StmtId\n /** op 名(如 `cad.fillet`)——用于报错信息与审计。 */\n readonly op: string\n /** 输入 part 名(`inputs.map(nameOf)` 的结果,已保证全部有名字)。 */\n readonly inputs: readonly PartName[]\n /** 产出 part 名(至少一个)。 */\n readonly outputs: readonly PartName[]\n /** provenance 类别 + 该类别的载荷。 */\n readonly provenance: Provenance\n /** `kind='kernel'` 时执行期记录的 hash 演化(`attachEvolution` 事后补上)。 */\n readonly evolution?: EvolutionRecord\n}\n\n/**\n * 登记入参(尚未解析成 `PartName` 的形态)。\n *\n * `inputs` 故意收 **Shape 句柄**而不是 `PartName`:N1 的判据就是\n * \"这个 Shape 有没有名字\",若调用方先自己 map 成名字,就正好把\n * \"查不到名字\"这一步跳过/默认了——那正是 N1 要防的。\n */\nexport interface LineageDraft {\n /** 声明本条语句的 id(N2 会与当前锚点核对)。 */\n readonly stmt: StmtId\n /** op 名。 */\n readonly op: string\n /** 输入 Shape 句柄(N1 在 register 内解析)。 */\n readonly inputs: readonly object[]\n /** 产出 part 名(非空;调用方从锚点/nameOf 拿到)。 */\n readonly outputs: readonly [PartName, ...PartName[]]\n /** provenance 类别 + 载荷。 */\n readonly provenance: Provenance\n}\n\n/** 登记所需的外部读口(由调用点注入,见文件头「依赖注入」)。 */\nexport interface LineageDeps {\n /** Shape → PartName(`runtime-state` 的 `nameOf`)。 */\n readonly nameOf: (shape: object) => PartName | undefined\n /** 当前执行语句锚点(`runtime-state` 的 `getCurrentStmt`)。 */\n readonly currentStmt: () => { readonly id: string } | undefined\n}\n\n// ── 错误 ──\n\n/** 血缘登记错误码(三条规则 N1/N2/N3)。 */\nexport type LineageErrorCode = 'E_TOPO_UNTRACKED_INPUT' | 'E_TOPO_NO_ANCHOR' | 'E_TOPO_DUPLICATE_STMT'\n\n/** 血缘登记失败。带稳定错误码,禁止静默兜底。 */\nexport class LineageError extends Error {\n /** 稳定错误码(宿主/args 校验按码识别)。 */\n readonly code: LineageErrorCode\n /** 出错的语句 id(若能确定)。 */\n readonly stmt?: string\n\n /**\n * @param code - the stable error code.\n * @param message - what went wrong, with the offending statement named.\n * @param stmt - the statement id, when known.\n */\n constructor(code: LineageErrorCode, message: string, stmt?: string) {\n super(message)\n this.name = 'LineageError'\n this.code = code\n this.stmt = stmt\n }\n}\n\n// ── 结构化比较(不引 node:util——topology/ 要能进浏览器构建)──\n\n/**\n * 两个 `RoleName` 是否相等(按值、递归)。\n *\n * 手写而不是 `JSON.stringify` 比较:键序会随写字面量的顺序变化\n * (`{index, op}` 与 `{op, index}` 是同一个值、不同的 JSON),\n * 而这两个函数是 N3「内容不同才报错」的判据——键序敏感会**误报冲突**。\n *\n * @param a - one role name.\n * @param b - the other role name.\n * @returns true when the two roles are structurally identical.\n */\nexport function roleNameEquals(a: RoleName, b: RoleName): boolean {\n switch (a.kind) {\n case 'semantic':\n return b.kind === 'semantic' && a.name === b.name\n case 'wall':\n return b.kind === 'wall' && a.index === b.index\n case 'imported':\n return b.kind === 'imported' && a.index === b.index\n case 'generated':\n return b.kind === 'generated' && a.op === b.op && a.index === b.index\n case 'hole':\n return b.kind === 'hole' && a.index === b.index && roleNameEquals(a.inner, b.inner)\n case 'replica':\n return b.kind === 'replica' && a.k === b.k && roleNameEquals(a.inner, b.inner)\n case 'splinter':\n return b.kind === 'splinter' && a.index === b.index && roleNameEquals(a.inner, b.inner)\n }\n}\n\n/**\n * 两条新造面规则是否相等(词汇表**逐项按序**比较——顺序是构造语义的一部分:\n * 侧面 i 对应第 i 条 profile 边,重排就是换了一个 role)。\n *\n * @param a - one rule.\n * @param b - the other rule.\n * @returns true when the two rules are structurally identical.\n */\nexport function newFaceRuleEquals(a: NewFaceRule, b: NewFaceRule): boolean {\n if (a.via === 'byAdjacency') return b.via === 'byAdjacency'\n if (b.via !== 'explicit') return false\n if (a.vocab.length !== b.vocab.length) return false\n for (let i = 0; i < a.vocab.length; i++) {\n if (!roleNameEquals(a.vocab[i], b.vocab[i])) return false\n }\n return true\n}\n\n/**\n * 两个 `Provenance` 是否相等(按值)。\n *\n * @param a - one provenance.\n * @param b - the other provenance.\n * @returns true when they are structurally identical.\n */\nexport function provenanceEquals(a: Provenance, b: Provenance): boolean {\n switch (a.kind) {\n case 'identity':\n return b.kind === 'identity'\n case 'subdivide':\n return b.kind === 'subdivide'\n case 'replicate':\n return b.kind === 'replicate' && a.k === b.k\n case 'unmodeled':\n return b.kind === 'unmodeled' && a.reason === b.reason\n case 'kernel':\n return b.kind === 'kernel' && newFaceRuleEquals(a.newFaces, b.newFaces)\n case 'construct':\n return b.kind === 'construct' && newFaceRuleEquals(a.newFaces, b.newFaces)\n }\n}\n\n/** 两个字符串数组是否逐项相等。 */\nfunction sameNames(a: readonly PartName[], b: readonly PartName[]): boolean {\n return a.length === b.length && a.every((x, i) => x === b[i])\n}\n\n// ── 血缘图 ──\n\n/**\n * 血缘图:两张表 + 一个登记函数。\n *\n * 实例化而非全局单例,是为了让 N1/N2/N3 的测试各用各的图、互不污染;\n * 执行期由 `runtime-state` 侧持有唯一实例(C1 保证单 runtime,不存在两图并存)。\n */\nexport class LineageGraph {\n private readonly nodes = new Map<StmtId, LineageNode>()\n private readonly partOwner = new Map<PartName, StmtId>()\n /**\n * 执行期旁挂:语句输出 part 的 roleTable(1.10 前置③)。\n *\n * 回走锚定需要 root 语句的「origin→role→hash[]」表;它本来只存在\n * `slot.roleTable`(解析缓存)里,删字段后唯一落点就是这里。\n * 不进 `LineageNode`(节点是身份数据,N3 比较不含它)。\n */\n private readonly outputTables = new Map<StmtId, ReadonlyMap<string, ReadonlyMap<string, readonly number[]>>>()\n /**\n * 执行期旁挂:语句输出 part 的 BREP 句柄(回走锚定/落地做 ordinal↔hash 换算用)。\n * 句柄是活对象不进节点;随 `clear()` 一起清(句柄生命周期由 solidCache 管)。\n */\n private readonly outputHandles = new Map<StmtId, unknown>()\n /**\n * 执行期旁挂:**part 名键**的 roleTable(1.10 前置③,op 读输入表用)。\n *\n * 为什么有语句键还要 part 键:op 实现读的是「输入 part 的表」。按语句反查\n * (stmtOf(part))在重赋值下会指到**本语句**——register 先于 impl 执行,\n * `part0 = translate(part0)` 的 partOwner 已被 s2 覆盖,impl 读输入表时\n * 拿到的是自己的输出。part 键表只在 `recordOutput`(impl 内 fromBrep 时)\n * 才覆盖 ⇒ impl 读表时看到的仍是上一条语句记录的旧表——时序天然正确。\n */\n private readonly outputTablesByPart = new Map<PartName, ReadonlyMap<string, ReadonlyMap<string, readonly number[]>>>()\n\n /**\n * 登记一条语句(N1/N2/N3 全在这里校验)。\n *\n * @param draft - the statement's lineage facts (inputs still as Shape handles).\n * @param deps - the injected readers (`nameOf` / `currentStmt`).\n * @returns the stored node.\n * @throws LineageError on N1 (untracked input), N2 (anchor mismatch), or N3 (conflicting re-register).\n */\n register(draft: LineageDraft, deps: LineageDeps): LineageNode {\n const stmt = draft.stmt\n\n // N2:当前锚点必须是本条语句,否则说明\"我拿到的 stmt 不是正在跑的那条\"。\n const anchor = deps.currentStmt()\n if (!anchor) {\n throw new LineageError(\n 'E_TOPO_NO_ANCHOR',\n `${draft.op} 登记血缘时无当前语句锚点(getCurrentStmt() 为空)`,\n stmt,\n )\n }\n if (anchor.id !== stmt) {\n throw new LineageError(\n 'E_TOPO_NO_ANCHOR',\n `${draft.op} 声明的语句 ${stmt} 与当前锚点 ${anchor.id} 不符`,\n stmt,\n )\n }\n\n // N1:输入 Shape 必须都有 PartName——**不许默认成链根**。\n const inputs: PartName[] = []\n for (let i = 0; i < draft.inputs.length; i++) {\n const name = deps.nameOf(draft.inputs[i])\n if (name === undefined) {\n throw new LineageError(\n 'E_TOPO_UNTRACKED_INPUT',\n `${draft.op} 的第 ${i} 个输入 Shape 没有 PartName(op 内部临时造的件?)。` +\n `不允许默认成链根——那会产生\"能解析但解析错面\"的假身份。`,\n stmt,\n )\n }\n inputs.push(name)\n }\n\n const node: LineageNode = {\n stmt,\n op: draft.op,\n inputs,\n outputs: [...draft.outputs],\n provenance: draft.provenance,\n }\n\n // N3:同一语句重复登记,若**身份内容**不同即为冲突。\n // 注意比较范围刻意**不含 evolution**:它在执行期事后补(`attachEvolution`),\n // 若纳入比较,第二次登记会因\"上次还没补 evolution\"而误报冲突。\n const existing = this.nodes.get(stmt)\n if (existing && !sameIdentity(existing, node)) {\n throw new LineageError(\n 'E_TOPO_DUPLICATE_STMT',\n `${stmt} 被重复登记且内容不同:` +\n `已登记 ${existing.op}(${existing.inputs.join(',')} → ${existing.outputs.join(',')}, ${existing.provenance.kind}),` +\n `本次为 ${node.op}(${node.inputs.join(',')} → ${node.outputs.join(',')}, ${node.provenance.kind})`,\n stmt,\n )\n }\n\n // PartName → StmtId:反查索引(名字 → 语句)。**最后写者胜**。\n //\n // 重赋值(`part0 = cad.translate(part0, …)`)是 faijs 的合法惯用法:后一条语句\n // 重新绑定同名 PartName,旧绑定随之失效。身份载体是 `(StmtId, RoleName)`,\n // PartName 只是反查索引,故覆盖更新即可——不报错。\n //\n // ⚠️ 曾经这里有一条 `E_TOPO_PART_REDEFINED` 守卫(把\"两名同出\"一律判为\n // \"反查歧义\")。§1.4/1.5 接线后它当场误杀了重赋值(8 例回退,见\n // `api/dual-form-contract.test.ts`),已废除:线性程序里\"两名同出\"就是重赋值,\n // 是合法的;而当两条语句真的同时存活并引用时,\"当前绑定\"语义本就该取最新。\n\n // ⚠️ 幂等重登记必须**保留已补挂的 evolution**:既然 N3 刻意不比较它,\n // 那它就不是\"本次登记的输入\",重登记时用不带 evolution 的新对象覆盖\n // 等于把先前记录的 hash 演化**静默丢掉**——而丢掉的正是 kernel 类推进 role\n // 所需的全部信息(重新算一遍几何也补不回来,因为演化只在执行那一刻可得)。\n this.nodes.set(stmt, existing?.evolution ? { ...node, evolution: existing.evolution } : node)\n for (const out of node.outputs) this.partOwner.set(out, stmt)\n return this.nodes.get(stmt)!\n }\n\n /**\n * 事后补挂 hash 演化(`kind='kernel'` 用)。\n *\n * 与 `register` 分开是因为演化记录发生在几何算完之后,而登记发生在调用边界;\n * 合成一个操作会让 N3 的\"内容比较\"必须处理\"evolution 可能晚到\"的时序问题。\n *\n * @param stmt - the statement whose evolution to attach.\n * @param evolution - the hash evolution produced by this statement.\n * @throws LineageError when the statement was never registered.\n */\n attachEvolution(stmt: StmtId, evolution: EvolutionRecord): void {\n const node = this.nodes.get(stmt)\n if (!node) {\n throw new LineageError(\n 'E_TOPO_NO_ANCHOR',\n `为未登记的语句 ${stmt} 挂 hash 演化——必须先 register`,\n stmt,\n )\n }\n this.nodes.set(stmt, { ...node, evolution })\n }\n\n /**\n * 按语句 id 取节点。\n *\n * @param stmt - the statement id to look up.\n * @returns the statement's LineageNode, or undefined when not registered.\n */\n node(stmt: StmtId): LineageNode | undefined {\n return this.nodes.get(stmt)\n }\n\n /**\n * 按 part 名反查产出它的语句 id。\n *\n * @param part - the part name to look up.\n * @returns the producing statement id, or undefined when unowned.\n */\n stmtOf(part: PartName): StmtId | undefined {\n return this.partOwner.get(part)\n }\n\n /**\n * 按 part 名反查产出它的节点。\n *\n * @param part - the part name to look up.\n * @returns the producing node, or undefined when unowned.\n */\n nodeOfPart(part: PartName): LineageNode | undefined {\n const stmt = this.partOwner.get(part)\n return stmt === undefined ? undefined : this.nodes.get(stmt)\n }\n\n /**\n * 找把 `part` 作为输入的下游节点(回走推进用,1.10 前置②)。\n *\n * 链行走的方向是「origin → 消费者 → 消费者的消费者」:中间 part 的产出方\n * 是 origin 自己(`stmtOf` 指回原点),不能用产出方找下一步。\n *\n * @param part - the part name consumed by the wanted node.\n * @returns the first (registration-order) node whose inputs contain the part.\n */\n nodeConsuming(part: PartName): LineageNode | undefined {\n for (const node of this.nodes.values()) {\n if (node.inputs.includes(part)) return node\n }\n return undefined\n }\n\n /** 已登记的语句数。 */\n get size(): number {\n return this.nodes.size\n }\n\n /**\n * 全部已登记语句 id(回走恢复需遍历候选 origin 时用)。\n *\n * @returns the registered statement ids.\n */\n stmtIds(): StmtId[] {\n return [...this.nodes.keys()]\n }\n\n /** 清空(每次执行开始时调用——一次执行内 `StmtId` 稳定)。 */\n clear(): void {\n this.nodes.clear()\n this.partOwner.clear()\n this.outputTables.clear()\n this.outputHandles.clear()\n this.outputTablesByPart.clear()\n }\n\n /**\n * 记录语句输出 part 的 roleTable 与句柄(1.10 前置③,执行期旁挂)。\n *\n * 调用点:`define-op.wrapped` 的 brep 分支——登记血缘时(或补挂演化时)\n * 顺手记录,读口是 `getSlot(outShape)`。表/句柄都可选(构造类 op 可能两者皆无)。\n *\n * @param stmt - the statement whose output is recorded.\n * @param roleTable - the output part's role table (origin→role→hash[]), if any.\n * @param solid - the output part's BREP handle, if any.\n * @param part - the output part name to also key the table under (part-key authority), if any.\n */\n recordOutput(stmt: StmtId, roleTable?: ReadonlyMap<string, ReadonlyMap<string, readonly number[]>>, solid?: unknown, part?: PartName): void {\n if (roleTable) this.outputTables.set(stmt, roleTable)\n if (solid !== undefined) this.outputHandles.set(stmt, solid)\n if (roleTable && part !== undefined) this.outputTablesByPart.set(part, roleTable)\n }\n\n /** 读语句输出 part 的 roleTable(回走锚定用)。\n *\n * @param stmt - the statement whose output table to read.\n * @returns the statement-keyed role table, or undefined when none was recorded.\n */\n outputTableOf(stmt: StmtId): ReadonlyMap<string, ReadonlyMap<string, readonly number[]>> | undefined {\n return this.outputTables.get(stmt)\n }\n\n /** 读语句输出 part 的 BREP 句柄(回走 ordinal↔hash 换算用)。\n *\n * @param stmt - the statement whose output handle to read.\n * @returns the statement-keyed BREP handle, or undefined when none was recorded.\n */\n outputHandleOf(stmt: StmtId): unknown | undefined {\n return this.outputHandles.get(stmt)\n }\n\n /**\n * 读 part 名键的 roleTable(op 实现读**输入**表用,1.10 前置③)。\n *\n * 语义 = 旧 `getSlot(input)?.roleTable`:impl 执行时刻,该 part 的表是\n * 上一条语句 `recordOutput` 记录的那份(本语句的覆盖发生在 impl 内\n * fromBrep 时,晚于任何输入读)。未记录(mesh 产物 / 未接血缘)→ undefined。\n *\n * @param part - the output part name whose role table to read.\n * @returns the part-keyed role table, or undefined when not recorded.\n */\n tableOfPart(part: PartName): ReadonlyMap<string, ReadonlyMap<string, readonly number[]>> | undefined {\n return this.outputTablesByPart.get(part)\n }\n}\n\n/**\n * 判断两节点是否\"身份内容\"相同(N3 用;刻意不含 `evolution`)。\n *\n * @param a - the stored node.\n * @param b - the incoming node.\n * @returns true when op / inputs / outputs / provenance all match.\n */\nfunction sameIdentity(a: LineageNode, b: LineageNode): boolean {\n return (\n a.op === b.op &&\n sameNames(a.inputs, b.inputs) &&\n sameNames(a.outputs, b.outputs) &&\n provenanceEquals(a.provenance, b.provenance)\n )\n}\n\n/**\n * globalThis 上的血缘图共享键与版本(见 `sharedLineageGraph`)。\n */\nconst LINEAGE_KEY = '__FAICAD_FAIJS_LINEAGE__'\nconst LINEAGE_VERSION = 1\n\n/**\n * 取(或建)挂在 globalThis 上的血缘图。\n *\n * **为什么必须挂 globalThis**:宿主 bundle 与第三方库(如 animation)可能各打一份\n * faijs 代码(node_modules 里 animation 内嵌一份、宿主一份)。模块级单例会让\n * 「建命名的一方」与「解析的一方」看到两张不同的表——求解侧 `roleTable` 恒空,\n * exact 路径永不命中,只剩几何兜底;而 brepkit 的 `uvBounds` 对平面返回 ±1e6\n * 哨兵,`surfaceCenterOfMass` 退化成参数原点求值,非居中模型上兜底全拒 →\n * `topo ref (face) not found in the current shape`(2026-10-16 装配选面 bug 实锤)。\n *\n * 与 `runtime-state.ts` 的 `getRuntimeState()` 同一机制——那边早就是 globalThis\n * (注释原话\"让两份 faijs 代码共享同一份状态……构建期去重是主手段,这里是兜底\"),\n * 血缘图是漏补的那一块。版本不符直接抛错,不静默错乱(与 N1/N2/N3 同精神:\n * 宁可在执行期就炸)。\n *\n * @returns the shared lineage graph singleton.\n */\nfunction sharedLineageGraph(): LineageGraph {\n const g = globalThis as unknown as Record<string, unknown>\n const existing = g[LINEAGE_KEY] as { version: number; graph: LineageGraph } | undefined\n if (existing) {\n if (existing.version !== LINEAGE_VERSION) {\n throw new Error(\n `[faijs] lineage version mismatch: loaded=${existing.version}, expected=${LINEAGE_VERSION}`,\n )\n }\n return existing.graph\n }\n const created = { version: LINEAGE_VERSION, graph: new LineageGraph() }\n g[LINEAGE_KEY] = created\n return created.graph\n}\n\n/**\n * 执行期共用的血缘图实例。\n *\n * 唯一性由约束 C1(禁止并发多 runtime)保证;测试请自建 `new LineageGraph()`。\n * **跨 faijs 实例共享**(globalThis),见 `sharedLineageGraph`。\n */\nexport const runtimeLineage: LineageGraph = sharedLineageGraph()\n"]}
|
|
@@ -20,14 +20,25 @@ export interface FaceCandidateEntry {
|
|
|
20
20
|
ordinal: number;
|
|
21
21
|
/** 会话内 hash(BREP:subShapeHashes;exact 匹配用)。 */
|
|
22
22
|
hash?: number;
|
|
23
|
-
/** BREP
|
|
23
|
+
/** BREP 现场句柄(exact 匹配 + 命中后回传活句柄用;打分不再优先走它)。 */
|
|
24
24
|
handle?: BrepHandle;
|
|
25
|
-
/**
|
|
25
|
+
/**
|
|
26
|
+
* 面行快照(存在 → 打分走 scoreCandidate row 路径)。
|
|
27
|
+
*
|
|
28
|
+
* BREP 路径也带(slot.faceHints,§3.6):行几何与 handle 同一次 execute 产出
|
|
29
|
+
* (同帧),且 brepkit 的 kernel 现场 center 会退化(uvBounds ±1e6 哨兵 →
|
|
30
|
+
* surfaceCenterOfMass 在参数原点求值),故 `toScoringCandidate` 改为 row 优先。
|
|
31
|
+
* `axis` 与 `faceRowToHint` 入参对齐——圆柱面的轴 hint 不能丢。
|
|
32
|
+
*/
|
|
26
33
|
row?: Readonly<{
|
|
27
34
|
surfaceType?: string;
|
|
28
35
|
normal?: readonly number[];
|
|
29
36
|
center?: readonly number[];
|
|
30
37
|
area?: number;
|
|
38
|
+
axis?: {
|
|
39
|
+
origin?: readonly number[] | null;
|
|
40
|
+
direction?: readonly number[] | null;
|
|
41
|
+
};
|
|
31
42
|
}>;
|
|
32
43
|
}
|
|
33
44
|
/** 面解析上下文:候选表 + role 表 + kernel(BREP 现场打分用,可为 null)+ 邻接(M3)。 */
|