@faicad/faijs 0.18.3 → 0.22.2
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.d.ts.map +1 -1
- package/dist/api/api-namespace.js +4 -1
- package/dist/api/api-namespace.js.map +1 -1
- package/dist/api/brep-mirror/joinery-brep.d.ts +1 -1
- package/dist/api/brep-mirror/joinery-brep.d.ts.map +1 -1
- package/dist/api/brep-mirror/joinery-brep.js +22 -20
- package/dist/api/brep-mirror/joinery-brep.js.map +1 -1
- package/dist/api/generated/script-face-manifest.d.ts +4 -0
- package/dist/api/generated/script-face-manifest.d.ts.map +1 -1
- package/dist/api/generated/script-face-manifest.js.map +1 -1
- package/dist/api/index.d.ts +4 -0
- package/dist/api/index.d.ts.map +1 -1
- package/dist/api/index.js +3 -0
- package/dist/api/index.js.map +1 -1
- package/dist/api/knurl.d.ts.map +1 -1
- package/dist/api/knurl.js +1 -0
- package/dist/api/knurl.js.map +1 -1
- package/dist/api/primitives.d.ts +4 -3
- package/dist/api/primitives.d.ts.map +1 -1
- package/dist/api/primitives.js +9 -3
- package/dist/api/primitives.js.map +1 -1
- package/dist/api/profile.d.ts +34 -5
- package/dist/api/profile.d.ts.map +1 -1
- package/dist/api/profile.js +168 -186
- package/dist/api/profile.js.map +1 -1
- package/dist/api/punch-hole.d.ts +77 -0
- package/dist/api/punch-hole.d.ts.map +1 -0
- package/dist/api/punch-hole.js +207 -0
- package/dist/api/punch-hole.js.map +1 -0
- package/dist/api/sketch-on-face.d.ts +85 -0
- package/dist/api/sketch-on-face.d.ts.map +1 -0
- package/dist/api/sketch-on-face.js +136 -0
- package/dist/api/sketch-on-face.js.map +1 -0
- package/dist/api/sketch-on-plane.d.ts +87 -0
- package/dist/api/sketch-on-plane.d.ts.map +1 -0
- package/dist/api/sketch-on-plane.js +106 -0
- package/dist/api/sketch-on-plane.js.map +1 -0
- package/dist/api/surface/arg-spec.d.ts +8 -0
- package/dist/api/surface/arg-spec.d.ts.map +1 -1
- package/dist/api/surface/arg-spec.js.map +1 -1
- package/dist/api/transform.d.ts +5 -5
- package/dist/api/transform.d.ts.map +1 -1
- package/dist/api/transform.js +12 -10
- package/dist/api/transform.js.map +1 -1
- package/dist/api/xml-dom.d.ts +27 -0
- package/dist/api/xml-dom.d.ts.map +1 -0
- package/dist/api/xml-dom.js +45 -0
- package/dist/api/xml-dom.js.map +1 -0
- package/dist/boolean/csg-backend.d.ts +6 -6
- package/dist/boolean/csg-backend.d.ts.map +1 -1
- package/dist/boolean/csg-backend.js +9 -9
- package/dist/boolean/csg-backend.js.map +1 -1
- package/dist/boolean/csg-core.d.ts +10 -10
- package/dist/boolean/csg-core.d.ts.map +1 -1
- package/dist/boolean/csg-core.js +24 -24
- package/dist/boolean/csg-core.js.map +1 -1
- package/dist/boolean/extrude-helpers.d.ts +8 -8
- package/dist/boolean/extrude-helpers.d.ts.map +1 -1
- package/dist/boolean/extrude-helpers.js +13 -13
- package/dist/boolean/extrude-helpers.js.map +1 -1
- package/dist/brep/brep-ops.d.ts +24 -10
- package/dist/brep/brep-ops.d.ts.map +1 -1
- package/dist/brep/brep-ops.js +46 -18
- package/dist/brep/brep-ops.js.map +1 -1
- package/dist/brep/brep-topology.d.ts.map +1 -1
- package/dist/brep/brep-topology.js +3 -1
- package/dist/brep/brep-topology.js.map +1 -1
- package/dist/brep/export/export-model.d.ts +79 -0
- package/dist/brep/export/export-model.d.ts.map +1 -0
- package/dist/brep/export/export-model.js +335 -0
- package/dist/brep/export/export-model.js.map +1 -0
- package/dist/brep/primitives-brep.d.ts.map +1 -1
- package/dist/brep/primitives-brep.js +3 -1
- package/dist/brep/primitives-brep.js.map +1 -1
- package/dist/brepkit-kernel/brepkitKernel.d.ts.map +1 -1
- package/dist/brepkit-kernel/brepkitKernel.js +4 -2
- package/dist/brepkit-kernel/brepkitKernel.js.map +1 -1
- package/dist/browser-host/csg-worker-protocol.d.ts +3 -3
- package/dist/browser-host/csg-worker-protocol.d.ts.map +1 -1
- package/dist/browser-host/csg-worker-protocol.js.map +1 -1
- package/dist/browser-host/csg-worker.js +3 -3
- package/dist/browser-host/csg-worker.js.map +1 -1
- package/dist/browser-host/inline-csg-backend.d.ts +3 -3
- package/dist/browser-host/inline-csg-backend.d.ts.map +1 -1
- package/dist/browser-host/inline-csg-backend.js +3 -3
- package/dist/browser-host/inline-csg-backend.js.map +1 -1
- package/dist/browser-host/worker-csg-backend.d.ts +3 -3
- package/dist/browser-host/worker-csg-backend.d.ts.map +1 -1
- package/dist/browser-host/worker-csg-backend.js.map +1 -1
- package/dist/cad-runtime/direct-executor.d.ts +4 -0
- package/dist/cad-runtime/direct-executor.d.ts.map +1 -1
- package/dist/cad-runtime/direct-executor.js +17 -1
- package/dist/cad-runtime/direct-executor.js.map +1 -1
- package/dist/cad-runtime/ports.d.ts +3 -3
- package/dist/cad-runtime/ports.d.ts.map +1 -1
- package/dist/cad-runtime/ports.js.map +1 -1
- package/dist/cad-runtime/runtime.d.ts +24 -1
- package/dist/cad-runtime/runtime.d.ts.map +1 -1
- package/dist/cad-runtime/runtime.js +53 -3
- package/dist/cad-runtime/runtime.js.map +1 -1
- package/dist/define-op.d.ts +22 -0
- package/dist/define-op.d.ts.map +1 -1
- package/dist/define-op.js +15 -0
- package/dist/define-op.js.map +1 -1
- package/dist/env-agnostic.d.ts +7 -7
- package/dist/env-agnostic.d.ts.map +1 -1
- package/dist/env-agnostic.js +3 -3
- package/dist/env-agnostic.js.map +1 -1
- package/dist/geometry2d/adapt.d.ts +46 -0
- package/dist/geometry2d/adapt.d.ts.map +1 -0
- package/dist/geometry2d/adapt.js +41 -0
- package/dist/geometry2d/adapt.js.map +1 -0
- package/dist/geometry2d/bbox2d.d.ts +82 -0
- package/dist/geometry2d/bbox2d.d.ts.map +1 -0
- package/dist/geometry2d/bbox2d.js +123 -0
- package/dist/geometry2d/bbox2d.js.map +1 -0
- package/dist/geometry2d/blueprint-sketcher.d.ts +27 -0
- package/dist/geometry2d/blueprint-sketcher.d.ts.map +1 -0
- package/dist/geometry2d/blueprint-sketcher.js +29 -0
- package/dist/geometry2d/blueprint-sketcher.js.map +1 -0
- package/dist/geometry2d/blueprint.d.ts +102 -0
- package/dist/geometry2d/blueprint.d.ts.map +1 -0
- package/dist/geometry2d/blueprint.js +225 -0
- package/dist/geometry2d/blueprint.js.map +1 -0
- package/dist/geometry2d/blueprints.d.ts +58 -0
- package/dist/geometry2d/blueprints.d.ts.map +1 -0
- package/dist/geometry2d/blueprints.js +72 -0
- package/dist/geometry2d/blueprints.js.map +1 -0
- package/dist/geometry2d/bridge/lift-on-plane.d.ts +50 -0
- package/dist/geometry2d/bridge/lift-on-plane.d.ts.map +1 -0
- package/dist/geometry2d/bridge/lift-on-plane.js +78 -0
- package/dist/geometry2d/bridge/lift-on-plane.js.map +1 -0
- package/dist/geometry2d/bridge/on-surface.d.ts +98 -0
- package/dist/geometry2d/bridge/on-surface.d.ts.map +1 -0
- package/dist/geometry2d/bridge/on-surface.js +94 -0
- package/dist/geometry2d/bridge/on-surface.js.map +1 -0
- package/dist/geometry2d/bridge/plane.d.ts +69 -0
- package/dist/geometry2d/bridge/plane.d.ts.map +1 -0
- package/dist/geometry2d/bridge/plane.js +96 -0
- package/dist/geometry2d/bridge/plane.js.map +1 -0
- package/dist/geometry2d/canned-blueprints.d.ts +44 -0
- package/dist/geometry2d/canned-blueprints.d.ts.map +1 -0
- package/dist/geometry2d/canned-blueprints.js +94 -0
- package/dist/geometry2d/canned-blueprints.js.map +1 -0
- package/dist/geometry2d/compound-blueprint.d.ts +72 -0
- package/dist/geometry2d/compound-blueprint.d.ts.map +1 -0
- package/dist/geometry2d/compound-blueprint.js +95 -0
- package/dist/geometry2d/compound-blueprint.js.map +1 -0
- package/dist/geometry2d/curve2d.d.ts +298 -0
- package/dist/geometry2d/curve2d.d.ts.map +1 -0
- package/dist/geometry2d/curve2d.js +1110 -0
- package/dist/geometry2d/curve2d.js.map +1 -0
- package/dist/geometry2d/index.d.ts +22 -0
- package/dist/geometry2d/index.d.ts.map +1 -0
- package/dist/geometry2d/index.js +21 -0
- package/dist/geometry2d/index.js.map +1 -0
- package/dist/geometry2d/organise.d.ts +28 -0
- package/dist/geometry2d/organise.d.ts.map +1 -0
- package/dist/geometry2d/organise.js +108 -0
- package/dist/geometry2d/organise.js.map +1 -0
- package/dist/geometry2d/pen-sketcher.d.ts +365 -0
- package/dist/geometry2d/pen-sketcher.d.ts.map +1 -0
- package/dist/geometry2d/pen-sketcher.js +520 -0
- package/dist/geometry2d/pen-sketcher.js.map +1 -0
- package/dist/geometry2d/point.d.ts +44 -0
- package/dist/geometry2d/point.d.ts.map +1 -0
- package/dist/geometry2d/point.js +57 -0
- package/dist/geometry2d/point.js.map +1 -0
- package/dist/geometry2d/svg-ellipse.d.ts +74 -0
- package/dist/geometry2d/svg-ellipse.d.ts.map +1 -0
- package/dist/geometry2d/svg-ellipse.js +163 -0
- package/dist/geometry2d/svg-ellipse.js.map +1 -0
- package/dist/lang/code-to-args.d.ts +29 -3
- package/dist/lang/code-to-args.d.ts.map +1 -1
- package/dist/lang/code-to-args.js +41 -2
- package/dist/lang/code-to-args.js.map +1 -1
- package/dist/lang/codegen.d.ts +45 -1
- package/dist/lang/codegen.d.ts.map +1 -1
- package/dist/lang/codegen.js +135 -6
- package/dist/lang/codegen.js.map +1 -1
- package/dist/lang/host-arg.d.ts +6 -0
- package/dist/lang/host-arg.d.ts.map +1 -1
- package/dist/lang/host-arg.js.map +1 -1
- package/dist/lang/metadata-extractor.d.ts +25 -0
- package/dist/lang/metadata-extractor.d.ts.map +1 -1
- package/dist/lang/metadata-extractor.js +289 -25
- package/dist/lang/metadata-extractor.js.map +1 -1
- package/dist/lang/parse-error.d.ts +7 -1
- package/dist/lang/parse-error.d.ts.map +1 -1
- package/dist/lang/parse-error.js.map +1 -1
- package/dist/lang/security-scanner.d.ts +9 -1
- package/dist/lang/security-scanner.d.ts.map +1 -1
- package/dist/lang/security-scanner.js +38 -1
- package/dist/lang/security-scanner.js.map +1 -1
- package/dist/lang/symbol-table.generated.d.ts +3 -0
- package/dist/lang/symbol-table.generated.d.ts.map +1 -1
- package/dist/lang/symbol-table.generated.js +3 -0
- package/dist/lang/symbol-table.generated.js.map +1 -1
- package/dist/mesh/io.d.ts +62 -9
- package/dist/mesh/io.d.ts.map +1 -1
- package/dist/mesh/io.js +124 -17
- package/dist/mesh/io.js.map +1 -1
- package/dist/mesh/threemf-loader.d.ts +15 -0
- package/dist/mesh/threemf-loader.d.ts.map +1 -0
- package/dist/mesh/threemf-loader.js +163 -0
- package/dist/mesh/threemf-loader.js.map +1 -0
- package/dist/mesh/transform.d.ts +2 -2
- package/dist/mesh/transform.d.ts.map +1 -1
- package/dist/mesh/transform.js +3 -3
- package/dist/mesh/transform.js.map +1 -1
- package/dist/mesh/types.d.ts +2 -2
- package/dist/mesh/types.d.ts.map +1 -1
- package/dist/mesh/types.js.map +1 -1
- package/dist/node-host/cli.d.ts.map +1 -1
- package/dist/node-host/cli.js +53 -26
- package/dist/node-host/cli.js.map +1 -1
- package/dist/occt-kernel/occtKernel.d.ts.map +1 -1
- package/dist/occt-kernel/occtKernel.js +4 -2
- package/dist/occt-kernel/occtKernel.js.map +1 -1
- package/dist/occt-kernel/topologyExt.d.ts.map +1 -1
- package/dist/occt-kernel/topologyExt.js +4 -1
- package/dist/occt-kernel/topologyExt.js.map +1 -1
- package/dist/runtime-state.d.ts +18 -0
- package/dist/runtime-state.d.ts.map +1 -1
- package/dist/runtime-state.js +23 -0
- package/dist/runtime-state.js.map +1 -1
- package/dist/sdk.d.ts +1 -1
- package/dist/sdk.d.ts.map +1 -1
- package/dist/sdk.js +1 -1
- package/dist/sdk.js.map +1 -1
- package/dist/tolerance.d.ts +38 -0
- package/dist/tolerance.d.ts.map +1 -0
- package/dist/tolerance.js +40 -0
- package/dist/tolerance.js.map +1 -0
- package/dist/topology/naming/score.js +3 -3
- package/dist/topology/naming/score.js.map +1 -1
- package/dist/units.d.ts +248 -0
- package/dist/units.d.ts.map +1 -0
- package/dist/units.js +397 -0
- package/dist/units.js.map +1 -0
- package/package.json +19 -2
package/dist/boolean/csg-core.js
CHANGED
|
@@ -201,10 +201,10 @@ export function createWedge(Manifold, Mesh, planeCenter, normal, widthDir, depth
|
|
|
201
201
|
* Returns an array of components, each being a Set of vertex indices.
|
|
202
202
|
* @param upper The upper mesh to scan for cap faces.
|
|
203
203
|
* @param normal The cutting plane normal.
|
|
204
|
-
* @param
|
|
204
|
+
* @param planeDistance The cutting plane offset along the normal.
|
|
205
205
|
* @returns An array of components, each a Set of vertex indices on the cap.
|
|
206
206
|
*/
|
|
207
|
-
export function detectCapComponents(upper, normal,
|
|
207
|
+
export function detectCapComponents(upper, normal, planeDistance) {
|
|
208
208
|
const mesh = upper.getMesh();
|
|
209
209
|
const eps = 0.001;
|
|
210
210
|
const numProp = mesh.numProp || 3;
|
|
@@ -221,13 +221,13 @@ export function detectCapComponents(upper, normal, originOffset) {
|
|
|
221
221
|
const i2 = triVerts[t * 3 + 2];
|
|
222
222
|
const d0 = Math.abs(mesh.vertProperties[i0 * numProp] * normal[0] +
|
|
223
223
|
mesh.vertProperties[i0 * numProp + 1] * normal[1] +
|
|
224
|
-
mesh.vertProperties[i0 * numProp + 2] * normal[2] -
|
|
224
|
+
mesh.vertProperties[i0 * numProp + 2] * normal[2] - planeDistance);
|
|
225
225
|
const d1 = Math.abs(mesh.vertProperties[i1 * numProp] * normal[0] +
|
|
226
226
|
mesh.vertProperties[i1 * numProp + 1] * normal[1] +
|
|
227
|
-
mesh.vertProperties[i1 * numProp + 2] * normal[2] -
|
|
227
|
+
mesh.vertProperties[i1 * numProp + 2] * normal[2] - planeDistance);
|
|
228
228
|
const d2 = Math.abs(mesh.vertProperties[i2 * numProp] * normal[0] +
|
|
229
229
|
mesh.vertProperties[i2 * numProp + 1] * normal[1] +
|
|
230
|
-
mesh.vertProperties[i2 * numProp + 2] * normal[2] -
|
|
230
|
+
mesh.vertProperties[i2 * numProp + 2] * normal[2] - planeDistance);
|
|
231
231
|
if (d0 < eps && d1 < eps && d2 < eps) {
|
|
232
232
|
capTris.push({ v0: i0, v1: i1, v2: i2 });
|
|
233
233
|
capVertSet.add(i0);
|
|
@@ -258,12 +258,12 @@ export function detectCapComponents(upper, normal, originOffset) {
|
|
|
258
258
|
* along the width direction.
|
|
259
259
|
* @param upper The upper mesh to measure.
|
|
260
260
|
* @param normal The cutting plane normal.
|
|
261
|
-
* @param
|
|
261
|
+
* @param planeDistance The cutting plane offset along the normal.
|
|
262
262
|
* @param widthDir The width direction along which to measure.
|
|
263
263
|
* @param comp Optional connected component to restrict the measurement to.
|
|
264
264
|
* @returns The cross-section extent along the width direction (0 when none found).
|
|
265
265
|
*/
|
|
266
|
-
export function computeCrossSectionWidth(upper, normal,
|
|
266
|
+
export function computeCrossSectionWidth(upper, normal, planeDistance, widthDir, comp) {
|
|
267
267
|
const mesh = upper.getMesh();
|
|
268
268
|
const eps = 0.001;
|
|
269
269
|
let minProj = Infinity;
|
|
@@ -278,7 +278,7 @@ export function computeCrossSectionWidth(upper, normal, originOffset, widthDir,
|
|
|
278
278
|
const x = mesh.vertProperties[base];
|
|
279
279
|
const y = mesh.vertProperties[base + 1];
|
|
280
280
|
const z = mesh.vertProperties[base + 2];
|
|
281
|
-
const dist = x * normal[0] + y * normal[1] + z * normal[2] -
|
|
281
|
+
const dist = x * normal[0] + y * normal[1] + z * normal[2] - planeDistance;
|
|
282
282
|
if (Math.abs(dist) < eps) {
|
|
283
283
|
const proj = x * widthDir[0] + y * widthDir[1] + z * widthDir[2];
|
|
284
284
|
if (proj < minProj)
|
|
@@ -297,12 +297,12 @@ export function computeCrossSectionWidth(upper, normal, originOffset, widthDir,
|
|
|
297
297
|
* Compute the centroid of vertices lying on the cutting plane.
|
|
298
298
|
* @param upper The upper mesh to scan.
|
|
299
299
|
* @param normal The cutting plane normal.
|
|
300
|
-
* @param
|
|
300
|
+
* @param planeDistance The cutting plane offset along the normal.
|
|
301
301
|
* @param fallback The centroid fallback when no vertex lies on the plane.
|
|
302
302
|
* @param comp Optional connected component to restrict the measurement to.
|
|
303
303
|
* @returns The computed centroid, or the fallback when none is found.
|
|
304
304
|
*/
|
|
305
|
-
export function computeCrossSectionCentroid(upper, normal,
|
|
305
|
+
export function computeCrossSectionCentroid(upper, normal, planeDistance, fallback, comp) {
|
|
306
306
|
const mesh = upper.getMesh();
|
|
307
307
|
const eps = 0.001;
|
|
308
308
|
let cx = 0, cy = 0, cz = 0;
|
|
@@ -316,7 +316,7 @@ export function computeCrossSectionCentroid(upper, normal, originOffset, fallbac
|
|
|
316
316
|
const x = mesh.vertProperties[base];
|
|
317
317
|
const y = mesh.vertProperties[base + 1];
|
|
318
318
|
const z = mesh.vertProperties[base + 2];
|
|
319
|
-
const dist = x * normal[0] + y * normal[1] + z * normal[2] -
|
|
319
|
+
const dist = x * normal[0] + y * normal[1] + z * normal[2] - planeDistance;
|
|
320
320
|
if (Math.abs(dist) < eps) {
|
|
321
321
|
cx += x;
|
|
322
322
|
cy += y;
|
|
@@ -335,7 +335,7 @@ export function computeCrossSectionCentroid(upper, normal, originOffset, fallbac
|
|
|
335
335
|
* @param Mesh - the Mesh constructor from the manifold module.
|
|
336
336
|
* @param original - the original manifold to split.
|
|
337
337
|
* @param normal - the cutting plane normal (unit vector).
|
|
338
|
-
* @param
|
|
338
|
+
* @param planeDistance - the plane equation origin offset along the normal.
|
|
339
339
|
* @param planeCenter - a point on the cutting plane used to center the wedge.
|
|
340
340
|
* @param widthDirInput - the width direction in the cutting plane (will be normalized).
|
|
341
341
|
* @param bboxWidthOnWidthDir - the model's bounding-box width along widthDir, used as a fallback cross-section width.
|
|
@@ -343,14 +343,14 @@ export function computeCrossSectionCentroid(upper, normal, originOffset, fallbac
|
|
|
343
343
|
* @param keepOriginal - when true, the original manifold is not deleted after splitting (default false).
|
|
344
344
|
* @returns a tuple of the split upper manifold, lower manifold, and the trimmed wedge mesh data (or null when empty).
|
|
345
345
|
*/
|
|
346
|
-
export function dovetailBooleanSplit(Manifold, Mesh, original, normal,
|
|
346
|
+
export function dovetailBooleanSplit(Manifold, Mesh, original, normal, planeDistance, planeCenter, widthDirInput, bboxWidthOnWidthDir, groove, keepOriginal = false) {
|
|
347
347
|
const widthDir = vec3Normalize(widthDirInput);
|
|
348
348
|
// Step 1: Split by plane → upper + lower
|
|
349
|
-
const [upper, lower] = original.splitByPlane(normal,
|
|
349
|
+
const [upper, lower] = original.splitByPlane(normal, planeDistance);
|
|
350
350
|
if (!keepOriginal)
|
|
351
351
|
original.delete();
|
|
352
352
|
// Step 2: Compute actual cross-section width at the cutting plane
|
|
353
|
-
let crossSectionWidth = computeCrossSectionWidth(upper, normal,
|
|
353
|
+
let crossSectionWidth = computeCrossSectionWidth(upper, normal, planeDistance, widthDir);
|
|
354
354
|
if (crossSectionWidth <= 0) {
|
|
355
355
|
crossSectionWidth = bboxWidthOnWidthDir;
|
|
356
356
|
}
|
|
@@ -466,7 +466,7 @@ export function createStraightTenon(Manifold, Mesh, centroid, normal, widthDir,
|
|
|
466
466
|
* @param Mesh - the Mesh constructor from the manifold module.
|
|
467
467
|
* @param original - the original manifold to split.
|
|
468
468
|
* @param normal - the cutting plane normal (unit vector).
|
|
469
|
-
* @param
|
|
469
|
+
* @param planeDistance - the plane equation origin offset along the normal.
|
|
470
470
|
* @param planeCenter - a point on the cutting plane used to center the joinery.
|
|
471
471
|
* @param widthDirInput - the width direction in the cutting plane (will be normalized).
|
|
472
472
|
* @param shape - the joinery shape: 'dowel' or 'tenon'.
|
|
@@ -475,25 +475,25 @@ export function createStraightTenon(Manifold, Mesh, centroid, normal, widthDir,
|
|
|
475
475
|
* @param selectedSections - optional list of indices selecting which cap sections receive joinery placement; null or empty means a single placement at the overall cross-section centroid.
|
|
476
476
|
* @returns a tuple of the split upper manifold, lower manifold, and the generated joinery mesh data (or null).
|
|
477
477
|
*/
|
|
478
|
-
export function dowelOrTenonBooleanSplit(Manifold, Mesh, original, normal,
|
|
478
|
+
export function dowelOrTenonBooleanSplit(Manifold, Mesh, original, normal, planeDistance, planeCenter, widthDirInput, shape, params, keepOriginal = false, selectedSections) {
|
|
479
479
|
const widthDir = vec3Normalize(widthDirInput);
|
|
480
480
|
const depthDir = vec3Normalize(vec3Cross(normal, widthDir));
|
|
481
481
|
// Step 1: Split by plane → upper + lower
|
|
482
|
-
const [upper, lower] = original.splitByPlane(normal,
|
|
482
|
+
const [upper, lower] = original.splitByPlane(normal, planeDistance);
|
|
483
483
|
if (!keepOriginal)
|
|
484
484
|
original.delete();
|
|
485
485
|
// Step 2: Detect cap components (multi-section support)
|
|
486
|
-
const components = detectCapComponents(upper, normal,
|
|
486
|
+
const components = detectCapComponents(upper, normal, planeDistance);
|
|
487
487
|
let placements;
|
|
488
488
|
if (components.length <= 1 || !selectedSections || selectedSections.length === 0) {
|
|
489
|
-
const centroid = computeCrossSectionCentroid(upper, normal,
|
|
489
|
+
const centroid = computeCrossSectionCentroid(upper, normal, planeDistance, planeCenter);
|
|
490
490
|
placements = [{ centroid }];
|
|
491
491
|
}
|
|
492
492
|
else {
|
|
493
493
|
const compInfo = components.map((comp, idx) => {
|
|
494
|
-
const compWidth = computeCrossSectionWidth(upper, normal,
|
|
495
|
-
const compCentroid = computeCrossSectionCentroid(upper, normal,
|
|
496
|
-
const compDepth = computeCrossSectionWidth(upper, normal,
|
|
494
|
+
const compWidth = computeCrossSectionWidth(upper, normal, planeDistance, widthDir, comp);
|
|
495
|
+
const compCentroid = computeCrossSectionCentroid(upper, normal, planeDistance, planeCenter, comp);
|
|
496
|
+
const compDepth = computeCrossSectionWidth(upper, normal, planeDistance, depthDir, comp);
|
|
497
497
|
const area = compWidth * compDepth;
|
|
498
498
|
return { idx, comp, area, centroid: compCentroid };
|
|
499
499
|
});
|
|
@@ -505,7 +505,7 @@ export function dowelOrTenonBooleanSplit(Manifold, Mesh, original, normal, origi
|
|
|
505
505
|
}
|
|
506
506
|
}
|
|
507
507
|
if (placements.length === 0) {
|
|
508
|
-
const centroid = computeCrossSectionCentroid(upper, normal,
|
|
508
|
+
const centroid = computeCrossSectionCentroid(upper, normal, planeDistance, planeCenter);
|
|
509
509
|
placements = [{ centroid }];
|
|
510
510
|
}
|
|
511
511
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"csg-core.js","sourceRoot":"","sources":["../../src/boolean/csg-core.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * csg-core — CSG 纯计算函数(从 csg-worker.ts 提取)\n *\n *\n * 这些函数不依赖 Worker 环境(无 self.onmessage / postMessage),\n * 可被 WorkerCsgBackend(经 csg-worker.ts)和 InlineCsgBackend(主线程直跑)共用。\n *\n * 依赖:manifold-3d 核心模块(Manifold / Mesh 构造器)、dovetail-math、joinery-shapes\n */\n\nimport type { Manifold as ManifoldInstance } from 'manifold-3d/manifold'\nimport {\n vec3Cross, vec3Normalize,\n type Vec3,\n} from './dovetail-math'\nimport {\n buildWedgeGeometry,\n buildDowelGeometry,\n buildStraightTenonGeometry,\n} from './joinery-shapes'\n\n// ── 类型别名 ──\n\ntype ManifoldCtor = typeof import('manifold-3d/manifold').Manifold\ntype MeshCtor = typeof import('manifold-3d/manifold').Mesh\n\n// ── Manifold → MeshData 转换 ──\n\n/**\n * Extract {positions, indices} from a Manifold mesh.\n * Handles the numProp > 3 case (manifold may carry extra property channels).\n * @param manifold The manifold from which to read mesh data.\n * @returns The extracted positions and indices buffers.\n */\nexport function manifoldToMeshData(manifold: ManifoldInstance): {\n positions: Float32Array; indices: Uint32Array\n} {\n const resultMesh = manifold.getMesh()\n const numProp = resultMesh.numProp || 3\n const vertPropsLen = resultMesh.vertProperties ? resultMesh.vertProperties.length : 0\n const vertCount = numProp > 0 ? Math.floor(vertPropsLen / numProp) : 0\n const positions = new Float32Array(vertCount * 3)\n for (let i = 0; i < vertCount; i++) {\n const base = i * numProp\n positions[i * 3] = resultMesh.vertProperties[base]\n positions[i * 3 + 1] = resultMesh.vertProperties[base + 1]\n positions[i * 3 + 2] = resultMesh.vertProperties[base + 2]\n }\n const triVerts = resultMesh.triVerts\n const indices = triVerts ? new Uint32Array(triVerts) : new Uint32Array(0)\n return { positions, indices }\n}\n\n// ── MeshData → Manifold ──\n\n/**\n * Build a Manifold from mesh data, welding duplicate vertices when the density\n * is too high (close to one independent vertex per triangle) before Manifold.ofMesh.\n * Shared by the Inline and Worker backends so both produce identical input conversion.\n * @param Manifold The Manifold constructor from the manifold module.\n * @param Mesh The Mesh constructor from the manifold module.\n * @param mesh The mesh data (positions and indices).\n * @returns The constructed Manifold instance.\n */\nexport function meshToManifold(\n Manifold: ManifoldCtor,\n Mesh: MeshCtor,\n mesh: { positions: Float32Array; indices: Uint32Array },\n): ManifoldInstance {\n const triCount = mesh.indices.length / 3\n const vertCount = mesh.positions.length / 3\n let positions = mesh.positions\n let indices = mesh.indices\n\n if (vertCount >= triCount * 3 * 0.9) {\n const welded = weldPositionsWorker(mesh.positions, mesh.indices, mesh.indices.length)\n positions = welded.positions\n indices = welded.indices\n }\n\n return Manifold.ofMesh(new Mesh({\n numProp: 3,\n vertProperties: positions,\n triVerts: indices,\n }))\n}\n\n/**\n * Sequentially apply a boolean operation across an array of Manifolds.\n * The caller is responsible for deleting the input manifolds and the result.\n * @param op The boolean operation to apply (union/subtract/intersect).\n * @param manifolds The manifolds to combine in order.\n * @returns The resulting Manifold of the chain.\n */\nexport function chainBoolean(\n op: 'union' | 'subtract' | 'intersect',\n manifolds: ManifoldInstance[],\n): ManifoldInstance {\n let result = manifolds[0]\n for (let i = 1; i < manifolds.length; i++) {\n switch (op) {\n case 'union':\n result = result.add(manifolds[i])\n break\n case 'subtract':\n result = result.subtract(manifolds[i])\n break\n case 'intersect':\n result = result.intersect(manifolds[i])\n break\n }\n }\n return result\n}\n\n// ── 顶点焊接 ──\n\n/**\n * Weld duplicate vertices using a quantized 1 µm grid.\n * Uses three nested numeric Maps (no string allocation).\n * @param positions The input vertex positions.\n * @param indices The input triangle indices.\n * @param count The number of indices to process.\n * @returns The welded positions and remapped indices buffers.\n */\nexport function weldPositionsWorker(\n positions: Float32Array,\n indices: Uint32Array,\n count: number,\n): { positions: Float32Array; indices: Uint32Array } {\n const mapX = new Map<number, Map<number, Map<number, number>>>()\n const weldedPosArr: number[] = []\n const weldedIdxArr: number[] = []\n\n for (let i = 0; i < count; i++) {\n const vi = indices[i]\n const x = positions[vi * 3]\n const y = positions[vi * 3 + 1]\n const z = positions[vi * 3 + 2]\n const qx = Math.round(x * 1e6)\n const qy = Math.round(y * 1e6)\n const qz = Math.round(z * 1e6)\n\n let mapY = mapX.get(qx)\n if (mapY === undefined) {\n mapY = new Map<number, Map<number, number>>()\n mapX.set(qx, mapY)\n }\n let mapZ = mapY.get(qy)\n if (mapZ === undefined) {\n mapZ = new Map<number, number>()\n mapY.set(qy, mapZ)\n }\n let ni = mapZ.get(qz)\n if (ni === undefined) {\n ni = weldedPosArr.length / 3\n mapZ.set(qz, ni)\n weldedPosArr.push(x, y, z)\n }\n weldedIdxArr.push(ni)\n }\n\n return {\n positions: new Float32Array(weldedPosArr),\n indices: new Uint32Array(weldedIdxArr),\n }\n}\n\n// ── Union-Find ──\n\n/** Simple union-find for clustering cap triangles by shared edges. */\nexport class SimpleUnionFind {\n private parent: number[]\n private rank: number[]\n\n /**\n * Create a union-find structure with n initial singletons.\n * @param n The number of elements.\n */\n constructor(n: number) {\n this.parent = Array.from({ length: n }, (_, i) => i)\n this.rank = new Array(n).fill(0)\n }\n\n /**\n * Find the root representative of the element x (with path compression).\n * @param x The element to look up.\n * @returns The root index of the set containing x.\n */\n find(x: number): number {\n if (this.parent[x] !== x) {\n this.parent[x] = this.find(this.parent[x])\n }\n return this.parent[x]\n }\n\n /**\n * Union the sets containing x and y.\n * @param x The first element.\n * @param y The second element.\n */\n union(x: number, y: number): void {\n const px = this.find(x)\n const py = this.find(y)\n if (px === py) return\n if (this.rank[px] < this.rank[py]) {\n this.parent[px] = py\n } else if (this.rank[px] > this.rank[py]) {\n this.parent[py] = px\n } else {\n this.parent[py] = px\n this.rank[px]++\n }\n }\n}\n\n// ── Wedge (trapezoidal prism) creation ──\n\n/**\n * Create a wedge (trapezoidal prism) Manifold from cutting-plane parameters.\n * @param Manifold The Manifold constructor from the manifold module.\n * @param Mesh The Mesh constructor from the manifold module.\n * @param planeCenter Center of the cutting plane.\n * @param normal Cutting plane normal (unit vector).\n * @param widthDir Extrusion direction (unit vector).\n * @param depth Wedge depth (mm).\n * @param width Wedge width (mm).\n * @param angleDeg Slant angle of the wedge sides (degrees).\n * @param extrudeLength Total extrusion length along widthDir (mm).\n * @returns The constructed wedge Manifold.\n */\nexport function createWedge(\n Manifold: ManifoldCtor,\n Mesh: MeshCtor,\n planeCenter: Vec3,\n normal: Vec3,\n widthDir: Vec3,\n depth: number,\n width: number,\n angleDeg: number,\n extrudeLength: number,\n): ManifoldInstance {\n const { positions, indices } = buildWedgeGeometry(\n planeCenter, normal, widthDir, depth, width, angleDeg, extrudeLength,\n )\n const mesh = new Mesh({\n numProp: 3,\n vertProperties: positions,\n triVerts: indices,\n })\n return Manifold.ofMesh(mesh)\n}\n\n// ── Cap component detection ──\n\n/**\n * Detect connected components of cap faces on the cutting plane.\n * Returns an array of components, each being a Set of vertex indices.\n * @param upper The upper mesh to scan for cap faces.\n * @param normal The cutting plane normal.\n * @param originOffset The cutting plane offset along the normal.\n * @returns An array of components, each a Set of vertex indices on the cap.\n */\nexport function detectCapComponents(\n upper: ManifoldInstance,\n normal: Vec3,\n originOffset: number,\n): Set<number>[] {\n const mesh = upper.getMesh()\n const eps = 0.001\n const numProp = mesh.numProp || 3\n const vertCount = Math.floor(mesh.vertProperties.length / numProp)\n const triVerts = mesh.triVerts\n if (!triVerts || triVerts.length === 0) return []\n\n const capVertSet = new Set<number>()\n interface CapTri { v0: number; v1: number; v2: number }\n const capTris: CapTri[] = []\n const triCount = triVerts.length / 3\n for (let t = 0; t < triCount; t++) {\n const i0 = triVerts[t * 3]\n const i1 = triVerts[t * 3 + 1]\n const i2 = triVerts[t * 3 + 2]\n const d0 = Math.abs(\n mesh.vertProperties[i0 * numProp] * normal[0] +\n mesh.vertProperties[i0 * numProp + 1] * normal[1] +\n mesh.vertProperties[i0 * numProp + 2] * normal[2] - originOffset)\n const d1 = Math.abs(\n mesh.vertProperties[i1 * numProp] * normal[0] +\n mesh.vertProperties[i1 * numProp + 1] * normal[1] +\n mesh.vertProperties[i1 * numProp + 2] * normal[2] - originOffset)\n const d2 = Math.abs(\n mesh.vertProperties[i2 * numProp] * normal[0] +\n mesh.vertProperties[i2 * numProp + 1] * normal[1] +\n mesh.vertProperties[i2 * numProp + 2] * normal[2] - originOffset)\n if (d0 < eps && d1 < eps && d2 < eps) {\n capTris.push({ v0: i0, v1: i1, v2: i2 })\n capVertSet.add(i0); capVertSet.add(i1); capVertSet.add(i2)\n }\n }\n if (capTris.length === 0) return []\n\n const uf = new SimpleUnionFind(vertCount)\n for (const tri of capTris) {\n uf.union(tri.v0, tri.v1)\n uf.union(tri.v1, tri.v2)\n uf.union(tri.v0, tri.v2)\n }\n\n const compMap = new Map<number, Set<number>>()\n for (const vi of capVertSet) {\n const root = uf.find(vi)\n if (!compMap.has(root)) compMap.set(root, new Set<number>())\n compMap.get(root)!.add(vi)\n }\n\n return Array.from(compMap.values())\n}\n\n// ── Cross-section width computation ──\n\n/**\n * Compute the actual extent of the model's cross-section at the cutting plane\n * along the width direction.\n * @param upper The upper mesh to measure.\n * @param normal The cutting plane normal.\n * @param originOffset The cutting plane offset along the normal.\n * @param widthDir The width direction along which to measure.\n * @param comp Optional connected component to restrict the measurement to.\n * @returns The cross-section extent along the width direction (0 when none found).\n */\nexport function computeCrossSectionWidth(\n upper: ManifoldInstance,\n normal: Vec3,\n originOffset: number,\n widthDir: Vec3,\n comp?: Set<number>,\n): number {\n const mesh = upper.getMesh()\n const eps = 0.001\n let minProj = Infinity\n let maxProj = -Infinity\n let found = false\n\n const numProp = mesh.numProp || 3\n const vertCount = Math.floor(mesh.vertProperties.length / numProp)\n for (let i = 0; i < vertCount; i++) {\n if (comp && !comp.has(i)) continue\n\n const base = i * numProp\n const x = mesh.vertProperties[base]\n const y = mesh.vertProperties[base + 1]\n const z = mesh.vertProperties[base + 2]\n\n const dist = x * normal[0] + y * normal[1] + z * normal[2] - originOffset\n if (Math.abs(dist) < eps) {\n const proj = x * widthDir[0] + y * widthDir[1] + z * widthDir[2]\n if (proj < minProj) minProj = proj\n if (proj > maxProj) maxProj = proj\n found = true\n }\n }\n\n if (!found) return 0\n return maxProj - minProj\n}\n\n// ── Cross-section centroid computation ──\n\n/**\n * Compute the centroid of vertices lying on the cutting plane.\n * @param upper The upper mesh to scan.\n * @param normal The cutting plane normal.\n * @param originOffset The cutting plane offset along the normal.\n * @param fallback The centroid fallback when no vertex lies on the plane.\n * @param comp Optional connected component to restrict the measurement to.\n * @returns The computed centroid, or the fallback when none is found.\n */\nexport function computeCrossSectionCentroid(\n upper: ManifoldInstance,\n normal: Vec3,\n originOffset: number,\n fallback: Vec3,\n comp?: Set<number>,\n): Vec3 {\n const mesh = upper.getMesh()\n const eps = 0.001\n let cx = 0, cy = 0, cz = 0\n let count = 0\n\n const numProp = mesh.numProp || 3\n const vertCount = Math.floor(mesh.vertProperties.length / numProp)\n for (let i = 0; i < vertCount; i++) {\n if (comp && !comp.has(i)) continue\n\n const base = i * numProp\n const x = mesh.vertProperties[base]\n const y = mesh.vertProperties[base + 1]\n const z = mesh.vertProperties[base + 2]\n\n const dist = x * normal[0] + y * normal[1] + z * normal[2] - originOffset\n if (Math.abs(dist) < eps) {\n cx += x\n cy += y\n cz += z\n count++\n }\n }\n\n if (count === 0) return fallback\n return [cx / count, cy / count, cz / count]\n}\n\n// ── Dovetail boolean split ──\n\n/**\n * Perform the dovetail split using boolean operations.\n * @param Manifold - the Manifold constructor from the manifold module.\n * @param Mesh - the Mesh constructor from the manifold module.\n * @param original - the original manifold to split.\n * @param normal - the cutting plane normal (unit vector).\n * @param originOffset - the plane equation origin offset along the normal.\n * @param planeCenter - a point on the cutting plane used to center the wedge.\n * @param widthDirInput - the width direction in the cutting plane (will be normalized).\n * @param bboxWidthOnWidthDir - the model's bounding-box width along widthDir, used as a fallback cross-section width.\n * @param groove - the dovetail groove design parameters (depth, tolerances, width, flaps angle).\n * @param keepOriginal - when true, the original manifold is not deleted after splitting (default false).\n * @returns a tuple of the split upper manifold, lower manifold, and the trimmed wedge mesh data (or null when empty).\n */\nexport function dovetailBooleanSplit(\n Manifold: ManifoldCtor,\n Mesh: MeshCtor,\n original: ManifoldInstance,\n normal: Vec3,\n originOffset: number,\n planeCenter: Vec3,\n widthDirInput: Vec3,\n bboxWidthOnWidthDir: number,\n groove: {\n depth: number\n depthTolerance: number\n width: number\n widthTolerance: number\n flapsAngle: number\n },\n keepOriginal: boolean = false,\n): [ManifoldInstance, ManifoldInstance,\n { positions: Float32Array; indices: Uint32Array } | null] {\n const widthDir = vec3Normalize(widthDirInput)\n\n // Step 1: Split by plane → upper + lower\n const [upper, lower] = original.splitByPlane(normal, originOffset)\n if (!keepOriginal) original.delete()\n\n // Step 2: Compute actual cross-section width at the cutting plane\n let crossSectionWidth = computeCrossSectionWidth(upper, normal, originOffset, widthDir)\n if (crossSectionWidth <= 0) {\n crossSectionWidth = bboxWidthOnWidthDir\n }\n const extrudeLength = crossSectionWidth + 0.2\n\n // Step 3: Create wedge W with generous overhang along widthDir\n const overhang = 20\n\n const wedgeW = createWedge(\n Manifold, Mesh,\n planeCenter, normal, widthDir,\n groove.depth, groove.width, groove.flapsAngle,\n extrudeLength + overhang,\n )\n\n // Trim the wedge to the model by intersecting with lower.\n let wedgeForUnion: ManifoldInstance\n let wedgeMeshData: { positions: Float32Array; indices: Uint32Array } | null\n let lowerForSubtract: ManifoldInstance\n\n if (!wedgeW.isEmpty() && !lower.isEmpty()) {\n const lowerMeshData = manifoldToMeshData(lower)\n\n const trimmedWedge = wedgeW.intersect(lower)\n wedgeW.delete()\n lower.delete()\n\n wedgeMeshData = trimmedWedge.isEmpty() ? null : manifoldToMeshData(trimmedWedge)\n wedgeForUnion = trimmedWedge\n\n lowerForSubtract = Manifold.ofMesh(new Mesh({\n numProp: 3,\n vertProperties: lowerMeshData.positions,\n triVerts: lowerMeshData.indices,\n }))\n } else {\n wedgeMeshData = null\n wedgeForUnion = wedgeW\n lowerForSubtract = lower\n }\n\n // Step 5: union(upper, wedgeForUnion) → upper'\n let upperResult: ManifoldInstance\n if (upper.isEmpty()) {\n upper.delete()\n upperResult = wedgeForUnion\n } else if (wedgeForUnion.isEmpty()) {\n wedgeForUnion.delete()\n upperResult = upper\n } else {\n upperResult = upper.add(wedgeForUnion)\n upper.delete()\n wedgeForUnion.delete()\n }\n\n // Step 6: Create tolerance wedge W_tol\n const wedgeTol = createWedge(\n Manifold, Mesh,\n planeCenter, normal, widthDir,\n groove.depth + groove.depthTolerance,\n groove.width + groove.widthTolerance,\n groove.flapsAngle,\n extrudeLength + overhang,\n )\n\n // Step 7: lower.subtract(wedgeTol) → lower'\n let lowerResult: ManifoldInstance\n if (lowerForSubtract.isEmpty()) {\n wedgeTol.delete()\n lowerResult = lowerForSubtract\n } else if (wedgeTol.isEmpty()) {\n wedgeTol.delete()\n lowerResult = lowerForSubtract\n } else {\n lowerResult = lowerForSubtract.subtract(wedgeTol)\n lowerForSubtract.delete()\n wedgeTol.delete()\n }\n\n return [upperResult, lowerResult, wedgeMeshData]\n}\n\n// ── Dowel (cylinder) creation ──\n\n/**\n * Create a cylindrical Manifold for the dowel tenon.\n * @param Manifold - the Manifold constructor from the manifold module.\n * @param Mesh - the Mesh constructor from the manifold module.\n * @param centroid - the center of the cylinder in the cutting plane.\n * @param normal - the cutting plane normal (unit vector, points \"up\").\n * @param widthDir - the width direction in the cutting plane (unit vector).\n * @param depthDir - the depth direction in the cutting plane (unit vector).\n * @param diameter - the cylinder diameter (mm).\n * @param height - the cylinder height (mm), extends along -normal.\n * @param segments - the number of circular segments (default 32).\n * @returns the resulting cylindrical Manifold instance.\n */\nexport function createDowel(\n Manifold: ManifoldCtor,\n Mesh: MeshCtor,\n centroid: Vec3,\n normal: Vec3,\n widthDir: Vec3,\n depthDir: Vec3,\n diameter: number,\n height: number,\n segments: number = 32,\n): ManifoldInstance {\n const { positions, indices } = buildDowelGeometry(\n centroid, normal, widthDir, depthDir, diameter, height, segments,\n )\n const mesh = new Mesh({\n numProp: 3,\n vertProperties: positions,\n triVerts: indices,\n })\n return Manifold.ofMesh(mesh)\n}\n\n// ── Straight tenon (box) creation ──\n\n/**\n * Create a box-shaped Manifold for the straight tenon.\n * @param Manifold - the Manifold constructor from the manifold module.\n * @param Mesh - the Mesh constructor from the manifold module.\n * @param centroid - the center of the box in the cutting plane.\n * @param normal - the cutting plane normal (unit vector, points \"up\").\n * @param widthDir - the width direction in the cutting plane (unit vector).\n * @param depthDir - the depth direction in the cutting plane (unit vector).\n * @param sideLength - the square cross-section side length (mm).\n * @param height - the box height (mm), extends along -normal.\n * @returns the resulting box-shaped Manifold instance.\n */\nexport function createStraightTenon(\n Manifold: ManifoldCtor,\n Mesh: MeshCtor,\n centroid: Vec3,\n normal: Vec3,\n widthDir: Vec3,\n depthDir: Vec3,\n sideLength: number,\n height: number,\n): ManifoldInstance {\n const { positions, indices } = buildStraightTenonGeometry(\n centroid, normal, widthDir, depthDir, sideLength, height,\n )\n const mesh = new Mesh({\n numProp: 3,\n vertProperties: positions,\n triVerts: indices,\n })\n return Manifold.ofMesh(mesh)\n}\n\n// ── Dowel / Straight-tenon boolean split ──\n\n/**\n * Perform the dowel (or straight-tenon) split using boolean operations.\n * @param Manifold - the Manifold constructor from the manifold module.\n * @param Mesh - the Mesh constructor from the manifold module.\n * @param original - the original manifold to split.\n * @param normal - the cutting plane normal (unit vector).\n * @param originOffset - the plane equation origin offset along the normal.\n * @param planeCenter - a point on the cutting plane used to center the joinery.\n * @param widthDirInput - the width direction in the cutting plane (will be normalized).\n * @param shape - the joinery shape: 'dowel' or 'tenon'.\n * @param params - the joinery sizing parameters (size, tolerances, height).\n * @param keepOriginal - when true, the original manifold is not deleted after splitting (default false).\n * @param selectedSections - optional list of indices selecting which cap sections receive joinery placement; null or empty means a single placement at the overall cross-section centroid.\n * @returns a tuple of the split upper manifold, lower manifold, and the generated joinery mesh data (or null).\n */\nexport function dowelOrTenonBooleanSplit(\n Manifold: ManifoldCtor,\n Mesh: MeshCtor,\n original: ManifoldInstance,\n normal: Vec3,\n originOffset: number,\n planeCenter: Vec3,\n widthDirInput: Vec3,\n shape: 'dowel' | 'tenon',\n params: {\n size: number\n sizeTolerance: number\n height: number\n heightTolerance: number\n },\n keepOriginal: boolean = false,\n selectedSections?: number[] | null,\n): [ManifoldInstance, ManifoldInstance,\n { positions: Float32Array; indices: Uint32Array } | null] {\n const widthDir = vec3Normalize(widthDirInput)\n const depthDir = vec3Normalize(vec3Cross(normal, widthDir))\n\n // Step 1: Split by plane → upper + lower\n const [upper, lower] = original.splitByPlane(normal, originOffset)\n if (!keepOriginal) original.delete()\n\n // Step 2: Detect cap components (multi-section support)\n const components = detectCapComponents(upper, normal, originOffset)\n\n // Build the list of joinery placements: one per selected section\n interface JoineryPlacement { centroid: Vec3 }\n let placements: JoineryPlacement[]\n\n if (components.length <= 1 || !selectedSections || selectedSections.length === 0) {\n const centroid = computeCrossSectionCentroid(upper, normal, originOffset, planeCenter)\n placements = [{ centroid }]\n } else {\n const compInfo = components.map((comp, idx) => {\n const compWidth = computeCrossSectionWidth(upper, normal, originOffset, widthDir, comp)\n const compCentroid = computeCrossSectionCentroid(upper, normal, originOffset, planeCenter, comp)\n const compDepth = computeCrossSectionWidth(upper, normal, originOffset, depthDir, comp)\n const area = compWidth * compDepth\n return { idx, comp, area, centroid: compCentroid }\n })\n compInfo.sort((a, b) => b.area - a.area)\n\n placements = []\n for (const selId of selectedSections) {\n if (selId < compInfo.length) {\n placements.push({ centroid: compInfo[selId].centroid })\n }\n }\n if (placements.length === 0) {\n const centroid = computeCrossSectionCentroid(upper, normal, originOffset, planeCenter)\n placements = [{ centroid }]\n }\n }\n\n // Step 3: For each placement, create shape C (no tolerance) and union into upper\n let shapeMeshData: { positions: Float32Array; indices: Uint32Array } | null = null\n\n let upperResult = upper\n let upperOwned = true\n\n for (let pIdx = 0; pIdx < placements.length; pIdx++) {\n const { centroid } = placements[pIdx]\n let shapeC: ManifoldInstance\n if (shape === 'dowel') {\n shapeC = createDowel(Manifold, Mesh, centroid, normal, widthDir, depthDir,\n params.size, params.height, 32)\n } else {\n shapeC = createStraightTenon(Manifold, Mesh, centroid, normal, widthDir, depthDir,\n params.size, params.height)\n }\n\n if (pIdx === 0) {\n shapeMeshData = shapeC.isEmpty() ? null : manifoldToMeshData(shapeC)\n }\n\n if (upperResult.isEmpty()) {\n if (upperOwned) upperResult.delete()\n upperResult = shapeC\n upperOwned = true\n } else if (shapeC.isEmpty()) {\n shapeC.delete()\n } else {\n const newUpper = upperResult.add(shapeC)\n if (upperOwned) upperResult.delete()\n upperResult = newUpper\n shapeC.delete()\n upperOwned = true\n }\n }\n\n // Step 4: For each placement, create shape C_tol (with tolerance) and subtract from lower\n const tolSize = params.size + params.sizeTolerance\n const tolHeight = params.height + params.heightTolerance\n\n let lowerResult = lower\n let lowerOwned = true\n\n for (const { centroid } of placements) {\n let shapeCTol: ManifoldInstance\n if (shape === 'dowel') {\n shapeCTol = createDowel(Manifold, Mesh, centroid, normal, widthDir, depthDir,\n tolSize, tolHeight, 32)\n } else {\n shapeCTol = createStraightTenon(Manifold, Mesh, centroid, normal, widthDir, depthDir,\n tolSize, tolHeight)\n }\n\n if (lowerResult.isEmpty()) {\n shapeCTol.delete()\n } else if (shapeCTol.isEmpty()) {\n shapeCTol.delete()\n } else {\n const newLower = lowerResult.subtract(shapeCTol)\n if (lowerOwned) lowerResult.delete()\n lowerResult = newLower\n shapeCTol.delete()\n lowerOwned = true\n }\n }\n\n return [upperResult, lowerResult, shapeMeshData]\n}\n"]}
|
|
1
|
+
{"version":3,"file":"csg-core.js","sourceRoot":"","sources":["../../src/boolean/csg-core.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * csg-core — CSG 纯计算函数(从 csg-worker.ts 提取)\n *\n *\n * 这些函数不依赖 Worker 环境(无 self.onmessage / postMessage),\n * 可被 WorkerCsgBackend(经 csg-worker.ts)和 InlineCsgBackend(主线程直跑)共用。\n *\n * 依赖:manifold-3d 核心模块(Manifold / Mesh 构造器)、dovetail-math、joinery-shapes\n */\n\nimport type { Manifold as ManifoldInstance } from 'manifold-3d/manifold'\nimport {\n vec3Cross, vec3Normalize,\n type Vec3,\n} from './dovetail-math'\nimport {\n buildWedgeGeometry,\n buildDowelGeometry,\n buildStraightTenonGeometry,\n} from './joinery-shapes'\n\n// ── 类型别名 ──\n\ntype ManifoldCtor = typeof import('manifold-3d/manifold').Manifold\ntype MeshCtor = typeof import('manifold-3d/manifold').Mesh\n\n// ── Manifold → MeshData 转换 ──\n\n/**\n * Extract {positions, indices} from a Manifold mesh.\n * Handles the numProp > 3 case (manifold may carry extra property channels).\n * @param manifold The manifold from which to read mesh data.\n * @returns The extracted positions and indices buffers.\n */\nexport function manifoldToMeshData(manifold: ManifoldInstance): {\n positions: Float32Array; indices: Uint32Array\n} {\n const resultMesh = manifold.getMesh()\n const numProp = resultMesh.numProp || 3\n const vertPropsLen = resultMesh.vertProperties ? resultMesh.vertProperties.length : 0\n const vertCount = numProp > 0 ? Math.floor(vertPropsLen / numProp) : 0\n const positions = new Float32Array(vertCount * 3)\n for (let i = 0; i < vertCount; i++) {\n const base = i * numProp\n positions[i * 3] = resultMesh.vertProperties[base]\n positions[i * 3 + 1] = resultMesh.vertProperties[base + 1]\n positions[i * 3 + 2] = resultMesh.vertProperties[base + 2]\n }\n const triVerts = resultMesh.triVerts\n const indices = triVerts ? new Uint32Array(triVerts) : new Uint32Array(0)\n return { positions, indices }\n}\n\n// ── MeshData → Manifold ──\n\n/**\n * Build a Manifold from mesh data, welding duplicate vertices when the density\n * is too high (close to one independent vertex per triangle) before Manifold.ofMesh.\n * Shared by the Inline and Worker backends so both produce identical input conversion.\n * @param Manifold The Manifold constructor from the manifold module.\n * @param Mesh The Mesh constructor from the manifold module.\n * @param mesh The mesh data (positions and indices).\n * @returns The constructed Manifold instance.\n */\nexport function meshToManifold(\n Manifold: ManifoldCtor,\n Mesh: MeshCtor,\n mesh: { positions: Float32Array; indices: Uint32Array },\n): ManifoldInstance {\n const triCount = mesh.indices.length / 3\n const vertCount = mesh.positions.length / 3\n let positions = mesh.positions\n let indices = mesh.indices\n\n if (vertCount >= triCount * 3 * 0.9) {\n const welded = weldPositionsWorker(mesh.positions, mesh.indices, mesh.indices.length)\n positions = welded.positions\n indices = welded.indices\n }\n\n return Manifold.ofMesh(new Mesh({\n numProp: 3,\n vertProperties: positions,\n triVerts: indices,\n }))\n}\n\n/**\n * Sequentially apply a boolean operation across an array of Manifolds.\n * The caller is responsible for deleting the input manifolds and the result.\n * @param op The boolean operation to apply (union/subtract/intersect).\n * @param manifolds The manifolds to combine in order.\n * @returns The resulting Manifold of the chain.\n */\nexport function chainBoolean(\n op: 'union' | 'subtract' | 'intersect',\n manifolds: ManifoldInstance[],\n): ManifoldInstance {\n let result = manifolds[0]\n for (let i = 1; i < manifolds.length; i++) {\n switch (op) {\n case 'union':\n result = result.add(manifolds[i])\n break\n case 'subtract':\n result = result.subtract(manifolds[i])\n break\n case 'intersect':\n result = result.intersect(manifolds[i])\n break\n }\n }\n return result\n}\n\n// ── 顶点焊接 ──\n\n/**\n * Weld duplicate vertices using a quantized 1 µm grid.\n * Uses three nested numeric Maps (no string allocation).\n * @param positions The input vertex positions.\n * @param indices The input triangle indices.\n * @param count The number of indices to process.\n * @returns The welded positions and remapped indices buffers.\n */\nexport function weldPositionsWorker(\n positions: Float32Array,\n indices: Uint32Array,\n count: number,\n): { positions: Float32Array; indices: Uint32Array } {\n const mapX = new Map<number, Map<number, Map<number, number>>>()\n const weldedPosArr: number[] = []\n const weldedIdxArr: number[] = []\n\n for (let i = 0; i < count; i++) {\n const vi = indices[i]\n const x = positions[vi * 3]\n const y = positions[vi * 3 + 1]\n const z = positions[vi * 3 + 2]\n const qx = Math.round(x * 1e6)\n const qy = Math.round(y * 1e6)\n const qz = Math.round(z * 1e6)\n\n let mapY = mapX.get(qx)\n if (mapY === undefined) {\n mapY = new Map<number, Map<number, number>>()\n mapX.set(qx, mapY)\n }\n let mapZ = mapY.get(qy)\n if (mapZ === undefined) {\n mapZ = new Map<number, number>()\n mapY.set(qy, mapZ)\n }\n let ni = mapZ.get(qz)\n if (ni === undefined) {\n ni = weldedPosArr.length / 3\n mapZ.set(qz, ni)\n weldedPosArr.push(x, y, z)\n }\n weldedIdxArr.push(ni)\n }\n\n return {\n positions: new Float32Array(weldedPosArr),\n indices: new Uint32Array(weldedIdxArr),\n }\n}\n\n// ── Union-Find ──\n\n/** Simple union-find for clustering cap triangles by shared edges. */\nexport class SimpleUnionFind {\n private parent: number[]\n private rank: number[]\n\n /**\n * Create a union-find structure with n initial singletons.\n * @param n The number of elements.\n */\n constructor(n: number) {\n this.parent = Array.from({ length: n }, (_, i) => i)\n this.rank = new Array(n).fill(0)\n }\n\n /**\n * Find the root representative of the element x (with path compression).\n * @param x The element to look up.\n * @returns The root index of the set containing x.\n */\n find(x: number): number {\n if (this.parent[x] !== x) {\n this.parent[x] = this.find(this.parent[x])\n }\n return this.parent[x]\n }\n\n /**\n * Union the sets containing x and y.\n * @param x The first element.\n * @param y The second element.\n */\n union(x: number, y: number): void {\n const px = this.find(x)\n const py = this.find(y)\n if (px === py) return\n if (this.rank[px] < this.rank[py]) {\n this.parent[px] = py\n } else if (this.rank[px] > this.rank[py]) {\n this.parent[py] = px\n } else {\n this.parent[py] = px\n this.rank[px]++\n }\n }\n}\n\n// ── Wedge (trapezoidal prism) creation ──\n\n/**\n * Create a wedge (trapezoidal prism) Manifold from cutting-plane parameters.\n * @param Manifold The Manifold constructor from the manifold module.\n * @param Mesh The Mesh constructor from the manifold module.\n * @param planeCenter Center of the cutting plane.\n * @param normal Cutting plane normal (unit vector).\n * @param widthDir Extrusion direction (unit vector).\n * @param depth Wedge depth (mm).\n * @param width Wedge width (mm).\n * @param angleDeg Slant angle of the wedge sides (degrees).\n * @param extrudeLength Total extrusion length along widthDir (mm).\n * @returns The constructed wedge Manifold.\n */\nexport function createWedge(\n Manifold: ManifoldCtor,\n Mesh: MeshCtor,\n planeCenter: Vec3,\n normal: Vec3,\n widthDir: Vec3,\n depth: number,\n width: number,\n angleDeg: number,\n extrudeLength: number,\n): ManifoldInstance {\n const { positions, indices } = buildWedgeGeometry(\n planeCenter, normal, widthDir, depth, width, angleDeg, extrudeLength,\n )\n const mesh = new Mesh({\n numProp: 3,\n vertProperties: positions,\n triVerts: indices,\n })\n return Manifold.ofMesh(mesh)\n}\n\n// ── Cap component detection ──\n\n/**\n * Detect connected components of cap faces on the cutting plane.\n * Returns an array of components, each being a Set of vertex indices.\n * @param upper The upper mesh to scan for cap faces.\n * @param normal The cutting plane normal.\n * @param planeDistance The cutting plane offset along the normal.\n * @returns An array of components, each a Set of vertex indices on the cap.\n */\nexport function detectCapComponents(\n upper: ManifoldInstance,\n normal: Vec3,\n planeDistance: number,\n): Set<number>[] {\n const mesh = upper.getMesh()\n const eps = 0.001\n const numProp = mesh.numProp || 3\n const vertCount = Math.floor(mesh.vertProperties.length / numProp)\n const triVerts = mesh.triVerts\n if (!triVerts || triVerts.length === 0) return []\n\n const capVertSet = new Set<number>()\n interface CapTri { v0: number; v1: number; v2: number }\n const capTris: CapTri[] = []\n const triCount = triVerts.length / 3\n for (let t = 0; t < triCount; t++) {\n const i0 = triVerts[t * 3]\n const i1 = triVerts[t * 3 + 1]\n const i2 = triVerts[t * 3 + 2]\n const d0 = Math.abs(\n mesh.vertProperties[i0 * numProp] * normal[0] +\n mesh.vertProperties[i0 * numProp + 1] * normal[1] +\n mesh.vertProperties[i0 * numProp + 2] * normal[2] - planeDistance)\n const d1 = Math.abs(\n mesh.vertProperties[i1 * numProp] * normal[0] +\n mesh.vertProperties[i1 * numProp + 1] * normal[1] +\n mesh.vertProperties[i1 * numProp + 2] * normal[2] - planeDistance)\n const d2 = Math.abs(\n mesh.vertProperties[i2 * numProp] * normal[0] +\n mesh.vertProperties[i2 * numProp + 1] * normal[1] +\n mesh.vertProperties[i2 * numProp + 2] * normal[2] - planeDistance)\n if (d0 < eps && d1 < eps && d2 < eps) {\n capTris.push({ v0: i0, v1: i1, v2: i2 })\n capVertSet.add(i0); capVertSet.add(i1); capVertSet.add(i2)\n }\n }\n if (capTris.length === 0) return []\n\n const uf = new SimpleUnionFind(vertCount)\n for (const tri of capTris) {\n uf.union(tri.v0, tri.v1)\n uf.union(tri.v1, tri.v2)\n uf.union(tri.v0, tri.v2)\n }\n\n const compMap = new Map<number, Set<number>>()\n for (const vi of capVertSet) {\n const root = uf.find(vi)\n if (!compMap.has(root)) compMap.set(root, new Set<number>())\n compMap.get(root)!.add(vi)\n }\n\n return Array.from(compMap.values())\n}\n\n// ── Cross-section width computation ──\n\n/**\n * Compute the actual extent of the model's cross-section at the cutting plane\n * along the width direction.\n * @param upper The upper mesh to measure.\n * @param normal The cutting plane normal.\n * @param planeDistance The cutting plane offset along the normal.\n * @param widthDir The width direction along which to measure.\n * @param comp Optional connected component to restrict the measurement to.\n * @returns The cross-section extent along the width direction (0 when none found).\n */\nexport function computeCrossSectionWidth(\n upper: ManifoldInstance,\n normal: Vec3,\n planeDistance: number,\n widthDir: Vec3,\n comp?: Set<number>,\n): number {\n const mesh = upper.getMesh()\n const eps = 0.001\n let minProj = Infinity\n let maxProj = -Infinity\n let found = false\n\n const numProp = mesh.numProp || 3\n const vertCount = Math.floor(mesh.vertProperties.length / numProp)\n for (let i = 0; i < vertCount; i++) {\n if (comp && !comp.has(i)) continue\n\n const base = i * numProp\n const x = mesh.vertProperties[base]\n const y = mesh.vertProperties[base + 1]\n const z = mesh.vertProperties[base + 2]\n\n const dist = x * normal[0] + y * normal[1] + z * normal[2] - planeDistance\n if (Math.abs(dist) < eps) {\n const proj = x * widthDir[0] + y * widthDir[1] + z * widthDir[2]\n if (proj < minProj) minProj = proj\n if (proj > maxProj) maxProj = proj\n found = true\n }\n }\n\n if (!found) return 0\n return maxProj - minProj\n}\n\n// ── Cross-section centroid computation ──\n\n/**\n * Compute the centroid of vertices lying on the cutting plane.\n * @param upper The upper mesh to scan.\n * @param normal The cutting plane normal.\n * @param planeDistance The cutting plane offset along the normal.\n * @param fallback The centroid fallback when no vertex lies on the plane.\n * @param comp Optional connected component to restrict the measurement to.\n * @returns The computed centroid, or the fallback when none is found.\n */\nexport function computeCrossSectionCentroid(\n upper: ManifoldInstance,\n normal: Vec3,\n planeDistance: number,\n fallback: Vec3,\n comp?: Set<number>,\n): Vec3 {\n const mesh = upper.getMesh()\n const eps = 0.001\n let cx = 0, cy = 0, cz = 0\n let count = 0\n\n const numProp = mesh.numProp || 3\n const vertCount = Math.floor(mesh.vertProperties.length / numProp)\n for (let i = 0; i < vertCount; i++) {\n if (comp && !comp.has(i)) continue\n\n const base = i * numProp\n const x = mesh.vertProperties[base]\n const y = mesh.vertProperties[base + 1]\n const z = mesh.vertProperties[base + 2]\n\n const dist = x * normal[0] + y * normal[1] + z * normal[2] - planeDistance\n if (Math.abs(dist) < eps) {\n cx += x\n cy += y\n cz += z\n count++\n }\n }\n\n if (count === 0) return fallback\n return [cx / count, cy / count, cz / count]\n}\n\n// ── Dovetail boolean split ──\n\n/**\n * Perform the dovetail split using boolean operations.\n * @param Manifold - the Manifold constructor from the manifold module.\n * @param Mesh - the Mesh constructor from the manifold module.\n * @param original - the original manifold to split.\n * @param normal - the cutting plane normal (unit vector).\n * @param planeDistance - the plane equation origin offset along the normal.\n * @param planeCenter - a point on the cutting plane used to center the wedge.\n * @param widthDirInput - the width direction in the cutting plane (will be normalized).\n * @param bboxWidthOnWidthDir - the model's bounding-box width along widthDir, used as a fallback cross-section width.\n * @param groove - the dovetail groove design parameters (depth, tolerances, width, flaps angle).\n * @param keepOriginal - when true, the original manifold is not deleted after splitting (default false).\n * @returns a tuple of the split upper manifold, lower manifold, and the trimmed wedge mesh data (or null when empty).\n */\nexport function dovetailBooleanSplit(\n Manifold: ManifoldCtor,\n Mesh: MeshCtor,\n original: ManifoldInstance,\n normal: Vec3,\n planeDistance: number,\n planeCenter: Vec3,\n widthDirInput: Vec3,\n bboxWidthOnWidthDir: number,\n groove: {\n depth: number\n depthTolerance: number\n width: number\n widthTolerance: number\n flapsAngle: number\n },\n keepOriginal: boolean = false,\n): [ManifoldInstance, ManifoldInstance,\n { positions: Float32Array; indices: Uint32Array } | null] {\n const widthDir = vec3Normalize(widthDirInput)\n\n // Step 1: Split by plane → upper + lower\n const [upper, lower] = original.splitByPlane(normal, planeDistance)\n if (!keepOriginal) original.delete()\n\n // Step 2: Compute actual cross-section width at the cutting plane\n let crossSectionWidth = computeCrossSectionWidth(upper, normal, planeDistance, widthDir)\n if (crossSectionWidth <= 0) {\n crossSectionWidth = bboxWidthOnWidthDir\n }\n const extrudeLength = crossSectionWidth + 0.2\n\n // Step 3: Create wedge W with generous overhang along widthDir\n const overhang = 20\n\n const wedgeW = createWedge(\n Manifold, Mesh,\n planeCenter, normal, widthDir,\n groove.depth, groove.width, groove.flapsAngle,\n extrudeLength + overhang,\n )\n\n // Trim the wedge to the model by intersecting with lower.\n let wedgeForUnion: ManifoldInstance\n let wedgeMeshData: { positions: Float32Array; indices: Uint32Array } | null\n let lowerForSubtract: ManifoldInstance\n\n if (!wedgeW.isEmpty() && !lower.isEmpty()) {\n const lowerMeshData = manifoldToMeshData(lower)\n\n const trimmedWedge = wedgeW.intersect(lower)\n wedgeW.delete()\n lower.delete()\n\n wedgeMeshData = trimmedWedge.isEmpty() ? null : manifoldToMeshData(trimmedWedge)\n wedgeForUnion = trimmedWedge\n\n lowerForSubtract = Manifold.ofMesh(new Mesh({\n numProp: 3,\n vertProperties: lowerMeshData.positions,\n triVerts: lowerMeshData.indices,\n }))\n } else {\n wedgeMeshData = null\n wedgeForUnion = wedgeW\n lowerForSubtract = lower\n }\n\n // Step 5: union(upper, wedgeForUnion) → upper'\n let upperResult: ManifoldInstance\n if (upper.isEmpty()) {\n upper.delete()\n upperResult = wedgeForUnion\n } else if (wedgeForUnion.isEmpty()) {\n wedgeForUnion.delete()\n upperResult = upper\n } else {\n upperResult = upper.add(wedgeForUnion)\n upper.delete()\n wedgeForUnion.delete()\n }\n\n // Step 6: Create tolerance wedge W_tol\n const wedgeTol = createWedge(\n Manifold, Mesh,\n planeCenter, normal, widthDir,\n groove.depth + groove.depthTolerance,\n groove.width + groove.widthTolerance,\n groove.flapsAngle,\n extrudeLength + overhang,\n )\n\n // Step 7: lower.subtract(wedgeTol) → lower'\n let lowerResult: ManifoldInstance\n if (lowerForSubtract.isEmpty()) {\n wedgeTol.delete()\n lowerResult = lowerForSubtract\n } else if (wedgeTol.isEmpty()) {\n wedgeTol.delete()\n lowerResult = lowerForSubtract\n } else {\n lowerResult = lowerForSubtract.subtract(wedgeTol)\n lowerForSubtract.delete()\n wedgeTol.delete()\n }\n\n return [upperResult, lowerResult, wedgeMeshData]\n}\n\n// ── Dowel (cylinder) creation ──\n\n/**\n * Create a cylindrical Manifold for the dowel tenon.\n * @param Manifold - the Manifold constructor from the manifold module.\n * @param Mesh - the Mesh constructor from the manifold module.\n * @param centroid - the center of the cylinder in the cutting plane.\n * @param normal - the cutting plane normal (unit vector, points \"up\").\n * @param widthDir - the width direction in the cutting plane (unit vector).\n * @param depthDir - the depth direction in the cutting plane (unit vector).\n * @param diameter - the cylinder diameter (mm).\n * @param height - the cylinder height (mm), extends along -normal.\n * @param segments - the number of circular segments (default 32).\n * @returns the resulting cylindrical Manifold instance.\n */\nexport function createDowel(\n Manifold: ManifoldCtor,\n Mesh: MeshCtor,\n centroid: Vec3,\n normal: Vec3,\n widthDir: Vec3,\n depthDir: Vec3,\n diameter: number,\n height: number,\n segments: number = 32,\n): ManifoldInstance {\n const { positions, indices } = buildDowelGeometry(\n centroid, normal, widthDir, depthDir, diameter, height, segments,\n )\n const mesh = new Mesh({\n numProp: 3,\n vertProperties: positions,\n triVerts: indices,\n })\n return Manifold.ofMesh(mesh)\n}\n\n// ── Straight tenon (box) creation ──\n\n/**\n * Create a box-shaped Manifold for the straight tenon.\n * @param Manifold - the Manifold constructor from the manifold module.\n * @param Mesh - the Mesh constructor from the manifold module.\n * @param centroid - the center of the box in the cutting plane.\n * @param normal - the cutting plane normal (unit vector, points \"up\").\n * @param widthDir - the width direction in the cutting plane (unit vector).\n * @param depthDir - the depth direction in the cutting plane (unit vector).\n * @param sideLength - the square cross-section side length (mm).\n * @param height - the box height (mm), extends along -normal.\n * @returns the resulting box-shaped Manifold instance.\n */\nexport function createStraightTenon(\n Manifold: ManifoldCtor,\n Mesh: MeshCtor,\n centroid: Vec3,\n normal: Vec3,\n widthDir: Vec3,\n depthDir: Vec3,\n sideLength: number,\n height: number,\n): ManifoldInstance {\n const { positions, indices } = buildStraightTenonGeometry(\n centroid, normal, widthDir, depthDir, sideLength, height,\n )\n const mesh = new Mesh({\n numProp: 3,\n vertProperties: positions,\n triVerts: indices,\n })\n return Manifold.ofMesh(mesh)\n}\n\n// ── Dowel / Straight-tenon boolean split ──\n\n/**\n * Perform the dowel (or straight-tenon) split using boolean operations.\n * @param Manifold - the Manifold constructor from the manifold module.\n * @param Mesh - the Mesh constructor from the manifold module.\n * @param original - the original manifold to split.\n * @param normal - the cutting plane normal (unit vector).\n * @param planeDistance - the plane equation origin offset along the normal.\n * @param planeCenter - a point on the cutting plane used to center the joinery.\n * @param widthDirInput - the width direction in the cutting plane (will be normalized).\n * @param shape - the joinery shape: 'dowel' or 'tenon'.\n * @param params - the joinery sizing parameters (size, tolerances, height).\n * @param keepOriginal - when true, the original manifold is not deleted after splitting (default false).\n * @param selectedSections - optional list of indices selecting which cap sections receive joinery placement; null or empty means a single placement at the overall cross-section centroid.\n * @returns a tuple of the split upper manifold, lower manifold, and the generated joinery mesh data (or null).\n */\nexport function dowelOrTenonBooleanSplit(\n Manifold: ManifoldCtor,\n Mesh: MeshCtor,\n original: ManifoldInstance,\n normal: Vec3,\n planeDistance: number,\n planeCenter: Vec3,\n widthDirInput: Vec3,\n shape: 'dowel' | 'tenon',\n params: {\n size: number\n sizeTolerance: number\n height: number\n heightTolerance: number\n },\n keepOriginal: boolean = false,\n selectedSections?: number[] | null,\n): [ManifoldInstance, ManifoldInstance,\n { positions: Float32Array; indices: Uint32Array } | null] {\n const widthDir = vec3Normalize(widthDirInput)\n const depthDir = vec3Normalize(vec3Cross(normal, widthDir))\n\n // Step 1: Split by plane → upper + lower\n const [upper, lower] = original.splitByPlane(normal, planeDistance)\n if (!keepOriginal) original.delete()\n\n // Step 2: Detect cap components (multi-section support)\n const components = detectCapComponents(upper, normal, planeDistance)\n\n // Build the list of joinery placements: one per selected section\n interface JoineryPlacement { centroid: Vec3 }\n let placements: JoineryPlacement[]\n\n if (components.length <= 1 || !selectedSections || selectedSections.length === 0) {\n const centroid = computeCrossSectionCentroid(upper, normal, planeDistance, planeCenter)\n placements = [{ centroid }]\n } else {\n const compInfo = components.map((comp, idx) => {\n const compWidth = computeCrossSectionWidth(upper, normal, planeDistance, widthDir, comp)\n const compCentroid = computeCrossSectionCentroid(upper, normal, planeDistance, planeCenter, comp)\n const compDepth = computeCrossSectionWidth(upper, normal, planeDistance, depthDir, comp)\n const area = compWidth * compDepth\n return { idx, comp, area, centroid: compCentroid }\n })\n compInfo.sort((a, b) => b.area - a.area)\n\n placements = []\n for (const selId of selectedSections) {\n if (selId < compInfo.length) {\n placements.push({ centroid: compInfo[selId].centroid })\n }\n }\n if (placements.length === 0) {\n const centroid = computeCrossSectionCentroid(upper, normal, planeDistance, planeCenter)\n placements = [{ centroid }]\n }\n }\n\n // Step 3: For each placement, create shape C (no tolerance) and union into upper\n let shapeMeshData: { positions: Float32Array; indices: Uint32Array } | null = null\n\n let upperResult = upper\n let upperOwned = true\n\n for (let pIdx = 0; pIdx < placements.length; pIdx++) {\n const { centroid } = placements[pIdx]\n let shapeC: ManifoldInstance\n if (shape === 'dowel') {\n shapeC = createDowel(Manifold, Mesh, centroid, normal, widthDir, depthDir,\n params.size, params.height, 32)\n } else {\n shapeC = createStraightTenon(Manifold, Mesh, centroid, normal, widthDir, depthDir,\n params.size, params.height)\n }\n\n if (pIdx === 0) {\n shapeMeshData = shapeC.isEmpty() ? null : manifoldToMeshData(shapeC)\n }\n\n if (upperResult.isEmpty()) {\n if (upperOwned) upperResult.delete()\n upperResult = shapeC\n upperOwned = true\n } else if (shapeC.isEmpty()) {\n shapeC.delete()\n } else {\n const newUpper = upperResult.add(shapeC)\n if (upperOwned) upperResult.delete()\n upperResult = newUpper\n shapeC.delete()\n upperOwned = true\n }\n }\n\n // Step 4: For each placement, create shape C_tol (with tolerance) and subtract from lower\n const tolSize = params.size + params.sizeTolerance\n const tolHeight = params.height + params.heightTolerance\n\n let lowerResult = lower\n let lowerOwned = true\n\n for (const { centroid } of placements) {\n let shapeCTol: ManifoldInstance\n if (shape === 'dowel') {\n shapeCTol = createDowel(Manifold, Mesh, centroid, normal, widthDir, depthDir,\n tolSize, tolHeight, 32)\n } else {\n shapeCTol = createStraightTenon(Manifold, Mesh, centroid, normal, widthDir, depthDir,\n tolSize, tolHeight)\n }\n\n if (lowerResult.isEmpty()) {\n shapeCTol.delete()\n } else if (shapeCTol.isEmpty()) {\n shapeCTol.delete()\n } else {\n const newLower = lowerResult.subtract(shapeCTol)\n if (lowerOwned) lowerResult.delete()\n lowerResult = newLower\n shapeCTol.delete()\n lowerOwned = true\n }\n }\n\n return [upperResult, lowerResult, shapeMeshData]\n}\n"]}
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
* 交互期的快速预览走 engine/components/extrude-preview-nosplit.ts(不 split 原模型)。
|
|
12
12
|
*
|
|
13
13
|
* 放在 engine/boolean/ 下的约束:**不得 import stores**(保持与 csg.ts 同层的纯度)。
|
|
14
|
-
* 平面参数(normal /
|
|
14
|
+
* 平面参数(normal / planeDistance)由调用方用 computePlaneParams 算好后传入。
|
|
15
15
|
*/
|
|
16
16
|
import * as THREE from 'three';
|
|
17
17
|
import type { ManifoldMeshData } from '../boolean/csg-backend.js';
|
|
@@ -41,15 +41,15 @@ export declare function computeExtrudeOffsets(mode: ExtrudeOffsetMode, length: n
|
|
|
41
41
|
back: number;
|
|
42
42
|
};
|
|
43
43
|
/**
|
|
44
|
-
* 由 computePlaneParams 的 (normal,
|
|
44
|
+
* 由 computePlaneParams 的 (normal, planeDistance) 构造 THREE 世界平面。
|
|
45
45
|
*
|
|
46
|
-
* 约定:平面方程为 `N · p =
|
|
47
|
-
* 故 constant = -
|
|
46
|
+
* 约定:平面方程为 `N · p = planeDistance`;THREE.Plane 用 `N · p + constant = 0`,
|
|
47
|
+
* 故 constant = -planeDistance。THREE 裁剪保留 distanceToPoint >= 0 的一侧(法线正侧)。
|
|
48
48
|
* @param normal - the cutting plane normal as a 3-component array.
|
|
49
|
-
* @param
|
|
49
|
+
* @param planeDistance - the plane equation origin offset along the normal.
|
|
50
50
|
* @returns a THREE.Plane and its normalized normal vector.
|
|
51
51
|
*/
|
|
52
|
-
export declare function makeWorldPlane(normal: [number, number, number],
|
|
52
|
+
export declare function makeWorldPlane(normal: [number, number, number], planeDistance: number): {
|
|
53
53
|
plane: THREE.Plane;
|
|
54
54
|
normalVec: THREE.Vector3;
|
|
55
55
|
};
|
|
@@ -61,12 +61,12 @@ export declare function makeWorldPlane(normal: [number, number, number], originO
|
|
|
61
61
|
*
|
|
62
62
|
* @param worldMesh 世界空间的源网格(局部几何 × matrixWorld)
|
|
63
63
|
* @param normal 切割平面法线(单位向量)
|
|
64
|
-
* @param
|
|
64
|
+
* @param planeDistance 平面方程 N·p = planeDistance 的右端
|
|
65
65
|
* @param length 拉伸长度 L
|
|
66
66
|
* @param mode 三段位移模式
|
|
67
67
|
* @returns the split front, back, and extruded middle mesh parts.
|
|
68
68
|
*/
|
|
69
|
-
export declare function buildExtrudeParts(worldMesh: ManifoldMeshData, normal: [number, number, number],
|
|
69
|
+
export declare function buildExtrudeParts(worldMesh: ManifoldMeshData, normal: [number, number, number], planeDistance: number, length: number, mode: ExtrudeOffsetMode): Promise<ExtrudeParts>;
|
|
70
70
|
/**
|
|
71
71
|
* 沿法线方向按 scaleFactor 缩放每个顶点到平面的有向距离。
|
|
72
72
|
* 平面上的顶点不动,离面顶点按比例外推。
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"extrude-helpers.d.ts","sourceRoot":"","sources":["../../src/boolean/extrude-helpers.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAE9B,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAA;AAE9D,qEAAqE;AACrE,MAAM,MAAM,iBAAiB,GAAG,UAAU,GAAG,SAAS,GAAG,UAAU,CAAA;AAEnE,mDAAmD;AACnD,eAAO,MAAM,eAAe,MAAM,CAAA;AAElC;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,gBAAgB,GAAG,IAAI,CAAA;IAC9B,IAAI,EAAE,gBAAgB,GAAG,IAAI,CAAA;IAC7B,QAAQ,EAAE,gBAAgB,GAAG,IAAI,CAAA;CAClC;AAED;;;;;;;;GAQG;AACH,wBAAgB,qBAAqB,CACnC,IAAI,EAAE,iBAAiB,EACvB,MAAM,EAAE,MAAM,GACb;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAUjC;AAED;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAC5B,MAAM,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAChC,
|
|
1
|
+
{"version":3,"file":"extrude-helpers.d.ts","sourceRoot":"","sources":["../../src/boolean/extrude-helpers.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAE9B,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAA;AAE9D,qEAAqE;AACrE,MAAM,MAAM,iBAAiB,GAAG,UAAU,GAAG,SAAS,GAAG,UAAU,CAAA;AAEnE,mDAAmD;AACnD,eAAO,MAAM,eAAe,MAAM,CAAA;AAElC;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,gBAAgB,GAAG,IAAI,CAAA;IAC9B,IAAI,EAAE,gBAAgB,GAAG,IAAI,CAAA;IAC7B,QAAQ,EAAE,gBAAgB,GAAG,IAAI,CAAA;CAClC;AAED;;;;;;;;GAQG;AACH,wBAAgB,qBAAqB,CACnC,IAAI,EAAE,iBAAiB,EACvB,MAAM,EAAE,MAAM,GACb;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAUjC;AAED;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAC5B,MAAM,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAChC,aAAa,EAAE,MAAM,GACpB;IAAE,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC;IAAC,SAAS,EAAE,KAAK,CAAC,OAAO,CAAA;CAAE,CAMlD;AAED;;;;;;;;;;;;GAYG;AACH,wBAAsB,iBAAiB,CACrC,SAAS,EAAE,gBAAgB,EAC3B,MAAM,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAChC,aAAa,EAAE,MAAM,EACrB,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,iBAAiB,GACtB,OAAO,CAAC,YAAY,CAAC,CAyBvB;AAED;;;;;;;;GAQG;AACH,wBAAgB,oBAAoB,CAClC,IAAI,EAAE,gBAAgB,EACtB,MAAM,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAChC,WAAW,EAAE,MAAM,EACnB,WAAW,EAAE,MAAM,GAClB,gBAAgB,CAUlB;AAED;;;;;;GAMG;AACH,wBAAgB,UAAU,CACxB,IAAI,EAAE,gBAAgB,EACtB,SAAS,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EACnC,QAAQ,EAAE,MAAM,GACf,gBAAgB,CAYlB"}
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
* 交互期的快速预览走 engine/components/extrude-preview-nosplit.ts(不 split 原模型)。
|
|
12
12
|
*
|
|
13
13
|
* 放在 engine/boolean/ 下的约束:**不得 import stores**(保持与 csg.ts 同层的纯度)。
|
|
14
|
-
* 平面参数(normal /
|
|
14
|
+
* 平面参数(normal / planeDistance)由调用方用 computePlaneParams 算好后传入。
|
|
15
15
|
*/
|
|
16
16
|
import * as THREE from 'three';
|
|
17
17
|
import { computeSplit } from '../boolean/csg-backend.js';
|
|
@@ -38,18 +38,18 @@ export function computeExtrudeOffsets(mode, length) {
|
|
|
38
38
|
}
|
|
39
39
|
}
|
|
40
40
|
/**
|
|
41
|
-
* 由 computePlaneParams 的 (normal,
|
|
41
|
+
* 由 computePlaneParams 的 (normal, planeDistance) 构造 THREE 世界平面。
|
|
42
42
|
*
|
|
43
|
-
* 约定:平面方程为 `N · p =
|
|
44
|
-
* 故 constant = -
|
|
43
|
+
* 约定:平面方程为 `N · p = planeDistance`;THREE.Plane 用 `N · p + constant = 0`,
|
|
44
|
+
* 故 constant = -planeDistance。THREE 裁剪保留 distanceToPoint >= 0 的一侧(法线正侧)。
|
|
45
45
|
* @param normal - the cutting plane normal as a 3-component array.
|
|
46
|
-
* @param
|
|
46
|
+
* @param planeDistance - the plane equation origin offset along the normal.
|
|
47
47
|
* @returns a THREE.Plane and its normalized normal vector.
|
|
48
48
|
*/
|
|
49
|
-
export function makeWorldPlane(normal,
|
|
49
|
+
export function makeWorldPlane(normal, planeDistance) {
|
|
50
50
|
const normalVec = new THREE.Vector3(normal[0], normal[1], normal[2]).normalize();
|
|
51
51
|
return {
|
|
52
|
-
plane: new THREE.Plane(normalVec.clone(), -
|
|
52
|
+
plane: new THREE.Plane(normalVec.clone(), -planeDistance),
|
|
53
53
|
normalVec,
|
|
54
54
|
};
|
|
55
55
|
}
|
|
@@ -61,25 +61,25 @@ export function makeWorldPlane(normal, originOffset) {
|
|
|
61
61
|
*
|
|
62
62
|
* @param worldMesh 世界空间的源网格(局部几何 × matrixWorld)
|
|
63
63
|
* @param normal 切割平面法线(单位向量)
|
|
64
|
-
* @param
|
|
64
|
+
* @param planeDistance 平面方程 N·p = planeDistance 的右端
|
|
65
65
|
* @param length 拉伸长度 L
|
|
66
66
|
* @param mode 三段位移模式
|
|
67
67
|
* @returns the split front, back, and extruded middle mesh parts.
|
|
68
68
|
*/
|
|
69
|
-
export async function buildExtrudeParts(worldMesh, normal,
|
|
69
|
+
export async function buildExtrudeParts(worldMesh, normal, planeDistance, length, mode) {
|
|
70
70
|
const { front: offsetFront, back: offsetBack } = computeExtrudeOffsets(mode, length);
|
|
71
71
|
// 拉伸方向 D 恒等于切割平面法线 N
|
|
72
72
|
const D = [normal[0], normal[1], normal[2]];
|
|
73
73
|
// 1. 平面处切开 → front / back
|
|
74
|
-
const splitResult = await computeSplit(worldMesh, normal,
|
|
74
|
+
const splitResult = await computeSplit(worldMesh, normal, planeDistance);
|
|
75
75
|
let front = splitResult.front;
|
|
76
76
|
let back = splitResult.back;
|
|
77
77
|
let extruded = null;
|
|
78
78
|
// 2. 从 front 再切一片厚 SLICE_THICKNESS 的薄壳
|
|
79
|
-
const capSplit = await computeSplit(splitResult.front, normal,
|
|
80
|
-
// 3. 薄壳以平面为锚点沿 N 放大 L/SLICE_THICKNESS → 占据 [
|
|
79
|
+
const capSplit = await computeSplit(splitResult.front, normal, planeDistance + SLICE_THICKNESS);
|
|
80
|
+
// 3. 薄壳以平面为锚点沿 N 放大 L/SLICE_THICKNESS → 占据 [planeDistance, planeDistance+L]
|
|
81
81
|
if (capSplit.back && capSplit.back.indices.length > 0) {
|
|
82
|
-
extruded = scaleMeshAlongNormal(capSplit.back, D,
|
|
82
|
+
extruded = scaleMeshAlongNormal(capSplit.back, D, planeDistance, length / SLICE_THICKNESS);
|
|
83
83
|
}
|
|
84
84
|
// 4. 三段各自沿 D 位移;中段起点对齐 back 侧
|
|
85
85
|
if (front)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"extrude-helpers.js","sourceRoot":"","sources":["../../src/boolean/extrude-helpers.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAC9B,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAA;AAMrD,mDAAmD;AACnD,MAAM,CAAC,MAAM,eAAe,GAAG,GAAG,CAAA;AAWlC;;;;;;;;GAQG;AACH,MAAM,UAAU,qBAAqB,CACnC,IAAuB,EACvB,MAAc;IAEd,QAAQ,IAAI,EAAE,CAAC;QACb,KAAK,SAAS;YACZ,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,EAAE,CAAA;QACnC,KAAK,UAAU;YACb,OAAO,EAAE,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,MAAM,EAAE,CAAA;QACpC,KAAK,UAAU,CAAC;QAChB;YACE,OAAO,EAAE,KAAK,EAAE,MAAM,GAAG,CAAC,EAAE,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,EAAE,CAAA;IACnD,CAAC;AACH,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,cAAc,CAC5B,MAAgC,EAChC,
|
|
1
|
+
{"version":3,"file":"extrude-helpers.js","sourceRoot":"","sources":["../../src/boolean/extrude-helpers.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * 拉伸(extrude)几何工具集 —— 从 ExtrudeRenderer.tsx 抽出的纯几何函数。\n *\n * 拉伸的语义(三段模型):在切割平面把模型切开,得到\n * - back(下半):沿法线 N 平移 offsetBack\n * - middle(中段):平面处的截面沿 N 挤出 L,落在 [offsetBack, offsetBack + L]\n * - front(上半):沿法线 N 平移 offsetFront\n * 其中 offsetFront - offsetBack === L 恒成立(见 computeExtrudeOffsets)。\n *\n * 本模块只负责「全分辨率、几何正确」的那条路径(预览提交 / 无预览直接执行)。\n * 交互期的快速预览走 engine/components/extrude-preview-nosplit.ts(不 split 原模型)。\n *\n * 放在 engine/boolean/ 下的约束:**不得 import stores**(保持与 csg.ts 同层的纯度)。\n * 平面参数(normal / planeDistance)由调用方用 computePlaneParams 算好后传入。\n */\nimport * as THREE from 'three'\nimport { computeSplit } from '../boolean/csg-backend'\nimport type { ManifoldMeshData } from '../boolean/csg-backend'\n\n/** 与 extrude-store 的 ExtrusionMode 结构兼容(此处不 import store,避免层级倒置)。 */\nexport type ExtrudeOffsetMode = 'centered' | 'forward' | 'backward'\n\n/** slice 法取薄片的厚度(沿法线),随后按 L/SLICE_THICKNESS 拉伸。 */\nexport const SLICE_THICKNESS = 0.2\n\n/**\n * The three mesh parts produced by an extrude operation.\n */\nexport interface ExtrudeParts {\n front: ManifoldMeshData | null\n back: ManifoldMeshData | null\n extruded: ManifoldMeshData | null\n}\n\n/**\n * 三段的位移量。不变量:front - back === length。\n * - centered:平面居中,上下各推 L/2\n * - forward:只推上半 L,下半不动\n * - backward:只拉下半 -L,上半不动\n * @param mode - the offset mode ('centered', 'forward', or 'backward').\n * @param length - the extrusion length L (mm).\n * @returns the front and back displacement amounts, with front - back === length.\n */\nexport function computeExtrudeOffsets(\n mode: ExtrudeOffsetMode,\n length: number,\n): { front: number; back: number } {\n switch (mode) {\n case 'forward':\n return { front: length, back: 0 }\n case 'backward':\n return { front: 0, back: -length }\n case 'centered':\n default:\n return { front: length / 2, back: -length / 2 }\n }\n}\n\n/**\n * 由 computePlaneParams 的 (normal, planeDistance) 构造 THREE 世界平面。\n *\n * 约定:平面方程为 `N · p = planeDistance`;THREE.Plane 用 `N · p + constant = 0`,\n * 故 constant = -planeDistance。THREE 裁剪保留 distanceToPoint >= 0 的一侧(法线正侧)。\n * @param normal - the cutting plane normal as a 3-component array.\n * @param planeDistance - the plane equation origin offset along the normal.\n * @returns a THREE.Plane and its normalized normal vector.\n */\nexport function makeWorldPlane(\n normal: [number, number, number],\n planeDistance: number,\n): { plane: THREE.Plane; normalVec: THREE.Vector3 } {\n const normalVec = new THREE.Vector3(normal[0], normal[1], normal[2]).normalize()\n return {\n plane: new THREE.Plane(normalVec.clone(), -planeDistance),\n normalVec,\n }\n}\n\n/**\n * 全分辨率构建拉伸三段(世界空间进、世界空间出)。\n *\n * 这是**提交路径的唯一真相**:预览无论用什么近似手段,执行时都走这里重算,\n * so preview geometry errors do not pollute the final model.\n *\n * @param worldMesh 世界空间的源网格(局部几何 × matrixWorld)\n * @param normal 切割平面法线(单位向量)\n * @param planeDistance 平面方程 N·p = planeDistance 的右端\n * @param length 拉伸长度 L\n * @param mode 三段位移模式\n * @returns the split front, back, and extruded middle mesh parts.\n */\nexport async function buildExtrudeParts(\n worldMesh: ManifoldMeshData,\n normal: [number, number, number],\n planeDistance: number,\n length: number,\n mode: ExtrudeOffsetMode,\n): Promise<ExtrudeParts> {\n const { front: offsetFront, back: offsetBack } = computeExtrudeOffsets(mode, length)\n // 拉伸方向 D 恒等于切割平面法线 N\n const D: [number, number, number] = [normal[0], normal[1], normal[2]]\n\n // 1. 平面处切开 → front / back\n const splitResult = await computeSplit(worldMesh, normal, planeDistance)\n let front: ManifoldMeshData | null = splitResult.front\n let back: ManifoldMeshData | null = splitResult.back\n let extruded: ManifoldMeshData | null = null\n\n // 2. 从 front 再切一片厚 SLICE_THICKNESS 的薄壳\n const capSplit = await computeSplit(splitResult.front, normal, planeDistance + SLICE_THICKNESS)\n\n // 3. 薄壳以平面为锚点沿 N 放大 L/SLICE_THICKNESS → 占据 [planeDistance, planeDistance+L]\n if (capSplit.back && capSplit.back.indices.length > 0) {\n extruded = scaleMeshAlongNormal(capSplit.back, D, planeDistance, length / SLICE_THICKNESS)\n }\n\n // 4. 三段各自沿 D 位移;中段起点对齐 back 侧\n if (front) front = offsetMesh(front, D, offsetFront)\n if (back) back = offsetMesh(back, D, offsetBack)\n if (extruded) extruded = offsetMesh(extruded, D, offsetBack)\n\n return { front, back, extruded }\n}\n\n/**\n * 沿法线方向按 scaleFactor 缩放每个顶点到平面的有向距离。\n * 平面上的顶点不动,离面顶点按比例外推。\n * @param mesh - the source mesh data to scale.\n * @param normal - the plane normal (unit vector).\n * @param planeOffset - the plane offset along the normal.\n * @param scaleFactor - the scaling factor applied to each vertex's signed distance to the plane.\n * @returns the scaled mesh data (positions rewritten, indices unchanged).\n */\nexport function scaleMeshAlongNormal(\n mesh: ManifoldMeshData,\n normal: [number, number, number],\n planeOffset: number,\n scaleFactor: number,\n): ManifoldMeshData {\n const out = new Float32Array(mesh.positions)\n for (let i = 0; i < out.length; i += 3) {\n const d = out[i] * normal[0] + out[i + 1] * normal[1] + out[i + 2] * normal[2] - planeOffset\n const delta = d * scaleFactor - d\n out[i] += normal[0] * delta\n out[i + 1] += normal[1] * delta\n out[i + 2] += normal[2] * delta\n }\n return { positions: out, indices: mesh.indices }\n}\n\n/**\n * 整体沿 direction 平移 distance(distance 为 0 时原样返回,不拷贝)。\n * @param mesh - the source mesh data to translate.\n * @param direction - the translation direction (not necessarily unit length).\n * @param distance - the translation distance (mm); 0 returns the mesh unchanged.\n * @returns the translated mesh data (positions rewritten, indices unchanged).\n */\nexport function offsetMesh(\n mesh: ManifoldMeshData,\n direction: [number, number, number],\n distance: number,\n): ManifoldMeshData {\n if (distance === 0) return mesh\n const dx = direction[0] * distance\n const dy = direction[1] * distance\n const dz = direction[2] * distance\n const out = new Float32Array(mesh.positions)\n for (let i = 0; i < out.length; i += 3) {\n out[i] += dx\n out[i + 1] += dy\n out[i + 2] += dz\n }\n return { positions: out, indices: mesh.indices }\n}\n"]}
|
package/dist/brep/brep-ops.d.ts
CHANGED
|
@@ -51,17 +51,17 @@ export declare function translateBrep(kernel: BrepEngineApi, solid: BrepHandle,
|
|
|
51
51
|
/**
|
|
52
52
|
* BREP 旋转:使用 OCCT transform(3x4 仿射矩阵)。
|
|
53
53
|
*
|
|
54
|
-
* 与 mesh 路径 rotate_euler(shape,
|
|
55
|
-
* -
|
|
54
|
+
* 与 mesh 路径 rotate_euler(shape, angles, pivot?) 一致:
|
|
55
|
+
* - angles 为 XYZ 欧拉角(角度制)
|
|
56
56
|
* - pivot 为旋转中心(可选,默认原点)
|
|
57
57
|
*
|
|
58
58
|
* @param kernel OCCT 内核
|
|
59
59
|
* @param solid 输入实体
|
|
60
|
-
* @param
|
|
60
|
+
* @param angles XYZ 欧拉角(角度制)
|
|
61
61
|
* @param pivot 旋转中心(可选)
|
|
62
62
|
* @returns 新实体
|
|
63
63
|
*/
|
|
64
|
-
export declare function rotateBrep(kernel: BrepEngineApi, solid: BrepHandle,
|
|
64
|
+
export declare function rotateBrep(kernel: BrepEngineApi, solid: BrepHandle, angles: Vec3, pivot?: Vec3): BrepHandle;
|
|
65
65
|
/**
|
|
66
66
|
* BREP 缩放:使用 OCCT transform(3x4 仿射矩阵)。
|
|
67
67
|
*
|
|
@@ -181,10 +181,16 @@ export declare function drillBrep(kernel: BrepEngineApi, solid: BrepHandle, para
|
|
|
181
181
|
export interface SplitBrepParams {
|
|
182
182
|
/** 切割平面法线 */
|
|
183
183
|
normal: Vec3;
|
|
184
|
-
/**
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
184
|
+
/**
|
|
185
|
+
* 切割平面位置:世界系平面方程 d 值(n·x = planeDistance)。
|
|
186
|
+
* 与 planeCenter 二选一必填;都缺省时抛错,不隐式回退。
|
|
187
|
+
*/
|
|
188
|
+
planeDistance?: number;
|
|
189
|
+
/**
|
|
190
|
+
* 切割平面位置:世界坐标点(平面中心)。
|
|
191
|
+
* 与 planeDistance 二选一必填;都缺省时抛错,不隐式回退。
|
|
192
|
+
*/
|
|
193
|
+
planeCenter?: Vec3;
|
|
188
194
|
}
|
|
189
195
|
/** splitBrep 的结果 */
|
|
190
196
|
export interface SplitBrepResult {
|
|
@@ -214,8 +220,16 @@ export declare function splitBrep(kernel: BrepEngineApi, solid: BrepHandle, para
|
|
|
214
220
|
export interface ExtrudeBrepParams {
|
|
215
221
|
/** 拉伸法线方向 */
|
|
216
222
|
normal: Vec3;
|
|
217
|
-
/**
|
|
218
|
-
|
|
223
|
+
/**
|
|
224
|
+
* 切割平面位置:世界系平面方程 d 值(n·x = planeDistance)。
|
|
225
|
+
* 与 planeCenter 二选一必填;都缺省时抛错,不隐式回退。
|
|
226
|
+
*/
|
|
227
|
+
planeDistance?: number;
|
|
228
|
+
/**
|
|
229
|
+
* 切割平面位置:世界坐标点(平面中心)。
|
|
230
|
+
* 与 planeDistance 二选一必填;都缺省时抛错,不隐式回退。
|
|
231
|
+
*/
|
|
232
|
+
planeCenter?: Vec3;
|
|
219
233
|
/** 拉伸长度 */
|
|
220
234
|
length: number;
|
|
221
235
|
/** 拉伸模式 */
|