@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.
Files changed (58) hide show
  1. package/dist/api/assembly/entities.js +14 -4
  2. package/dist/api/assembly/entities.js.map +1 -1
  3. package/dist/api/extrude.d.ts.map +1 -1
  4. package/dist/api/extrude.js +4 -1
  5. package/dist/api/extrude.js.map +1 -1
  6. package/dist/api/fillet.d.ts.map +1 -1
  7. package/dist/api/fillet.js +47 -0
  8. package/dist/api/fillet.js.map +1 -1
  9. package/dist/api/generated/script-face-manifest.js +1 -1
  10. package/dist/api/generated/script-face-manifest.js.map +1 -1
  11. package/dist/api/generated/topology.js +1 -1
  12. package/dist/api/generated/topology.js.map +1 -1
  13. package/dist/api/primitives.d.ts +3 -2
  14. package/dist/api/primitives.d.ts.map +1 -1
  15. package/dist/api/primitives.js +3 -2
  16. package/dist/api/primitives.js.map +1 -1
  17. package/dist/api/surface/arg-spec.d.ts.map +1 -1
  18. package/dist/api/surface/arg-spec.js +5 -6
  19. package/dist/api/surface/arg-spec.js.map +1 -1
  20. package/dist/api/topo-resolve.d.ts.map +1 -1
  21. package/dist/api/topo-resolve.js +24 -5
  22. package/dist/api/topo-resolve.js.map +1 -1
  23. package/dist/brepkit-kernel/brepkitKernel.d.ts.map +1 -1
  24. package/dist/brepkit-kernel/brepkitKernel.js +13 -2
  25. package/dist/brepkit-kernel/brepkitKernel.js.map +1 -1
  26. package/dist/brepkit-kernel/brepkitWasm.d.ts +3 -1
  27. package/dist/brepkit-kernel/brepkitWasm.d.ts.map +1 -1
  28. package/dist/brepkit-kernel/brepkitWasm.js +6 -2
  29. package/dist/brepkit-kernel/brepkitWasm.js.map +1 -1
  30. package/dist/cad-runtime/runtime.d.ts.map +1 -1
  31. package/dist/cad-runtime/runtime.js +15 -2
  32. package/dist/cad-runtime/runtime.js.map +1 -1
  33. package/dist/extra/ops/load.d.ts.map +1 -1
  34. package/dist/extra/ops/load.js +40 -2
  35. package/dist/extra/ops/load.js.map +1 -1
  36. package/dist/mesh/primitives.d.ts +6 -4
  37. package/dist/mesh/primitives.d.ts.map +1 -1
  38. package/dist/mesh/primitives.js +15 -8
  39. package/dist/mesh/primitives.js.map +1 -1
  40. package/dist/mesh/types.d.ts +4 -3
  41. package/dist/mesh/types.d.ts.map +1 -1
  42. package/dist/mesh/types.js.map +1 -1
  43. package/dist/primitives/brep-primitives.d.ts.map +1 -1
  44. package/dist/primitives/brep-primitives.js +39 -12
  45. package/dist/primitives/brep-primitives.js.map +1 -1
  46. package/dist/topology/naming/geom-hint.d.ts +12 -0
  47. package/dist/topology/naming/geom-hint.d.ts.map +1 -1
  48. package/dist/topology/naming/geom-hint.js +1 -1
  49. package/dist/topology/naming/geom-hint.js.map +1 -1
  50. package/dist/topology/naming/lineage.d.ts +1 -0
  51. package/dist/topology/naming/lineage.d.ts.map +1 -1
  52. package/dist/topology/naming/lineage.js +37 -1
  53. package/dist/topology/naming/lineage.js.map +1 -1
  54. package/dist/topology/naming/resolve-face.d.ts +13 -2
  55. package/dist/topology/naming/resolve-face.d.ts.map +1 -1
  56. package/dist/topology/naming/resolve-face.js +18 -2
  57. package/dist/topology/naming/resolve-face.js.map +1 -1
  58. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"resolve-face.d.ts","sourceRoot":"","sources":["../../../src/topology/naming/resolve-face.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAA;AACjE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAA;AACzD,OAAO,KAAK,EAAY,WAAW,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,SAAS,CAAA;AAG/E,+CAA+C;AAC/C,MAAM,WAAW,kBAAkB;IACjC,gEAAgE;IAChE,OAAO,EAAE,MAAM,CAAA;IACf,+CAA+C;IAC/C,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,uCAAuC;IACvC,MAAM,CAAC,EAAE,UAAU,CAAA;IACnB,2DAA2D;IAC3D,GAAG,CAAC,EAAE,QAAQ,CAAC;QACb,WAAW,CAAC,EAAE,MAAM,CAAA;QACpB,MAAM,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;QAC1B,MAAM,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;QAC1B,IAAI,CAAC,EAAE,MAAM,CAAA;KACd,CAAC,CAAA;CACH;AAED,gEAAgE;AAChE,MAAM,WAAW,iBAAiB;IAChC,oDAAoD;IACpD,QAAQ,CAAC,MAAM,EAAE,aAAa,GAAG,IAAI,CAAA;IACrC,oCAAoC;IACpC,QAAQ,CAAC,KAAK,EAAE,SAAS,kBAAkB,EAAE,CAAA;IAC7C,qEAAqE;IACrE,QAAQ,CAAC,SAAS,CAAC,EAAE,SAAS,CAAA;IAC9B,wDAAwD;IACxD,QAAQ,CAAC,KAAK,CAAC,EAAE,SAAS,kBAAkB,EAAE,CAAA;IAC9C,2DAA2D;IAC3D,QAAQ,CAAC,QAAQ,CAAC,EAAE,SAAS,oBAAoB,EAAE,CAAA;IACnD,iEAAiE;IACjE,QAAQ,CAAC,aAAa,CAAC,EAAE,aAAa,CAAC,SAAS,MAAM,EAAE,CAAC,CAAA;IACzD,yFAAyF;IACzF,QAAQ,CAAC,iBAAiB,CAAC,EAAE,aAAa,CAAC,SAAS,MAAM,EAAE,CAAC,CAAA;IAC7D,iEAAiE;IACjE,QAAQ,CAAC,iBAAiB,CAAC,EAAE,aAAa,CAAC,SAAS,MAAM,EAAE,CAAC,CAAA;IAC7D,qEAAqE;IACrE,QAAQ,CAAC,mBAAmB,CAAC,EAAE,aAAa,CAAC,SAAS,MAAM,EAAE,CAAC,CAAA;CAChE;AAED,0DAA0D;AAC1D,MAAM,WAAW,kBAAkB;IACjC,kBAAkB;IAClB,OAAO,EAAE,MAAM,CAAA;IACf,4BAA4B;IAC5B,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,uCAAuC;IACvC,MAAM,CAAC,EAAE,UAAU,CAAA;IACnB,uCAAuC;IACvC,IAAI,CAAC,EAAE;QACL,MAAM,CAAC,EAAE,MAAM,CAAA;QACf,QAAQ,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;KAC7B,CAAA;CACF;AAED,sDAAsD;AACtD,MAAM,WAAW,oBAAoB;IACnC,mBAAmB;IACnB,OAAO,EAAE,MAAM,CAAA;IACf,gBAAgB;IAChB,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,iBAAiB;IACjB,MAAM,CAAC,EAAE,UAAU,CAAA;IACnB,YAAY;IACZ,QAAQ,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;CAC7B;AAkDD;;;;;;GAMG;AACH,wBAAgB,eAAe,CAC7B,GAAG,EAAE,WAAW,EAChB,GAAG,EAAE,iBAAiB,GACrB,cAAc,CAAC;IAAE,MAAM,CAAC,EAAE,UAAU,CAAA;CAAE,CAAC,CA4CzC"}
1
+ {"version":3,"file":"resolve-face.d.ts","sourceRoot":"","sources":["../../../src/topology/naming/resolve-face.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAA;AACjE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAA;AACzD,OAAO,KAAK,EAAY,WAAW,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,SAAS,CAAA;AAG/E,+CAA+C;AAC/C,MAAM,WAAW,kBAAkB;IACjC,gEAAgE;IAChE,OAAO,EAAE,MAAM,CAAA;IACf,+CAA+C;IAC/C,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,gDAAgD;IAChD,MAAM,CAAC,EAAE,UAAU,CAAA;IACnB;;;;;;;OAOG;IACH,GAAG,CAAC,EAAE,QAAQ,CAAC;QACb,WAAW,CAAC,EAAE,MAAM,CAAA;QACpB,MAAM,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;QAC1B,MAAM,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;QAC1B,IAAI,CAAC,EAAE,MAAM,CAAA;QACb,IAAI,CAAC,EAAE;YAAE,MAAM,CAAC,EAAE,SAAS,MAAM,EAAE,GAAG,IAAI,CAAC;YAAC,SAAS,CAAC,EAAE,SAAS,MAAM,EAAE,GAAG,IAAI,CAAA;SAAE,CAAA;KACnF,CAAC,CAAA;CACH;AAED,gEAAgE;AAChE,MAAM,WAAW,iBAAiB;IAChC,oDAAoD;IACpD,QAAQ,CAAC,MAAM,EAAE,aAAa,GAAG,IAAI,CAAA;IACrC,oCAAoC;IACpC,QAAQ,CAAC,KAAK,EAAE,SAAS,kBAAkB,EAAE,CAAA;IAC7C,qEAAqE;IACrE,QAAQ,CAAC,SAAS,CAAC,EAAE,SAAS,CAAA;IAC9B,wDAAwD;IACxD,QAAQ,CAAC,KAAK,CAAC,EAAE,SAAS,kBAAkB,EAAE,CAAA;IAC9C,2DAA2D;IAC3D,QAAQ,CAAC,QAAQ,CAAC,EAAE,SAAS,oBAAoB,EAAE,CAAA;IACnD,iEAAiE;IACjE,QAAQ,CAAC,aAAa,CAAC,EAAE,aAAa,CAAC,SAAS,MAAM,EAAE,CAAC,CAAA;IACzD,yFAAyF;IACzF,QAAQ,CAAC,iBAAiB,CAAC,EAAE,aAAa,CAAC,SAAS,MAAM,EAAE,CAAC,CAAA;IAC7D,iEAAiE;IACjE,QAAQ,CAAC,iBAAiB,CAAC,EAAE,aAAa,CAAC,SAAS,MAAM,EAAE,CAAC,CAAA;IAC7D,qEAAqE;IACrE,QAAQ,CAAC,mBAAmB,CAAC,EAAE,aAAa,CAAC,SAAS,MAAM,EAAE,CAAC,CAAA;CAChE;AAED,0DAA0D;AAC1D,MAAM,WAAW,kBAAkB;IACjC,kBAAkB;IAClB,OAAO,EAAE,MAAM,CAAA;IACf,4BAA4B;IAC5B,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,uCAAuC;IACvC,MAAM,CAAC,EAAE,UAAU,CAAA;IACnB,uCAAuC;IACvC,IAAI,CAAC,EAAE;QACL,MAAM,CAAC,EAAE,MAAM,CAAA;QACf,QAAQ,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;KAC7B,CAAA;CACF;AAED,sDAAsD;AACtD,MAAM,WAAW,oBAAoB;IACnC,mBAAmB;IACnB,OAAO,EAAE,MAAM,CAAA;IACf,gBAAgB;IAChB,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,iBAAiB;IACjB,MAAM,CAAC,EAAE,UAAU,CAAA;IACnB,YAAY;IACZ,QAAQ,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;CAC7B;AAkED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAC7B,GAAG,EAAE,WAAW,EAChB,GAAG,EAAE,iBAAiB,GACrB,cAAc,CAAC;IAAE,MAAM,CAAC,EAAE,UAAU,CAAA;CAAE,CAAC,CA4CzC"}
@@ -12,9 +12,25 @@
12
12
  * 任何一步定不了案就返回三态(调用方抛 TopoRefError),绝不静默拿序号硬取。
13
13
  */
14
14
  import { scoreCandidate, MIN_SCORE, AMBIGUITY_THRESHOLD } from './score.js';
15
- /** 打分候选 → 候选条目(handle 优先、row 兜底,与 score.ts FaceCandidate 同构)。 */
15
+ /**
16
+ * 打分候选 → 候选条目(**row 优先**、kernel 现场兜底,与 score.ts FaceCandidate 同构)。
17
+ *
18
+ * 曾经是 handle 优先(`c.handle !== undefined ? { handle } : { row }`),那让 BREP
19
+ * 路径的打分一律走 kernel 现场——而 brepkit 的 `uvBounds` 对平面返回 ±1e6 哨兵,
20
+ * `surfaceCenterOfMass` 在参数原点求值:非居中模型上 center 全错(`[20,20,0]` 退
21
+ * 化成 `[0,0,0]`),距 hint 质心 28mm > 10mm 硬门 → 全候选被拒 →
22
+ * `topo ref (face) not found in the current shape`(2026-10-16 装配选面 bug)。
23
+ * 居中模型只因"参数原点恰好等于质心"而侥幸通过——是巧合,不是正确性。
24
+ *
25
+ * 行快照与 handle 同一次 execute 产出(同帧不陈旧),几何就是命名行的同一来源
26
+ * (`geom-hint.ts` 的 `faceRowToHint`),且 derived 解析(`resolve-derived.ts` 的
27
+ * `normalOf`)早已走 row——这里把主解析路径对齐过来。
28
+ *
29
+ * @param c - the face candidate entry.
30
+ * @returns the scoring candidate (row first, live handle as fallback).
31
+ */
16
32
  function toScoringCandidate(c) {
17
- return c.handle !== undefined ? { handle: c.handle } : { row: c.row };
33
+ return c.row !== undefined ? { row: c.row } : { handle: c.handle };
18
34
  }
19
35
  /** 一组候选对 hint 打分:best / secondBest / scored。 */
20
36
  function scoreCandidates(hint, candidates, ctx) {
@@ -1 +1 @@
1
- {"version":3,"file":"resolve-face.js","sourceRoot":"","sources":["../../../src/topology/naming/resolve-face.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * resolve-face.ts — 面 TopoRef 解析(移植 brepjs shapeRefFns.resolveRef,§2.5)\n *\n * 解析策略:\n * 1. 精确:roleTable[origin][role] 的 hash 命中当前面\n * - 恰好 1 → exact;0 → deleted;多个(1→多分裂)→ 只在这几个候选间用 hint 打分\n * 2. 几何兜底(role 缺失 / 分裂打分未命中):在当前全部面上按 hint 打分\n * - BREP:kernel 现场几何;mesh/primitive:命名槽面 hint 快照\n * 3. 最优分 > MIN_SCORE 且与次优差 ≥ AMBIGUITY_THRESHOLD → geometric-fallback;\n * 否则 ambiguous(并列)/ not-found(无超阈值候选)\n *\n * 任何一步定不了案就返回三态(调用方抛 TopoRefError),绝不静默拿序号硬取。\n */\n\nimport type { BrepEngineApi } from '../../brep/engine/primitives'\nimport type { BrepHandle } from '../../brep/engine/types'\nimport type { FaceHint, FaceTopoRef, RoleTable, TopoResolution } from './types'\nimport { scoreCandidate, MIN_SCORE, AMBIGUITY_THRESHOLD } from './score'\n\n/** 单个面候选:枚举序号 + 会话内 hash +(BREP 句柄 或 面行快照)。 */\nexport interface FaceCandidateEntry {\n /** 面枚举序号(1 起,TopExp::MapShapes 序;与 FaceRow.id 的 `o1.fN` 同序)。 */\n ordinal: number\n /** 会话内 hash(BREP:subShapeHashes;exact 匹配用)。 */\n hash?: number\n /** BREP 现场句柄(存在 → 打分走 kernel 现场几何)。 */\n handle?: BrepHandle\n /** mesh/primitive 面行快照(存在 → 打分走 scoreCandidate row 路径)。 */\n row?: Readonly<{\n surfaceType?: string\n normal?: readonly number[]\n center?: readonly number[]\n area?: number\n }>\n}\n\n/** 面解析上下文:候选表 + role 表 + kernel(BREP 现场打分用,可为 null)+ 邻接(M3)。 */\nexport interface ResolutionContext {\n /** OCCT 内核(mesh/primitive 路径为 null——打分走 row 快照)。 */\n readonly kernel: BrepEngineApi | null\n /** 当前快照的全部面候选(按枚举序,ordinal 1 起)。 */\n readonly faces: readonly FaceCandidateEntry[]\n /** 该 part 的 RoleTable(BREP 链上的 part 有;mesh/primitive 无 → 只走几何兜底)。 */\n readonly roleTable?: RoleTable\n /** 边候选表(ordinal 1 起 ↔ 数组下标 0 起;edge lineage 解析用,M3)。 */\n readonly edges?: readonly EdgeCandidateEntry[]\n /** 顶点候选表(ordinal 1 起 ↔ 数组下标 0 起;vertex lineage 解析用,M3)。 */\n readonly vertices?: readonly VertexCandidateEntry[]\n /** face ordinal(1 起) → 邻接 face ordinal 列表(derived/布尔缝解析用,M3)。 */\n readonly faceAdjacency?: ReadonlyArray<readonly number[]>\n /** face ordinal(1 起) → 邻接 edge ordinal 列表(edge lineage 用,M3;mesh 为空 → 边 lineage 不可用)。 */\n readonly faceEdgeAdjacency?: ReadonlyArray<readonly number[]>\n /** edge ordinal(1 起) → 邻接 face ordinal 列表(edge lineage 用,M3)。 */\n readonly edgeFaceAdjacency?: ReadonlyArray<readonly number[]>\n /** face ordinal(1 起) → 邻接 vertex ordinal 列表(vertex lineage 用,M3)。 */\n readonly faceVertexAdjacency?: ReadonlyArray<readonly number[]>\n}\n\n/** 边候选:序号 + length/midpoint hint(edge lineage 解析用,M3)。 */\nexport interface EdgeCandidateEntry {\n /** 边枚举序号(1 起)。 */\n ordinal: number\n /** 会话内 hash(exact 匹配预留)。 */\n hash?: number\n /** BREP 现场句柄(存在 → 打分走 kernel 现场几何)。 */\n handle?: BrepHandle\n /** 边几何 hint(length/midpoint;候选裁决用)。 */\n hint?: {\n length?: number\n midpoint?: readonly number[]\n }\n}\n\n/** 顶点候选:序号 + position hint(vertex lineage 解析用,M3)。 */\nexport interface VertexCandidateEntry {\n /** 顶点枚举序号(1 起)。 */\n ordinal: number\n /** 会话内 hash。 */\n hash?: number\n /** BREP 现场句柄。 */\n handle?: BrepHandle\n /** 顶点坐标。 */\n position?: readonly number[]\n}\n\n/** 打分候选 → 候选条目(handle 优先、row 兜底,与 score.ts FaceCandidate 同构)。 */\nfunction toScoringCandidate(c: FaceCandidateEntry): { handle?: BrepHandle; row?: FaceCandidateEntry['row'] } {\n return c.handle !== undefined ? { handle: c.handle } : { row: c.row }\n}\n\n/** 一组候选对 hint 打分:best / secondBest / scored。 */\nfunction scoreCandidates(\n hint: FaceHint,\n candidates: readonly FaceCandidateEntry[],\n ctx: ResolutionContext,\n): { scored: Array<{ candidate: FaceCandidateEntry; score: number }>; best?: FaceCandidateEntry; bestScore: number; secondBestScore: number } {\n let bestScore = -Infinity\n let secondBestScore = -Infinity\n let best: FaceCandidateEntry | undefined\n const scored: Array<{ candidate: FaceCandidateEntry; score: number }> = []\n for (const c of candidates) {\n const score = scoreCandidate(ctx.kernel, hint, toScoringCandidate(c))\n if (score > MIN_SCORE) scored.push({ candidate: c, score })\n if (score > bestScore) {\n secondBestScore = bestScore\n bestScore = score\n best = c\n } else if (score > secondBestScore) {\n secondBestScore = score\n }\n }\n return { scored, best, bestScore, secondBestScore }\n}\n\n/** 打分结果 → 三态(match / ambiguous / none)。 */\nfunction outcomeOf(\n hint: FaceHint,\n candidates: readonly FaceCandidateEntry[],\n ctx: ResolutionContext,\n): { kind: 'match'; candidate: FaceCandidateEntry } | { kind: 'ambiguous'; candidates: FaceCandidateEntry[] } | { kind: 'none' } {\n const { scored, best, bestScore, secondBestScore } = scoreCandidates(hint, candidates, ctx)\n if (best !== undefined && bestScore > MIN_SCORE) {\n if (bestScore - secondBestScore < AMBIGUITY_THRESHOLD && scored.length > 1) {\n const competitive = scored\n .filter((e) => e.score >= bestScore - AMBIGUITY_THRESHOLD)\n .map((e) => e.candidate)\n return { kind: 'ambiguous', candidates: competitive }\n }\n return { kind: 'match', candidate: best }\n }\n return { kind: 'none' }\n}\n\n/**\n * 解析面 TopoRef 到当前快照的序号/句柄。\n *\n * @param ref - the face TopoRef to resolve.\n * @param ctx - the resolution context (candidates + role table + kernel).\n * @returns the three-state TopoResolution.\n */\nexport function resolveFaceTopo(\n ref: FaceTopoRef,\n ctx: ResolutionContext,\n): TopoResolution<{ handle?: BrepHandle }> {\n // 1. 精确:role 的追踪 hash 在候选面中命中\n const targetHashes = ctx.roleTable?.get(ref.origin)?.get(ref.role)\n if (targetHashes !== undefined && targetHashes.length > 0) {\n const survivors = ctx.faces.filter((f) => f.hash !== undefined && targetHashes.includes(f.hash))\n if (survivors.length === 1) {\n const [only] = survivors\n if (only) {\n return { ok: true, entity: { handle: only.handle }, ordinal: only.ordinal, confidence: 'exact' }\n }\n } else if (survivors.length === 0) {\n return { ok: false, reason: 'deleted' }\n } else {\n // 1→多分裂:只在后继内裁决,不与全形状竞争\n const split = outcomeOf(ref.hint, survivors, ctx)\n if (split.kind === 'match') {\n return {\n ok: true,\n entity: { handle: split.candidate.handle },\n ordinal: split.candidate.ordinal,\n confidence: 'geometric-fallback',\n }\n }\n if (split.kind === 'ambiguous') {\n return { ok: false, reason: 'ambiguous', candidatesOrdinal: split.candidates.map((c) => c.ordinal) }\n }\n // 'none' → 落到全形状几何兜底\n }\n }\n\n // 2. 几何兜底:全形状打分\n const all = outcomeOf(ref.hint, ctx.faces, ctx)\n if (all.kind === 'match') {\n return {\n ok: true,\n entity: { handle: all.candidate.handle },\n ordinal: all.candidate.ordinal,\n confidence: 'geometric-fallback',\n }\n }\n if (all.kind === 'ambiguous') {\n return { ok: false, reason: 'ambiguous', candidatesOrdinal: all.candidates.map((c) => c.ordinal) }\n }\n return { ok: false, reason: 'not-found' }\n}\n"]}
1
+ {"version":3,"file":"resolve-face.js","sourceRoot":"","sources":["../../../src/topology/naming/resolve-face.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * resolve-face.ts — 面 TopoRef 解析(移植 brepjs shapeRefFns.resolveRef,§2.5)\n *\n * 解析策略:\n * 1. 精确:roleTable[origin][role] 的 hash 命中当前面\n * - 恰好 1 → exact;0 → deleted;多个(1→多分裂)→ 只在这几个候选间用 hint 打分\n * 2. 几何兜底(role 缺失 / 分裂打分未命中):在当前全部面上按 hint 打分\n * - BREP:kernel 现场几何;mesh/primitive:命名槽面 hint 快照\n * 3. 最优分 > MIN_SCORE 且与次优差 ≥ AMBIGUITY_THRESHOLD → geometric-fallback;\n * 否则 ambiguous(并列)/ not-found(无超阈值候选)\n *\n * 任何一步定不了案就返回三态(调用方抛 TopoRefError),绝不静默拿序号硬取。\n */\n\nimport type { BrepEngineApi } from '../../brep/engine/primitives'\nimport type { BrepHandle } from '../../brep/engine/types'\nimport type { FaceHint, FaceTopoRef, RoleTable, TopoResolution } from './types'\nimport { scoreCandidate, MIN_SCORE, AMBIGUITY_THRESHOLD } from './score'\n\n/** 单个面候选:枚举序号 + 会话内 hash +(BREP 句柄 或 面行快照)。 */\nexport interface FaceCandidateEntry {\n /** 面枚举序号(1 起,TopExp::MapShapes 序;与 FaceRow.id 的 `o1.fN` 同序)。 */\n ordinal: number\n /** 会话内 hash(BREP:subShapeHashes;exact 匹配用)。 */\n hash?: number\n /** BREP 现场句柄(exact 匹配 + 命中后回传活句柄用;打分不再优先走它)。 */\n handle?: BrepHandle\n /**\n * 面行快照(存在 → 打分走 scoreCandidate row 路径)。\n *\n * BREP 路径也带(slot.faceHints,§3.6):行几何与 handle 同一次 execute 产出\n * (同帧),且 brepkit 的 kernel 现场 center 会退化(uvBounds ±1e6 哨兵 →\n * surfaceCenterOfMass 在参数原点求值),故 `toScoringCandidate` 改为 row 优先。\n * `axis` 与 `faceRowToHint` 入参对齐——圆柱面的轴 hint 不能丢。\n */\n row?: Readonly<{\n surfaceType?: string\n normal?: readonly number[]\n center?: readonly number[]\n area?: number\n axis?: { origin?: readonly number[] | null; direction?: readonly number[] | null }\n }>\n}\n\n/** 面解析上下文:候选表 + role 表 + kernel(BREP 现场打分用,可为 null)+ 邻接(M3)。 */\nexport interface ResolutionContext {\n /** OCCT 内核(mesh/primitive 路径为 null——打分走 row 快照)。 */\n readonly kernel: BrepEngineApi | null\n /** 当前快照的全部面候选(按枚举序,ordinal 1 起)。 */\n readonly faces: readonly FaceCandidateEntry[]\n /** 该 part 的 RoleTable(BREP 链上的 part 有;mesh/primitive 无 → 只走几何兜底)。 */\n readonly roleTable?: RoleTable\n /** 边候选表(ordinal 1 起 ↔ 数组下标 0 起;edge lineage 解析用,M3)。 */\n readonly edges?: readonly EdgeCandidateEntry[]\n /** 顶点候选表(ordinal 1 起 ↔ 数组下标 0 起;vertex lineage 解析用,M3)。 */\n readonly vertices?: readonly VertexCandidateEntry[]\n /** face ordinal(1 起) → 邻接 face ordinal 列表(derived/布尔缝解析用,M3)。 */\n readonly faceAdjacency?: ReadonlyArray<readonly number[]>\n /** face ordinal(1 起) → 邻接 edge ordinal 列表(edge lineage 用,M3;mesh 为空 → 边 lineage 不可用)。 */\n readonly faceEdgeAdjacency?: ReadonlyArray<readonly number[]>\n /** edge ordinal(1 起) → 邻接 face ordinal 列表(edge lineage 用,M3)。 */\n readonly edgeFaceAdjacency?: ReadonlyArray<readonly number[]>\n /** face ordinal(1 起) → 邻接 vertex ordinal 列表(vertex lineage 用,M3)。 */\n readonly faceVertexAdjacency?: ReadonlyArray<readonly number[]>\n}\n\n/** 边候选:序号 + length/midpoint hint(edge lineage 解析用,M3)。 */\nexport interface EdgeCandidateEntry {\n /** 边枚举序号(1 起)。 */\n ordinal: number\n /** 会话内 hash(exact 匹配预留)。 */\n hash?: number\n /** BREP 现场句柄(存在 → 打分走 kernel 现场几何)。 */\n handle?: BrepHandle\n /** 边几何 hint(length/midpoint;候选裁决用)。 */\n hint?: {\n length?: number\n midpoint?: readonly number[]\n }\n}\n\n/** 顶点候选:序号 + position hint(vertex lineage 解析用,M3)。 */\nexport interface VertexCandidateEntry {\n /** 顶点枚举序号(1 起)。 */\n ordinal: number\n /** 会话内 hash。 */\n hash?: number\n /** BREP 现场句柄。 */\n handle?: BrepHandle\n /** 顶点坐标。 */\n position?: readonly number[]\n}\n\n/**\n * 打分候选 → 候选条目(**row 优先**、kernel 现场兜底,与 score.ts FaceCandidate 同构)。\n *\n * 曾经是 handle 优先(`c.handle !== undefined ? { handle } : { row }`),那让 BREP\n * 路径的打分一律走 kernel 现场——而 brepkit 的 `uvBounds` 对平面返回 ±1e6 哨兵,\n * `surfaceCenterOfMass` 在参数原点求值:非居中模型上 center 全错(`[20,20,0]` 退\n * 化成 `[0,0,0]`),距 hint 质心 28mm > 10mm 硬门 → 全候选被拒 →\n * `topo ref (face) not found in the current shape`(2026-10-16 装配选面 bug)。\n * 居中模型只因\"参数原点恰好等于质心\"而侥幸通过——是巧合,不是正确性。\n *\n * 行快照与 handle 同一次 execute 产出(同帧不陈旧),几何就是命名行的同一来源\n * (`geom-hint.ts` 的 `faceRowToHint`),且 derived 解析(`resolve-derived.ts` 的\n * `normalOf`)早已走 row——这里把主解析路径对齐过来。\n *\n * @param c - the face candidate entry.\n * @returns the scoring candidate (row first, live handle as fallback).\n */\nfunction toScoringCandidate(c: FaceCandidateEntry): { handle?: BrepHandle; row?: FaceCandidateEntry['row'] } {\n return c.row !== undefined ? { row: c.row } : { handle: c.handle }\n}\n\n/** 一组候选对 hint 打分:best / secondBest / scored。 */\nfunction scoreCandidates(\n hint: FaceHint,\n candidates: readonly FaceCandidateEntry[],\n ctx: ResolutionContext,\n): { scored: Array<{ candidate: FaceCandidateEntry; score: number }>; best?: FaceCandidateEntry; bestScore: number; secondBestScore: number } {\n let bestScore = -Infinity\n let secondBestScore = -Infinity\n let best: FaceCandidateEntry | undefined\n const scored: Array<{ candidate: FaceCandidateEntry; score: number }> = []\n for (const c of candidates) {\n const score = scoreCandidate(ctx.kernel, hint, toScoringCandidate(c))\n if (score > MIN_SCORE) scored.push({ candidate: c, score })\n if (score > bestScore) {\n secondBestScore = bestScore\n bestScore = score\n best = c\n } else if (score > secondBestScore) {\n secondBestScore = score\n }\n }\n return { scored, best, bestScore, secondBestScore }\n}\n\n/** 打分结果 → 三态(match / ambiguous / none)。 */\nfunction outcomeOf(\n hint: FaceHint,\n candidates: readonly FaceCandidateEntry[],\n ctx: ResolutionContext,\n): { kind: 'match'; candidate: FaceCandidateEntry } | { kind: 'ambiguous'; candidates: FaceCandidateEntry[] } | { kind: 'none' } {\n const { scored, best, bestScore, secondBestScore } = scoreCandidates(hint, candidates, ctx)\n if (best !== undefined && bestScore > MIN_SCORE) {\n if (bestScore - secondBestScore < AMBIGUITY_THRESHOLD && scored.length > 1) {\n const competitive = scored\n .filter((e) => e.score >= bestScore - AMBIGUITY_THRESHOLD)\n .map((e) => e.candidate)\n return { kind: 'ambiguous', candidates: competitive }\n }\n return { kind: 'match', candidate: best }\n }\n return { kind: 'none' }\n}\n\n/**\n * 解析面 TopoRef 到当前快照的序号/句柄。\n *\n * @param ref - the face TopoRef to resolve.\n * @param ctx - the resolution context (candidates + role table + kernel).\n * @returns the three-state TopoResolution.\n */\nexport function resolveFaceTopo(\n ref: FaceTopoRef,\n ctx: ResolutionContext,\n): TopoResolution<{ handle?: BrepHandle }> {\n // 1. 精确:role 的追踪 hash 在候选面中命中\n const targetHashes = ctx.roleTable?.get(ref.origin)?.get(ref.role)\n if (targetHashes !== undefined && targetHashes.length > 0) {\n const survivors = ctx.faces.filter((f) => f.hash !== undefined && targetHashes.includes(f.hash))\n if (survivors.length === 1) {\n const [only] = survivors\n if (only) {\n return { ok: true, entity: { handle: only.handle }, ordinal: only.ordinal, confidence: 'exact' }\n }\n } else if (survivors.length === 0) {\n return { ok: false, reason: 'deleted' }\n } else {\n // 1→多分裂:只在后继内裁决,不与全形状竞争\n const split = outcomeOf(ref.hint, survivors, ctx)\n if (split.kind === 'match') {\n return {\n ok: true,\n entity: { handle: split.candidate.handle },\n ordinal: split.candidate.ordinal,\n confidence: 'geometric-fallback',\n }\n }\n if (split.kind === 'ambiguous') {\n return { ok: false, reason: 'ambiguous', candidatesOrdinal: split.candidates.map((c) => c.ordinal) }\n }\n // 'none' → 落到全形状几何兜底\n }\n }\n\n // 2. 几何兜底:全形状打分\n const all = outcomeOf(ref.hint, ctx.faces, ctx)\n if (all.kind === 'match') {\n return {\n ok: true,\n entity: { handle: all.candidate.handle },\n ordinal: all.candidate.ordinal,\n confidence: 'geometric-fallback',\n }\n }\n if (all.kind === 'ambiguous') {\n return { ok: false, reason: 'ambiguous', candidatesOrdinal: all.candidates.map((c) => c.ordinal) }\n }\n return { ok: false, reason: 'not-found' }\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@faicad/faijs",
3
- "version": "0.35.2",
3
+ "version": "0.35.8",
4
4
  "faijs": {
5
5
  "lib": {
6
6
  "role": "host"