brepjs 13.0.0 → 13.2.0
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/2d.cjs +3 -3
- package/dist/2d.js +3 -3
- package/dist/{arrayAccess-CccV7jov.js → arrayAccess-Dps31ERU.js} +3 -3
- package/dist/{arrayAccess-BF8Hm4-H.cjs → arrayAccess-peFKE9Ob.cjs} +3 -3
- package/dist/{blueprint-mSGgCL3V.js → blueprint-DYCdRlW5.js} +8 -8
- package/dist/{blueprint-BP3P8Ado.cjs → blueprint-PLJan-W5.cjs} +8 -8
- package/dist/{blueprintFns-BQ-MP_Vy.cjs → blueprintFns-Bsx25BG7.cjs} +3 -3
- package/dist/{blueprintFns-DWFkjbDT.js → blueprintFns-eWh7NpZx.js} +3 -3
- package/dist/{boolean2D-Cqfwz60G.js → boolean2D-52qVCooY.js} +10 -10
- package/dist/{boolean2D-D76Hc7Wx.cjs → boolean2D-CtB21ajK.cjs} +10 -10
- package/dist/{booleanFns-CYPXeNVN.cjs → booleanFns-BrptUFkP.cjs} +25 -13
- package/dist/{booleanFns-B79ALtKn.js → booleanFns-iM6UPb8e.js} +25 -13
- package/dist/brepjs.cjs +43 -311
- package/dist/brepjs.js +23 -306
- package/dist/core/errors.d.ts +7 -0
- package/dist/core/errors.d.ts.map +1 -1
- package/dist/core.cjs +3 -3
- package/dist/core.js +3 -3
- package/dist/{cornerFinder-BSwshSGB.js → cornerFinder-C7aDyYLJ.js} +2 -2
- package/dist/{cornerFinder-sg0JNgux.cjs → cornerFinder-SF-xmMO1.cjs} +2 -2
- package/dist/{curveFns-D_s3LdNT.js → curveFns-C-jU1_Y_.js} +2 -2
- package/dist/{curveFns-CJjkUGyW.cjs → curveFns-ywh7Ctyk.cjs} +2 -2
- package/dist/{drawFns-oyqai_HD.js → drawFns-D-0p86Lf.js} +13 -13
- package/dist/{drawFns-0CYuQn0J.cjs → drawFns-DknEB-Qs.cjs} +13 -13
- package/dist/{errors-B1fl3mAU.js → errors-B_T0aMQF.js} +7 -0
- package/dist/{errors-C85KVJr-.cjs → errors-DupKEMqI.cjs} +7 -0
- package/dist/{extrudeFns-0kBZvqJz.cjs → extrudeFns-CGCIbydL.cjs} +2 -2
- package/dist/{extrudeFns-lDvV4ir2.js → extrudeFns-LsH1rDMa.js} +2 -2
- package/dist/{faceFns-8BurpAGN.cjs → faceFns-8dGb8q3J.cjs} +2 -2
- package/dist/{faceFns-Bne5RIvn.js → faceFns-EnGcKFAr.js} +2 -2
- package/dist/{helpers-CxexSe1n.js → helpers-Rf0vhX6I.js} +6 -6
- package/dist/{helpers-D8DIMw2U.cjs → helpers-pQpV9Mwh.cjs} +6 -6
- package/dist/{historyFns-BTeasREV.js → historyFns-XkjLAQyu.js} +5 -5
- package/dist/{historyFns-BAzQr6EP.cjs → historyFns-lNalnOdR.cjs} +5 -5
- package/dist/{importFns-D__wN_Pq.cjs → importFns-BSH9cGIp.cjs} +36 -4
- package/dist/{importFns-clldr3EF.js → importFns-Bgs-FYAP.js} +31 -5
- package/dist/index.d.ts +8 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/io/stepConfigFns.d.ts +27 -0
- package/dist/io/stepConfigFns.d.ts.map +1 -0
- package/dist/io.cjs +3 -2
- package/dist/io.d.ts +1 -0
- package/dist/io.d.ts.map +1 -1
- package/dist/io.js +3 -3
- package/dist/kernel/brepkit/booleanOps.d.ts +7 -1
- package/dist/kernel/brepkit/booleanOps.d.ts.map +1 -1
- package/dist/kernel/brepkit/brepkitAdapter.d.ts +5 -4
- package/dist/kernel/brepkit/brepkitAdapter.d.ts.map +1 -1
- package/dist/kernel/brepkit/evolutionOps.d.ts +4 -4
- package/dist/kernel/brepkit/evolutionOps.d.ts.map +1 -1
- package/dist/kernel/interfaces/booleanOps.d.ts +3 -1
- package/dist/kernel/interfaces/booleanOps.d.ts.map +1 -1
- package/dist/kernel/interfaces/evolutionOps.d.ts +4 -4
- package/dist/kernel/interfaces/evolutionOps.d.ts.map +1 -1
- package/dist/kernel/occt/booleanOps.d.ts +7 -1
- package/dist/kernel/occt/booleanOps.d.ts.map +1 -1
- package/dist/kernel/occt/defaultAdapter.d.ts +5 -4
- package/dist/kernel/occt/defaultAdapter.d.ts.map +1 -1
- package/dist/kernel/occt/evolutionOps.d.ts +2 -2
- package/dist/kernel/occt/evolutionOps.d.ts.map +1 -1
- package/dist/kernel/occt/historyOps.d.ts +4 -4
- package/dist/kernel/occt/historyOps.d.ts.map +1 -1
- package/dist/kernel/occt/wasmTypes/occtBuilders.d.ts +4 -0
- package/dist/kernel/occt/wasmTypes/occtBuilders.d.ts.map +1 -1
- package/dist/kernel/types.d.ts +30 -0
- package/dist/kernel/types.d.ts.map +1 -1
- package/dist/{measureFns-DrMZGJ6r.cjs → measureFns-CFdHa_fj.cjs} +3 -3
- package/dist/{measureFns-C4WqH4OT.js → measureFns-D7J6qUY_.js} +3 -3
- package/dist/measurement.cjs +1 -1
- package/dist/measurement.js +1 -1
- package/dist/{meshFns-DvOM43vV.cjs → meshFns-2XnDXgIh.cjs} +3 -3
- package/dist/{meshFns--M5PTyHG.js → meshFns-B7uklc4M.js} +3 -3
- package/dist/operations.cjs +2 -2
- package/dist/operations.js +2 -2
- package/dist/{planeOps-DPintPbl.js → planeOps-BuBXTLBr.js} +1 -1
- package/dist/{planeOps-DdkIuVjk.cjs → planeOps-cTxDywpG.cjs} +1 -1
- package/dist/primitiveFns-CASk8g16.js +1452 -0
- package/dist/primitiveFns-DKtvEA0i.cjs +1817 -0
- package/dist/query.cjs +2 -2
- package/dist/query.js +2 -2
- package/dist/result.cjs +1 -1
- package/dist/result.js +1 -1
- package/dist/{shapeTypes-GmE4D5Q_.cjs → shapeTypes-CElaawp7.cjs} +114 -9
- package/dist/{shapeTypes-D38b_BKF.js → shapeTypes-CYb8Byqj.js} +114 -9
- package/dist/sketching.cjs +2 -2
- package/dist/sketching.js +2 -2
- package/dist/{solidBuilders-FaTmd_PS.js → solidBuilders-ClJxiUa3.js} +3 -3
- package/dist/{solidBuilders-BqU0oT2q.cjs → solidBuilders-Cs4XyL58.cjs} +3 -3
- package/dist/{surfaceBuilders-DiCVk_Un.js → surfaceBuilders-DnGdDW8i.js} +3 -3
- package/dist/{surfaceBuilders-BzDQQ4EG.cjs → surfaceBuilders-ZUTb3z6i.cjs} +3 -3
- package/dist/topology/booleanDiagnosticFns.d.ts +18 -0
- package/dist/topology/booleanDiagnosticFns.d.ts.map +1 -0
- package/dist/topology/booleanFns.d.ts.map +1 -1
- package/dist/topology/evolutionFns.d.ts +71 -0
- package/dist/topology/evolutionFns.d.ts.map +1 -0
- package/dist/topology/healingFns.d.ts +17 -0
- package/dist/topology/healingFns.d.ts.map +1 -1
- package/dist/topology/modifierFns.d.ts +15 -0
- package/dist/topology/modifierFns.d.ts.map +1 -1
- package/dist/topology/positionFns.d.ts +15 -0
- package/dist/topology/positionFns.d.ts.map +1 -0
- package/dist/topology.cjs +18 -6
- package/dist/topology.d.ts +6 -1
- package/dist/topology.d.ts.map +1 -1
- package/dist/topology.js +7 -7
- package/dist/vectors.cjs +1 -1
- package/dist/vectors.js +1 -1
- package/package.json +1 -1
- package/dist/primitiveFns-BXufrcii.cjs +0 -1063
- package/dist/primitiveFns-u3Bbdvlw.js +0 -806
|
@@ -1,806 +0,0 @@
|
|
|
1
|
-
import { Y as getKernel, _ as isSolid, c as createSolid, h as isShape3D, p as isFace, r as castShapeWithKnownType, t as castShape, x as isClosedWire, y as isWire } from "./shapeTypes-D38b_BKF.js";
|
|
2
|
-
import { C as isErr, _ as andThen, d as validationError, i as kernelError, k as ok, l as typeCastError, t as BrepErrorCode, w as isOk, y as err } from "./errors-B1fl3mAU.js";
|
|
3
|
-
import { _ as DEG2RAD, v as HASH_CODE_MAX } from "./vecOps-B9-MTeC8.js";
|
|
4
|
-
import { _ as downcast } from "./faceFns-Bne5RIvn.js";
|
|
5
|
-
import { I as getFaces, L as getOrCreateCache, v as translate, z as getWires } from "./arrayAccess-CccV7jov.js";
|
|
6
|
-
import { a as makeNonPlanarFace, c as makeBSplineApproximation, d as makeEllipse, f as makeEllipseArc, g as makeThreePointArc, h as makeTangentArc, i as makeNewFaceWithinFace, l as makeBezierCurve, m as makeLine, o as makePolygon, p as makeHelix, r as makeFace, s as assembleWire, t as addHolesInFace, u as makeCircle } from "./surfaceBuilders-DiCVk_Un.js";
|
|
7
|
-
import { a as makeOffset, c as makeTorus, i as makeEllipsoid, l as makeVertex, n as makeCone, o as makeSolid, r as makeCylinder, s as makeSphere, t as makeCompound, u as weldShellsAndFaces } from "./solidBuilders-FaTmd_PS.js";
|
|
8
|
-
//#region src/topology/threeHelpers.ts
|
|
9
|
-
/**
|
|
10
|
-
* Convert a ShapeMesh into BufferGeometry-compatible typed arrays.
|
|
11
|
-
*
|
|
12
|
-
* The returned arrays can be used directly with Three.js:
|
|
13
|
-
* ```ts
|
|
14
|
-
* const geo = new THREE.BufferGeometry();
|
|
15
|
-
* geo.setAttribute('position', new THREE.BufferAttribute(data.position, 3));
|
|
16
|
-
* geo.setAttribute('normal', new THREE.BufferAttribute(data.normal, 3));
|
|
17
|
-
* geo.setIndex(new THREE.BufferAttribute(data.index, 1));
|
|
18
|
-
* ```
|
|
19
|
-
*/
|
|
20
|
-
function toBufferGeometryData(mesh) {
|
|
21
|
-
return {
|
|
22
|
-
position: mesh.vertices,
|
|
23
|
-
normal: mesh.normals,
|
|
24
|
-
index: mesh.triangles
|
|
25
|
-
};
|
|
26
|
-
}
|
|
27
|
-
/**
|
|
28
|
-
* Convert a ShapeMesh into grouped BufferGeometry data with face material groups.
|
|
29
|
-
*
|
|
30
|
-
* Each face becomes a separate group, allowing per-face materials in Three.js:
|
|
31
|
-
* ```ts
|
|
32
|
-
* const data = toGroupedBufferGeometryData(mesh);
|
|
33
|
-
* const geo = new THREE.BufferGeometry();
|
|
34
|
-
* geo.setAttribute('position', new THREE.BufferAttribute(data.position, 3));
|
|
35
|
-
* geo.setAttribute('normal', new THREE.BufferAttribute(data.normal, 3));
|
|
36
|
-
* geo.setIndex(new THREE.BufferAttribute(data.index, 1));
|
|
37
|
-
* for (const g of data.groups) {
|
|
38
|
-
* geo.addGroup(g.start, g.count, g.materialIndex);
|
|
39
|
-
* }
|
|
40
|
-
* ```
|
|
41
|
-
*/
|
|
42
|
-
function toGroupedBufferGeometryData(mesh) {
|
|
43
|
-
return {
|
|
44
|
-
position: mesh.vertices,
|
|
45
|
-
normal: mesh.normals,
|
|
46
|
-
index: mesh.triangles,
|
|
47
|
-
groups: mesh.faceGroups.map((g, i) => ({
|
|
48
|
-
start: g.start,
|
|
49
|
-
count: g.count,
|
|
50
|
-
materialIndex: i,
|
|
51
|
-
faceId: g.faceId
|
|
52
|
-
}))
|
|
53
|
-
};
|
|
54
|
-
}
|
|
55
|
-
/**
|
|
56
|
-
* Convert an EdgeMesh into position data for THREE.LineSegments.
|
|
57
|
-
*
|
|
58
|
-
* ```ts
|
|
59
|
-
* const geo = new THREE.BufferGeometry();
|
|
60
|
-
* geo.setAttribute('position', new THREE.BufferAttribute(data.position, 3));
|
|
61
|
-
* const lines = new THREE.LineSegments(geo, material);
|
|
62
|
-
* ```
|
|
63
|
-
*/
|
|
64
|
-
function toLineGeometryData(mesh) {
|
|
65
|
-
return { position: mesh.lines };
|
|
66
|
-
}
|
|
67
|
-
//#endregion
|
|
68
|
-
//#region src/topology/chamferAngleFns.ts
|
|
69
|
-
/**
|
|
70
|
-
* Chamfer with distance + angle — functional API.
|
|
71
|
-
*
|
|
72
|
-
* Provides chamferDistAngle() which chamfers edges using a distance
|
|
73
|
-
* measured along one face and an angle to determine the chamfer on the other.
|
|
74
|
-
*/
|
|
75
|
-
/**
|
|
76
|
-
* Chamfer edges of a shape using distance + angle.
|
|
77
|
-
*
|
|
78
|
-
* The distance is measured along the face that contains the edge, and the
|
|
79
|
-
* angle (in degrees) determines how the chamfer cuts into the adjacent face.
|
|
80
|
-
*
|
|
81
|
-
* @param shape - The 3D shape to chamfer.
|
|
82
|
-
* @param edges - Edges to chamfer (must not be empty).
|
|
83
|
-
* @param distance - Chamfer distance along the face (must be positive).
|
|
84
|
-
* @param angleDeg - Chamfer angle in degrees (must be in range (0, 90)).
|
|
85
|
-
* @returns Ok with the chamfered shape, or Err on invalid input or kernel failure.
|
|
86
|
-
*
|
|
87
|
-
* @remarks Uses `BRepFilletAPI_MakeChamfer.AddDA(dist, angle, edge, face)` internally.
|
|
88
|
-
*/
|
|
89
|
-
function chamferDistAngle(shape, edges, distance, angleDeg) {
|
|
90
|
-
if (edges.length === 0) return err(validationError("CHAMFER_ANGLE_NO_EDGES", "chamferDistAngle requires at least one edge", void 0, { edgeCount: 0 }));
|
|
91
|
-
if (distance <= 0) return err(validationError("CHAMFER_ANGLE_BAD_DISTANCE", `distance must be positive, got ${distance}`, void 0, { distance }));
|
|
92
|
-
if (angleDeg <= 0 || angleDeg >= 90) return err(validationError("CHAMFER_ANGLE_BAD_ANGLE", `angleDeg must be in range (0, 90), got ${angleDeg}`, void 0, { angleDeg }));
|
|
93
|
-
let raw;
|
|
94
|
-
try {
|
|
95
|
-
const kernel = getKernel();
|
|
96
|
-
const rawEdges = edges.map((e) => e.wrapped);
|
|
97
|
-
raw = kernel.chamferDistAngle(shape.wrapped, rawEdges, distance, angleDeg);
|
|
98
|
-
} catch (e) {
|
|
99
|
-
return err(kernelError("CHAMFER_ANGLE_FAILED", `chamferDistAngle kernel call failed: ${e instanceof Error ? e.message : String(e)}`, e, {
|
|
100
|
-
distance,
|
|
101
|
-
angleDeg,
|
|
102
|
-
edgeCount: edges.length
|
|
103
|
-
}));
|
|
104
|
-
}
|
|
105
|
-
const downcastResult = downcast(raw);
|
|
106
|
-
if (isErr(downcastResult)) return downcastResult;
|
|
107
|
-
const wrapped = castShape(downcastResult.value);
|
|
108
|
-
if (!isShape3D(wrapped)) {
|
|
109
|
-
wrapped[Symbol.dispose]();
|
|
110
|
-
return err(typeCastError("CHAMFER_ANGLE_NOT_3D", "chamferDistAngle did not produce a 3D shape"));
|
|
111
|
-
}
|
|
112
|
-
return ok(wrapped);
|
|
113
|
-
}
|
|
114
|
-
//#endregion
|
|
115
|
-
//#region src/topology/adjacencyFns.ts
|
|
116
|
-
/**
|
|
117
|
-
* Topology adjacency queries — find related sub-shapes within a parent shape.
|
|
118
|
-
*
|
|
119
|
-
* Uses cached topology extraction and an edge→faces adjacency map
|
|
120
|
-
* (built once per parent shape and cached) to avoid redundant WASM calls.
|
|
121
|
-
*/
|
|
122
|
-
function wrapAll(shapes, type) {
|
|
123
|
-
return shapes.map((s) => castShapeWithKnownType(s, type));
|
|
124
|
-
}
|
|
125
|
-
/**
|
|
126
|
-
* Iterate sub-shapes of `parentKernel` of the given `type`, deduplicate by
|
|
127
|
-
* hash+isSame, and return branded handles of type `T`.
|
|
128
|
-
*
|
|
129
|
-
* Used by edgesOfFace, wiresOfFace, and verticesOfEdge — all of which need
|
|
130
|
-
* the same deduplicated-children pattern on a raw KernelShape.
|
|
131
|
-
*/
|
|
132
|
-
function deduplicatedSubShapes(parentKernel, type) {
|
|
133
|
-
const kernel = getKernel();
|
|
134
|
-
const items = kernel.iterShapes(parentKernel, type);
|
|
135
|
-
const results = [];
|
|
136
|
-
const seen = /* @__PURE__ */ new Map();
|
|
137
|
-
for (const item of items) {
|
|
138
|
-
const hash = kernel.hashCode(item, HASH_CODE_MAX);
|
|
139
|
-
const bucket = seen.get(hash);
|
|
140
|
-
if (!bucket) {
|
|
141
|
-
seen.set(hash, [item]);
|
|
142
|
-
results.push(item);
|
|
143
|
-
} else if (!bucket.some((r) => kernel.isSame(r, item))) {
|
|
144
|
-
bucket.push(item);
|
|
145
|
-
results.push(item);
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
return wrapAll(results, type);
|
|
149
|
-
}
|
|
150
|
-
/**
|
|
151
|
-
* Build or retrieve the cached edge→faces adjacency map for a parent shape.
|
|
152
|
-
* Maps edge hash codes to edge-face pairs, storing the edge alongside each
|
|
153
|
-
* face so facesOfEdge can verify via isSame without re-extracting face edges.
|
|
154
|
-
*/
|
|
155
|
-
function getEdgeToFacesMap(parent) {
|
|
156
|
-
const cache = getOrCreateCache(parent);
|
|
157
|
-
if (cache.edgeToFaces) return cache.edgeToFaces;
|
|
158
|
-
const kernel = getKernel();
|
|
159
|
-
const edgeToFaces = /* @__PURE__ */ new Map();
|
|
160
|
-
const allFaces = kernel.iterShapes(parent.wrapped, "face");
|
|
161
|
-
for (const f of allFaces) {
|
|
162
|
-
const edges = kernel.iterShapes(f, "edge");
|
|
163
|
-
for (const e of edges) {
|
|
164
|
-
const hash = kernel.hashCode(e, HASH_CODE_MAX);
|
|
165
|
-
let bucket = edgeToFaces.get(hash);
|
|
166
|
-
if (!bucket) {
|
|
167
|
-
bucket = [];
|
|
168
|
-
edgeToFaces.set(hash, bucket);
|
|
169
|
-
}
|
|
170
|
-
if (!bucket.some((entry) => kernel.isSame(entry.edge, e) && kernel.isSame(entry.face, f))) bucket.push({
|
|
171
|
-
edge: e,
|
|
172
|
-
face: f
|
|
173
|
-
});
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
cache.edgeToFaces = edgeToFaces;
|
|
177
|
-
return edgeToFaces;
|
|
178
|
-
}
|
|
179
|
-
/**
|
|
180
|
-
* Get all faces adjacent to a given edge within a parent shape.
|
|
181
|
-
*
|
|
182
|
-
* An edge typically borders exactly two faces in a solid, or one face
|
|
183
|
-
* if the edge is on a boundary.
|
|
184
|
-
*
|
|
185
|
-
* @param parent - The parent shape to search within.
|
|
186
|
-
* @param edge - The edge whose adjacent faces to find.
|
|
187
|
-
* @returns Array of unique faces containing the given edge.
|
|
188
|
-
*/
|
|
189
|
-
function facesOfEdge(parent, edge) {
|
|
190
|
-
const kernel = getKernel();
|
|
191
|
-
const edgeToFaces = getEdgeToFacesMap(parent);
|
|
192
|
-
const hash = kernel.hashCode(edge.wrapped, HASH_CODE_MAX);
|
|
193
|
-
const bucket = edgeToFaces.get(hash) ?? [];
|
|
194
|
-
const results = [];
|
|
195
|
-
const seen = /* @__PURE__ */ new Map();
|
|
196
|
-
for (const entry of bucket) {
|
|
197
|
-
if (!kernel.isSame(entry.edge, edge.wrapped)) continue;
|
|
198
|
-
const fHash = kernel.hashCode(entry.face, HASH_CODE_MAX);
|
|
199
|
-
const fBucket = seen.get(fHash);
|
|
200
|
-
if (!fBucket) {
|
|
201
|
-
seen.set(fHash, [entry.face]);
|
|
202
|
-
results.push(entry.face);
|
|
203
|
-
} else if (!fBucket.some((r) => kernel.isSame(r, entry.face))) {
|
|
204
|
-
fBucket.push(entry.face);
|
|
205
|
-
results.push(entry.face);
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
|
-
return wrapAll(results, "face");
|
|
209
|
-
}
|
|
210
|
-
/**
|
|
211
|
-
* Get all edges bounding a face.
|
|
212
|
-
*
|
|
213
|
-
* @param face - The face whose edges to enumerate.
|
|
214
|
-
* @returns Array of unique edges forming the face boundary.
|
|
215
|
-
*/
|
|
216
|
-
function edgesOfFace(face) {
|
|
217
|
-
return deduplicatedSubShapes(face.wrapped, "edge");
|
|
218
|
-
}
|
|
219
|
-
/**
|
|
220
|
-
* Get all wires of a face (outer wire + inner hole wires).
|
|
221
|
-
* All wires bounding a face are closed by definition.
|
|
222
|
-
*
|
|
223
|
-
* @param face - The face whose wires to enumerate.
|
|
224
|
-
*/
|
|
225
|
-
function wiresOfFace(face) {
|
|
226
|
-
return deduplicatedSubShapes(face.wrapped, "wire");
|
|
227
|
-
}
|
|
228
|
-
/**
|
|
229
|
-
* Get the start and end vertices of an edge.
|
|
230
|
-
*
|
|
231
|
-
* @param edge - The edge whose vertices to retrieve.
|
|
232
|
-
* @returns Array of 1-2 vertices (1 if degenerate/closed, 2 otherwise).
|
|
233
|
-
*/
|
|
234
|
-
function verticesOfEdge(edge) {
|
|
235
|
-
return deduplicatedSubShapes(edge.wrapped, "vertex");
|
|
236
|
-
}
|
|
237
|
-
/**
|
|
238
|
-
* Get all faces that share at least one edge with the given face.
|
|
239
|
-
*
|
|
240
|
-
* The returned list does not include the input face itself.
|
|
241
|
-
* Uses the cached edge→faces adjacency map for the parent shape.
|
|
242
|
-
*
|
|
243
|
-
* @param parent - The parent shape to search within.
|
|
244
|
-
* @param face - The face whose neighbors to find.
|
|
245
|
-
* @returns Array of unique adjacent faces (excluding the input face).
|
|
246
|
-
*/
|
|
247
|
-
function adjacentFaces(parent, face) {
|
|
248
|
-
const kernel = getKernel();
|
|
249
|
-
const edgeToFaces = getEdgeToFacesMap(parent);
|
|
250
|
-
const faceEdgeHandles = deduplicatedSubShapes(face.wrapped, "edge");
|
|
251
|
-
const neighborRaw = [];
|
|
252
|
-
const seen = /* @__PURE__ */ new Map();
|
|
253
|
-
for (const edgeHandle of faceEdgeHandles) {
|
|
254
|
-
const hash = kernel.hashCode(edgeHandle.wrapped, HASH_CODE_MAX);
|
|
255
|
-
const entries = edgeToFaces.get(hash) ?? [];
|
|
256
|
-
for (const entry of entries) {
|
|
257
|
-
if (kernel.isSame(entry.face, face.wrapped)) continue;
|
|
258
|
-
const fHash = kernel.hashCode(entry.face, HASH_CODE_MAX);
|
|
259
|
-
const bucket = seen.get(fHash);
|
|
260
|
-
if (!bucket) {
|
|
261
|
-
seen.set(fHash, [entry.face]);
|
|
262
|
-
neighborRaw.push(entry.face);
|
|
263
|
-
} else if (!bucket.some((r) => kernel.isSame(r, entry.face))) {
|
|
264
|
-
bucket.push(entry.face);
|
|
265
|
-
neighborRaw.push(entry.face);
|
|
266
|
-
}
|
|
267
|
-
}
|
|
268
|
-
}
|
|
269
|
-
return wrapAll(neighborRaw, "face");
|
|
270
|
-
}
|
|
271
|
-
/**
|
|
272
|
-
* Get all edges shared between two faces.
|
|
273
|
-
*
|
|
274
|
-
* @param face1 - The first face.
|
|
275
|
-
* @param face2 - The second face.
|
|
276
|
-
* @returns Array of edges present in both faces (via isSame comparison).
|
|
277
|
-
*/
|
|
278
|
-
function sharedEdges(face1, face2) {
|
|
279
|
-
const kernel = getKernel();
|
|
280
|
-
const edges1 = kernel.iterShapes(face1.wrapped, "edge");
|
|
281
|
-
const edges2 = kernel.iterShapes(face2.wrapped, "edge");
|
|
282
|
-
const edge2Map = /* @__PURE__ */ new Map();
|
|
283
|
-
for (const e2 of edges2) {
|
|
284
|
-
const hash = kernel.hashCode(e2, HASH_CODE_MAX);
|
|
285
|
-
let bucket = edge2Map.get(hash);
|
|
286
|
-
if (!bucket) {
|
|
287
|
-
bucket = [];
|
|
288
|
-
edge2Map.set(hash, bucket);
|
|
289
|
-
}
|
|
290
|
-
bucket.push(e2);
|
|
291
|
-
}
|
|
292
|
-
const shared = [];
|
|
293
|
-
for (const e1 of edges1) if (edge2Map.get(kernel.hashCode(e1, 2147483647))?.some((e2) => kernel.isSame(e1, e2))) shared.push(e1);
|
|
294
|
-
return wrapAll(shared, "edge");
|
|
295
|
-
}
|
|
296
|
-
//#endregion
|
|
297
|
-
//#region src/topology/healingFns.ts
|
|
298
|
-
/**
|
|
299
|
-
* Shape healing and validation functions.
|
|
300
|
-
*
|
|
301
|
-
* Uses ShapeFix_Solid, ShapeFix_Face, ShapeFix_Wire, and BRepCheck_Analyzer
|
|
302
|
-
* to validate and repair shapes.
|
|
303
|
-
*/
|
|
304
|
-
/**
|
|
305
|
-
* Check if a shape is valid according to kernel geometry and topology checks.
|
|
306
|
-
*/
|
|
307
|
-
function isValid(shape) {
|
|
308
|
-
return getKernel().isValid(shape.wrapped);
|
|
309
|
-
}
|
|
310
|
-
/**
|
|
311
|
-
* Attempt to heal/fix a solid shape.
|
|
312
|
-
*
|
|
313
|
-
* Uses ShapeFix_Solid to repair topology issues like gaps, wrong orientation, etc.
|
|
314
|
-
*/
|
|
315
|
-
function healSolid(solid) {
|
|
316
|
-
if (!isSolid(solid)) return err(validationError("NOT_A_SOLID", "Input shape is not a solid"));
|
|
317
|
-
const alreadyValid = isValid(solid);
|
|
318
|
-
try {
|
|
319
|
-
const result = getKernel().healSolid(solid.wrapped);
|
|
320
|
-
if (!result) {
|
|
321
|
-
if (alreadyValid) return ok(solid);
|
|
322
|
-
return err(kernelError(BrepErrorCode.HEAL_NO_EFFECT, "Solid healing had no effect — shape is still invalid"));
|
|
323
|
-
}
|
|
324
|
-
const cast = castShape(result);
|
|
325
|
-
if (!isSolid(cast)) return err(kernelError("HEAL_RESULT_NOT_SOLID", "Healed result is not a solid"));
|
|
326
|
-
if (!isValid(cast)) return err(kernelError("HEAL_SOLID_INCOMPLETE", "Healed result is still invalid after ShapeFix_Solid"));
|
|
327
|
-
return ok(cast);
|
|
328
|
-
} catch (e) {
|
|
329
|
-
return err(kernelError("HEAL_SOLID_FAILED", "Solid healing failed", e));
|
|
330
|
-
}
|
|
331
|
-
}
|
|
332
|
-
/**
|
|
333
|
-
* Attempt to heal/fix a face.
|
|
334
|
-
*
|
|
335
|
-
* Uses ShapeFix_Face to repair wire ordering, orientation, and geometry issues.
|
|
336
|
-
*/
|
|
337
|
-
function healFace(face) {
|
|
338
|
-
if (!isFace(face)) return err(validationError("NOT_A_FACE", "Input shape is not a face"));
|
|
339
|
-
try {
|
|
340
|
-
const cast = castShape(getKernel().healFace(face.wrapped));
|
|
341
|
-
if (!isFace(cast)) return err(kernelError("HEAL_RESULT_NOT_FACE", "Healed result is not a face"));
|
|
342
|
-
return ok(cast);
|
|
343
|
-
} catch (e) {
|
|
344
|
-
return err(kernelError("HEAL_FACE_FAILED", "Face healing failed", e));
|
|
345
|
-
}
|
|
346
|
-
}
|
|
347
|
-
/**
|
|
348
|
-
* Attempt to heal/fix a wire.
|
|
349
|
-
*
|
|
350
|
-
* Uses ShapeFix_Wire to repair edge connectivity, gaps, and self-intersections.
|
|
351
|
-
* Requires a face for surface context; pass `undefined` to use a default planar context.
|
|
352
|
-
*/
|
|
353
|
-
function healWire(wire, face) {
|
|
354
|
-
if (!isWire(wire)) return err(validationError("NOT_A_WIRE", "Input shape is not a wire"));
|
|
355
|
-
try {
|
|
356
|
-
const cast = castShape(getKernel().healWire(wire.wrapped, face?.wrapped));
|
|
357
|
-
if (!isWire(cast)) return err(kernelError("HEAL_RESULT_NOT_WIRE", "Healed result is not a wire"));
|
|
358
|
-
return ok(cast);
|
|
359
|
-
} catch (e) {
|
|
360
|
-
return err(kernelError("HEAL_WIRE_FAILED", "Wire healing failed", e));
|
|
361
|
-
}
|
|
362
|
-
}
|
|
363
|
-
/**
|
|
364
|
-
* Attempt to heal any shape by dispatching to the appropriate fixer.
|
|
365
|
-
*
|
|
366
|
-
* Supports solids, faces, and wires. For other shape types, returns the
|
|
367
|
-
* input unchanged.
|
|
368
|
-
*/
|
|
369
|
-
function heal(shape) {
|
|
370
|
-
if (isSolid(shape)) return healSolid(shape);
|
|
371
|
-
if (isFace(shape)) return healFace(shape);
|
|
372
|
-
if (isWire(shape)) return healWire(shape);
|
|
373
|
-
return ok(shape);
|
|
374
|
-
}
|
|
375
|
-
/**
|
|
376
|
-
* Automatically heal a shape using the appropriate shape-level fixer.
|
|
377
|
-
*
|
|
378
|
-
* If the shape is already valid, returns it unchanged with a no-op report.
|
|
379
|
-
* Uses ShapeFix_Solid/Face/Wire depending on shape type, which internally
|
|
380
|
-
* handles sub-shape healing and reconstruction.
|
|
381
|
-
*/
|
|
382
|
-
function autoHeal(shape, options) {
|
|
383
|
-
const fixWires = options?.fixWires !== false;
|
|
384
|
-
const fixFaces = options?.fixFaces !== false;
|
|
385
|
-
const fixSolids = options?.fixSolids !== false;
|
|
386
|
-
const fixSelfIntersection = options?.fixSelfIntersection === true;
|
|
387
|
-
const sewTolerance = options?.sewTolerance;
|
|
388
|
-
const steps = [];
|
|
389
|
-
const diagnostics = [];
|
|
390
|
-
if (isValid(shape)) return ok({
|
|
391
|
-
shape,
|
|
392
|
-
report: {
|
|
393
|
-
isValid: true,
|
|
394
|
-
alreadyValid: true,
|
|
395
|
-
wiresHealed: 0,
|
|
396
|
-
facesHealed: 0,
|
|
397
|
-
solidHealed: false,
|
|
398
|
-
steps: ["Shape already valid"],
|
|
399
|
-
diagnostics: [{
|
|
400
|
-
name: "validation",
|
|
401
|
-
attempted: true,
|
|
402
|
-
succeeded: true
|
|
403
|
-
}]
|
|
404
|
-
}
|
|
405
|
-
});
|
|
406
|
-
steps.push("Shape invalid — applying shape-level healing");
|
|
407
|
-
const wiresBefore = getWires(shape).length;
|
|
408
|
-
const facesBefore = getFaces(shape).length;
|
|
409
|
-
let current = shape;
|
|
410
|
-
let solidHealed = false;
|
|
411
|
-
if (sewTolerance !== void 0) try {
|
|
412
|
-
current = castShape(getKernel().sew([current.wrapped], sewTolerance));
|
|
413
|
-
steps.push(`Applied sewing with tolerance ${sewTolerance}`);
|
|
414
|
-
diagnostics.push({
|
|
415
|
-
name: "sew",
|
|
416
|
-
attempted: true,
|
|
417
|
-
succeeded: true,
|
|
418
|
-
detail: `tolerance=${sewTolerance}`
|
|
419
|
-
});
|
|
420
|
-
} catch (e) {
|
|
421
|
-
const detail = e instanceof Error ? e.message : String(e);
|
|
422
|
-
steps.push(`Sewing failed: ${detail}`);
|
|
423
|
-
diagnostics.push({
|
|
424
|
-
name: "sew",
|
|
425
|
-
attempted: true,
|
|
426
|
-
succeeded: false,
|
|
427
|
-
detail
|
|
428
|
-
});
|
|
429
|
-
}
|
|
430
|
-
if (fixSelfIntersection && fixWires) {
|
|
431
|
-
const wires = getWires(current);
|
|
432
|
-
let fixCount = 0;
|
|
433
|
-
for (const wire of wires) try {
|
|
434
|
-
getKernel().fixSelfIntersection(wire.wrapped);
|
|
435
|
-
fixCount++;
|
|
436
|
-
} catch {}
|
|
437
|
-
steps.push(`Self-intersection fix: ${fixCount}/${wires.length} wires`);
|
|
438
|
-
diagnostics.push({
|
|
439
|
-
name: "fixSelfIntersection",
|
|
440
|
-
attempted: true,
|
|
441
|
-
succeeded: fixCount > 0,
|
|
442
|
-
detail: `${fixCount}/${wires.length} wires fixed`
|
|
443
|
-
});
|
|
444
|
-
}
|
|
445
|
-
if (isSolid(current) && fixSolids || isFace(current) && fixFaces || isWire(current) && fixWires) {
|
|
446
|
-
const healResult = heal(current);
|
|
447
|
-
if (isOk(healResult)) {
|
|
448
|
-
current = healResult.value;
|
|
449
|
-
if (isSolid(shape)) {
|
|
450
|
-
solidHealed = true;
|
|
451
|
-
steps.push("Applied ShapeFix_Solid");
|
|
452
|
-
diagnostics.push({
|
|
453
|
-
name: "healSolid",
|
|
454
|
-
attempted: true,
|
|
455
|
-
succeeded: true
|
|
456
|
-
});
|
|
457
|
-
} else if (isFace(shape)) {
|
|
458
|
-
steps.push("Applied ShapeFix_Face");
|
|
459
|
-
diagnostics.push({
|
|
460
|
-
name: "healFace",
|
|
461
|
-
attempted: true,
|
|
462
|
-
succeeded: true
|
|
463
|
-
});
|
|
464
|
-
} else {
|
|
465
|
-
steps.push("Applied ShapeFix_Wire");
|
|
466
|
-
diagnostics.push({
|
|
467
|
-
name: "healWire",
|
|
468
|
-
attempted: true,
|
|
469
|
-
succeeded: true
|
|
470
|
-
});
|
|
471
|
-
}
|
|
472
|
-
} else {
|
|
473
|
-
steps.push("Shape-level healing failed");
|
|
474
|
-
diagnostics.push({
|
|
475
|
-
name: "healShape",
|
|
476
|
-
attempted: true,
|
|
477
|
-
succeeded: false
|
|
478
|
-
});
|
|
479
|
-
}
|
|
480
|
-
} else diagnostics.push({
|
|
481
|
-
name: "healShape",
|
|
482
|
-
attempted: false,
|
|
483
|
-
succeeded: false,
|
|
484
|
-
detail: "skipped by options"
|
|
485
|
-
});
|
|
486
|
-
const wiresAfter = getWires(current).length;
|
|
487
|
-
const facesAfter = getFaces(current).length;
|
|
488
|
-
const wiresHealed = Math.abs(wiresAfter - wiresBefore);
|
|
489
|
-
const facesHealed = Math.abs(facesAfter - facesBefore);
|
|
490
|
-
if (wiresHealed > 0) steps.push(`Wire count changed by ${wiresHealed}`);
|
|
491
|
-
if (facesHealed > 0) steps.push(`Face count changed by ${facesHealed}`);
|
|
492
|
-
const valid = isValid(current);
|
|
493
|
-
steps.push(valid ? "Final validation: valid" : "Final validation: still invalid");
|
|
494
|
-
diagnostics.push({
|
|
495
|
-
name: "finalValidation",
|
|
496
|
-
attempted: true,
|
|
497
|
-
succeeded: valid
|
|
498
|
-
});
|
|
499
|
-
return ok({
|
|
500
|
-
shape: current,
|
|
501
|
-
report: {
|
|
502
|
-
isValid: valid,
|
|
503
|
-
alreadyValid: false,
|
|
504
|
-
wiresHealed,
|
|
505
|
-
facesHealed,
|
|
506
|
-
solidHealed,
|
|
507
|
-
steps,
|
|
508
|
-
diagnostics
|
|
509
|
-
}
|
|
510
|
-
});
|
|
511
|
-
}
|
|
512
|
-
//#endregion
|
|
513
|
-
//#region src/topology/primitiveFns.ts
|
|
514
|
-
/**
|
|
515
|
-
* Create a box with the given dimensions.
|
|
516
|
-
*
|
|
517
|
-
* @param width - Size along X.
|
|
518
|
-
* @param depth - Size along Y.
|
|
519
|
-
* @param height - Size along Z.
|
|
520
|
-
*/
|
|
521
|
-
function box(width, depth, height, options) {
|
|
522
|
-
const solid = createSolid(getKernel().makeBox(width, depth, height));
|
|
523
|
-
const center = options?.at ?? (options?.centered ? [
|
|
524
|
-
0,
|
|
525
|
-
0,
|
|
526
|
-
0
|
|
527
|
-
] : void 0);
|
|
528
|
-
if (center) return translate(solid, [
|
|
529
|
-
center[0] - width / 2,
|
|
530
|
-
center[1] - depth / 2,
|
|
531
|
-
center[2] - height / 2
|
|
532
|
-
]);
|
|
533
|
-
return solid;
|
|
534
|
-
}
|
|
535
|
-
/**
|
|
536
|
-
* Create a cylinder with the given radius and height.
|
|
537
|
-
*/
|
|
538
|
-
function cylinder(radius, height, options) {
|
|
539
|
-
const at = options?.at ?? [
|
|
540
|
-
0,
|
|
541
|
-
0,
|
|
542
|
-
0
|
|
543
|
-
];
|
|
544
|
-
const axis = options?.axis ?? [
|
|
545
|
-
0,
|
|
546
|
-
0,
|
|
547
|
-
1
|
|
548
|
-
];
|
|
549
|
-
let solid = makeCylinder(radius, height, at, axis);
|
|
550
|
-
if (options?.centered) {
|
|
551
|
-
const halfShift = [
|
|
552
|
-
-axis[0] * height * .5,
|
|
553
|
-
-axis[1] * height * .5,
|
|
554
|
-
-axis[2] * height * .5
|
|
555
|
-
];
|
|
556
|
-
solid = translate(solid, halfShift);
|
|
557
|
-
}
|
|
558
|
-
return solid;
|
|
559
|
-
}
|
|
560
|
-
/**
|
|
561
|
-
* Create a sphere with the given radius.
|
|
562
|
-
*/
|
|
563
|
-
function sphere(radius, options) {
|
|
564
|
-
let solid = makeSphere(radius);
|
|
565
|
-
if (options?.at) solid = translate(solid, options.at);
|
|
566
|
-
return solid;
|
|
567
|
-
}
|
|
568
|
-
/**
|
|
569
|
-
* Create a cone (or frustum) with the given radii and height.
|
|
570
|
-
*
|
|
571
|
-
* @param bottomRadius - Radius at the base.
|
|
572
|
-
* @param topRadius - Radius at the top (0 for a full cone).
|
|
573
|
-
* @param height - Height of the cone.
|
|
574
|
-
*/
|
|
575
|
-
function cone(bottomRadius, topRadius, height, options) {
|
|
576
|
-
const at = options?.at ?? [
|
|
577
|
-
0,
|
|
578
|
-
0,
|
|
579
|
-
0
|
|
580
|
-
];
|
|
581
|
-
const axis = options?.axis ?? [
|
|
582
|
-
0,
|
|
583
|
-
0,
|
|
584
|
-
1
|
|
585
|
-
];
|
|
586
|
-
let solid = makeCone(bottomRadius, topRadius, height, at, axis);
|
|
587
|
-
if (options?.centered) {
|
|
588
|
-
const halfShift = [
|
|
589
|
-
-axis[0] * height * .5,
|
|
590
|
-
-axis[1] * height * .5,
|
|
591
|
-
-axis[2] * height * .5
|
|
592
|
-
];
|
|
593
|
-
solid = translate(solid, halfShift);
|
|
594
|
-
}
|
|
595
|
-
return solid;
|
|
596
|
-
}
|
|
597
|
-
/**
|
|
598
|
-
* Create a torus with the given major and minor radii.
|
|
599
|
-
*/
|
|
600
|
-
function torus(majorRadius, minorRadius, options) {
|
|
601
|
-
return makeTorus(majorRadius, minorRadius, options?.at ?? [
|
|
602
|
-
0,
|
|
603
|
-
0,
|
|
604
|
-
0
|
|
605
|
-
], options?.axis ?? [
|
|
606
|
-
0,
|
|
607
|
-
0,
|
|
608
|
-
1
|
|
609
|
-
]);
|
|
610
|
-
}
|
|
611
|
-
/**
|
|
612
|
-
* Create an ellipsoid with the given axis half-lengths.
|
|
613
|
-
*
|
|
614
|
-
* @param rx - Half-length along X.
|
|
615
|
-
* @param ry - Half-length along Y.
|
|
616
|
-
* @param rz - Half-length along Z.
|
|
617
|
-
*/
|
|
618
|
-
function ellipsoid(rx, ry, rz, options) {
|
|
619
|
-
let solid = makeEllipsoid(rx, ry, rz);
|
|
620
|
-
if (options?.at) solid = translate(solid, options.at);
|
|
621
|
-
return solid;
|
|
622
|
-
}
|
|
623
|
-
/** Create a straight edge between two 3D points. */
|
|
624
|
-
function line(from, to) {
|
|
625
|
-
return makeLine(from, to);
|
|
626
|
-
}
|
|
627
|
-
/** Create a circular edge with the given radius. */
|
|
628
|
-
function circle(radius, options) {
|
|
629
|
-
const axisDir = options?.axis ?? [
|
|
630
|
-
0,
|
|
631
|
-
0,
|
|
632
|
-
1
|
|
633
|
-
];
|
|
634
|
-
return makeCircle(radius, options?.at ?? [
|
|
635
|
-
0,
|
|
636
|
-
0,
|
|
637
|
-
0
|
|
638
|
-
], axisDir);
|
|
639
|
-
}
|
|
640
|
-
/**
|
|
641
|
-
* Create an elliptical edge.
|
|
642
|
-
*
|
|
643
|
-
* @returns An error if `minorRadius` exceeds `majorRadius`.
|
|
644
|
-
*/
|
|
645
|
-
function ellipse(majorRadius, minorRadius, options) {
|
|
646
|
-
const axisDir = options?.axis ?? [
|
|
647
|
-
0,
|
|
648
|
-
0,
|
|
649
|
-
1
|
|
650
|
-
];
|
|
651
|
-
return makeEllipse(majorRadius, minorRadius, options?.at ?? [
|
|
652
|
-
0,
|
|
653
|
-
0,
|
|
654
|
-
0
|
|
655
|
-
], axisDir, options?.xDir);
|
|
656
|
-
}
|
|
657
|
-
/**
|
|
658
|
-
* Create a helical wire.
|
|
659
|
-
*
|
|
660
|
-
* @param pitch - Vertical distance per full turn.
|
|
661
|
-
* @param height - Total height.
|
|
662
|
-
* @param radius - Helix radius.
|
|
663
|
-
*/
|
|
664
|
-
function helix(pitch, height, radius, options) {
|
|
665
|
-
return makeHelix(pitch, height, radius, options?.at ?? [
|
|
666
|
-
0,
|
|
667
|
-
0,
|
|
668
|
-
0
|
|
669
|
-
], options?.axis ?? [
|
|
670
|
-
0,
|
|
671
|
-
0,
|
|
672
|
-
1
|
|
673
|
-
], options?.lefthand ?? false);
|
|
674
|
-
}
|
|
675
|
-
/** Create a circular arc edge passing through three points. */
|
|
676
|
-
function threePointArc(p1, p2, p3) {
|
|
677
|
-
return makeThreePointArc(p1, p2, p3);
|
|
678
|
-
}
|
|
679
|
-
/**
|
|
680
|
-
* Create an elliptical arc edge between two angles.
|
|
681
|
-
*
|
|
682
|
-
* All angles are in **degrees** (unlike the legacy `makeEllipseArc` which used radians).
|
|
683
|
-
*
|
|
684
|
-
* @param startAngle - Start angle in degrees.
|
|
685
|
-
* @param endAngle - End angle in degrees.
|
|
686
|
-
*/
|
|
687
|
-
function ellipseArc(majorRadius, minorRadius, startAngle, endAngle, options) {
|
|
688
|
-
const axisDir = options?.axis ?? [
|
|
689
|
-
0,
|
|
690
|
-
0,
|
|
691
|
-
1
|
|
692
|
-
];
|
|
693
|
-
return makeEllipseArc(majorRadius, minorRadius, startAngle * DEG2RAD, endAngle * DEG2RAD, options?.at ?? [
|
|
694
|
-
0,
|
|
695
|
-
0,
|
|
696
|
-
0
|
|
697
|
-
], axisDir, options?.xDir);
|
|
698
|
-
}
|
|
699
|
-
/**
|
|
700
|
-
* Create a B-spline edge that approximates a set of 3D points.
|
|
701
|
-
*
|
|
702
|
-
* @returns An error if the approximation algorithm fails.
|
|
703
|
-
*/
|
|
704
|
-
function bsplineApprox(points, config) {
|
|
705
|
-
return makeBSplineApproximation(points, config);
|
|
706
|
-
}
|
|
707
|
-
/**
|
|
708
|
-
* Create a Bezier curve edge from control points.
|
|
709
|
-
*
|
|
710
|
-
* @param points - Two or more control points.
|
|
711
|
-
*/
|
|
712
|
-
function bezier(points) {
|
|
713
|
-
return makeBezierCurve(points);
|
|
714
|
-
}
|
|
715
|
-
/**
|
|
716
|
-
* Create a circular arc edge tangent to a direction at the start point.
|
|
717
|
-
*/
|
|
718
|
-
function tangentArc(startPoint, startTgt, endPoint) {
|
|
719
|
-
return makeTangentArc(startPoint, startTgt, endPoint);
|
|
720
|
-
}
|
|
721
|
-
/**
|
|
722
|
-
* Assemble edges and/or wires into a single connected wire.
|
|
723
|
-
*/
|
|
724
|
-
function wire(listOfEdges) {
|
|
725
|
-
return assembleWire(listOfEdges);
|
|
726
|
-
}
|
|
727
|
-
/**
|
|
728
|
-
* Assemble edges into a wire and verify it forms a closed loop.
|
|
729
|
-
*
|
|
730
|
-
* Combines {@link wire} + the `closedWire` smart constructor in a single step.
|
|
731
|
-
* Returns an error if the edges cannot be assembled or the wire is not closed.
|
|
732
|
-
*
|
|
733
|
-
* @example
|
|
734
|
-
* ```ts
|
|
735
|
-
* const cw = unwrap(wireLoop([e1, e2, e3, e4]));
|
|
736
|
-
* const f = unwrap(face(cw)); // ClosedWire accepted directly
|
|
737
|
-
* ```
|
|
738
|
-
*/
|
|
739
|
-
function wireLoop(listOfEdges) {
|
|
740
|
-
return andThen(assembleWire(listOfEdges), (w) => {
|
|
741
|
-
if (isClosedWire(w)) return ok(w);
|
|
742
|
-
return err(validationError("WIRE_NOT_CLOSED", "Assembled wire is not closed: start and end points do not coincide"));
|
|
743
|
-
});
|
|
744
|
-
}
|
|
745
|
-
/**
|
|
746
|
-
* Create a planar face from a closed wire, optionally with holes.
|
|
747
|
-
* The resulting face is always oriented (consistent normal direction).
|
|
748
|
-
*/
|
|
749
|
-
function face(w, holes) {
|
|
750
|
-
return makeFace(w, holes);
|
|
751
|
-
}
|
|
752
|
-
/**
|
|
753
|
-
* Create a non-planar face from a wire using surface filling.
|
|
754
|
-
* The resulting face is always oriented.
|
|
755
|
-
*/
|
|
756
|
-
function filledFace(w) {
|
|
757
|
-
return makeNonPlanarFace(w);
|
|
758
|
-
}
|
|
759
|
-
/**
|
|
760
|
-
* Create a face bounded by a wire on an existing face's surface.
|
|
761
|
-
* The resulting face inherits orientation from the origin face.
|
|
762
|
-
*/
|
|
763
|
-
function subFace(originFace, w) {
|
|
764
|
-
return makeNewFaceWithinFace(originFace, w);
|
|
765
|
-
}
|
|
766
|
-
/**
|
|
767
|
-
* Create a polygonal face from three or more coplanar points.
|
|
768
|
-
* The resulting face is always oriented.
|
|
769
|
-
*/
|
|
770
|
-
function polygon(points) {
|
|
771
|
-
return makePolygon(points);
|
|
772
|
-
}
|
|
773
|
-
/** Create a vertex at a 3D point. */
|
|
774
|
-
function vertex(point) {
|
|
775
|
-
return makeVertex(point);
|
|
776
|
-
}
|
|
777
|
-
/**
|
|
778
|
-
* Build a compound from multiple shapes.
|
|
779
|
-
*/
|
|
780
|
-
function compound(shapeArray) {
|
|
781
|
-
return makeCompound(shapeArray);
|
|
782
|
-
}
|
|
783
|
-
/**
|
|
784
|
-
* Weld faces and shells into a single solid.
|
|
785
|
-
* The resulting solid is always validated.
|
|
786
|
-
*/
|
|
787
|
-
function solid(facesOrShells) {
|
|
788
|
-
return makeSolid(facesOrShells);
|
|
789
|
-
}
|
|
790
|
-
/**
|
|
791
|
-
* Create an offset shape from a face.
|
|
792
|
-
*/
|
|
793
|
-
function offsetFace(f, distance, tolerance) {
|
|
794
|
-
return makeOffset(f, distance, tolerance);
|
|
795
|
-
}
|
|
796
|
-
/**
|
|
797
|
-
* Weld faces and shells into a single shell.
|
|
798
|
-
*/
|
|
799
|
-
function sewShells(facesOrShells, ignoreType) {
|
|
800
|
-
return weldShellsAndFaces(facesOrShells, ignoreType);
|
|
801
|
-
}
|
|
802
|
-
function addHoles(f, holes) {
|
|
803
|
-
return addHolesInFace(f, holes);
|
|
804
|
-
}
|
|
805
|
-
//#endregion
|
|
806
|
-
export { healFace as A, chamferDistAngle as B, threePointArc as C, wireLoop as D, wire as E, edgesOfFace as F, toGroupedBufferGeometryData as H, facesOfEdge as I, sharedEdges as L, healWire as M, isValid as N, autoHeal as O, adjacentFaces as P, verticesOfEdge as R, tangentArc as S, vertex as T, toLineGeometryData as U, toBufferGeometryData as V, polygon as _, circle as a, sphere as b, cylinder as c, ellipsoid as d, face as f, offsetFace as g, line as h, bsplineApprox as i, healSolid as j, heal as k, ellipse as l, helix as m, bezier as n, compound as o, filledFace as p, box as r, cone as s, addHoles as t, ellipseArc as u, sewShells as v, torus as w, subFace as x, solid as y, wiresOfFace as z };
|