@faicad/faijs 0.32.3 → 0.33.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/api/api-namespace.js +3 -3
- package/dist/api/api-namespace.js.map +1 -1
- package/dist/api/assembly/index.d.ts +1 -0
- package/dist/api/assembly/index.d.ts.map +1 -1
- package/dist/api/assembly/index.js +1 -0
- package/dist/api/assembly/index.js.map +1 -1
- package/dist/api/assembly/lower.d.ts.map +1 -1
- package/dist/api/assembly/lower.js +7 -0
- package/dist/api/assembly/lower.js.map +1 -1
- package/dist/api/assembly/normalize.d.ts.map +1 -1
- package/dist/api/assembly/normalize.js +2 -1
- package/dist/api/assembly/normalize.js.map +1 -1
- package/dist/api/assembly/solve-tree.d.ts +46 -0
- package/dist/api/assembly/solve-tree.d.ts.map +1 -0
- package/dist/api/assembly/solve-tree.js +135 -0
- package/dist/api/assembly/solve-tree.js.map +1 -0
- package/dist/api/assembly/solve.d.ts +7 -0
- package/dist/api/assembly/solve.d.ts.map +1 -1
- package/dist/api/assembly/solve.js.map +1 -1
- package/dist/api/assembly/solvers/assembly-tree.d.ts +4 -0
- package/dist/api/assembly/solvers/assembly-tree.d.ts.map +1 -1
- package/dist/api/assembly/solvers/assembly-tree.js +1 -0
- package/dist/api/assembly/solvers/assembly-tree.js.map +1 -1
- package/dist/api/assembly/solvers/global-solver.d.ts.map +1 -1
- package/dist/api/assembly/solvers/global-solver.js +210 -3
- package/dist/api/assembly/solvers/global-solver.js.map +1 -1
- package/dist/api/assembly/solvers/types.d.ts +8 -0
- package/dist/api/assembly/solvers/types.d.ts.map +1 -1
- package/dist/api/assembly/solvers/types.js.map +1 -1
- package/dist/api/assembly/types.d.ts +32 -1
- package/dist/api/assembly/types.d.ts.map +1 -1
- package/dist/api/assembly/types.js.map +1 -1
- package/dist/api/assembly/validate.d.ts +2 -2
- package/dist/api/assembly/validate.d.ts.map +1 -1
- package/dist/api/assembly/validate.js +24 -2
- package/dist/api/assembly/validate.js.map +1 -1
- package/dist/api/cadquery-selectors/edge.js +1 -1
- package/dist/api/cadquery-selectors/edge.js.map +1 -1
- package/dist/api/cadquery-selectors/entity.d.ts +29 -20
- package/dist/api/cadquery-selectors/entity.d.ts.map +1 -1
- package/dist/api/cadquery-selectors/entity.js +26 -20
- package/dist/api/cadquery-selectors/entity.js.map +1 -1
- package/dist/api/cadquery-selectors/face.d.ts +4 -2
- package/dist/api/cadquery-selectors/face.d.ts.map +1 -1
- package/dist/api/cadquery-selectors/face.js +8 -7
- package/dist/api/cadquery-selectors/face.js.map +1 -1
- package/dist/api/cadquery-selectors/resolve.d.ts +7 -6
- package/dist/api/cadquery-selectors/resolve.d.ts.map +1 -1
- package/dist/api/cadquery-selectors/resolve.js +13 -11
- package/dist/api/cadquery-selectors/resolve.js.map +1 -1
- package/dist/api/chamfer.js +1 -1
- package/dist/api/chamfer.js.map +1 -1
- package/dist/api/draft.js +1 -1
- package/dist/api/draft.js.map +1 -1
- package/dist/api/edge-ref.js +2 -2
- package/dist/api/edge-ref.js.map +1 -1
- package/dist/api/engrave.js +1 -1
- package/dist/api/engrave.js.map +1 -1
- package/dist/api/export-3mf.js +1 -1
- package/dist/api/export-3mf.js.map +1 -1
- package/dist/api/export-brep.js +1 -1
- package/dist/api/export-brep.js.map +1 -1
- package/dist/api/export-step.d.ts +12 -13
- package/dist/api/export-step.d.ts.map +1 -1
- package/dist/api/export-step.js +19 -17
- package/dist/api/export-step.js.map +1 -1
- package/dist/api/extrude.js +3 -3
- package/dist/api/extrude.js.map +1 -1
- package/dist/api/face-ref.js +2 -2
- package/dist/api/face-ref.js.map +1 -1
- package/dist/api/feature-repair.js +2 -2
- package/dist/api/feature-repair.js.map +1 -1
- package/dist/api/fillet-variable.js +1 -1
- package/dist/api/fillet-variable.js.map +1 -1
- package/dist/api/fillet.js +1 -1
- package/dist/api/fillet.js.map +1 -1
- package/dist/api/geom.js +1 -1
- package/dist/api/geom.js.map +1 -1
- package/dist/api/import-step.d.ts.map +1 -1
- package/dist/api/import-step.js +4 -2
- package/dist/api/import-step.js.map +1 -1
- package/dist/api/pattern.js +1 -1
- package/dist/api/pattern.js.map +1 -1
- package/dist/api/place.js +1 -1
- package/dist/api/place.js.map +1 -1
- package/dist/api/punch-hole.js +1 -1
- package/dist/api/punch-hole.js.map +1 -1
- package/dist/api/replicate.js +1 -1
- package/dist/api/replicate.js.map +1 -1
- package/dist/api/revolve.js +1 -1
- package/dist/api/revolve.js.map +1 -1
- package/dist/api/section-by-plane.js +1 -1
- package/dist/api/section-by-plane.js.map +1 -1
- package/dist/api/shell.js +1 -1
- package/dist/api/shell.js.map +1 -1
- package/dist/api/sketch-on-face.js +1 -1
- package/dist/api/sketch-on-face.js.map +1 -1
- package/dist/api/split-by-plane.js +1 -1
- package/dist/api/split-by-plane.js.map +1 -1
- package/dist/api/split.js +1 -1
- package/dist/api/split.js.map +1 -1
- package/dist/api/thicken.js +1 -1
- package/dist/api/thicken.js.map +1 -1
- package/dist/api/topo-resolve.js +4 -4
- package/dist/api/topo-resolve.js.map +1 -1
- package/dist/api/transform.js +1 -1
- package/dist/api/transform.js.map +1 -1
- package/dist/api/view/view-projection.d.ts +8 -0
- package/dist/api/view/view-projection.d.ts.map +1 -1
- package/dist/api/view/view-projection.js +73 -2
- package/dist/api/view/view-projection.js.map +1 -1
- package/dist/boolean/cross-section.d.ts.map +1 -1
- package/dist/boolean/cross-section.js +3 -1
- package/dist/boolean/cross-section.js.map +1 -1
- package/dist/brep/brep-ops.d.ts +26 -0
- package/dist/brep/brep-ops.d.ts.map +1 -1
- package/dist/brep/brep-ops.js +45 -0
- package/dist/brep/brep-ops.js.map +1 -1
- package/dist/brep/brep-topology.js +1 -1
- package/dist/brep/brep-topology.js.map +1 -1
- package/dist/brep/engine/adapters/brep-mock.d.ts.map +1 -1
- package/dist/brep/engine/adapters/brep-mock.js +2 -0
- package/dist/brep/engine/adapters/brep-mock.js.map +1 -1
- package/dist/brep/engine/primitives.d.ts +17 -0
- package/dist/brep/engine/primitives.d.ts.map +1 -1
- package/dist/brep/engine/primitives.js.map +1 -1
- package/dist/brep/export/export-model.d.ts.map +1 -1
- package/dist/brep/export/export-model.js +36 -11
- package/dist/brep/export/export-model.js.map +1 -1
- package/dist/brep/export/step-flat.d.ts +35 -0
- package/dist/brep/export/step-flat.d.ts.map +1 -0
- package/dist/brep/export/step-flat.js +94 -0
- package/dist/brep/export/step-flat.js.map +1 -0
- package/dist/brep/export/step.d.ts.map +1 -1
- package/dist/brep/export/step.js +42 -21
- package/dist/brep/export/step.js.map +1 -1
- package/dist/brep/handle-bridge.d.ts +4 -4
- package/dist/brep/handle-bridge.js +4 -4
- package/dist/brep/handle-bridge.js.map +1 -1
- package/dist/brep/svg/svg-to-solid.d.ts +3 -17
- package/dist/brep/svg/svg-to-solid.d.ts.map +1 -1
- package/dist/brep/svg/svg-to-solid.js +16 -317
- package/dist/brep/svg/svg-to-solid.js.map +1 -1
- package/dist/brepkit-kernel/brepkitKernel.d.ts.map +1 -1
- package/dist/brepkit-kernel/brepkitKernel.js +10 -0
- package/dist/brepkit-kernel/brepkitKernel.js.map +1 -1
- package/dist/brepkit-kernel/brepkitWasm.d.ts +1 -1
- package/dist/brepkit-kernel/brepkitWasm.d.ts.map +1 -1
- package/dist/brepkit-kernel/brepkitWasm.js +7 -6
- package/dist/brepkit-kernel/brepkitWasm.js.map +1 -1
- package/dist/brepkit-kernel/multi-version-test.d.ts +7 -7
- package/dist/brepkit-kernel/multi-version-test.d.ts.map +1 -1
- package/dist/brepkit-kernel/multi-version-test.js +10 -10
- package/dist/brepkit-kernel/multi-version-test.js.map +1 -1
- package/dist/cad-runtime/direct-executor.js +2 -2
- package/dist/cad-runtime/direct-executor.js.map +1 -1
- package/dist/cad-runtime/runtime.js +5 -5
- package/dist/cad-runtime/runtime.js.map +1 -1
- package/dist/geometry2d/curve2d.js +42 -1
- package/dist/geometry2d/curve2d.js.map +1 -1
- package/dist/math3d/Box3.js.map +1 -1
- package/dist/math3d/Euler.js.map +1 -1
- package/dist/math3d/Mat4.js.map +1 -1
- package/dist/math3d/Plane.js.map +1 -1
- package/dist/math3d/Quat.js.map +1 -1
- package/dist/math3d/Vec2.js.map +1 -1
- package/dist/math3d/Vec3.js.map +1 -1
- package/dist/math3d/index.js.map +1 -1
- package/dist/mesh/meshdata/contour.d.ts +34 -0
- package/dist/mesh/meshdata/contour.d.ts.map +1 -0
- package/dist/mesh/meshdata/contour.js +39 -0
- package/dist/mesh/meshdata/contour.js.map +1 -0
- package/dist/mesh/meshdata/extrude.d.ts +25 -0
- package/dist/mesh/meshdata/extrude.d.ts.map +1 -0
- package/dist/mesh/meshdata/extrude.js +198 -0
- package/dist/mesh/meshdata/extrude.js.map +1 -0
- package/dist/mesh/meshdata/index.js.map +1 -1
- package/dist/mesh/meshdata/ops.js.map +1 -1
- package/dist/mesh/meshdata/parametric.js.map +1 -1
- package/dist/mesh/meshdata/weld.js.map +1 -1
- package/dist/node-host/cli.d.ts.map +1 -1
- package/dist/node-host/cli.js +3 -2
- package/dist/node-host/cli.js.map +1 -1
- package/dist/occt-kernel/occt-primitives.d.ts.map +1 -1
- package/dist/occt-kernel/occt-primitives.js +2 -0
- package/dist/occt-kernel/occt-primitives.js.map +1 -1
- package/dist/primitives/svg/svg-path.d.ts +192 -0
- package/dist/primitives/svg/svg-path.d.ts.map +1 -0
- package/dist/primitives/svg/svg-path.js +776 -0
- package/dist/primitives/svg/svg-path.js.map +1 -0
- package/dist/third-party/earcut.d.ts +19 -0
- package/dist/third-party/earcut.d.ts.map +1 -0
- package/dist/third-party/earcut.js +575 -0
- package/dist/third-party/earcut.js.map +1 -0
- package/package.json +10 -3
|
@@ -5,8 +5,10 @@
|
|
|
5
5
|
* (含其私有 `NAMED_VIEW_TO_AXIS`、`bboxMax`/`bboxMin`、`cad` 单例)。仅 import
|
|
6
6
|
* 路径改为 core 内部相对路径,逻辑逐行不变,零功能增减。
|
|
7
7
|
*
|
|
8
|
-
* @platform
|
|
9
|
-
* `getBrepApi()
|
|
8
|
+
* @platform neutral — 2026-10-12 内核无关化:面枚举/比较全部经
|
|
9
|
+
* `getBrepApi()`(BrepEngineApi,引擎中立)访问当前装配引擎,occt / brepkit
|
|
10
|
+
* 均可求值(双内核等价测试 `test/api/cadquery-selectors/selectors-brepkit.test.ts`
|
|
11
|
+
* 钉住)。此前直连 occt-wasm `getKernel()` 的 occt 耦合已移除。
|
|
10
12
|
*/
|
|
11
13
|
import type { Shape } from '../../mesh/types.js';
|
|
12
14
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"face.d.ts","sourceRoot":"","sources":["../../../src/api/cadquery-selectors/face.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"face.d.ts","sourceRoot":"","sources":["../../../src/api/cadquery-selectors/face.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAOH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAA;AAuE7C;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAsB,mBAAmB,CACvC,KAAK,EAAE,KAAK,EACZ,GAAG,EAAE,MAAM,EACX,YAAY,CAAC,EAAE,MAAM,GACpB,OAAO,CAAC;IAAE,MAAM,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IAAC,MAAM,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAA;CAAE,CAAC,CAsQjF"}
|
|
@@ -5,11 +5,12 @@
|
|
|
5
5
|
* (含其私有 `NAMED_VIEW_TO_AXIS`、`bboxMax`/`bboxMin`、`cad` 单例)。仅 import
|
|
6
6
|
* 路径改为 core 内部相对路径,逻辑逐行不变,零功能增减。
|
|
7
7
|
*
|
|
8
|
-
* @platform
|
|
9
|
-
* `getBrepApi()
|
|
8
|
+
* @platform neutral — 2026-10-12 内核无关化:面枚举/比较全部经
|
|
9
|
+
* `getBrepApi()`(BrepEngineApi,引擎中立)访问当前装配引擎,occt / brepkit
|
|
10
|
+
* 均可求值(双内核等价测试 `test/api/cadquery-selectors/selectors-brepkit.test.ts`
|
|
11
|
+
* 钉住)。此前直连 occt-wasm `getKernel()` 的 occt 耦合已移除。
|
|
10
12
|
*/
|
|
11
13
|
import { createApiNamespace } from '../api-namespace.js';
|
|
12
|
-
import { getKernel } from '../../occt-kernel/occtKernel.js';
|
|
13
14
|
import { getBrepApi } from '../../brep/handle-bridge.js';
|
|
14
15
|
import { brepOf } from '../../shape.js';
|
|
15
16
|
import { asBrepShape } from './borrow-bridge.js';
|
|
@@ -148,7 +149,7 @@ export async function resolveFaceSelector(shape, sel, centerOption) {
|
|
|
148
149
|
if (!handleM) {
|
|
149
150
|
throw new Error(`[cq-compat] selector "${sel}": BREP unavailable`);
|
|
150
151
|
}
|
|
151
|
-
const kernelM =
|
|
152
|
+
const kernelM = getBrepApi();
|
|
152
153
|
const faceList = kernelM.getSubShapes(handleM, 'face');
|
|
153
154
|
if (faceList.length === 0) {
|
|
154
155
|
throw new Error(`[cq-compat] selector "${sel}": shape has no faces`);
|
|
@@ -159,7 +160,7 @@ export async function resolveFaceSelector(shape, sel, centerOption) {
|
|
|
159
160
|
return [n.x, n.y, n.z];
|
|
160
161
|
};
|
|
161
162
|
const comOf = (f) => {
|
|
162
|
-
const c = kernelM.
|
|
163
|
+
const c = kernelM.surfaceCenterOfMass(f);
|
|
163
164
|
return [c.x, c.y, c.z];
|
|
164
165
|
};
|
|
165
166
|
const dot = (a, b) => a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
|
|
@@ -187,7 +188,7 @@ export async function resolveFaceSelector(shape, sel, centerOption) {
|
|
|
187
188
|
// ── Face-based selection (BREP kernel available) ──
|
|
188
189
|
try {
|
|
189
190
|
const handle = brepOf(shape);
|
|
190
|
-
const kernel =
|
|
191
|
+
const kernel = getBrepApi();
|
|
191
192
|
if (handle && dir) {
|
|
192
193
|
const faces = kernel.getSubShapes(handle, 'face');
|
|
193
194
|
const cands = [];
|
|
@@ -285,7 +286,7 @@ export async function resolveFaceSelector(shape, sel, centerOption) {
|
|
|
285
286
|
}
|
|
286
287
|
else {
|
|
287
288
|
// CenterOfMass: surface (area-weighted) centroid
|
|
288
|
-
const com = kernel.
|
|
289
|
+
const com = kernel.surfaceCenterOfMass(best.handle);
|
|
289
290
|
origin = [com.x, com.y, com.z];
|
|
290
291
|
}
|
|
291
292
|
return { center: origin, normal };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"face.js","sourceRoot":"","sources":["../../../src/api/cadquery-selectors/face.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * cadquery-selectors/face — CadQuery face 字符串选择器\n *\n * 等价搬运自 `packages/faijs-cadquery/src/workplane.ts` 的 `resolveFaceSelector`\n * (含其私有 `NAMED_VIEW_TO_AXIS`、`bboxMax`/`bboxMin`、`cad` 单例)。仅 import\n * 路径改为 core 内部相对路径,逻辑逐行不变,零功能增减。\n *\n * @platform occt — face 选择对 BREP 面做枚举/比较,经 `getKernel()` 与\n * `getBrepApi()` 访问 occt 原生内核(getSubShapes / surface 查询等)。\n */\n\nimport { createApiNamespace } from '../api-namespace'\nimport { getKernel } from '../../occt-kernel/occtKernel'\nimport { getBrepApi } from '../../brep/handle-bridge'\nimport type { BrepEngineApi } from '../../brep/engine/primitives'\nimport type { BrepHandle } from '../../brep/engine/types'\nimport { brepOf } from '../../shape'\nimport type { OcctKernel, ShapeHandle } from 'occt-wasm'\nimport type { Shape } from '../../mesh/types'\nimport { asBrepShape } from './borrow-bridge'\n\n// ── cad namespace singleton (created once at module load) ──────────────────\nconst cad = createApiNamespace() as Record<string, (...args: unknown[]) => Promise<Shape>>\n\n/** core 直连 helpers(原 cq-compat 私有 helper,等价搬运)。 */\nfunction kern(): BrepEngineApi {\n return getBrepApi()\n}\nfunction ownHandle(shape: Shape): BrepHandle {\n return brepOf(shape) as BrepHandle\n}\n\n/** Get bbox max of a shape (via cad.bboxMax — synchronous). */\nfunction bboxMax(shape: Shape): [number, number, number] {\n return cad.bboxMax(shape) as unknown as [number, number, number]\n}\n\n/** Get bbox min of a shape. */\nfunction bboxMin(shape: Shape): [number, number, number] {\n return cad.bboxMin(shape) as unknown as [number, number, number]\n}\n\n/**\n * Resolve a face selector to a world-space point (face center) and normal.\n *\n * CadQuery semantics: `faces(\">Z\")` selects the face(s) at the extreme of the\n * axis, and `workplane()` places the origin at the selected face's center —\n * `centerOption: \"CenterOfMass\"` (default) uses the face's surface centroid,\n * `\"CenterOfBoundBox\"` uses the face's bounding-box center.\n *\n * Supported forms: \">Z\", \"<Z\", \">X\", \"<X\", \">Y\", \"<Y\", \"+Z\"/\"-Z\" aliases, each\n * with an optional CadQuery-style index suffix like \">Z[-2]\". The six CadQuery\n * named views (\"front\"/\"back\"/\"left\"/\"right\"/\"top\"/\"bottom\") are accepted and\n * normalised to their axis equivalent (front=>\">Z\", back=>\"<Z\", left=>\"<X\",\n * right=>\">X\", top=>\">Y\", bottom=>\"<Y\"). This\n * implementation enumerates the actual BREP faces and picks the one whose\n * bbox-center is the extreme along the selector axis (ties broken by larger\n * surface area, so a main face wins over a small coplanar boss face). When the\n * shape has no BREP handle or the kernel is unavailable, it falls back to the\n * whole-shape bounding-box approximation.\n *\n * Indexed selectors (`\">Z[-2]\"`) follow CadQuery's DirectionMinMaxSelector\n * indexing, verified against the installed cadquery 2.8.0: `\">A[k]\"` lists all\n * faces ASCENDING along axis A (`[0]` = lowest, `[-1]` = highest); `\"<A[k]\"`\n * lists them DESCENDING (`[0]` = highest). The picked face's normal is the\n * outward direction (away from the shape bbox center).\n *\n * @param shape - Shape whose BREP faces are enumerated for selection.\n * @param sel - Selector string, e.g. \">Z\", \"<X\", \">Z[-2]\", or a named view\n * (\"front\"/\"back\"/\"left\"/\"right\"/\"top\"/\"bottom\").\n * @param centerOption - Optional center computation option forwarded to the\n * face-center evaluation.\n * @returns Promise resolving to the selected face's center point and outward\n * normal.\n */\n/**\n * CadQuery named views → axis selector (cadquery/selectors.py:687-694).\n * Verified against installed cadquery 2.8.0 by evaluating\n * `Workplane().rect(1,1).extrude(1).faces(n).val()` for each name.\n */\nconst NAMED_VIEW_TO_AXIS: Record<string, string> = {\n front: '>Z',\n back: '<Z',\n left: '<X',\n right: '>X',\n top: '>Y',\n bottom: '<Y',\n}\n\n/**\n * Resolve a CadQuery-style face selector string to the selected face's center\n * point and outward normal.\n *\n * Supported forms: \">Z\", \"<Z\", \">X\", \"<X\", \">Y\", \"<Y\", each with an optional\n * CadQuery-style index suffix like \">Z[-2]\", plus the six named views\n * (\"front\"/\"back\"/\"left\"/\"right\"/\"top\"/\"bottom\") which are aliases for the\n * corresponding axis selectors per cadquery/selectors.py:687-694.\n * @param shape - Shape whose BREP faces are enumerated for selection.\n * @param sel - Selector string, e.g. \">Z\", \"front\", \">Z[-2]\".\n * @param centerOption - Optional center computation option forwarded to the\n * face-center evaluation.\n * @returns Promise resolving to the selected face's center point and outward\n * normal.\n * @throws Error when the selector matches no face or has unknown syntax\n * (never falls back silently).\n */\nexport async function resolveFaceSelector(\n shape: Shape,\n sel: string,\n centerOption?: string,\n): Promise<{ center: [number, number, number]; normal: [number, number, number] }> {\n // compatOp 提升边界:实参可能是借用视图(见 asBrepShape 注释)——归一为真实\n // Shape,否则 brepOf 为 undefined 会落到 bbox 兜底并在 cad.bboxMax 崩溃。\n shape = asBrepShape(shape)\n // CadQuery named views are aliases for an axis DirectionMinMaxSelector\n // (cadquery/selectors.py:687-694):\n // front=>(0,0,1,max) back=>(0,0,1,min) left=>(1,0,0,min)\n // right=>(1,0,0,max) top=>(0,1,0,max) bottom=>(0,1,0,min)\n // Normalise once so every branch below sees a plain axis selector; without\n // this the lookup misses and the whole-shape bbox fallback silently returns\n // the shape centre instead of the face plane (half-a-hole volume error).\n sel = NAMED_VIEW_TO_AXIS[sel.trim().toLowerCase()] ?? sel\n // Strip index suffix like [-2]\n const baseSel = sel.replace(/\\[-?\\d+\\]$/, '')\n const axisDir: Record<string, { axis: 0 | 1 | 2; sign: 1 | -1 }> = {\n '>Z': { axis: 2, sign: 1 }, '+Z': { axis: 2, sign: 1 },\n '<Z': { axis: 2, sign: -1 }, '-Z': { axis: 2, sign: -1 },\n '>X': { axis: 0, sign: 1 }, '+X': { axis: 0, sign: 1 },\n '<X': { axis: 0, sign: -1 }, '-X': { axis: 0, sign: -1 },\n '>Y': { axis: 1, sign: 1 }, '+Y': { axis: 1, sign: 1 },\n '<Y': { axis: 1, sign: -1 }, '-Y': { axis: 1, sign: -1 },\n }\n const normals: Record<string, [number, number, number]> = {\n '>Z': [0, 0, 1], '+Z': [0, 0, 1], '<Z': [0, 0, -1], '-Z': [0, 0, -1],\n '>X': [1, 0, 0], '+X': [1, 0, 0], '<X': [-1, 0, 0], '-X': [-1, 0, 0],\n '>Y': [0, 1, 0], '+Y': [0, 1, 0], '<Y': [0, -1, 0], '-Y': [0, -1, 0],\n }\n const dir = axisDir[baseSel]\n const fallbackNormal = normals[baseSel] ?? ([0, 0, 1] as [number, number, number])\n\n // ── Multi-axis direction selectors (\"+XY\", \">XZ\", \"-YZ\" … cadquery\n // selectors.py:625 axes table XY=(1,1,0) XZ=(1,0,1) YZ=(0,1,1)) ──\n // '+'/'-' → DirectionSelector: only faces whose outward normal is PARALLEL\n // to the (±) direction (angle < 1e-4 rad, selectors.py:234). '>'/'<' →\n // DirectionMinMaxSelector (selectors.py:399): the face whose center of MASS\n // is farthest along the direction. Index suffixes mean DirectionNthSelector\n // there — not supported, throw instead of silently approximating.\n const multi = /^([<>+-])(XY|XZ|YZ)$/.exec(baseSel)\n if (multi) {\n if (/\\[-?\\d+\\]$/.test(sel.trim())) {\n throw new Error(\n `[cq-compat] selector \"${sel}\": indexed multi-axis selectors not supported`,\n )\n }\n const axesTable: Record<string, [number, number, number]> = {\n XY: [1, 1, 0],\n XZ: [1, 0, 1],\n YZ: [0, 1, 1],\n }\n let d = axesTable[multi[2]]\n if (multi[1] === '-') d = [-d[0], -d[1], -d[2]]\n const dLen = Math.hypot(d[0], d[1], d[2])\n const dirV: [number, number, number] = [d[0] / dLen, d[1] / dLen, d[2] / dLen]\n const handleM = brepOf(shape)\n if (!handleM) {\n throw new Error(`[cq-compat] selector \"${sel}\": BREP unavailable`)\n }\n const kernelM = getKernel() as unknown as OcctKernel\n const faceList = kernelM.getSubShapes(handleM as unknown as ShapeHandle, 'face') as unknown as ShapeHandle[]\n if (faceList.length === 0) {\n throw new Error(`[cq-compat] selector \"${sel}\": shape has no faces`)\n }\n const faceNormalOf = (f: ShapeHandle): [number, number, number] => {\n const uv = kernelM.uvBounds(f)\n const n = kernelM.surfaceNormal(f, (uv.uMin + uv.uMax) / 2, (uv.vMin + uv.vMax) / 2)\n return [n.x, n.y, n.z]\n }\n const comOf = (f: ShapeHandle): [number, number, number] => {\n const c = kernelM.getSurfaceCenterOfMass(f)\n return [c.x, c.y, c.z]\n }\n const dot = (a: [number, number, number], b: [number, number, number]): number =>\n a[0] * b[0] + a[1] * b[1] + a[2] * b[2]\n\n if (multi[1] === '+' || multi[1] === '-') {\n // DirectionSelector: angle(normal, dir) < 1e-4 rad (selectors.py:235).\n const PAR_TOL = Math.cos(1e-4)\n const found = faceList.find((f) => dot(faceNormalOf(f), dirV) > PAR_TOL)\n if (!found) {\n throw new Error(\n `[cq-compat] selector \"${sel}\": no face with normal parallel to the direction`,\n )\n }\n return { center: comOf(found), normal: faceNormalOf(found) }\n }\n // '>'/'<': DirectionMinMaxSelector over center-of-mass projections.\n let bestF: ShapeHandle | null = null\n let bestVal = 0\n for (const f of faceList) {\n const val = dot(comOf(f), dirV)\n if (!bestF || (multi[1] === '>' ? val > bestVal + 1e-9 : val < bestVal - 1e-9)) {\n bestF = f\n bestVal = val\n }\n }\n return { center: comOf(bestF!), normal: faceNormalOf(bestF!) }\n }\n\n // ── Face-based selection (BREP kernel available) ──\n try {\n const handle = brepOf(shape)\n const kernel = getKernel() as unknown as OcctKernel\n if (handle && dir) {\n const faces = kernel.getSubShapes(handle as unknown as ShapeHandle, 'face') as unknown as ShapeHandle[]\n const cands: { handle: ShapeHandle; center: [number, number, number] }[] = []\n for (const f of faces) {\n const bb = kernel.getBoundingBox(f)\n cands.push({\n handle: f,\n center: [\n (bb.xmin + bb.xmax) / 2,\n (bb.ymin + bb.ymax) / 2,\n (bb.zmin + bb.zmax) / 2,\n ],\n })\n }\n let best: { handle: ShapeHandle; center: [number, number, number] } | null = null\n let normal = fallbackNormal\n // Extract the index suffix, if any.\n const idxMatch = /\\[(-?\\d+)\\]$/.exec(sel.trim())\n if (idxMatch) {\n // CadQuery face indexing (verified vs cadquery 2.8.0):\n // '>A[k]' / '<A[k]' DirectionMinMaxSelector: '>' ascending, '<' descending\n // '+A[k]' / '-A[k]' DirectionSelector: list the extreme face first, then\n // inward — '-' ascending, '+' descending along A\n // (faces(\"-Y\")[1] is the 2nd -Y face from the -Y extreme,\n // NOT the +Y extreme face).\n // Only faces PERPENDICULAR to the axis participate (bbox thin along the axis).\n // For '+'/'-' selectors we additionally keep only faces whose outward normal\n // is parallel to the selector axis with the matching sign (CadQuery filters\n // by exact normal direction), so a boss face and its base sibling don't\n // collide in the index.\n const sc = baseSel[0]\n const isDirSelector = sc === '+' || sc === '-'\n const perp: typeof cands = cands.filter((cd) => {\n const bb = kernel.getBoundingBox(cd.handle)\n const ext = [bb.xmax - bb.xmin, bb.ymax - bb.ymin, bb.zmax - bb.zmin][dir.axis]\n if (ext > 0.1) return false\n if (isDirSelector) {\n const uv = kernel.uvBounds(cd.handle)\n const n = kernel.surfaceNormal(cd.handle, (uv.uMin + uv.uMax) / 2, (uv.vMin + uv.vMax) / 2)\n const nv: [number, number, number] = [n.x, n.y, n.z]\n if (Math.abs(nv[dir.axis]) < 0.999) return false\n if (Math.sign(nv[dir.axis]) !== dir.sign) return false\n }\n return true\n })\n const idx = parseInt(idxMatch[1], 10)\n const asc = sc === '>' || sc === '-'\n const sorted = perp\n .slice()\n .sort((a, b) => (asc ? a.center[dir.axis] - b.center[dir.axis] : b.center[dir.axis] - a.center[dir.axis]))\n const pick = idx < 0 ? sorted.length + idx : idx\n if (pick < 0 || pick >= sorted.length) {\n throw new Error(\n `[cq-compat] selector \"${sel}\": index ${idx} out of range (${sorted.length} faces)`,\n )\n }\n best = sorted[pick]\n if (isDirSelector) {\n // DirectionSelector: the outward normal is exactly the selector axis/sign.\n normal = fallbackNormal\n } else {\n // DirectionMinMaxSelector: outward normal from face position vs shape centre.\n const max = bboxMax(shape)\n const min = bboxMin(shape)\n const shapeCenter = [(max[0] + min[0]) / 2, (max[1] + min[1]) / 2, (max[2] + min[2]) / 2]\n normal = [0, 0, 0]\n normal[dir.axis] = best.center[dir.axis] >= shapeCenter[dir.axis] ? 1 : -1\n }\n } else {\n for (const cd of cands) {\n const val = cd.center[dir.axis]\n if (!best) {\n best = cd\n continue\n }\n const bestVal = best.center[dir.axis]\n if (dir.sign === 1 ? val > bestVal + 1e-6 : val < bestVal - 1e-6) {\n best = cd\n } else if (Math.abs(val - bestVal) <= 1e-6) {\n // Tie (e.g. coplanar faces at the same extreme): prefer the larger face\n const area = kernel.getSurfaceArea(cd.handle)\n if (area > kernel.getSurfaceArea(best.handle)) best = cd\n }\n }\n }\n if (best) {\n let origin: [number, number, number]\n if (centerOption === 'CenterOfBoundBox') {\n origin = best.center\n } else {\n // CenterOfMass: surface (area-weighted) centroid\n const com = kernel.getSurfaceCenterOfMass(best.handle)\n origin = [com.x, com.y, com.z]\n }\n return { center: origin, normal }\n }\n }\n } catch (e) {\n if (e instanceof Error && e.message.includes('out of range')) throw e\n // No BREP / kernel not ready — fall through to bbox approximation\n }\n\n // ── Fallback: whole-shape bbox (previous behavior) ──\n const max = bboxMax(shape)\n const min = bboxMin(shape)\n const center: [number, number, number] = [\n (max[0] + min[0]) / 2,\n (max[1] + min[1]) / 2,\n (max[2] + min[2]) / 2,\n ]\n\n const m = /^([<>+-])([XYZ])(?:\\[(-?\\d+)\\])?$/.exec(sel.trim())\n if (!m) {\n // Default: return center\n return { center, normal: [0, 0, 1] }\n }\n const [, sign, axisChar, idxStr] = m\n const axis = axisChar === 'X' ? 0 : axisChar === 'Y' ? 1 : 2\n // '>' and '+' select the max side; '<' and '-' select the min side.\n const maxDir = sign === '>' || sign === '+'\n const normal: [number, number, number] = [0, 0, 0]\n normal[axis] = maxDir ? 1 : -1\n\n if (idxStr === undefined) {\n const extreme: [number, number, number] = [center[0], center[1], center[2]]\n extreme[axis] = maxDir ? max[axis] : min[axis]\n return { center: extreme, normal }\n }\n\n // Indexed selector — enumerate real faces and sort by bbox center along axis.\n // CadQuery semantics: '>A[k]' ascending, '<A[k]' descending (see doc above).\n const idx = parseInt(idxStr, 10)\n const faces = kern().getSubShapes(ownHandle(shape), 'face') as unknown[]\n type Entry = { c: [number, number, number]; bounds: Record<string, number> }\n const entries: Entry[] = faces.map((f) => {\n const b = kern().getBoundingBox(f as BrepHandle) as unknown as Record<string, number>\n return {\n c: [(b.xmin + b.xmax) / 2, (b.ymin + b.ymax) / 2, (b.zmin + b.zmax) / 2],\n bounds: b,\n }\n })\n if (entries.length === 0) {\n throw new Error(`[cq-compat] selector \"${sel}\": shape has no faces`)\n }\n entries.sort((a, b) => (maxDir ? a.c[axis] - b.c[axis] : b.c[axis] - a.c[axis]))\n const pick = idx < 0 ? entries.length + idx : idx\n if (pick < 0 || pick >= entries.length) {\n throw new Error(\n `[cq-compat] selector \"${sel}\": index ${idx} out of range (${entries.length} faces)`,\n )\n }\n const fb = entries[pick].bounds\n const faceCenter: [number, number, number] = [\n (fb.xmin + fb.xmax) / 2,\n (fb.ymin + fb.ymax) / 2,\n (fb.zmin + fb.zmax) / 2,\n ]\n // Outward normal: away from the shape bbox center along the axis.\n normal[axis] = faceCenter[axis] >= center[axis] ? 1 : -1\n return { center: faceCenter, normal }\n}"]}
|
|
1
|
+
{"version":3,"file":"face.js","sourceRoot":"","sources":["../../../src/api/cadquery-selectors/face.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * cadquery-selectors/face — CadQuery face 字符串选择器\n *\n * 等价搬运自 `packages/faijs-cadquery/src/workplane.ts` 的 `resolveFaceSelector`\n * (含其私有 `NAMED_VIEW_TO_AXIS`、`bboxMax`/`bboxMin`、`cad` 单例)。仅 import\n * 路径改为 core 内部相对路径,逻辑逐行不变,零功能增减。\n *\n * @platform neutral — 2026-10-12 内核无关化:面枚举/比较全部经\n * `getBrepApi()`(BrepEngineApi,引擎中立)访问当前装配引擎,occt / brepkit\n * 均可求值(双内核等价测试 `test/api/cadquery-selectors/selectors-brepkit.test.ts`\n * 钉住)。此前直连 occt-wasm `getKernel()` 的 occt 耦合已移除。\n */\n\nimport { createApiNamespace } from '../api-namespace'\nimport { getBrepApi } from '../../brep/handle-bridge'\nimport type { BrepEngineApi } from '../../brep/engine/primitives'\nimport type { BrepHandle } from '../../brep/engine/types'\nimport { brepOf } from '../../shape'\nimport type { Shape } from '../../mesh/types'\nimport { asBrepShape } from './borrow-bridge'\n\n// ── cad namespace singleton (created once at module load) ──────────────────\nconst cad = createApiNamespace() as Record<string, (...args: unknown[]) => Promise<Shape>>\n\n/** core 直连 helpers(原 cq-compat 私有 helper,等价搬运)。 */\nfunction kern(): BrepEngineApi {\n return getBrepApi()\n}\nfunction ownHandle(shape: Shape): BrepHandle {\n return brepOf(shape) as BrepHandle\n}\n\n/** Get bbox max of a shape (via cad.bboxMax — synchronous). */\nfunction bboxMax(shape: Shape): [number, number, number] {\n return cad.bboxMax(shape) as unknown as [number, number, number]\n}\n\n/** Get bbox min of a shape. */\nfunction bboxMin(shape: Shape): [number, number, number] {\n return cad.bboxMin(shape) as unknown as [number, number, number]\n}\n\n/**\n * Resolve a face selector to a world-space point (face center) and normal.\n *\n * CadQuery semantics: `faces(\">Z\")` selects the face(s) at the extreme of the\n * axis, and `workplane()` places the origin at the selected face's center —\n * `centerOption: \"CenterOfMass\"` (default) uses the face's surface centroid,\n * `\"CenterOfBoundBox\"` uses the face's bounding-box center.\n *\n * Supported forms: \">Z\", \"<Z\", \">X\", \"<X\", \">Y\", \"<Y\", \"+Z\"/\"-Z\" aliases, each\n * with an optional CadQuery-style index suffix like \">Z[-2]\". The six CadQuery\n * named views (\"front\"/\"back\"/\"left\"/\"right\"/\"top\"/\"bottom\") are accepted and\n * normalised to their axis equivalent (front=>\">Z\", back=>\"<Z\", left=>\"<X\",\n * right=>\">X\", top=>\">Y\", bottom=>\"<Y\"). This\n * implementation enumerates the actual BREP faces and picks the one whose\n * bbox-center is the extreme along the selector axis (ties broken by larger\n * surface area, so a main face wins over a small coplanar boss face). When the\n * shape has no BREP handle or the kernel is unavailable, it falls back to the\n * whole-shape bounding-box approximation.\n *\n * Indexed selectors (`\">Z[-2]\"`) follow CadQuery's DirectionMinMaxSelector\n * indexing, verified against the installed cadquery 2.8.0: `\">A[k]\"` lists all\n * faces ASCENDING along axis A (`[0]` = lowest, `[-1]` = highest); `\"<A[k]\"`\n * lists them DESCENDING (`[0]` = highest). The picked face's normal is the\n * outward direction (away from the shape bbox center).\n *\n * @param shape - Shape whose BREP faces are enumerated for selection.\n * @param sel - Selector string, e.g. \">Z\", \"<X\", \">Z[-2]\", or a named view\n * (\"front\"/\"back\"/\"left\"/\"right\"/\"top\"/\"bottom\").\n * @param centerOption - Optional center computation option forwarded to the\n * face-center evaluation.\n * @returns Promise resolving to the selected face's center point and outward\n * normal.\n */\n/**\n * CadQuery named views → axis selector (cadquery/selectors.py:687-694).\n * Verified against installed cadquery 2.8.0 by evaluating\n * `Workplane().rect(1,1).extrude(1).faces(n).val()` for each name.\n */\nconst NAMED_VIEW_TO_AXIS: Record<string, string> = {\n front: '>Z',\n back: '<Z',\n left: '<X',\n right: '>X',\n top: '>Y',\n bottom: '<Y',\n}\n\n/**\n * Resolve a CadQuery-style face selector string to the selected face's center\n * point and outward normal.\n *\n * Supported forms: \">Z\", \"<Z\", \">X\", \"<X\", \">Y\", \"<Y\", each with an optional\n * CadQuery-style index suffix like \">Z[-2]\", plus the six named views\n * (\"front\"/\"back\"/\"left\"/\"right\"/\"top\"/\"bottom\") which are aliases for the\n * corresponding axis selectors per cadquery/selectors.py:687-694.\n * @param shape - Shape whose BREP faces are enumerated for selection.\n * @param sel - Selector string, e.g. \">Z\", \"front\", \">Z[-2]\".\n * @param centerOption - Optional center computation option forwarded to the\n * face-center evaluation.\n * @returns Promise resolving to the selected face's center point and outward\n * normal.\n * @throws Error when the selector matches no face or has unknown syntax\n * (never falls back silently).\n */\nexport async function resolveFaceSelector(\n shape: Shape,\n sel: string,\n centerOption?: string,\n): Promise<{ center: [number, number, number]; normal: [number, number, number] }> {\n // compatOp 提升边界:实参可能是借用视图(见 asBrepShape 注释)——归一为真实\n // Shape,否则 brepOf 为 undefined 会落到 bbox 兜底并在 cad.bboxMax 崩溃。\n shape = asBrepShape(shape)\n // CadQuery named views are aliases for an axis DirectionMinMaxSelector\n // (cadquery/selectors.py:687-694):\n // front=>(0,0,1,max) back=>(0,0,1,min) left=>(1,0,0,min)\n // right=>(1,0,0,max) top=>(0,1,0,max) bottom=>(0,1,0,min)\n // Normalise once so every branch below sees a plain axis selector; without\n // this the lookup misses and the whole-shape bbox fallback silently returns\n // the shape centre instead of the face plane (half-a-hole volume error).\n sel = NAMED_VIEW_TO_AXIS[sel.trim().toLowerCase()] ?? sel\n // Strip index suffix like [-2]\n const baseSel = sel.replace(/\\[-?\\d+\\]$/, '')\n const axisDir: Record<string, { axis: 0 | 1 | 2; sign: 1 | -1 }> = {\n '>Z': { axis: 2, sign: 1 }, '+Z': { axis: 2, sign: 1 },\n '<Z': { axis: 2, sign: -1 }, '-Z': { axis: 2, sign: -1 },\n '>X': { axis: 0, sign: 1 }, '+X': { axis: 0, sign: 1 },\n '<X': { axis: 0, sign: -1 }, '-X': { axis: 0, sign: -1 },\n '>Y': { axis: 1, sign: 1 }, '+Y': { axis: 1, sign: 1 },\n '<Y': { axis: 1, sign: -1 }, '-Y': { axis: 1, sign: -1 },\n }\n const normals: Record<string, [number, number, number]> = {\n '>Z': [0, 0, 1], '+Z': [0, 0, 1], '<Z': [0, 0, -1], '-Z': [0, 0, -1],\n '>X': [1, 0, 0], '+X': [1, 0, 0], '<X': [-1, 0, 0], '-X': [-1, 0, 0],\n '>Y': [0, 1, 0], '+Y': [0, 1, 0], '<Y': [0, -1, 0], '-Y': [0, -1, 0],\n }\n const dir = axisDir[baseSel]\n const fallbackNormal = normals[baseSel] ?? ([0, 0, 1] as [number, number, number])\n\n // ── Multi-axis direction selectors (\"+XY\", \">XZ\", \"-YZ\" … cadquery\n // selectors.py:625 axes table XY=(1,1,0) XZ=(1,0,1) YZ=(0,1,1)) ──\n // '+'/'-' → DirectionSelector: only faces whose outward normal is PARALLEL\n // to the (±) direction (angle < 1e-4 rad, selectors.py:234). '>'/'<' →\n // DirectionMinMaxSelector (selectors.py:399): the face whose center of MASS\n // is farthest along the direction. Index suffixes mean DirectionNthSelector\n // there — not supported, throw instead of silently approximating.\n const multi = /^([<>+-])(XY|XZ|YZ)$/.exec(baseSel)\n if (multi) {\n if (/\\[-?\\d+\\]$/.test(sel.trim())) {\n throw new Error(\n `[cq-compat] selector \"${sel}\": indexed multi-axis selectors not supported`,\n )\n }\n const axesTable: Record<string, [number, number, number]> = {\n XY: [1, 1, 0],\n XZ: [1, 0, 1],\n YZ: [0, 1, 1],\n }\n let d = axesTable[multi[2]]\n if (multi[1] === '-') d = [-d[0], -d[1], -d[2]]\n const dLen = Math.hypot(d[0], d[1], d[2])\n const dirV: [number, number, number] = [d[0] / dLen, d[1] / dLen, d[2] / dLen]\n const handleM = brepOf(shape)\n if (!handleM) {\n throw new Error(`[cq-compat] selector \"${sel}\": BREP unavailable`)\n }\n const kernelM = getBrepApi()\n const faceList = kernelM.getSubShapes(handleM as BrepHandle, 'face')\n if (faceList.length === 0) {\n throw new Error(`[cq-compat] selector \"${sel}\": shape has no faces`)\n }\n const faceNormalOf = (f: BrepHandle): [number, number, number] => {\n const uv = kernelM.uvBounds(f)\n const n = kernelM.surfaceNormal(f, (uv.uMin + uv.uMax) / 2, (uv.vMin + uv.vMax) / 2)\n return [n.x, n.y, n.z]\n }\n const comOf = (f: BrepHandle): [number, number, number] => {\n const c = kernelM.surfaceCenterOfMass(f)\n return [c.x, c.y, c.z]\n }\n const dot = (a: [number, number, number], b: [number, number, number]): number =>\n a[0] * b[0] + a[1] * b[1] + a[2] * b[2]\n\n if (multi[1] === '+' || multi[1] === '-') {\n // DirectionSelector: angle(normal, dir) < 1e-4 rad (selectors.py:235).\n const PAR_TOL = Math.cos(1e-4)\n const found = faceList.find((f) => dot(faceNormalOf(f), dirV) > PAR_TOL)\n if (!found) {\n throw new Error(\n `[cq-compat] selector \"${sel}\": no face with normal parallel to the direction`,\n )\n }\n return { center: comOf(found), normal: faceNormalOf(found) }\n }\n // '>'/'<': DirectionMinMaxSelector over center-of-mass projections.\n let bestF: BrepHandle | null = null\n let bestVal = 0\n for (const f of faceList) {\n const val = dot(comOf(f), dirV)\n if (!bestF || (multi[1] === '>' ? val > bestVal + 1e-9 : val < bestVal - 1e-9)) {\n bestF = f\n bestVal = val\n }\n }\n return { center: comOf(bestF!), normal: faceNormalOf(bestF!) }\n }\n\n // ── Face-based selection (BREP kernel available) ──\n try {\n const handle = brepOf(shape)\n const kernel = getBrepApi()\n if (handle && dir) {\n const faces = kernel.getSubShapes(handle as BrepHandle, 'face')\n const cands: { handle: BrepHandle; center: [number, number, number] }[] = []\n for (const f of faces) {\n const bb = kernel.getBoundingBox(f)\n cands.push({\n handle: f,\n center: [\n (bb.xmin + bb.xmax) / 2,\n (bb.ymin + bb.ymax) / 2,\n (bb.zmin + bb.zmax) / 2,\n ],\n })\n }\n let best: { handle: BrepHandle; center: [number, number, number] } | null = null\n let normal = fallbackNormal\n // Extract the index suffix, if any.\n const idxMatch = /\\[(-?\\d+)\\]$/.exec(sel.trim())\n if (idxMatch) {\n // CadQuery face indexing (verified vs cadquery 2.8.0):\n // '>A[k]' / '<A[k]' DirectionMinMaxSelector: '>' ascending, '<' descending\n // '+A[k]' / '-A[k]' DirectionSelector: list the extreme face first, then\n // inward — '-' ascending, '+' descending along A\n // (faces(\"-Y\")[1] is the 2nd -Y face from the -Y extreme,\n // NOT the +Y extreme face).\n // Only faces PERPENDICULAR to the axis participate (bbox thin along the axis).\n // For '+'/'-' selectors we additionally keep only faces whose outward normal\n // is parallel to the selector axis with the matching sign (CadQuery filters\n // by exact normal direction), so a boss face and its base sibling don't\n // collide in the index.\n const sc = baseSel[0]\n const isDirSelector = sc === '+' || sc === '-'\n const perp: typeof cands = cands.filter((cd) => {\n const bb = kernel.getBoundingBox(cd.handle)\n const ext = [bb.xmax - bb.xmin, bb.ymax - bb.ymin, bb.zmax - bb.zmin][dir.axis]\n if (ext > 0.1) return false\n if (isDirSelector) {\n const uv = kernel.uvBounds(cd.handle)\n const n = kernel.surfaceNormal(cd.handle, (uv.uMin + uv.uMax) / 2, (uv.vMin + uv.vMax) / 2)\n const nv: [number, number, number] = [n.x, n.y, n.z]\n if (Math.abs(nv[dir.axis]) < 0.999) return false\n if (Math.sign(nv[dir.axis]) !== dir.sign) return false\n }\n return true\n })\n const idx = parseInt(idxMatch[1], 10)\n const asc = sc === '>' || sc === '-'\n const sorted = perp\n .slice()\n .sort((a, b) => (asc ? a.center[dir.axis] - b.center[dir.axis] : b.center[dir.axis] - a.center[dir.axis]))\n const pick = idx < 0 ? sorted.length + idx : idx\n if (pick < 0 || pick >= sorted.length) {\n throw new Error(\n `[cq-compat] selector \"${sel}\": index ${idx} out of range (${sorted.length} faces)`,\n )\n }\n best = sorted[pick]\n if (isDirSelector) {\n // DirectionSelector: the outward normal is exactly the selector axis/sign.\n normal = fallbackNormal\n } else {\n // DirectionMinMaxSelector: outward normal from face position vs shape centre.\n const max = bboxMax(shape)\n const min = bboxMin(shape)\n const shapeCenter = [(max[0] + min[0]) / 2, (max[1] + min[1]) / 2, (max[2] + min[2]) / 2]\n normal = [0, 0, 0]\n normal[dir.axis] = best.center[dir.axis] >= shapeCenter[dir.axis] ? 1 : -1\n }\n } else {\n for (const cd of cands) {\n const val = cd.center[dir.axis]\n if (!best) {\n best = cd\n continue\n }\n const bestVal = best.center[dir.axis]\n if (dir.sign === 1 ? val > bestVal + 1e-6 : val < bestVal - 1e-6) {\n best = cd\n } else if (Math.abs(val - bestVal) <= 1e-6) {\n // Tie (e.g. coplanar faces at the same extreme): prefer the larger face\n const area = kernel.getSurfaceArea(cd.handle)\n if (area > kernel.getSurfaceArea(best.handle)) best = cd\n }\n }\n }\n if (best) {\n let origin: [number, number, number]\n if (centerOption === 'CenterOfBoundBox') {\n origin = best.center\n } else {\n // CenterOfMass: surface (area-weighted) centroid\n const com = kernel.surfaceCenterOfMass(best.handle)\n origin = [com.x, com.y, com.z]\n }\n return { center: origin, normal }\n }\n }\n } catch (e) {\n if (e instanceof Error && e.message.includes('out of range')) throw e\n // No BREP / kernel not ready — fall through to bbox approximation\n }\n\n // ── Fallback: whole-shape bbox (previous behavior) ──\n const max = bboxMax(shape)\n const min = bboxMin(shape)\n const center: [number, number, number] = [\n (max[0] + min[0]) / 2,\n (max[1] + min[1]) / 2,\n (max[2] + min[2]) / 2,\n ]\n\n const m = /^([<>+-])([XYZ])(?:\\[(-?\\d+)\\])?$/.exec(sel.trim())\n if (!m) {\n // Default: return center\n return { center, normal: [0, 0, 1] }\n }\n const [, sign, axisChar, idxStr] = m\n const axis = axisChar === 'X' ? 0 : axisChar === 'Y' ? 1 : 2\n // '>' and '+' select the max side; '<' and '-' select the min side.\n const maxDir = sign === '>' || sign === '+'\n const normal: [number, number, number] = [0, 0, 0]\n normal[axis] = maxDir ? 1 : -1\n\n if (idxStr === undefined) {\n const extreme: [number, number, number] = [center[0], center[1], center[2]]\n extreme[axis] = maxDir ? max[axis] : min[axis]\n return { center: extreme, normal }\n }\n\n // Indexed selector — enumerate real faces and sort by bbox center along axis.\n // CadQuery semantics: '>A[k]' ascending, '<A[k]' descending (see doc above).\n const idx = parseInt(idxStr, 10)\n const faces = kern().getSubShapes(ownHandle(shape), 'face') as unknown[]\n type Entry = { c: [number, number, number]; bounds: Record<string, number> }\n const entries: Entry[] = faces.map((f) => {\n const b = kern().getBoundingBox(f as BrepHandle) as unknown as Record<string, number>\n return {\n c: [(b.xmin + b.xmax) / 2, (b.ymin + b.ymax) / 2, (b.zmin + b.zmax) / 2],\n bounds: b,\n }\n })\n if (entries.length === 0) {\n throw new Error(`[cq-compat] selector \"${sel}\": shape has no faces`)\n }\n entries.sort((a, b) => (maxDir ? a.c[axis] - b.c[axis] : b.c[axis] - a.c[axis]))\n const pick = idx < 0 ? entries.length + idx : idx\n if (pick < 0 || pick >= entries.length) {\n throw new Error(\n `[cq-compat] selector \"${sel}\": index ${idx} out of range (${entries.length} faces)`,\n )\n }\n const fb = entries[pick].bounds\n const faceCenter: [number, number, number] = [\n (fb.xmin + fb.xmax) / 2,\n (fb.ymin + fb.ymax) / 2,\n (fb.zmin + fb.zmax) / 2,\n ]\n // Outward normal: away from the shape bbox center along the axis.\n normal[axis] = faceCenter[axis] >= center[axis] ? 1 : -1\n return { center: faceCenter, normal }\n}"]}
|
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
import type { EntityKind, SelStep } from './types.js';
|
|
2
|
-
import type { EntityGeom
|
|
2
|
+
import type { EntityGeom } from './entity.js';
|
|
3
|
+
import type { BrepHandle } from '../../brep/engine/types.js';
|
|
3
4
|
/** A set of candidate entities with their owning shape (for normal orientation). */
|
|
4
5
|
export interface Selection {
|
|
5
|
-
owner:
|
|
6
|
+
owner: BrepHandle | null;
|
|
6
7
|
items: EntityGeom[];
|
|
7
8
|
}
|
|
8
|
-
/** A fully-resolved narrowing chain: the surviving kind and
|
|
9
|
+
/** A fully-resolved narrowing chain: the surviving kind and engine handles. */
|
|
9
10
|
export interface ChainResult {
|
|
10
11
|
kind: EntityKind;
|
|
11
|
-
handles:
|
|
12
|
+
handles: BrepHandle[];
|
|
12
13
|
}
|
|
13
14
|
/**
|
|
14
15
|
* Multi-step `{kind, sel}` narrowing (plan §4.5). Each step collects the `kind`
|
|
@@ -23,7 +24,7 @@ export interface ChainResult {
|
|
|
23
24
|
* @param chain - The ordered per-kind narrowing steps to apply.
|
|
24
25
|
* @returns The final kind and the surviving kernel handles at that kind.
|
|
25
26
|
*/
|
|
26
|
-
export declare function resolveSelection(owner:
|
|
27
|
+
export declare function resolveSelection(owner: BrepHandle | null, chain: SelStep[]): ChainResult;
|
|
27
28
|
/**
|
|
28
29
|
* Narrow a single step and return the surviving kernel handles. Backs the
|
|
29
30
|
* `resolveEdgeSelection` / `resolveVertexSelector` / `resolveFaceEdgeSelection`
|
|
@@ -34,7 +35,7 @@ export declare function resolveSelection(owner: ShapeHandle | null, chain: SelSt
|
|
|
34
35
|
* @param sel - The CadQuery selector string for the step (may be empty).
|
|
35
36
|
* @returns The surviving kernel handles after the single-step narrowing.
|
|
36
37
|
*/
|
|
37
|
-
export declare function resolveStepHandles(owner:
|
|
38
|
+
export declare function resolveStepHandles(owner: BrepHandle | null, kind: EntityKind, sel: string): BrepHandle[];
|
|
38
39
|
/** ValueError-equivalent for an empty input to a N-th selector. */
|
|
39
40
|
export declare class EmptyNthError extends Error {
|
|
40
41
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resolve.d.ts","sourceRoot":"","sources":["../../../src/api/cadquery-selectors/resolve.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"resolve.d.ts","sourceRoot":"","sources":["../../../src/api/cadquery-selectors/resolve.ts"],"names":[],"mappings":"AAuBA,OAAO,KAAK,EAAY,UAAU,EAAgB,OAAO,EAAQ,MAAM,SAAS,CAAA;AAChF,OAAO,KAAK,EAAE,UAAU,EAAM,MAAM,UAAU,CAAA;AAC9C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAA;AAazD,oFAAoF;AACpF,MAAM,WAAW,SAAS;IACxB,KAAK,EAAE,UAAU,GAAG,IAAI,CAAA;IACxB,KAAK,EAAE,UAAU,EAAE,CAAA;CACpB;AAED,+EAA+E;AAC/E,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,UAAU,CAAA;IAChB,OAAO,EAAE,UAAU,EAAE,CAAA;CACtB;AASD;;;;;;;;;;;;GAYG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI,EAAE,KAAK,EAAE,OAAO,EAAE,GAAG,WAAW,CAwBxF;AAcD;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,UAAU,GAAG,IAAI,EACxB,IAAI,EAAE,UAAU,EAChB,GAAG,EAAE,MAAM,GACV,UAAU,EAAE,CAEd;AAoDD,mEAAmE;AACnE,qBAAa,aAAc,SAAQ,KAAK;CAAG"}
|
|
@@ -16,15 +16,15 @@
|
|
|
16
16
|
* Validated against the LOCKED cadquery 2.8.0 probe (C:\cqenv\sel_probe.py)
|
|
17
17
|
* — cube_off ground truth recorded in plan §5.2.
|
|
18
18
|
*
|
|
19
|
-
* @platform
|
|
20
|
-
*
|
|
21
|
-
*
|
|
19
|
+
* @platform neutral — 2026-10-12 内核无关化:identity 去重经 `getBrepApi()`
|
|
20
|
+
* (BrepEngineApi)访问当前装配引擎;occt / brepkit 均可求值(双内核等价测试
|
|
21
|
+
* `test/api/cadquery-selectors/selectors-brepkit.test.ts` 钉住)。
|
|
22
22
|
*/
|
|
23
|
-
import {
|
|
23
|
+
import { getBrepApi } from '../../brep/handle-bridge.js';
|
|
24
24
|
import { faceGeom, edgeGeom, vertexGeom, subShapeHandles } from './entity.js';
|
|
25
25
|
import { parseSelector } from './grammar.js';
|
|
26
26
|
import { NTH_TOLERANCE, isAligned, isDirectionCandidate, isParallel, isPerpendicular, typeMatches, entityDirection, } from './predicates.js';
|
|
27
|
-
/** Project
|
|
27
|
+
/** Project an engine handle of the given kind into its `EntityGeom`. */
|
|
28
28
|
function project(handle, kind) {
|
|
29
29
|
if (kind === 'face')
|
|
30
30
|
return faceGeom(handle);
|
|
@@ -46,10 +46,14 @@ function project(handle, kind) {
|
|
|
46
46
|
* @returns The final kind and the surviving kernel handles at that kind.
|
|
47
47
|
*/
|
|
48
48
|
export function resolveSelection(owner, chain) {
|
|
49
|
+
// ⚠️ 内核无关化 GOTCHA(2026-10-12 实测修复):owner 是内核句柄(BrepHandle =
|
|
50
|
+
// number & brand),**brepkit 的合法句柄可以是 0**(occt-wasm 从 1 开始)。
|
|
51
|
+
// 必须用 `!== null` 判断,绝不能用 truthy(`owner ? [owner] : []` 会把 0 号
|
|
52
|
+
// solid 丢弃成空候选)。
|
|
49
53
|
if (chain.length === 0) {
|
|
50
|
-
return { kind: 'face', handles: owner ? subShapeHandles(owner, 'face') : [] };
|
|
54
|
+
return { kind: 'face', handles: owner !== null ? subShapeHandles(owner, 'face') : [] };
|
|
51
55
|
}
|
|
52
|
-
let candidates = owner ? [owner] : [];
|
|
56
|
+
let candidates = owner !== null ? [owner] : [];
|
|
53
57
|
let kind = chain[0].kind;
|
|
54
58
|
for (const step of chain) {
|
|
55
59
|
// ① collect: sub-entities of each candidate, union/ordered, dedup by identity.
|
|
@@ -67,15 +71,13 @@ export function resolveSelection(owner, chain) {
|
|
|
67
71
|
/** Deduplicate kernel handles by KERNEL identity (isSame), preserving order. */
|
|
68
72
|
function dedupByIsSame(handles) {
|
|
69
73
|
const out = [];
|
|
74
|
+
const k = getBrepApi();
|
|
70
75
|
for (const h of handles) {
|
|
71
|
-
if (!out.some((o) =>
|
|
76
|
+
if (!out.some((o) => k.isSame(o, h)))
|
|
72
77
|
out.push(h);
|
|
73
78
|
}
|
|
74
79
|
return out;
|
|
75
80
|
}
|
|
76
|
-
function kernOf() {
|
|
77
|
-
return getKernel();
|
|
78
|
-
}
|
|
79
81
|
// ─── single-kind conveniences (plan §4.6) ────────────────────────────────
|
|
80
82
|
/**
|
|
81
83
|
* Narrow a single step and return the surviving kernel handles. Backs the
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resolve.js","sourceRoot":"","sources":["../../../src/api/cadquery-selectors/resolve.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * cadquery-selectors/resolve — evaluate a parsed `SelectorExpr` against a set\n * of candidate entities (plan §4.5). Clean-room re-encoding of\n * `cadquery/selectors.py`:\n *\n * · `_SimpleStringSyntaxSelector._chooseSelector` — atom → selector object\n * · `_NthSelector.cluster`/`filter` — center-projection sort + cluster\n * · `BaseDirSelector.filter` — linear edges / planar faces only, else drop\n * · `BinarySelector` set algebra (`AndSelector`/`SumSelector`/\n * `SubtractSelector`/`InverseSelector`) from the expression grammar.\n *\n * Every child of a set operation is applied to the SAME full input list and its\n * results combined (upstream `BinarySelector.filter`), so operands do not chain\n * into each other.\n *\n * Validated against the LOCKED cadquery 2.8.0 probe (C:\\cqenv\\sel_probe.py)\n * — cube_off ground truth recorded in plan §5.2.\n *\n * @platform occt — narrowing evaluates kernel `ShapeHandle`s through the\n * native occt-kernel (`getKernel()`: isSame identity dedup etc.), so this\n * module is occt-coupled by nature.\n */\nimport { getKernel } from '../../occt-kernel/occtKernel'\nimport type { OcctKernel } from 'occt-wasm'\nimport type { AtomDesc, EntityKind, SelectorExpr, SelStep, Vec3 } from './types'\nimport type { EntityGeom, P3, ShapeHandle } from './entity'\nimport { faceGeom, edgeGeom, vertexGeom, subShapeHandles } from './entity'\nimport { parseSelector } from './grammar'\nimport {\n NTH_TOLERANCE,\n isAligned,\n isDirectionCandidate,\n isParallel,\n isPerpendicular,\n typeMatches,\n entityDirection,\n} from './predicates'\n\n/** A set of candidate entities with their owning shape (for normal orientation). */\nexport interface Selection {\n owner: ShapeHandle | null\n items: EntityGeom[]\n}\n\n/** A fully-resolved narrowing chain: the surviving kind and kernel handles. */\nexport interface ChainResult {\n kind: EntityKind\n handles: ShapeHandle[]\n}\n\n/** Project a kernel handle of the given kind into its `EntityGeom`. */\nfunction project(handle: ShapeHandle, kind: EntityKind): EntityGeom {\n if (kind === 'face') return faceGeom(handle)\n if (kind === 'edge') return edgeGeom(handle)\n return vertexGeom(handle)\n}\n\n/**\n * Multi-step `{kind, sel}` narrowing (plan §4.5). Each step collects the `kind`\n * sub-entities of every currently-held object, dedups by kernel identity, then\n * filters by the parsed selector. An empty `sel` collects without filtering\n * (CadQuery `.vertices()` / `.edges()`, whose `_filter` is a no-op).\n *\n * resolveSelection(shape, [{face,'+Z'},{vertex,'<XY'}])\n * → the +Z face's vertices with the smallest x+y, in the order they appear.\n *\n * @param owner - The owning shape handle to start from (or `null` for empty).\n * @param chain - The ordered per-kind narrowing steps to apply.\n * @returns The final kind and the surviving kernel handles at that kind.\n */\nexport function resolveSelection(owner: ShapeHandle | null, chain: SelStep[]): ChainResult {\n if (chain.length === 0) {\n return { kind: 'face', handles: owner ? subShapeHandles(owner, 'face') : [] }\n }\n let candidates: ShapeHandle[] = owner ? [owner] : []\n let kind: EntityKind = chain[0].kind\n for (const step of chain) {\n // ① collect: sub-entities of each candidate, union/ordered, dedup by identity.\n const gathered: ShapeHandle[] = dedupByIsSame(\n candidates.flatMap((o) => subShapeHandles(o, step.kind)),\n )\n // ② filter: resolve the selector over the gathered views.\n const items = gathered.map((h) => project(h, step.kind))\n candidates =\n step.sel.trim() === ''\n ? gathered\n : evalExpr({ owner, items }, parseSelector(step.sel)).map((g) => g._handle)\n kind = step.kind\n }\n return { kind, handles: candidates }\n}\n\n/** Deduplicate kernel handles by KERNEL identity (isSame), preserving order. */\nfunction dedupByIsSame(handles: ShapeHandle[]): ShapeHandle[] {\n const out: ShapeHandle[] = []\n for (const h of handles) {\n if (!out.some((o) => kernOf().isSame(o as never, h as never))) out.push(h)\n }\n return out\n}\n\nfunction kernOf(): OcctKernel {\n return getKernel() as unknown as OcctKernel\n}\n\n// ─── single-kind conveniences (plan §4.6) ────────────────────────────────\n\n/**\n * Narrow a single step and return the surviving kernel handles. Backs the\n * `resolveEdgeSelection` / `resolveVertexSelector` / `resolveFaceEdgeSelection`\n * projections.\n *\n * @param owner - The owning shape handle to start from (or `null` for empty).\n * @param kind - The topological kind of the step.\n * @param sel - The CadQuery selector string for the step (may be empty).\n * @returns The surviving kernel handles after the single-step narrowing.\n */\nexport function resolveStepHandles(\n owner: ShapeHandle | null,\n kind: EntityKind,\n sel: string,\n): ShapeHandle[] {\n return resolveSelection(owner, [{ kind, sel }]).handles\n}\n\n/** Center dot direction — the ordering key for the N-th selectors. */\nfunction projKey(g: EntityGeom, axis: Vec3): number {\n const c = g.center()\n return c.x * axis.x + c.y * axis.y + c.z * axis.z\n}\n\n/**\n * `_NthSelector.cluster` + `filter`: sort by key, cluster consecutive items\n * within `NTH_TOLERANCE`, then return the cluster at index `n` of the list\n * reversed when `max` is false. An empty input raises (upstream\n * `_NthSelector.filter` ValueError); an out-of-range `n` raises IndexError.\n */\nfunction nthCluster(items: EntityGeom[], axis: Vec3, max: boolean, n: number): EntityGeom[] {\n if (items.length === 0) {\n throw new EmptyNthError('Can not return the Nth element of an empty list')\n }\n\n const keyed = items\n .map((g) => ({ g, key: projKey(g, axis) }))\n .sort((a, b) => a.key - b.key)\n\n const clusters: EntityGeom[][] = []\n let cur = [keyed[0].g]\n let start = keyed[0].key\n for (let i = 1; i < keyed.length; i++) {\n const { g, key } = keyed[i]\n if (Math.abs(key - start) <= NTH_TOLERANCE) {\n cur.push(g)\n } else {\n clusters.push(cur)\n cur = [g]\n start = key\n }\n }\n clusters.push(cur)\n\n // `_NthSelector.filter`: descending requires reversing the cluster list first.\n if (!max) clusters.reverse()\n\n // Python-style negative index (e.g. `>Z[-2]` ⇔ `clusters[-2]`).\n const idx = n < 0 ? clusters.length + n : n\n const out = clusters[idx]\n if (out === undefined) {\n throw new RangeError(\n `Attempted to access index ${n} of a list with length ${clusters.length}`,\n )\n }\n return out\n}\n\n/** ValueError-equivalent for an empty input to a N-th selector. */\nexport class EmptyNthError extends Error {}\n\n// ── set operations (BinarySelector) ────────────────────────────────────────\n\n/** `AndSelector`: intersection by kernel identity. */\nfunction intersect(a: EntityGeom[], b: EntityGeom[]): EntityGeom[] {\n const bs = new Set(b.map((g) => g.hash()))\n return a.filter((g) => bs.has(g.hash()))\n}\n\n/** `SumSelector`: union (no duplicates) by kernel identity. */\nfunction union(a: EntityGeom[], b: EntityGeom[]): EntityGeom[] {\n const seen = new Set<number>()\n const out: EntityGeom[] = []\n for (const g of a.concat(b)) {\n const h = g.hash()\n if (!seen.has(h)) {\n seen.add(h)\n out.push(g)\n }\n }\n return out\n}\n\n/** `SubtractSelector`: set difference by kernel identity. */\nfunction subtract(a: EntityGeom[], b: EntityGeom[]): EntityGeom[] {\n const bs = new Set(b.map((g) => g.hash()))\n return a.filter((g) => !bs.has(g.hash()))\n}\n\n// ── atom application ──────────────────────────────────────────────────────\n\n/** BaseDirSelector filter: the direction test over allowed entity kinds. */\nfunction filterByTest(\n items: EntityGeom[],\n owner: ShapeHandle | null,\n test: (d: P3) => boolean,\n): EntityGeom[] {\n const out: EntityGeom[] = []\n for (const g of items) {\n if (!isDirectionCandidate(g)) continue\n const d = entityDirection(g, owner ?? undefined)\n if (d !== null && test(d)) out.push(g)\n }\n return out\n}\n\n/** Apply one atom to the full candidate list, mirroring each selector.filter. */\nfunction applyAtom(items: EntityGeom[], owner: ShapeHandle | null, desc: AtomDesc): EntityGeom[] {\n switch (desc.kind) {\n case 'dir':\n // `DirectionSelector` (bare `X` or `(x,y,z)`): angle≈0, signed — same as\n // the `+` operator (upstream `only_dir` maps to DirectionSelector).\n return filterByTest(items, owner, (d) => isAligned(d, desc.vec, 1))\n case 'signed':\n return filterByTest(items, owner, (d) => isAligned(d, desc.vec, desc.sign))\n case 'parallel':\n return filterByTest(items, owner, (d) => isParallel(d, desc.vec))\n case 'perpendicular':\n return filterByTest(items, owner, (d) => isPerpendicular(d, desc.vec))\n case 'type':\n return items.filter((g) => typeMatches(g, desc.name))\n case 'minmax':\n // `DirectionMinMaxSelector` = CenterNthSelector(n=-1, max) — no pre-filter.\n return nthCluster(items, desc.vec, desc.max, -1)\n case 'minmaxNth': {\n // `DirectionNthSelector`: parallel pre-filter, then Nth cluster.\n const parallel = filterByTest(items, owner, (d) => isParallel(d, desc.vec))\n return nthCluster(parallel, desc.vec, desc.max, desc.n)\n }\n case 'centerNth': {\n // `CenterNthSelector`: no pre-filter, arbitrary index (n=-1 when absent).\n const n = desc.n ?? -1\n return nthCluster(items, desc.vec, desc.max, n)\n }\n }\n}\n\n// ── expression evaluation ─────────────────────────────────────────────────\n\n/** Evaluate an expression over the candidate list (upstream `Selector.filter`). */\nfunction evalExpr(sel: Selection, expr: SelectorExpr): EntityGeom[] {\n const { items, owner } = sel\n switch (expr.op) {\n case 'atom':\n return applyAtom(items, owner, expr.desc)\n case 'and': {\n let acc: EntityGeom[] | null = null\n for (const t of expr.terms) {\n const r = evalExpr({ items, owner }, t)\n acc = acc === null ? r : intersect(acc, r)\n }\n return acc ?? []\n }\n case 'or': {\n let acc: EntityGeom[] = []\n for (const t of expr.terms) {\n acc = union(acc, evalExpr({ items, owner }, t))\n }\n return acc\n }\n case 'exc': {\n let acc: EntityGeom[] = evalExpr({ items, owner }, expr.terms[0])\n for (let i = 1; i < expr.terms.length; i++) {\n acc = subtract(acc, evalExpr({ items, owner }, expr.terms[i]))\n }\n return acc\n }\n case 'not': {\n // `InverseSelector`: complement of the operand within the full list.\n const r = evalExpr({ items, owner }, expr.term)\n return subtract(items, r)\n }\n }\n}"]}
|
|
1
|
+
{"version":3,"file":"resolve.js","sourceRoot":"","sources":["../../../src/api/cadquery-selectors/resolve.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * cadquery-selectors/resolve — evaluate a parsed `SelectorExpr` against a set\n * of candidate entities (plan §4.5). Clean-room re-encoding of\n * `cadquery/selectors.py`:\n *\n * · `_SimpleStringSyntaxSelector._chooseSelector` — atom → selector object\n * · `_NthSelector.cluster`/`filter` — center-projection sort + cluster\n * · `BaseDirSelector.filter` — linear edges / planar faces only, else drop\n * · `BinarySelector` set algebra (`AndSelector`/`SumSelector`/\n * `SubtractSelector`/`InverseSelector`) from the expression grammar.\n *\n * Every child of a set operation is applied to the SAME full input list and its\n * results combined (upstream `BinarySelector.filter`), so operands do not chain\n * into each other.\n *\n * Validated against the LOCKED cadquery 2.8.0 probe (C:\\cqenv\\sel_probe.py)\n * — cube_off ground truth recorded in plan §5.2.\n *\n * @platform neutral — 2026-10-12 内核无关化:identity 去重经 `getBrepApi()`\n * (BrepEngineApi)访问当前装配引擎;occt / brepkit 均可求值(双内核等价测试\n * `test/api/cadquery-selectors/selectors-brepkit.test.ts` 钉住)。\n */\nimport { getBrepApi } from '../../brep/handle-bridge'\nimport type { AtomDesc, EntityKind, SelectorExpr, SelStep, Vec3 } from './types'\nimport type { EntityGeom, P3 } from './entity'\nimport type { BrepHandle } from '../../brep/engine/types'\nimport { faceGeom, edgeGeom, vertexGeom, subShapeHandles } from './entity'\nimport { parseSelector } from './grammar'\nimport {\n NTH_TOLERANCE,\n isAligned,\n isDirectionCandidate,\n isParallel,\n isPerpendicular,\n typeMatches,\n entityDirection,\n} from './predicates'\n\n/** A set of candidate entities with their owning shape (for normal orientation). */\nexport interface Selection {\n owner: BrepHandle | null\n items: EntityGeom[]\n}\n\n/** A fully-resolved narrowing chain: the surviving kind and engine handles. */\nexport interface ChainResult {\n kind: EntityKind\n handles: BrepHandle[]\n}\n\n/** Project an engine handle of the given kind into its `EntityGeom`. */\nfunction project(handle: BrepHandle, kind: EntityKind): EntityGeom {\n if (kind === 'face') return faceGeom(handle)\n if (kind === 'edge') return edgeGeom(handle)\n return vertexGeom(handle)\n}\n\n/**\n * Multi-step `{kind, sel}` narrowing (plan §4.5). Each step collects the `kind`\n * sub-entities of every currently-held object, dedups by kernel identity, then\n * filters by the parsed selector. An empty `sel` collects without filtering\n * (CadQuery `.vertices()` / `.edges()`, whose `_filter` is a no-op).\n *\n * resolveSelection(shape, [{face,'+Z'},{vertex,'<XY'}])\n * → the +Z face's vertices with the smallest x+y, in the order they appear.\n *\n * @param owner - The owning shape handle to start from (or `null` for empty).\n * @param chain - The ordered per-kind narrowing steps to apply.\n * @returns The final kind and the surviving kernel handles at that kind.\n */\nexport function resolveSelection(owner: BrepHandle | null, chain: SelStep[]): ChainResult {\n // ⚠️ 内核无关化 GOTCHA(2026-10-12 实测修复):owner 是内核句柄(BrepHandle =\n // number & brand),**brepkit 的合法句柄可以是 0**(occt-wasm 从 1 开始)。\n // 必须用 `!== null` 判断,绝不能用 truthy(`owner ? [owner] : []` 会把 0 号\n // solid 丢弃成空候选)。\n if (chain.length === 0) {\n return { kind: 'face', handles: owner !== null ? subShapeHandles(owner, 'face') : [] }\n }\n let candidates: BrepHandle[] = owner !== null ? [owner] : []\n let kind: EntityKind = chain[0].kind\n for (const step of chain) {\n // ① collect: sub-entities of each candidate, union/ordered, dedup by identity.\n const gathered: BrepHandle[] = dedupByIsSame(\n candidates.flatMap((o) => subShapeHandles(o, step.kind)),\n )\n // ② filter: resolve the selector over the gathered views.\n const items = gathered.map((h) => project(h, step.kind))\n candidates =\n step.sel.trim() === ''\n ? gathered\n : evalExpr({ owner, items }, parseSelector(step.sel)).map((g) => g._handle)\n kind = step.kind\n }\n return { kind, handles: candidates }\n}\n\n/** Deduplicate kernel handles by KERNEL identity (isSame), preserving order. */\nfunction dedupByIsSame(handles: BrepHandle[]): BrepHandle[] {\n const out: BrepHandle[] = []\n const k = getBrepApi()\n for (const h of handles) {\n if (!out.some((o) => k.isSame(o, h))) out.push(h)\n }\n return out\n}\n\n// ─── single-kind conveniences (plan §4.6) ────────────────────────────────\n\n/**\n * Narrow a single step and return the surviving kernel handles. Backs the\n * `resolveEdgeSelection` / `resolveVertexSelector` / `resolveFaceEdgeSelection`\n * projections.\n *\n * @param owner - The owning shape handle to start from (or `null` for empty).\n * @param kind - The topological kind of the step.\n * @param sel - The CadQuery selector string for the step (may be empty).\n * @returns The surviving kernel handles after the single-step narrowing.\n */\nexport function resolveStepHandles(\n owner: BrepHandle | null,\n kind: EntityKind,\n sel: string,\n): BrepHandle[] {\n return resolveSelection(owner, [{ kind, sel }]).handles\n}\n\n/** Center dot direction — the ordering key for the N-th selectors. */\nfunction projKey(g: EntityGeom, axis: Vec3): number {\n const c = g.center()\n return c.x * axis.x + c.y * axis.y + c.z * axis.z\n}\n\n/**\n * `_NthSelector.cluster` + `filter`: sort by key, cluster consecutive items\n * within `NTH_TOLERANCE`, then return the cluster at index `n` of the list\n * reversed when `max` is false. An empty input raises (upstream\n * `_NthSelector.filter` ValueError); an out-of-range `n` raises IndexError.\n */\nfunction nthCluster(items: EntityGeom[], axis: Vec3, max: boolean, n: number): EntityGeom[] {\n if (items.length === 0) {\n throw new EmptyNthError('Can not return the Nth element of an empty list')\n }\n\n const keyed = items\n .map((g) => ({ g, key: projKey(g, axis) }))\n .sort((a, b) => a.key - b.key)\n\n const clusters: EntityGeom[][] = []\n let cur = [keyed[0].g]\n let start = keyed[0].key\n for (let i = 1; i < keyed.length; i++) {\n const { g, key } = keyed[i]\n if (Math.abs(key - start) <= NTH_TOLERANCE) {\n cur.push(g)\n } else {\n clusters.push(cur)\n cur = [g]\n start = key\n }\n }\n clusters.push(cur)\n\n // `_NthSelector.filter`: descending requires reversing the cluster list first.\n if (!max) clusters.reverse()\n\n // Python-style negative index (e.g. `>Z[-2]` ⇔ `clusters[-2]`).\n const idx = n < 0 ? clusters.length + n : n\n const out = clusters[idx]\n if (out === undefined) {\n throw new RangeError(\n `Attempted to access index ${n} of a list with length ${clusters.length}`,\n )\n }\n return out\n}\n\n/** ValueError-equivalent for an empty input to a N-th selector. */\nexport class EmptyNthError extends Error {}\n\n// ── set operations (BinarySelector) ────────────────────────────────────────\n\n/** `AndSelector`: intersection by kernel identity. */\nfunction intersect(a: EntityGeom[], b: EntityGeom[]): EntityGeom[] {\n const bs = new Set(b.map((g) => g.hash()))\n return a.filter((g) => bs.has(g.hash()))\n}\n\n/** `SumSelector`: union (no duplicates) by kernel identity. */\nfunction union(a: EntityGeom[], b: EntityGeom[]): EntityGeom[] {\n const seen = new Set<number>()\n const out: EntityGeom[] = []\n for (const g of a.concat(b)) {\n const h = g.hash()\n if (!seen.has(h)) {\n seen.add(h)\n out.push(g)\n }\n }\n return out\n}\n\n/** `SubtractSelector`: set difference by kernel identity. */\nfunction subtract(a: EntityGeom[], b: EntityGeom[]): EntityGeom[] {\n const bs = new Set(b.map((g) => g.hash()))\n return a.filter((g) => !bs.has(g.hash()))\n}\n\n// ── atom application ──────────────────────────────────────────────────────\n\n/** BaseDirSelector filter: the direction test over allowed entity kinds. */\nfunction filterByTest(\n items: EntityGeom[],\n owner: BrepHandle | null,\n test: (d: P3) => boolean,\n): EntityGeom[] {\n const out: EntityGeom[] = []\n for (const g of items) {\n if (!isDirectionCandidate(g)) continue\n const d = entityDirection(g, owner ?? undefined)\n if (d !== null && test(d)) out.push(g)\n }\n return out\n}\n\n/** Apply one atom to the full candidate list, mirroring each selector.filter. */\nfunction applyAtom(items: EntityGeom[], owner: BrepHandle | null, desc: AtomDesc): EntityGeom[] {\n switch (desc.kind) {\n case 'dir':\n // `DirectionSelector` (bare `X` or `(x,y,z)`): angle≈0, signed — same as\n // the `+` operator (upstream `only_dir` maps to DirectionSelector).\n return filterByTest(items, owner, (d) => isAligned(d, desc.vec, 1))\n case 'signed':\n return filterByTest(items, owner, (d) => isAligned(d, desc.vec, desc.sign))\n case 'parallel':\n return filterByTest(items, owner, (d) => isParallel(d, desc.vec))\n case 'perpendicular':\n return filterByTest(items, owner, (d) => isPerpendicular(d, desc.vec))\n case 'type':\n return items.filter((g) => typeMatches(g, desc.name))\n case 'minmax':\n // `DirectionMinMaxSelector` = CenterNthSelector(n=-1, max) — no pre-filter.\n return nthCluster(items, desc.vec, desc.max, -1)\n case 'minmaxNth': {\n // `DirectionNthSelector`: parallel pre-filter, then Nth cluster.\n const parallel = filterByTest(items, owner, (d) => isParallel(d, desc.vec))\n return nthCluster(parallel, desc.vec, desc.max, desc.n)\n }\n case 'centerNth': {\n // `CenterNthSelector`: no pre-filter, arbitrary index (n=-1 when absent).\n const n = desc.n ?? -1\n return nthCluster(items, desc.vec, desc.max, n)\n }\n }\n}\n\n// ── expression evaluation ─────────────────────────────────────────────────\n\n/** Evaluate an expression over the candidate list (upstream `Selector.filter`). */\nfunction evalExpr(sel: Selection, expr: SelectorExpr): EntityGeom[] {\n const { items, owner } = sel\n switch (expr.op) {\n case 'atom':\n return applyAtom(items, owner, expr.desc)\n case 'and': {\n let acc: EntityGeom[] | null = null\n for (const t of expr.terms) {\n const r = evalExpr({ items, owner }, t)\n acc = acc === null ? r : intersect(acc, r)\n }\n return acc ?? []\n }\n case 'or': {\n let acc: EntityGeom[] = []\n for (const t of expr.terms) {\n acc = union(acc, evalExpr({ items, owner }, t))\n }\n return acc\n }\n case 'exc': {\n let acc: EntityGeom[] = evalExpr({ items, owner }, expr.terms[0])\n for (let i = 1; i < expr.terms.length; i++) {\n acc = subtract(acc, evalExpr({ items, owner }, expr.terms[i]))\n }\n return acc\n }\n case 'not': {\n // `InverseSelector`: complement of the operand within the full list.\n const r = evalExpr({ items, owner }, expr.term)\n return subtract(items, r)\n }\n }\n}"]}
|
package/dist/api/chamfer.js
CHANGED
|
@@ -188,7 +188,7 @@ function chamferBrep(input, params) {
|
|
|
188
188
|
// L1 面:chamferDistAngle/枚举/命名(D12)。equal 分支经 face-evolution 走 occt 平台面。
|
|
189
189
|
const kernel = getBrepApi();
|
|
190
190
|
const solid = brepOf(input);
|
|
191
|
-
if (
|
|
191
|
+
if (solid === undefined)
|
|
192
192
|
throw new Error('[api/chamfer] E_CHAMFER_NO_BREP: input is not BREP');
|
|
193
193
|
const edges = params.edges ?? [];
|
|
194
194
|
const type = params.type;
|
package/dist/api/chamfer.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chamfer.js","sourceRoot":"","sources":["../../src/api/chamfer.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * api chamfer — chamfer 倒角库函数(BREP-only,directEdit 族)\n *\n * 平台分层(2026-09-26 B 批降级):**中立 op**(不再声明 `engines:['occt']`)。\n * equal 分支按引擎事实**静态定轨**(与 intersect 同构,读 `hasNativeHistory`——\n * 引擎身份是唯一判据,没有能力集可读):\n * - occt(原生有 `chamferWithHistory`)→ `chamferWithRoleTable`(→ face-evolution.ts 的\n * occt 原生 `chamferWithHistory`,D3 面演化 + roleTable 传播)——历史路径,不回退;\n * - brepkit(无 `chamferWithHistory`,但裸 `kernel.chamfer` 是真实现)→ L1 裸\n * `kernel.chamfer(solid, edges, width)`:几何正确,**无面演化、无 roleTable 传播**\n * (如实降级,不伪造恒等映射)。\n * distanceAngle / twoDistances 分支本就走 L1 `kernel.chamferDistAngle`(brepkit 真实现,\n * 度→弧度方言在 brepkitKernel 内消化);occt 上仍挂 identityEvolution + 原 roleTable\n * (既有行为,零回退),brepkit 上同样不伪造演化。\n *\n * 与 drill/engrave 的差异:没有 mesh 实现(defineOp({ brep })),输入非 BREP\n * 时由 dispatchPath 抛 E_MESH_UNSUPPORTED。\n *\n * 类型:\n * - equal(对称):occt→chamferWithHistory;brepkit→kernel.chamfer(solid, edges, width)\n * - distanceAngle:kernel.chamferDistAngle(solid, edges, width, angle)\n * - twoDistances(双距):逐边按 §3.5 换算(width1,width2 + β → dF, θ),\n * per-edge 调 kernel.chamferDistAngle;凹棱(β ≥ 180°)→ E_CHAMFER_REFLEX_EDGE。\n */\n\nimport type { Shape } from '../mesh/types'\nimport { solidToShape } from '../brep/brep-ops'\nimport { chamferWithRoleTable, identityEvolution } from '../brep/face-evolution'\nimport { getBrepApi } from '../brep/handle-bridge'\nimport { getCurrentStmt } from '../runtime-state'\nimport { hasNativeHistory } from '../brep/engine/native-history'\nimport { fromBrep, brepOf, inputRoleTable } from '../shape'\nimport { defineOp } from '../sdk'\nimport type { BrepEngineApi } from '../brep/engine/primitives'\nimport type { BrepHandle } from '../brep/engine/types'\nimport type { EdgeTopoRef, ResolutionContext } from '../topology/naming'\nimport { resolveTopoRef, facesForQualifier, TopoRefError } from '../topology/naming'\nimport type { Provenance } from '../topology/naming/lineage'\nimport { buildEdgeResolutionContext, buildEdgeContextFromSolid } from './topo-resolve'\nimport { OpError } from './internal/result-unwrap'\nimport { meshKernelFailure, meshSolidEntry, meshSolidProduct, resolveMeshEdges } from './internal/mesh-solid-op'\nimport { angleBetweenNormals, materialDihedralFromNormalAngle, chamferAngleFromDistances } from './chamfer-math'\n\n// ── 参数自校验(api 层被直接 import 时的防御层)──\n\n/**\n * Validate chamfer parameters: `edges` must be a non-empty array of EdgeTopoRef,\n * each with kind key \"edge\" and a two-entry faces pair — or of 1-based ordinals\n * when `opts.allowOrdinals` (the mesh chain, which has no role layer to match\n * edges against).\n * @param params the raw chamfer operation parameters.\n * @param opts the selector-form options (mesh chain allows ordinals).\n */\nexport function assertChamferParams(\n params: Record<string, unknown>,\n opts?: { readonly allowOrdinals?: boolean },\n): void {\n const edges = params.edges\n if (!Array.isArray(edges) || edges.length === 0) {\n throw new Error('E_CHAMFER_NO_EDGES: chamfer requires at least one edge')\n }\n for (const e of edges) {\n if (opts?.allowOrdinals && typeof e === 'number') {\n if (!Number.isInteger(e) || e < 1) {\n throw new Error('E_CHAMFER_BAD_EDGE_REF: an edge ordinal must be a positive integer (1-based)')\n }\n continue\n }\n if (!e || typeof e !== 'object' || (e as { kind?: unknown }).kind !== 'edge') {\n throw new Error('E_CHAMFER_BAD_EDGE_REF: every edge entry must be an EdgeTopoRef with kind:\"edge\"')\n }\n const faces = (e as { faces?: unknown }).faces\n if (!Array.isArray(faces) || faces.length !== 2) {\n throw new Error('E_CHAMFER_BAD_EDGE_REF: EdgeTopoRef.faces must be a two-entry RoleQualifier pair')\n }\n }\n const type = params.type\n if (type !== 'equal' && type !== 'twoDistances' && type !== 'distanceAngle') {\n throw new Error('E_CHAMFER_BAD_TYPE: type must be equal | twoDistances | distanceAngle')\n }\n if (type === 'equal' || type === 'distanceAngle') {\n const width = params.width\n if (typeof width !== 'number' || !Number.isFinite(width) || width <= 0) {\n throw new Error('E_CHAMFER_BAD_WIDTH: chamfer.width must be a positive number')\n }\n if (type === 'distanceAngle') {\n const angle = params.angle\n if (typeof angle !== 'number' || !Number.isFinite(angle) || angle <= 0 || angle >= 90) {\n throw new Error('E_CHAMFER_BAD_ANGLE: chamfer.angle must be in (0, 90) degrees')\n }\n }\n } else {\n const w1 = params.width1\n const w2 = params.width2\n if (typeof w1 !== 'number' || !Number.isFinite(w1) || w1 <= 0) {\n throw new Error('E_CHAMFER_BAD_WIDTH: chamfer.width1 must be a positive number')\n }\n if (typeof w2 !== 'number' || !Number.isFinite(w2) || w2 <= 0) {\n throw new Error('E_CHAMFER_BAD_WIDTH: chamfer.width2 must be a positive number')\n }\n }\n}\n\n// ── §3.5 几何换算 ──\n\n/** 面中心外法向(与 captureFaceHint 同口径)。 */\nfunction faceMidNormal(kernel: BrepEngineApi, face: BrepHandle): [number, number, number] {\n const uv = kernel.uvBounds(face)\n const n = kernel.surfaceNormal(face, (uv.uMin + uv.uMax) / 2, (uv.vMin + uv.vMax) / 2)\n return [n.x, n.y, n.z]\n}\n\nfunction dot3(a: readonly number[], b: readonly number[]): number {\n return a[0] * b[0] + a[1] * b[1] + a[2] * b[2]\n}\n\nfunction radToDeg(rad: number): number {\n return (rad * 180) / Math.PI\n}\n\n/** 复刻 occt-wasm 的双层枚举(config.rs:517-527):返回内核选用的参考面在\n * `faceHandles`(getSubShapes(solid,'face'))数组中的下标(0 起);找不到 → null。 */\nfunction refFaceIndex(kernel: BrepEngineApi, faceHandles: BrepHandle[], edge: BrepHandle): number | null {\n for (let fi = 0; fi < faceHandles.length; fi++) {\n for (const fe of kernel.getSubShapes(faceHandles[fi], 'edge')) {\n if (kernel.isSame(fe, edge)) return fi\n }\n }\n return null\n}\n\n/** 两邻面 outer-normal 夹角 → β(材料侧二面角,弧度)。 */\nfunction materialDihedralRad(kernel: BrepEngineApi, ctx: ResolutionContext, a: number, b: number): number {\n const ha = ctx.faces[a - 1]?.handle\n const hb = ctx.faces[b - 1]?.handle\n if (ha === undefined || hb === undefined) {\n throw new TopoRefError('E_TOPO_NOT_FOUND', 'edge', `chamfer: adjacent face ${a}/${b} has no live handle`)\n }\n const gamma = angleBetweenNormals(dot3(faceMidNormal(kernel, ha), faceMidNormal(kernel, hb)))\n return materialDihedralFromNormalAngle(gamma)\n}\n\n/**\n * twoDistances 单边换算:width1/width2 + β(§3.5)→ (dF, θ) 供一次 chamferDistAngle。\n * 参考面由内核自选(refOrdinal 的面);width1 对应 faces[0] 侧、width2 对应 faces[1] 侧。\n *\n * @param kernel the OCCT kernel.\n * @param ctx the edge resolution context (faces with live handles).\n * @param refAOrdinal resolved ordinal of `EdgeTopoRef.faces[0]` (1-based).\n * @param refBOrdinal resolved ordinal of `EdgeTopoRef.faces[1]` (1-based).\n * @param refOrdinal the kernel reference face ordinal (1-based; the F in §3.5).\n * @param width1 the `width1` argument.\n * @param width2 the `width2` argument.\n * @returns { dF, angleDeg } for a single `kernel.chamferDistAngle` call.\n */\nexport function twoDistParams(\n kernel: BrepEngineApi,\n ctx: ResolutionContext,\n refAOrdinal: number,\n refBOrdinal: number,\n refOrdinal: number,\n width1: number,\n width2: number,\n): { distance: number; angleDeg: number } {\n const betaRad = materialDihedralRad(kernel, ctx, refAOrdinal, refBOrdinal)\n // dF/dO:§3.5 —— 内核参考面 == faces[0] → width1,== faces[1] → width2。\n let dF: number\n let dO: number\n if (refOrdinal === refAOrdinal) {\n dF = width1\n dO = width2\n } else if (refOrdinal === refBOrdinal) {\n dF = width2\n dO = width1\n } else {\n throw new Error(`E_CHAMFER_EDGE_MISMATCH: kernel ref face ordinal ${refOrdinal} not in [${refAOrdinal}, ${refBOrdinal}]`)\n }\n const angleRad = chamferAngleFromDistances(dF, dO, betaRad)\n return { distance: dF, angleDeg: radToDeg(angleRad) }\n}\n\n/** 解析一条 EdgeTopoRef → (ordinal, handle);失败抛命名层 TopoRefError。 */\nfunction resolveEdge(ctx: ResolutionContext, ref: EdgeTopoRef): { ordinal: number; handle: BrepHandle } {\n const r = resolveTopoRef(ref, ctx)\n if (r.handle === undefined) {\n throw new TopoRefError('E_TOPO_NOT_FOUND', 'edge', `chamfer: edge resolved without handle (${ref.faces[0].role}/${ref.faces[1].role})`)\n }\n return { ordinal: r.ordinal, handle: r.handle as BrepHandle }\n}\n\n/** twoDistances 逐边构建(§3.6 V1):每条边一次 chamferDistAngle。 */\nfunction chamferTwoDistances(\n kernel: BrepEngineApi,\n edges: EdgeTopoRef[],\n startCtx: ResolutionContext,\n solid: BrepHandle,\n width1: number,\n width2: number,\n): BrepHandle {\n let resultSolid = solid\n for (const ref of edges) {\n const ctx = resultSolid === solid ? startCtx : buildEdgeContextFromSolid(kernel, resultSolid, startCtx.roleTable)\n const entity = resolveEdge(ctx, ref)\n const faces = resultSolid === solid ? startCtx.faces : ctx.faces\n const idx = refFaceIndex(kernel, faces.map((f) => f.handle).filter((h): h is BrepHandle => h !== undefined), entity.handle)\n if (idx === null) {\n throw new Error('E_CHAMFER_EDGE_MISMATCH: kernel cannot locate ref face (bug)')\n }\n const a = facesForQualifier(ref.faces[0], ctx)[0]\n const b = facesForQualifier(ref.faces[1], ctx)[0]\n const refOrdinal = idx + 1\n const p = twoDistParams(kernel, ctx, a?.ordinal ?? -1, b?.ordinal ?? -1, refOrdinal, width1, width2)\n resultSolid = kernel.chamferDistAngle(resultSolid, [entity.handle], p.distance, p.angleDeg)\n }\n return resultSolid\n}\n\n/** BREP-only 主入口(§3.6 flow)。 */\nfunction chamferBrep(input: Shape, params: Record<string, unknown>): Shape {\n // L1 面:chamferDistAngle/枚举/命名(D12)。equal 分支经 face-evolution 走 occt 平台面。\n const kernel = getBrepApi()\n const solid = brepOf(input) as BrepHandle | undefined\n if (!solid) throw new Error('[api/chamfer] E_CHAMFER_NO_BREP: input is not BREP')\n\n const edges = (params.edges as unknown as EdgeTopoRef[] | undefined) ?? []\n const type = params.type as string\n const ctx = buildEdgeResolutionContext(kernel, input as object)\n if (!ctx) throw new TopoRefError('E_TOPO_NOT_FOUND', 'edge', 'input has no edge naming context')\n\n // 输入 roleTable + outStmt(与 boolean.ts / fillet.ts 同构)。Phase 1.6:origin=StmtId。\n const inputTable = inputRoleTable(input) as ReadonlyMap<unknown, unknown> | undefined\n const outStmt = String(getCurrentStmt()?.id ?? '')\n\n // 静态定轨:当前引擎是否原生实现 chamferWithHistory 面演化核函数(引擎事实,非运行时\n // 探测)。occt 有 → equal 走 chamferWithRoleTable 历史路径;brepkit 没有\n // (裸 kernel.chamfer 是真实现,但无 *WithHistory)→ L1 裸调用,\n // 不伪造面演化/roleTable(与 intersect 降级同构)。\n const useHistory = hasNativeHistory('chamferWithHistory')\n\n let resultSolid: BrepHandle\n let faceEvolution: Map<number, number[]> | undefined\n let roleTable: ReadonlyMap<unknown, unknown> | undefined\n\n switch (type) {\n case 'equal': {\n const edgeHandles = edges.map((e) => resolveEdge(ctx, e).handle)\n if (useHistory) {\n // occt 历史路径(P5:chamferWithHistory + roleTable 传播,§3.2 末段)\n const r = chamferWithRoleTable(\n kernel,\n solid,\n edgeHandles,\n params.width as number,\n inputTable ?? new Map(),\n outStmt,\n )\n resultSolid = r.result\n faceEvolution = r.faceEvolution\n roleTable = r.roleTable\n } else {\n // brepkit 裸降级:kernel.chamfer(solid, edges, width)——几何正确,无面演化。\n resultSolid = kernel.chamfer(solid, edgeHandles, params.width as number)\n faceEvolution = undefined\n roleTable = undefined\n }\n break\n }\n case 'distanceAngle':\n resultSolid = kernel.chamferDistAngle(solid, edges.map((e) => resolveEdge(ctx, e).handle), params.width as number, params.angle as number)\n if (useHistory) {\n // occt:chamferDistAngle 无 WithHistory 版本——用恒等面演化 + 原表(既有行为)。\n faceEvolution = identityEvolution(kernel, resultSolid)\n roleTable = inputTable\n } else {\n // brepkit:不伪造演化/roleTable。\n faceEvolution = undefined\n roleTable = undefined\n }\n break\n case 'twoDistances':\n resultSolid = chamferTwoDistances(kernel, edges, ctx, solid, params.width1 as number, params.width2 as number)\n if (useHistory) {\n faceEvolution = identityEvolution(kernel, resultSolid)\n roleTable = inputTable\n } else {\n faceEvolution = undefined\n roleTable = undefined\n }\n break\n default:\n throw new Error('E_CHAMFER_BAD_TYPE')\n }\n\n return fromBrep(\n solidToShape(kernel, resultSolid),\n faceEvolution ? { solid: resultSolid, faceEvolution, roleTable } : { solid: resultSolid, roleTable },\n )\n}\n\n/**\n * 网格实体路径:对近似拓扑里识别出的边倒角(方案 2026-10-01 §3.5 三明治)。\n *\n * 支持的形态与 BREP 路径的差异:\n * - `equal` → L1 裸 `kernel.chamfer`;`distanceAngle` → `kernel.chamferDistAngle`;\n * - `twoDistances` **不支持**:它要把 `faces[0]/faces[1]` 两个 role 限定符解析到面,\n * 再由内核选中的参考面决定 width1/width2 各归哪一侧。近似拓扑没有 role 层,\n * 这两个限定符无从解析——如实拒绝,不猜一个参考面(猜错 = 倒角落在错误的一侧)。\n *\n * 与 fillet 同一条 GOTCHA:一次请求里的全部边交给内核会在共面边链上被整体拒绝,\n * 本实现如实失败,不自动拆成逐边重试。\n *\n * @param input - the mesh-solid input.\n * @param params - the validated chamfer parameters.\n * @returns the chamfered mesh solid as a new mesh part.\n */\nfunction chamferMeshSolid(input: Shape, params: Record<string, unknown>): Shape {\n const type = params.type as string\n const edges = (params.edges as unknown as (number | EdgeTopoRef)[] | undefined) ?? []\n if (type === 'twoDistances') {\n throw new OpError(\n 'chamfer',\n 'E_MESH_SOLID_UNSUPPORTED',\n '[api/chamfer] twoDistances needs role-resolvable adjacent faces to decide which side ' +\n 'carries width1/width2; a mesh solid has no role layer — use type:\"equal\" or \"distanceAngle\"',\n )\n }\n const entry = meshSolidEntry(input, 'chamfer')\n const edgeHandles = resolveMeshEdges(entry, edges, 'chamfer')\n\n let result: BrepHandle\n try {\n result = type === 'distanceAngle'\n ? entry.kernel.chamferDistAngle(entry.solid, edgeHandles, params.width as number, params.angle as number)\n : entry.kernel.chamfer(entry.solid, edgeHandles, params.width as number)\n } catch (cause) {\n throw meshKernelFailure(\n 'chamfer',\n 'E_CHAMFER_FAILED',\n `chamfer(type=${type}) on ${edgeHandles.length} edge(s)`,\n cause,\n )\n }\n return meshSolidProduct(entry, result)\n}\n\n/**\n * 在几何体上倒角(等距 / 双距 / 距角)。\n * @group 特征\n * @inputs 1\n * @async true\n * @qual ok\n * @name chamfer\n * @note BREP 输入走完整三形态;**网格实体**输入只支持 `equal` / `distanceAngle`\n * (`twoDistances` 需要 role 可解析的邻面,近似拓扑没有 role)。\n * `width1` 沿 faces[0] 侧、`width2` 沿 faces[1] 侧(BREP 路径)。\n * @returns Shape 倒角后的几何。\n * @param input - 目标几何。type:Shape required:true\n * @param params.edges - 参与倒角的边(EdgeTopoRef[],条目为相邻两面的 role 线路)。type:EdgeTopoRef[] required:true\n * @param params.type - 倒角类型(equal | twoDistances | distanceAngle)。type:string required:true\n * @param params.width - type=equal: 倒角宽度(mm)。type:number 默认 1\n * @param params.width1 - type=twoDistances: 沿 faces[0] 侧距离(mm)。type:number\n * @param params.width2 - type=twoDistances: 沿 faces[1] 侧距离(mm)。type:number\n * @param params.angle - type=distanceAngle: 与参考面夹角(度,(0,90))。type:number\n * @example\n * const p = await cad.chamfer(part0, { edges: [{ kind:'edge', faces:[{ origin:'box', role:'box:top' }, { origin:'box', role:'box:front' }], hint:{ kind:'edge' } }], type:'equal', width:1 })\n * const q = await cad.chamfer(meshPart, { edges: [3], type:'equal', width:1 })\n */\nexport const chamfer = defineOp({\n // 中立 op(2026-09-26 B 批):不再声明 engines——equal 路径按引擎事实静态分派\n // (occt→chamferWithHistory 历史路径;brepkit→裸 kernel.chamfer 无演化降级)。\n // meshEngines:网格实体路径由 brepkit 网格后端提供(方案 2026-10-01 §3.4)。\n meshEngines: ['brepkit'],\n mesh(input: Shape, params: Record<string, unknown>) {\n assertChamferParams(params, { allowOrdinals: true })\n return chamferMeshSolid(input, params)\n },\n brep(input: Shape, params: Record<string, unknown>) {\n assertChamferParams(params)\n return chamferBrep(input, params)\n },\n naming: { kind: 'kernel', newFaces: { via: 'byAdjacency' } } as Provenance,\n\n paramDims: {},\n})\n"]}
|
|
1
|
+
{"version":3,"file":"chamfer.js","sourceRoot":"","sources":["../../src/api/chamfer.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * api chamfer — chamfer 倒角库函数(BREP-only,directEdit 族)\n *\n * 平台分层(2026-09-26 B 批降级):**中立 op**(不再声明 `engines:['occt']`)。\n * equal 分支按引擎事实**静态定轨**(与 intersect 同构,读 `hasNativeHistory`——\n * 引擎身份是唯一判据,没有能力集可读):\n * - occt(原生有 `chamferWithHistory`)→ `chamferWithRoleTable`(→ face-evolution.ts 的\n * occt 原生 `chamferWithHistory`,D3 面演化 + roleTable 传播)——历史路径,不回退;\n * - brepkit(无 `chamferWithHistory`,但裸 `kernel.chamfer` 是真实现)→ L1 裸\n * `kernel.chamfer(solid, edges, width)`:几何正确,**无面演化、无 roleTable 传播**\n * (如实降级,不伪造恒等映射)。\n * distanceAngle / twoDistances 分支本就走 L1 `kernel.chamferDistAngle`(brepkit 真实现,\n * 度→弧度方言在 brepkitKernel 内消化);occt 上仍挂 identityEvolution + 原 roleTable\n * (既有行为,零回退),brepkit 上同样不伪造演化。\n *\n * 与 drill/engrave 的差异:没有 mesh 实现(defineOp({ brep })),输入非 BREP\n * 时由 dispatchPath 抛 E_MESH_UNSUPPORTED。\n *\n * 类型:\n * - equal(对称):occt→chamferWithHistory;brepkit→kernel.chamfer(solid, edges, width)\n * - distanceAngle:kernel.chamferDistAngle(solid, edges, width, angle)\n * - twoDistances(双距):逐边按 §3.5 换算(width1,width2 + β → dF, θ),\n * per-edge 调 kernel.chamferDistAngle;凹棱(β ≥ 180°)→ E_CHAMFER_REFLEX_EDGE。\n */\n\nimport type { Shape } from '../mesh/types'\nimport { solidToShape } from '../brep/brep-ops'\nimport { chamferWithRoleTable, identityEvolution } from '../brep/face-evolution'\nimport { getBrepApi } from '../brep/handle-bridge'\nimport { getCurrentStmt } from '../runtime-state'\nimport { hasNativeHistory } from '../brep/engine/native-history'\nimport { fromBrep, brepOf, inputRoleTable } from '../shape'\nimport { defineOp } from '../sdk'\nimport type { BrepEngineApi } from '../brep/engine/primitives'\nimport type { BrepHandle } from '../brep/engine/types'\nimport type { EdgeTopoRef, ResolutionContext } from '../topology/naming'\nimport { resolveTopoRef, facesForQualifier, TopoRefError } from '../topology/naming'\nimport type { Provenance } from '../topology/naming/lineage'\nimport { buildEdgeResolutionContext, buildEdgeContextFromSolid } from './topo-resolve'\nimport { OpError } from './internal/result-unwrap'\nimport { meshKernelFailure, meshSolidEntry, meshSolidProduct, resolveMeshEdges } from './internal/mesh-solid-op'\nimport { angleBetweenNormals, materialDihedralFromNormalAngle, chamferAngleFromDistances } from './chamfer-math'\n\n// ── 参数自校验(api 层被直接 import 时的防御层)──\n\n/**\n * Validate chamfer parameters: `edges` must be a non-empty array of EdgeTopoRef,\n * each with kind key \"edge\" and a two-entry faces pair — or of 1-based ordinals\n * when `opts.allowOrdinals` (the mesh chain, which has no role layer to match\n * edges against).\n * @param params the raw chamfer operation parameters.\n * @param opts the selector-form options (mesh chain allows ordinals).\n */\nexport function assertChamferParams(\n params: Record<string, unknown>,\n opts?: { readonly allowOrdinals?: boolean },\n): void {\n const edges = params.edges\n if (!Array.isArray(edges) || edges.length === 0) {\n throw new Error('E_CHAMFER_NO_EDGES: chamfer requires at least one edge')\n }\n for (const e of edges) {\n if (opts?.allowOrdinals && typeof e === 'number') {\n if (!Number.isInteger(e) || e < 1) {\n throw new Error('E_CHAMFER_BAD_EDGE_REF: an edge ordinal must be a positive integer (1-based)')\n }\n continue\n }\n if (!e || typeof e !== 'object' || (e as { kind?: unknown }).kind !== 'edge') {\n throw new Error('E_CHAMFER_BAD_EDGE_REF: every edge entry must be an EdgeTopoRef with kind:\"edge\"')\n }\n const faces = (e as { faces?: unknown }).faces\n if (!Array.isArray(faces) || faces.length !== 2) {\n throw new Error('E_CHAMFER_BAD_EDGE_REF: EdgeTopoRef.faces must be a two-entry RoleQualifier pair')\n }\n }\n const type = params.type\n if (type !== 'equal' && type !== 'twoDistances' && type !== 'distanceAngle') {\n throw new Error('E_CHAMFER_BAD_TYPE: type must be equal | twoDistances | distanceAngle')\n }\n if (type === 'equal' || type === 'distanceAngle') {\n const width = params.width\n if (typeof width !== 'number' || !Number.isFinite(width) || width <= 0) {\n throw new Error('E_CHAMFER_BAD_WIDTH: chamfer.width must be a positive number')\n }\n if (type === 'distanceAngle') {\n const angle = params.angle\n if (typeof angle !== 'number' || !Number.isFinite(angle) || angle <= 0 || angle >= 90) {\n throw new Error('E_CHAMFER_BAD_ANGLE: chamfer.angle must be in (0, 90) degrees')\n }\n }\n } else {\n const w1 = params.width1\n const w2 = params.width2\n if (typeof w1 !== 'number' || !Number.isFinite(w1) || w1 <= 0) {\n throw new Error('E_CHAMFER_BAD_WIDTH: chamfer.width1 must be a positive number')\n }\n if (typeof w2 !== 'number' || !Number.isFinite(w2) || w2 <= 0) {\n throw new Error('E_CHAMFER_BAD_WIDTH: chamfer.width2 must be a positive number')\n }\n }\n}\n\n// ── §3.5 几何换算 ──\n\n/** 面中心外法向(与 captureFaceHint 同口径)。 */\nfunction faceMidNormal(kernel: BrepEngineApi, face: BrepHandle): [number, number, number] {\n const uv = kernel.uvBounds(face)\n const n = kernel.surfaceNormal(face, (uv.uMin + uv.uMax) / 2, (uv.vMin + uv.vMax) / 2)\n return [n.x, n.y, n.z]\n}\n\nfunction dot3(a: readonly number[], b: readonly number[]): number {\n return a[0] * b[0] + a[1] * b[1] + a[2] * b[2]\n}\n\nfunction radToDeg(rad: number): number {\n return (rad * 180) / Math.PI\n}\n\n/** 复刻 occt-wasm 的双层枚举(config.rs:517-527):返回内核选用的参考面在\n * `faceHandles`(getSubShapes(solid,'face'))数组中的下标(0 起);找不到 → null。 */\nfunction refFaceIndex(kernel: BrepEngineApi, faceHandles: BrepHandle[], edge: BrepHandle): number | null {\n for (let fi = 0; fi < faceHandles.length; fi++) {\n for (const fe of kernel.getSubShapes(faceHandles[fi], 'edge')) {\n if (kernel.isSame(fe, edge)) return fi\n }\n }\n return null\n}\n\n/** 两邻面 outer-normal 夹角 → β(材料侧二面角,弧度)。 */\nfunction materialDihedralRad(kernel: BrepEngineApi, ctx: ResolutionContext, a: number, b: number): number {\n const ha = ctx.faces[a - 1]?.handle\n const hb = ctx.faces[b - 1]?.handle\n if (ha === undefined || hb === undefined) {\n throw new TopoRefError('E_TOPO_NOT_FOUND', 'edge', `chamfer: adjacent face ${a}/${b} has no live handle`)\n }\n const gamma = angleBetweenNormals(dot3(faceMidNormal(kernel, ha), faceMidNormal(kernel, hb)))\n return materialDihedralFromNormalAngle(gamma)\n}\n\n/**\n * twoDistances 单边换算:width1/width2 + β(§3.5)→ (dF, θ) 供一次 chamferDistAngle。\n * 参考面由内核自选(refOrdinal 的面);width1 对应 faces[0] 侧、width2 对应 faces[1] 侧。\n *\n * @param kernel the OCCT kernel.\n * @param ctx the edge resolution context (faces with live handles).\n * @param refAOrdinal resolved ordinal of `EdgeTopoRef.faces[0]` (1-based).\n * @param refBOrdinal resolved ordinal of `EdgeTopoRef.faces[1]` (1-based).\n * @param refOrdinal the kernel reference face ordinal (1-based; the F in §3.5).\n * @param width1 the `width1` argument.\n * @param width2 the `width2` argument.\n * @returns { dF, angleDeg } for a single `kernel.chamferDistAngle` call.\n */\nexport function twoDistParams(\n kernel: BrepEngineApi,\n ctx: ResolutionContext,\n refAOrdinal: number,\n refBOrdinal: number,\n refOrdinal: number,\n width1: number,\n width2: number,\n): { distance: number; angleDeg: number } {\n const betaRad = materialDihedralRad(kernel, ctx, refAOrdinal, refBOrdinal)\n // dF/dO:§3.5 —— 内核参考面 == faces[0] → width1,== faces[1] → width2。\n let dF: number\n let dO: number\n if (refOrdinal === refAOrdinal) {\n dF = width1\n dO = width2\n } else if (refOrdinal === refBOrdinal) {\n dF = width2\n dO = width1\n } else {\n throw new Error(`E_CHAMFER_EDGE_MISMATCH: kernel ref face ordinal ${refOrdinal} not in [${refAOrdinal}, ${refBOrdinal}]`)\n }\n const angleRad = chamferAngleFromDistances(dF, dO, betaRad)\n return { distance: dF, angleDeg: radToDeg(angleRad) }\n}\n\n/** 解析一条 EdgeTopoRef → (ordinal, handle);失败抛命名层 TopoRefError。 */\nfunction resolveEdge(ctx: ResolutionContext, ref: EdgeTopoRef): { ordinal: number; handle: BrepHandle } {\n const r = resolveTopoRef(ref, ctx)\n if (r.handle === undefined) {\n throw new TopoRefError('E_TOPO_NOT_FOUND', 'edge', `chamfer: edge resolved without handle (${ref.faces[0].role}/${ref.faces[1].role})`)\n }\n return { ordinal: r.ordinal, handle: r.handle as BrepHandle }\n}\n\n/** twoDistances 逐边构建(§3.6 V1):每条边一次 chamferDistAngle。 */\nfunction chamferTwoDistances(\n kernel: BrepEngineApi,\n edges: EdgeTopoRef[],\n startCtx: ResolutionContext,\n solid: BrepHandle,\n width1: number,\n width2: number,\n): BrepHandle {\n let resultSolid = solid\n for (const ref of edges) {\n const ctx = resultSolid === solid ? startCtx : buildEdgeContextFromSolid(kernel, resultSolid, startCtx.roleTable)\n const entity = resolveEdge(ctx, ref)\n const faces = resultSolid === solid ? startCtx.faces : ctx.faces\n const idx = refFaceIndex(kernel, faces.map((f) => f.handle).filter((h): h is BrepHandle => h !== undefined), entity.handle)\n if (idx === null) {\n throw new Error('E_CHAMFER_EDGE_MISMATCH: kernel cannot locate ref face (bug)')\n }\n const a = facesForQualifier(ref.faces[0], ctx)[0]\n const b = facesForQualifier(ref.faces[1], ctx)[0]\n const refOrdinal = idx + 1\n const p = twoDistParams(kernel, ctx, a?.ordinal ?? -1, b?.ordinal ?? -1, refOrdinal, width1, width2)\n resultSolid = kernel.chamferDistAngle(resultSolid, [entity.handle], p.distance, p.angleDeg)\n }\n return resultSolid\n}\n\n/** BREP-only 主入口(§3.6 flow)。 */\nfunction chamferBrep(input: Shape, params: Record<string, unknown>): Shape {\n // L1 面:chamferDistAngle/枚举/命名(D12)。equal 分支经 face-evolution 走 occt 平台面。\n const kernel = getBrepApi()\n const solid = brepOf(input) as BrepHandle | undefined\n if (solid === undefined) throw new Error('[api/chamfer] E_CHAMFER_NO_BREP: input is not BREP')\n\n const edges = (params.edges as unknown as EdgeTopoRef[] | undefined) ?? []\n const type = params.type as string\n const ctx = buildEdgeResolutionContext(kernel, input as object)\n if (!ctx) throw new TopoRefError('E_TOPO_NOT_FOUND', 'edge', 'input has no edge naming context')\n\n // 输入 roleTable + outStmt(与 boolean.ts / fillet.ts 同构)。Phase 1.6:origin=StmtId。\n const inputTable = inputRoleTable(input) as ReadonlyMap<unknown, unknown> | undefined\n const outStmt = String(getCurrentStmt()?.id ?? '')\n\n // 静态定轨:当前引擎是否原生实现 chamferWithHistory 面演化核函数(引擎事实,非运行时\n // 探测)。occt 有 → equal 走 chamferWithRoleTable 历史路径;brepkit 没有\n // (裸 kernel.chamfer 是真实现,但无 *WithHistory)→ L1 裸调用,\n // 不伪造面演化/roleTable(与 intersect 降级同构)。\n const useHistory = hasNativeHistory('chamferWithHistory')\n\n let resultSolid: BrepHandle\n let faceEvolution: Map<number, number[]> | undefined\n let roleTable: ReadonlyMap<unknown, unknown> | undefined\n\n switch (type) {\n case 'equal': {\n const edgeHandles = edges.map((e) => resolveEdge(ctx, e).handle)\n if (useHistory) {\n // occt 历史路径(P5:chamferWithHistory + roleTable 传播,§3.2 末段)\n const r = chamferWithRoleTable(\n kernel,\n solid,\n edgeHandles,\n params.width as number,\n inputTable ?? new Map(),\n outStmt,\n )\n resultSolid = r.result\n faceEvolution = r.faceEvolution\n roleTable = r.roleTable\n } else {\n // brepkit 裸降级:kernel.chamfer(solid, edges, width)——几何正确,无面演化。\n resultSolid = kernel.chamfer(solid, edgeHandles, params.width as number)\n faceEvolution = undefined\n roleTable = undefined\n }\n break\n }\n case 'distanceAngle':\n resultSolid = kernel.chamferDistAngle(solid, edges.map((e) => resolveEdge(ctx, e).handle), params.width as number, params.angle as number)\n if (useHistory) {\n // occt:chamferDistAngle 无 WithHistory 版本——用恒等面演化 + 原表(既有行为)。\n faceEvolution = identityEvolution(kernel, resultSolid)\n roleTable = inputTable\n } else {\n // brepkit:不伪造演化/roleTable。\n faceEvolution = undefined\n roleTable = undefined\n }\n break\n case 'twoDistances':\n resultSolid = chamferTwoDistances(kernel, edges, ctx, solid, params.width1 as number, params.width2 as number)\n if (useHistory) {\n faceEvolution = identityEvolution(kernel, resultSolid)\n roleTable = inputTable\n } else {\n faceEvolution = undefined\n roleTable = undefined\n }\n break\n default:\n throw new Error('E_CHAMFER_BAD_TYPE')\n }\n\n return fromBrep(\n solidToShape(kernel, resultSolid),\n faceEvolution ? { solid: resultSolid, faceEvolution, roleTable } : { solid: resultSolid, roleTable },\n )\n}\n\n/**\n * 网格实体路径:对近似拓扑里识别出的边倒角(方案 2026-10-01 §3.5 三明治)。\n *\n * 支持的形态与 BREP 路径的差异:\n * - `equal` → L1 裸 `kernel.chamfer`;`distanceAngle` → `kernel.chamferDistAngle`;\n * - `twoDistances` **不支持**:它要把 `faces[0]/faces[1]` 两个 role 限定符解析到面,\n * 再由内核选中的参考面决定 width1/width2 各归哪一侧。近似拓扑没有 role 层,\n * 这两个限定符无从解析——如实拒绝,不猜一个参考面(猜错 = 倒角落在错误的一侧)。\n *\n * 与 fillet 同一条 GOTCHA:一次请求里的全部边交给内核会在共面边链上被整体拒绝,\n * 本实现如实失败,不自动拆成逐边重试。\n *\n * @param input - the mesh-solid input.\n * @param params - the validated chamfer parameters.\n * @returns the chamfered mesh solid as a new mesh part.\n */\nfunction chamferMeshSolid(input: Shape, params: Record<string, unknown>): Shape {\n const type = params.type as string\n const edges = (params.edges as unknown as (number | EdgeTopoRef)[] | undefined) ?? []\n if (type === 'twoDistances') {\n throw new OpError(\n 'chamfer',\n 'E_MESH_SOLID_UNSUPPORTED',\n '[api/chamfer] twoDistances needs role-resolvable adjacent faces to decide which side ' +\n 'carries width1/width2; a mesh solid has no role layer — use type:\"equal\" or \"distanceAngle\"',\n )\n }\n const entry = meshSolidEntry(input, 'chamfer')\n const edgeHandles = resolveMeshEdges(entry, edges, 'chamfer')\n\n let result: BrepHandle\n try {\n result = type === 'distanceAngle'\n ? entry.kernel.chamferDistAngle(entry.solid, edgeHandles, params.width as number, params.angle as number)\n : entry.kernel.chamfer(entry.solid, edgeHandles, params.width as number)\n } catch (cause) {\n throw meshKernelFailure(\n 'chamfer',\n 'E_CHAMFER_FAILED',\n `chamfer(type=${type}) on ${edgeHandles.length} edge(s)`,\n cause,\n )\n }\n return meshSolidProduct(entry, result)\n}\n\n/**\n * 在几何体上倒角(等距 / 双距 / 距角)。\n * @group 特征\n * @inputs 1\n * @async true\n * @qual ok\n * @name chamfer\n * @note BREP 输入走完整三形态;**网格实体**输入只支持 `equal` / `distanceAngle`\n * (`twoDistances` 需要 role 可解析的邻面,近似拓扑没有 role)。\n * `width1` 沿 faces[0] 侧、`width2` 沿 faces[1] 侧(BREP 路径)。\n * @returns Shape 倒角后的几何。\n * @param input - 目标几何。type:Shape required:true\n * @param params.edges - 参与倒角的边(EdgeTopoRef[],条目为相邻两面的 role 线路)。type:EdgeTopoRef[] required:true\n * @param params.type - 倒角类型(equal | twoDistances | distanceAngle)。type:string required:true\n * @param params.width - type=equal: 倒角宽度(mm)。type:number 默认 1\n * @param params.width1 - type=twoDistances: 沿 faces[0] 侧距离(mm)。type:number\n * @param params.width2 - type=twoDistances: 沿 faces[1] 侧距离(mm)。type:number\n * @param params.angle - type=distanceAngle: 与参考面夹角(度,(0,90))。type:number\n * @example\n * const p = await cad.chamfer(part0, { edges: [{ kind:'edge', faces:[{ origin:'box', role:'box:top' }, { origin:'box', role:'box:front' }], hint:{ kind:'edge' } }], type:'equal', width:1 })\n * const q = await cad.chamfer(meshPart, { edges: [3], type:'equal', width:1 })\n */\nexport const chamfer = defineOp({\n // 中立 op(2026-09-26 B 批):不再声明 engines——equal 路径按引擎事实静态分派\n // (occt→chamferWithHistory 历史路径;brepkit→裸 kernel.chamfer 无演化降级)。\n // meshEngines:网格实体路径由 brepkit 网格后端提供(方案 2026-10-01 §3.4)。\n meshEngines: ['brepkit'],\n mesh(input: Shape, params: Record<string, unknown>) {\n assertChamferParams(params, { allowOrdinals: true })\n return chamferMeshSolid(input, params)\n },\n brep(input: Shape, params: Record<string, unknown>) {\n assertChamferParams(params)\n return chamferBrep(input, params)\n },\n naming: { kind: 'kernel', newFaces: { via: 'byAdjacency' } } as Provenance,\n\n paramDims: {},\n})\n"]}
|
package/dist/api/draft.js
CHANGED
|
@@ -36,7 +36,7 @@ function draftBrep(input, params) {
|
|
|
36
36
|
}
|
|
37
37
|
const kernel = getBrepApi();
|
|
38
38
|
const solid = brepOf(input);
|
|
39
|
-
if (
|
|
39
|
+
if (solid === undefined)
|
|
40
40
|
throw new Error('E_DRAFT_NO_BREP: draft input is not BREP');
|
|
41
41
|
const ctx = buildEdgeResolutionContext(kernel, input);
|
|
42
42
|
if (!ctx)
|