fluidcad 0.0.28 → 0.0.30
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/lib/dist/common/profiler.d.ts +12 -0
- package/lib/dist/common/profiler.js +35 -0
- package/lib/dist/common/scene-object.d.ts +3 -0
- package/lib/dist/common/scene-object.js +3 -0
- package/lib/dist/common/shape-history-tracker.d.ts +9 -1
- package/lib/dist/common/shape-history-tracker.js +37 -23
- package/lib/dist/core/2d/aline.d.ts +13 -13
- package/lib/dist/core/2d/aline.js +20 -11
- package/lib/dist/core/2d/arc.d.ts +6 -6
- package/lib/dist/core/2d/arc.js +19 -15
- package/lib/dist/core/2d/back.d.ts +12 -0
- package/lib/dist/core/2d/back.js +11 -0
- package/lib/dist/core/2d/circle.d.ts +2 -2
- package/lib/dist/core/2d/circle.js +14 -10
- package/lib/dist/core/2d/ellipse.d.ts +35 -0
- package/lib/dist/core/2d/ellipse.js +65 -0
- package/lib/dist/core/2d/hline.d.ts +20 -13
- package/lib/dist/core/2d/hline.js +33 -15
- package/lib/dist/core/2d/index.d.ts +2 -0
- package/lib/dist/core/2d/index.js +2 -0
- package/lib/dist/core/2d/intersect.d.ts +2 -2
- package/lib/dist/core/2d/intersect.js +7 -3
- package/lib/dist/core/2d/line.d.ts +2 -2
- package/lib/dist/core/2d/line.js +14 -10
- package/lib/dist/core/2d/offset.d.ts +4 -4
- package/lib/dist/core/2d/offset.js +9 -5
- package/lib/dist/core/2d/polygon.d.ts +4 -4
- package/lib/dist/core/2d/polygon.js +24 -20
- package/lib/dist/core/2d/project.d.ts +2 -2
- package/lib/dist/core/2d/project.js +7 -3
- package/lib/dist/core/2d/rect.d.ts +2 -2
- package/lib/dist/core/2d/rect.js +22 -21
- package/lib/dist/core/2d/slot.d.ts +6 -6
- package/lib/dist/core/2d/slot.js +29 -32
- package/lib/dist/core/2d/vline.d.ts +20 -13
- package/lib/dist/core/2d/vline.js +29 -15
- package/lib/dist/core/interfaces.d.ts +62 -0
- package/lib/dist/core/mirror.d.ts +7 -7
- package/lib/dist/core/mirror.js +17 -11
- package/lib/dist/core/part.d.ts +3 -1
- package/lib/dist/core/part.js +1 -1
- package/lib/dist/core/rotate.d.ts +5 -5
- package/lib/dist/core/rotate.js +4 -1
- package/lib/dist/core/sketch.d.ts +3 -1
- package/lib/dist/core/sketch.js +1 -1
- package/lib/dist/core/translate.d.ts +9 -9
- package/lib/dist/features/2d/aline.d.ts +8 -5
- package/lib/dist/features/2d/aline.js +70 -18
- package/lib/dist/features/2d/back.d.ts +14 -0
- package/lib/dist/features/2d/back.js +35 -0
- package/lib/dist/features/2d/ellipse.d.ts +23 -0
- package/lib/dist/features/2d/ellipse.js +75 -0
- package/lib/dist/features/2d/hline.d.ts +9 -4
- package/lib/dist/features/2d/hline.js +65 -14
- package/lib/dist/features/2d/offset.d.ts +3 -0
- package/lib/dist/features/2d/offset.js +27 -3
- package/lib/dist/features/2d/sketch.d.ts +1 -0
- package/lib/dist/features/2d/sketch.js +15 -0
- package/lib/dist/features/2d/vline.d.ts +9 -4
- package/lib/dist/features/2d/vline.js +67 -15
- package/lib/dist/features/common.js +2 -1
- package/lib/dist/features/extrude-base.d.ts +19 -1
- package/lib/dist/features/extrude-base.js +75 -12
- package/lib/dist/features/extrude-two-distances.js +32 -27
- package/lib/dist/features/extrude.d.ts +39 -0
- package/lib/dist/features/extrude.js +196 -156
- package/lib/dist/features/fuse.js +2 -1
- package/lib/dist/features/lazy-scene-object.d.ts +1 -0
- package/lib/dist/features/lazy-scene-object.js +3 -0
- package/lib/dist/features/lazy-vertex.d.ts +1 -0
- package/lib/dist/features/lazy-vertex.js +3 -0
- package/lib/dist/features/loft.js +11 -8
- package/lib/dist/features/mirror-shape.d.ts +2 -0
- package/lib/dist/features/mirror-shape.js +16 -0
- package/lib/dist/features/mirror-shape2d.d.ts +2 -0
- package/lib/dist/features/mirror-shape2d.js +22 -1
- package/lib/dist/features/revolve.d.ts +31 -0
- package/lib/dist/features/revolve.js +178 -95
- package/lib/dist/features/rotate.d.ts +2 -0
- package/lib/dist/features/rotate.js +16 -0
- package/lib/dist/features/rotate2d.d.ts +2 -0
- package/lib/dist/features/rotate2d.js +16 -0
- package/lib/dist/features/select.js +2 -1
- package/lib/dist/features/simple-extruder.d.ts +3 -1
- package/lib/dist/features/simple-extruder.js +13 -9
- package/lib/dist/features/subtract.d.ts +2 -2
- package/lib/dist/features/subtract.js +3 -3
- package/lib/dist/features/sweep.d.ts +14 -0
- package/lib/dist/features/sweep.js +93 -80
- package/lib/dist/features/translate.d.ts +2 -0
- package/lib/dist/features/translate.js +23 -2
- package/lib/dist/filters/edge/edge-filter.d.ts +6 -0
- package/lib/dist/filters/edge/edge-filter.js +11 -0
- package/lib/dist/filters/face/face-filter.d.ts +6 -0
- package/lib/dist/filters/face/face-filter.js +11 -0
- package/lib/dist/filters/filter-base.d.ts +7 -1
- package/lib/dist/filters/filter-base.js +8 -0
- package/lib/dist/filters/filter-builder-base.js +11 -0
- package/lib/dist/filters/from-object.d.ts +14 -0
- package/lib/dist/filters/from-object.js +40 -0
- package/lib/dist/helpers/scene-helpers.d.ts +2 -0
- package/lib/dist/helpers/scene-helpers.js +68 -48
- package/lib/dist/oc/color-transfer.js +6 -0
- package/lib/dist/oc/edge-ops.d.ts +1 -0
- package/lib/dist/oc/edge-ops.js +17 -0
- package/lib/dist/oc/extrude-ops.d.ts +18 -1
- package/lib/dist/oc/extrude-ops.js +34 -1
- package/lib/dist/oc/geometry.d.ts +1 -0
- package/lib/dist/oc/geometry.js +27 -0
- package/lib/dist/oc/mesh.js +11 -9
- package/lib/dist/oc/ray-intersect.d.ts +16 -0
- package/lib/dist/oc/ray-intersect.js +91 -0
- package/lib/dist/oc/thin-face-maker.d.ts +0 -1
- package/lib/dist/oc/thin-face-maker.js +2 -20
- package/lib/dist/rendering/render.d.ts +2 -1
- package/lib/dist/rendering/render.js +72 -33
- package/lib/dist/rendering/scene.d.ts +4 -0
- package/lib/dist/tests/features/2d/back.test.d.ts +1 -0
- package/lib/dist/tests/features/2d/back.test.js +60 -0
- package/lib/dist/tests/features/2d/circle.test.js +1 -1
- package/lib/dist/tests/features/2d/constrained.test.js +4 -4
- package/lib/dist/tests/features/2d/ellipse.test.d.ts +1 -0
- package/lib/dist/tests/features/2d/ellipse.test.js +100 -0
- package/lib/dist/tests/features/2d/line.test.js +89 -3
- package/lib/dist/tests/features/2d/offset.test.js +1 -1
- package/lib/dist/tests/features/2d/polygon.test.js +2 -2
- package/lib/dist/tests/features/2d/rect.test.js +1 -1
- package/lib/dist/tests/features/2d/slot-from-edge.test.js +1 -1
- package/lib/dist/tests/features/2d/slot.test.js +1 -1
- package/lib/dist/tests/features/mirror.test.js +58 -0
- package/lib/dist/tests/features/mirror2d.test.js +63 -0
- package/lib/dist/tests/features/rotate.test.js +62 -0
- package/lib/dist/tests/features/rotate2d.test.js +47 -0
- package/lib/dist/tests/features/thin-revolve.test.js +37 -1
- package/lib/dist/tests/features/translate.test.js +63 -0
- package/lib/dist/tests/perf/record-fusion-history.bench.test.d.ts +1 -0
- package/lib/dist/tests/perf/record-fusion-history.bench.test.js +77 -0
- package/lib/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/server/dist/index.js +77 -45
- package/server/dist/ws-protocol.d.ts +11 -0
- package/ui/dist/assets/{index-BrW_x4uc.js → index-6Ep4GPxf.js} +131 -77
- package/ui/dist/assets/index-DRKfe6N9.css +2 -0
- package/ui/dist/index.html +2 -2
- package/ui/dist/assets/index-gPoNOiIs.css +0 -2
|
@@ -1,17 +1,19 @@
|
|
|
1
1
|
import { Face } from "../common/face.js";
|
|
2
2
|
import { Shape } from "../common/shape.js";
|
|
3
3
|
import { Plane } from "../math/plane.js";
|
|
4
|
+
import { Profiler } from "../common/profiler.js";
|
|
4
5
|
export declare class Extruder {
|
|
5
6
|
private faces;
|
|
6
7
|
private plane;
|
|
7
8
|
distance: number;
|
|
8
9
|
draft?: [number, number];
|
|
9
10
|
endOffset?: number;
|
|
11
|
+
private profiler?;
|
|
10
12
|
private firstFaces;
|
|
11
13
|
private lastFaces;
|
|
12
14
|
private sideFaces;
|
|
13
15
|
private _internalFaces;
|
|
14
|
-
constructor(faces: Face[], plane: Plane, distance: number, draft?: [number, number], endOffset?: number);
|
|
16
|
+
constructor(faces: Face[], plane: Plane, distance: number, draft?: [number, number], endOffset?: number, profiler?: Profiler);
|
|
15
17
|
getStartFaces(): Face[];
|
|
16
18
|
getEndFaces(): Face[];
|
|
17
19
|
getSideFaces(): Face[];
|
|
@@ -8,16 +8,18 @@ export class Extruder {
|
|
|
8
8
|
distance;
|
|
9
9
|
draft;
|
|
10
10
|
endOffset;
|
|
11
|
+
profiler;
|
|
11
12
|
firstFaces;
|
|
12
13
|
lastFaces;
|
|
13
14
|
sideFaces;
|
|
14
15
|
_internalFaces;
|
|
15
|
-
constructor(faces, plane, distance, draft, endOffset) {
|
|
16
|
+
constructor(faces, plane, distance, draft, endOffset, profiler) {
|
|
16
17
|
this.faces = faces;
|
|
17
18
|
this.plane = plane;
|
|
18
19
|
this.distance = distance;
|
|
19
20
|
this.draft = draft;
|
|
20
21
|
this.endOffset = endOffset;
|
|
22
|
+
this.profiler = profiler;
|
|
21
23
|
}
|
|
22
24
|
getStartFaces() {
|
|
23
25
|
return this.firstFaces;
|
|
@@ -42,16 +44,18 @@ export class Extruder {
|
|
|
42
44
|
let lastFaces = [];
|
|
43
45
|
let sideFaces = [];
|
|
44
46
|
let internalFaces = [];
|
|
45
|
-
|
|
46
|
-
const
|
|
47
|
-
|
|
48
|
-
|
|
47
|
+
const p = this.profiler;
|
|
48
|
+
const fusedFaces = p
|
|
49
|
+
? p.record('Fuse profile faces', () => BooleanOps.fuseFaces(this.faces))
|
|
50
|
+
: BooleanOps.fuseFaces(this.faces);
|
|
49
51
|
for (const face of fusedFaces.result) {
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
52
|
+
let { solid, firstFace, lastFace } = p
|
|
53
|
+
? p.record('Make prism from face', () => ExtrudeOps.makePrismFromVec(face, vec))
|
|
54
|
+
: ExtrudeOps.makePrismFromVec(face, vec);
|
|
53
55
|
if (this.draft) {
|
|
54
|
-
const draftResult =
|
|
56
|
+
const draftResult = p
|
|
57
|
+
? p.record('Apply draft', () => this.applyDraft(solid, firstFace, lastFace, this.plane))
|
|
58
|
+
: this.applyDraft(solid, firstFace, lastFace, this.plane);
|
|
55
59
|
solid = draftResult.solid;
|
|
56
60
|
firstFace = draftResult.firstFace;
|
|
57
61
|
lastFace = draftResult.lastFace;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { SceneObject } from "../common/scene-object.js";
|
|
1
|
+
import { BuildSceneObjectContext, SceneObject } from "../common/scene-object.js";
|
|
2
2
|
export declare class Subtract extends SceneObject {
|
|
3
3
|
solid1: SceneObject;
|
|
4
4
|
solid2: SceneObject;
|
|
5
5
|
constructor(solid1: SceneObject, solid2: SceneObject);
|
|
6
|
-
build(): void;
|
|
6
|
+
build(context: BuildSceneObjectContext): void;
|
|
7
7
|
compareTo(other: Subtract): boolean;
|
|
8
8
|
getType(): string;
|
|
9
9
|
serialize(): {
|
|
@@ -11,14 +11,14 @@ export class Subtract extends SceneObject {
|
|
|
11
11
|
this.solid1 = solid1;
|
|
12
12
|
this.solid2 = solid2;
|
|
13
13
|
}
|
|
14
|
-
build() {
|
|
14
|
+
build(context) {
|
|
15
|
+
const p = context.getProfiler();
|
|
15
16
|
const stock = this.solid1.getShapes();
|
|
16
17
|
const toBeRemoved = this.solid2.getShapes();
|
|
17
18
|
const stockCompound = ShapeOps.makeCompound(stock);
|
|
18
19
|
const toBeRemovedCompound = ShapeOps.makeCompound(toBeRemoved);
|
|
19
|
-
const result = BooleanOps.cutShapes(stockCompound, toBeRemovedCompound);
|
|
20
|
+
const result = p.record('Cut solids', () => BooleanOps.cutShapes(stockCompound, toBeRemovedCompound));
|
|
20
21
|
const shapes = Explorer.findShapes(result.getShape(), Explorer.getOcShapeType("solid"));
|
|
21
|
-
console.log('Subtract Result:::::', shapes.length);
|
|
22
22
|
const newShapes = shapes.map(s => ShapeOps.cleanShapeRaw(s)).map(s => Solid.fromTopoDSSolid(Explorer.toSolid(s)));
|
|
23
23
|
for (const shape of toBeRemoved) {
|
|
24
24
|
this.solid2.removeShape(shape, this);
|
|
@@ -7,6 +7,20 @@ export declare class Sweep extends ExtrudeBase implements ISweep {
|
|
|
7
7
|
constructor(path: SceneObject, extrudable?: Extrudable);
|
|
8
8
|
get path(): SceneObject;
|
|
9
9
|
build(context: BuildSceneObjectContext): void;
|
|
10
|
+
/** Plain sweep: classify by inner-wire detection on the start face. */
|
|
11
|
+
private buildSweep;
|
|
12
|
+
/** Thin sweep: shell-like profile with inward/outward offsets. */
|
|
13
|
+
private buildSweepThin;
|
|
14
|
+
/**
|
|
15
|
+
* Run the sweep and split the resulting faces using OC's `FirstShape` /
|
|
16
|
+
* `LastShape` (the profile at each end of the spine). Anything else is a
|
|
17
|
+
* side face for the caller to refine.
|
|
18
|
+
*/
|
|
19
|
+
private runSweep;
|
|
20
|
+
/** Inner-wire classification used by both regular sweep and closed thin profiles. */
|
|
21
|
+
private classifySweepByInnerWires;
|
|
22
|
+
/** Remove source + path, then dispatch to cut or fuse path. */
|
|
23
|
+
private dispatchFinalize;
|
|
10
24
|
private getSpineWire;
|
|
11
25
|
getDependencies(): SceneObject[];
|
|
12
26
|
createCopy(remap: Map<SceneObject, SceneObject>): SceneObject;
|
|
@@ -3,7 +3,7 @@ import { SweepOps } from "../oc/sweep-ops.js";
|
|
|
3
3
|
import { WireOps } from "../oc/wire-ops.js";
|
|
4
4
|
import { FaceMaker2 } from "../oc/face-maker2.js";
|
|
5
5
|
import { ExtrudeBase } from "./extrude-base.js";
|
|
6
|
-
import {
|
|
6
|
+
import { cutWithSceneObjects } from "../helpers/scene-helpers.js";
|
|
7
7
|
import { ThinFaceMaker } from "../oc/thin-face-maker.js";
|
|
8
8
|
export class Sweep extends ExtrudeBase {
|
|
9
9
|
_path;
|
|
@@ -15,42 +15,72 @@ export class Sweep extends ExtrudeBase {
|
|
|
15
15
|
return this._path;
|
|
16
16
|
}
|
|
17
17
|
build(context) {
|
|
18
|
+
const p = context.getProfiler();
|
|
18
19
|
const plane = this.extrudable.getPlane();
|
|
19
|
-
const pickedFaces = this.resolvePickedFaces(plane);
|
|
20
|
+
const pickedFaces = p.record('Resolve picked faces', () => this.resolvePickedFaces(plane));
|
|
20
21
|
if (pickedFaces !== null && pickedFaces.length === 0) {
|
|
21
22
|
return;
|
|
22
23
|
}
|
|
23
|
-
// Extract spine wire from path
|
|
24
|
-
const spineWire = this.getSpineWire(this._path);
|
|
25
|
-
// Extract profile faces from extrudable
|
|
26
|
-
let profileFaces = pickedFaces ?? FaceMaker2.getRegions(this.extrudable.getGeometries(), plane, this.getDrill());
|
|
27
|
-
let inwardEdges;
|
|
28
|
-
let outwardEdges;
|
|
29
24
|
if (this.isThin()) {
|
|
30
|
-
const thinResult = ThinFaceMaker.make(this.extrudable.getGeometries(), plane, this._thin[0], this._thin[1]);
|
|
31
|
-
|
|
32
|
-
inwardEdges = thinResult.inwardEdges;
|
|
33
|
-
outwardEdges = thinResult.outwardEdges;
|
|
25
|
+
const thinResult = p.record('Make thin faces', () => ThinFaceMaker.make(this.extrudable.getGeometries(), plane, this._thin[0], this._thin[1]));
|
|
26
|
+
this.buildSweepThin(thinResult, plane, context);
|
|
34
27
|
}
|
|
28
|
+
else {
|
|
29
|
+
const profileFaces = pickedFaces ?? p.record('Resolve faces', () => FaceMaker2.getRegions(this.extrudable.getGeometries(), plane, this.getDrill()));
|
|
30
|
+
this.buildSweep(profileFaces, plane, context);
|
|
31
|
+
}
|
|
32
|
+
this.setFinalShapes(this.getShapes());
|
|
33
|
+
}
|
|
34
|
+
/** Plain sweep: classify by inner-wire detection on the start face. */
|
|
35
|
+
buildSweep(profileFaces, plane, context) {
|
|
36
|
+
const swept = this.runSweep(profileFaces, context);
|
|
37
|
+
const classified = this.classifySweepByInnerWires(swept, plane);
|
|
38
|
+
this.dispatchFinalize(swept.solids, classified, plane, context);
|
|
39
|
+
}
|
|
40
|
+
/** Thin sweep: shell-like profile with inward/outward offsets. */
|
|
41
|
+
buildSweepThin(thinResult, plane, context) {
|
|
42
|
+
const swept = this.runSweep(thinResult.faces, context);
|
|
43
|
+
let classified;
|
|
44
|
+
if (thinResult.inwardEdges.length > 0) {
|
|
45
|
+
const reclass = this.reclassifyThinFaces(swept.sideFaces, swept.startFaces, plane, thinResult.inwardEdges, thinResult.outwardEdges);
|
|
46
|
+
classified = {
|
|
47
|
+
startFaces: swept.startFaces,
|
|
48
|
+
endFaces: swept.endFaces,
|
|
49
|
+
sideFaces: reclass.sideFaces,
|
|
50
|
+
internalFaces: reclass.internalFaces,
|
|
51
|
+
capFaces: reclass.capFaces,
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
else {
|
|
55
|
+
classified = this.classifySweepByInnerWires(swept, plane);
|
|
56
|
+
}
|
|
57
|
+
this.dispatchFinalize(swept.solids, classified, plane, context);
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Run the sweep and split the resulting faces using OC's `FirstShape` /
|
|
61
|
+
* `LastShape` (the profile at each end of the spine). Anything else is a
|
|
62
|
+
* side face for the caller to refine.
|
|
63
|
+
*/
|
|
64
|
+
runSweep(profileFaces, context) {
|
|
35
65
|
if (profileFaces.length === 0) {
|
|
36
66
|
throw new Error("Could not extract profile faces from extrudable.");
|
|
37
67
|
}
|
|
38
|
-
|
|
39
|
-
const
|
|
40
|
-
const
|
|
41
|
-
|
|
68
|
+
const p = context.getProfiler();
|
|
69
|
+
const spineWire = p.record('Get spine wire', () => this.getSpineWire(this._path));
|
|
70
|
+
const sweepResult = p.record('Make sweep', () => SweepOps.makeSweep(spineWire, profileFaces));
|
|
71
|
+
const solids = sweepResult.solids;
|
|
42
72
|
const startFaces = [];
|
|
43
73
|
const endFaces = [];
|
|
44
|
-
|
|
74
|
+
const sideFaces = [];
|
|
45
75
|
const firstShapeFromOC = sweepResult.firstShape;
|
|
46
76
|
const lastShapeFromOC = sweepResult.lastShape;
|
|
47
|
-
for (const shape of
|
|
48
|
-
const
|
|
49
|
-
|
|
50
|
-
if (firstShapeFromOC &&
|
|
77
|
+
for (const shape of solids) {
|
|
78
|
+
for (const f of Explorer.findFacesWrapped(shape)) {
|
|
79
|
+
const raw = f.getShape();
|
|
80
|
+
if (firstShapeFromOC && raw.IsSame(firstShapeFromOC)) {
|
|
51
81
|
startFaces.push(f);
|
|
52
82
|
}
|
|
53
|
-
else if (lastShapeFromOC &&
|
|
83
|
+
else if (lastShapeFromOC && raw.IsSame(lastShapeFromOC)) {
|
|
54
84
|
endFaces.push(f);
|
|
55
85
|
}
|
|
56
86
|
else {
|
|
@@ -58,76 +88,59 @@ export class Sweep extends ExtrudeBase {
|
|
|
58
88
|
}
|
|
59
89
|
}
|
|
60
90
|
}
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
for (const sf of startFaces) {
|
|
72
|
-
for (const wire of sf.getWires()) {
|
|
73
|
-
if (!wire.isCW(plane.normal)) {
|
|
74
|
-
for (const edge of wire.getEdges()) {
|
|
75
|
-
innerWireEdges.push(edge);
|
|
76
|
-
}
|
|
91
|
+
return { solids, startFaces, endFaces, sideFaces };
|
|
92
|
+
}
|
|
93
|
+
/** Inner-wire classification used by both regular sweep and closed thin profiles. */
|
|
94
|
+
classifySweepByInnerWires(swept, plane) {
|
|
95
|
+
const innerWireEdges = [];
|
|
96
|
+
for (const sf of swept.startFaces) {
|
|
97
|
+
for (const wire of sf.getWires()) {
|
|
98
|
+
if (!wire.isCW(plane.normal)) {
|
|
99
|
+
for (const edge of wire.getEdges()) {
|
|
100
|
+
innerWireEdges.push(edge);
|
|
77
101
|
}
|
|
78
102
|
}
|
|
79
103
|
}
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
104
|
+
}
|
|
105
|
+
const sideFaces = [];
|
|
106
|
+
const internalFaces = [];
|
|
107
|
+
if (innerWireEdges.length === 0) {
|
|
108
|
+
sideFaces.push(...swept.sideFaces);
|
|
109
|
+
}
|
|
110
|
+
else {
|
|
111
|
+
for (const f of swept.sideFaces) {
|
|
112
|
+
const isInternal = f.getEdges().some(fe => innerWireEdges.some(iwe => fe.getShape().IsPartner(iwe.getShape())));
|
|
113
|
+
if (isInternal) {
|
|
114
|
+
internalFaces.push(f);
|
|
115
|
+
}
|
|
116
|
+
else {
|
|
117
|
+
sideFaces.push(f);
|
|
90
118
|
}
|
|
91
|
-
sideFaces = remaining;
|
|
92
119
|
}
|
|
93
120
|
}
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
121
|
+
return {
|
|
122
|
+
startFaces: swept.startFaces,
|
|
123
|
+
endFaces: swept.endFaces,
|
|
124
|
+
sideFaces,
|
|
125
|
+
internalFaces,
|
|
126
|
+
capFaces: [],
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
/** Remove source + path, then dispatch to cut or fuse path. */
|
|
130
|
+
dispatchFinalize(solids, classified, plane, context) {
|
|
100
131
|
this.extrudable.removeShapes(this);
|
|
101
132
|
this._path.removeShapes(this);
|
|
102
|
-
// Handle boolean operation based on operation mode
|
|
103
133
|
if (this._operationMode === 'remove') {
|
|
104
134
|
const scope = this.resolveFusionScope(context.getSceneObjects());
|
|
105
|
-
|
|
106
|
-
this.
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
this.addShapes(newShapes);
|
|
112
|
-
this.recordShapeFacesAndEdgesAsAdditions(newShapes);
|
|
113
|
-
this.classifyExtrudeEdges();
|
|
114
|
-
this.setFinalShapes(this.getShapes());
|
|
135
|
+
this.setState('start-faces', classified.startFaces);
|
|
136
|
+
this.setState('end-faces', classified.endFaces);
|
|
137
|
+
this.setState('side-faces', classified.sideFaces);
|
|
138
|
+
this.setState('internal-faces', classified.internalFaces);
|
|
139
|
+
this.setState('cap-faces', classified.capFaces);
|
|
140
|
+
cutWithSceneObjects(scope, solids, plane, 0, this, { recordHistoryFor: this });
|
|
115
141
|
return;
|
|
116
142
|
}
|
|
117
|
-
|
|
118
|
-
recordHistoryFor: this,
|
|
119
|
-
});
|
|
120
|
-
for (const modifiedShape of fusionResult.modifiedShapes) {
|
|
121
|
-
if (modifiedShape.object) {
|
|
122
|
-
modifiedShape.object.removeShape(modifiedShape.shape, this);
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
this.addShapes(fusionResult.newShapes);
|
|
126
|
-
if (fusionResult.toolHistory) {
|
|
127
|
-
this.remapClassifiedFaces(fusionResult.toolHistory);
|
|
128
|
-
}
|
|
129
|
-
this.classifyExtrudeEdges();
|
|
130
|
-
this.setFinalShapes(this.getShapes());
|
|
143
|
+
this.finalizeAndFuse(solids, classified, context);
|
|
131
144
|
}
|
|
132
145
|
getSpineWire(pathObj) {
|
|
133
146
|
const shapes = pathObj.getShapes({ excludeMeta: false });
|
|
@@ -4,8 +4,10 @@ export declare class Translate extends SceneObject {
|
|
|
4
4
|
private amount;
|
|
5
5
|
private copy;
|
|
6
6
|
private _targetObjects;
|
|
7
|
+
private _excludedObjects;
|
|
7
8
|
constructor(amount: LazyVertex, copy?: boolean, ...targets: SceneObject[]);
|
|
8
9
|
get targetObjects(): SceneObject[];
|
|
10
|
+
exclude(...objects: SceneObject[]): this;
|
|
9
11
|
build(context: BuildSceneObjectContext): void;
|
|
10
12
|
getDependencies(): SceneObject[];
|
|
11
13
|
createCopy(remap: Map<SceneObject, SceneObject>): SceneObject;
|
|
@@ -5,6 +5,7 @@ export class Translate extends SceneObject {
|
|
|
5
5
|
amount;
|
|
6
6
|
copy;
|
|
7
7
|
_targetObjects = null;
|
|
8
|
+
_excludedObjects = [];
|
|
8
9
|
constructor(amount, copy = false, ...targets) {
|
|
9
10
|
super();
|
|
10
11
|
this.amount = amount;
|
|
@@ -14,8 +15,15 @@ export class Translate extends SceneObject {
|
|
|
14
15
|
get targetObjects() {
|
|
15
16
|
return this._targetObjects;
|
|
16
17
|
}
|
|
18
|
+
exclude(...objects) {
|
|
19
|
+
this._excludedObjects.push(...objects);
|
|
20
|
+
return this;
|
|
21
|
+
}
|
|
17
22
|
build(context) {
|
|
18
|
-
|
|
23
|
+
let objects = this.targetObjects || context.getSceneObjects();
|
|
24
|
+
if (this._excludedObjects.length > 0) {
|
|
25
|
+
objects = objects.filter(obj => !this._excludedObjects.includes(obj));
|
|
26
|
+
}
|
|
19
27
|
for (const obj of objects) {
|
|
20
28
|
const shapes = obj.getShapes();
|
|
21
29
|
for (const shape of shapes) {
|
|
@@ -40,7 +48,12 @@ export class Translate extends SceneObject {
|
|
|
40
48
|
const targets = this.targetObjects
|
|
41
49
|
? this.targetObjects.map(obj => remap.get(obj) || obj)
|
|
42
50
|
: [];
|
|
43
|
-
|
|
51
|
+
const copy = new Translate(this.amount, this.copy, ...targets);
|
|
52
|
+
if (this._excludedObjects.length > 0) {
|
|
53
|
+
const remappedExcluded = this._excludedObjects.map(obj => remap.get(obj) || obj);
|
|
54
|
+
copy.exclude(...remappedExcluded);
|
|
55
|
+
}
|
|
56
|
+
return copy;
|
|
44
57
|
}
|
|
45
58
|
compareTo(other) {
|
|
46
59
|
if (!(other instanceof Translate)) {
|
|
@@ -65,6 +78,14 @@ export class Translate extends SceneObject {
|
|
|
65
78
|
return false;
|
|
66
79
|
}
|
|
67
80
|
}
|
|
81
|
+
if (this._excludedObjects.length !== other._excludedObjects.length) {
|
|
82
|
+
return false;
|
|
83
|
+
}
|
|
84
|
+
for (let i = 0; i < this._excludedObjects.length; i++) {
|
|
85
|
+
if (!this._excludedObjects[i].compareTo(other._excludedObjects[i])) {
|
|
86
|
+
return false;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
68
89
|
return true;
|
|
69
90
|
}
|
|
70
91
|
getType() {
|
|
@@ -123,5 +123,11 @@ export declare class EdgeFilterBuilder extends FilterBuilderBase<Edge> {
|
|
|
123
123
|
offset?: number;
|
|
124
124
|
partial?: boolean;
|
|
125
125
|
}): this;
|
|
126
|
+
/**
|
|
127
|
+
* Restricts the selection to edges originating from the given scene objects.
|
|
128
|
+
* Recursive: passing a container picks up edges from its descendants.
|
|
129
|
+
* @param sceneObjects - Scene objects whose edges (and edges of their sub-shapes) are matched against.
|
|
130
|
+
*/
|
|
131
|
+
from(...sceneObjects: ISceneObject[]): this;
|
|
126
132
|
static build(): EdgeFilterBuilder;
|
|
127
133
|
}
|
|
@@ -11,6 +11,7 @@ import { PlaneObjectBase } from "../../features/plane-renderable-base.js";
|
|
|
11
11
|
import { AtIndexFilter, NotAtIndexFilter } from "./at-index.js";
|
|
12
12
|
import { BelongsToFaceFilter, NotBelongsToFaceFilter } from "./belongs-to-face.js";
|
|
13
13
|
import { BelongsToFaceFromSceneObjectFilter, NotBelongsToFaceFromSceneObjectFilter } from "./belongs-to-object.js";
|
|
14
|
+
import { FromSceneObjectFilter } from "../from-object.js";
|
|
14
15
|
import { IntersectsWithFilter, NotIntersectsWithFilter } from "./intersects-with.js";
|
|
15
16
|
import { AbovePlaneFilter, BelowPlaneFilter } from "./above-below.js";
|
|
16
17
|
import { SceneObject } from "../../common/scene-object.js";
|
|
@@ -330,6 +331,16 @@ export class EdgeFilterBuilder extends FilterBuilderBase {
|
|
|
330
331
|
this.filters.push(filter);
|
|
331
332
|
return this;
|
|
332
333
|
}
|
|
334
|
+
/**
|
|
335
|
+
* Restricts the selection to edges originating from the given scene objects.
|
|
336
|
+
* Recursive: passing a container picks up edges from its descendants.
|
|
337
|
+
* @param sceneObjects - Scene objects whose edges (and edges of their sub-shapes) are matched against.
|
|
338
|
+
*/
|
|
339
|
+
from(...sceneObjects) {
|
|
340
|
+
const filter = new FromSceneObjectFilter(sceneObjects, "edge");
|
|
341
|
+
this.filters.push(filter);
|
|
342
|
+
return this;
|
|
343
|
+
}
|
|
333
344
|
static build() {
|
|
334
345
|
return new EdgeFilterBuilder();
|
|
335
346
|
}
|
|
@@ -119,4 +119,10 @@ export declare class FaceFilterBuilder extends FilterBuilderBase<Face> {
|
|
|
119
119
|
* @param count - The number of edges to exclude.
|
|
120
120
|
*/
|
|
121
121
|
notEdgeCount(count: number): this;
|
|
122
|
+
/**
|
|
123
|
+
* Restricts the selection to faces originating from the given scene objects.
|
|
124
|
+
* Recursive: passing a container picks up faces from its descendants.
|
|
125
|
+
* @param sceneObjects - Scene objects whose faces (and faces of their sub-shapes) are matched against.
|
|
126
|
+
*/
|
|
127
|
+
from(...sceneObjects: ISceneObject[]): this;
|
|
122
128
|
}
|
|
@@ -12,6 +12,7 @@ import { PlaneObjectBase } from "../../features/plane-renderable-base.js";
|
|
|
12
12
|
import { AtIndexFilter, NotAtIndexFilter } from "./at-index.js";
|
|
13
13
|
import { HasEdgeFilter, NotHasEdgeFilter } from "./has-edge.js";
|
|
14
14
|
import { HasEdgeFromSceneObjectFilter, NotHasEdgeFromSceneObjectFilter } from "./has-object.js";
|
|
15
|
+
import { FromSceneObjectFilter } from "../from-object.js";
|
|
15
16
|
import { EdgeCountFilter, NotEdgeCountFilter } from "./edge-count.js";
|
|
16
17
|
import { IntersectsWithFilter, NotIntersectsWithFilter } from "./intersects-with.js";
|
|
17
18
|
import { SceneObject } from "../../common/scene-object.js";
|
|
@@ -305,4 +306,14 @@ export class FaceFilterBuilder extends FilterBuilderBase {
|
|
|
305
306
|
this.filters.push(filter);
|
|
306
307
|
return this;
|
|
307
308
|
}
|
|
309
|
+
/**
|
|
310
|
+
* Restricts the selection to faces originating from the given scene objects.
|
|
311
|
+
* Recursive: passing a container picks up faces from its descendants.
|
|
312
|
+
* @param sceneObjects - Scene objects whose faces (and faces of their sub-shapes) are matched against.
|
|
313
|
+
*/
|
|
314
|
+
from(...sceneObjects) {
|
|
315
|
+
const filter = new FromSceneObjectFilter(sceneObjects, "face");
|
|
316
|
+
this.filters.push(filter);
|
|
317
|
+
return this;
|
|
318
|
+
}
|
|
308
319
|
}
|
|
@@ -1,8 +1,14 @@
|
|
|
1
1
|
import { Matrix4 } from "../math/matrix4.js";
|
|
2
|
-
import { Comparable } from "../common/scene-object.js";
|
|
2
|
+
import { Comparable, SceneObject } from "../common/scene-object.js";
|
|
3
3
|
import { Shape } from "../common/shapes.js";
|
|
4
4
|
export declare abstract class FilterBase<TShape extends Shape> implements Comparable<FilterBase<TShape>> {
|
|
5
5
|
abstract match(shape: TShape): boolean;
|
|
6
6
|
abstract compareTo(other: FilterBase<TShape>): boolean;
|
|
7
7
|
abstract transform(matrix: Matrix4): FilterBase<TShape>;
|
|
8
|
+
/**
|
|
9
|
+
* Returns a copy of this filter with any internal SceneObject references
|
|
10
|
+
* rewritten through the given remap. Filters that don't hold SceneObject
|
|
11
|
+
* references can keep the default no-op.
|
|
12
|
+
*/
|
|
13
|
+
remap(_remap: Map<SceneObject, SceneObject>): FilterBase<TShape>;
|
|
8
14
|
}
|
|
@@ -1,2 +1,10 @@
|
|
|
1
1
|
export class FilterBase {
|
|
2
|
+
/**
|
|
3
|
+
* Returns a copy of this filter with any internal SceneObject references
|
|
4
|
+
* rewritten through the given remap. Filters that don't hold SceneObject
|
|
5
|
+
* references can keep the default no-op.
|
|
6
|
+
*/
|
|
7
|
+
remap(_remap) {
|
|
8
|
+
return this;
|
|
9
|
+
}
|
|
2
10
|
}
|
|
@@ -39,6 +39,17 @@ export class FilterBuilderBase {
|
|
|
39
39
|
/**
|
|
40
40
|
* @internal
|
|
41
41
|
*/
|
|
42
|
+
remap(remap) {
|
|
43
|
+
const remappedBuilder = new FilterBuilderBase();
|
|
44
|
+
for (const filter of this.filters) {
|
|
45
|
+
remappedBuilder.filter(filter.remap(remap));
|
|
46
|
+
}
|
|
47
|
+
remappedBuilder._withTangents = this._withTangents;
|
|
48
|
+
return remappedBuilder;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* @internal
|
|
52
|
+
*/
|
|
42
53
|
equals(other) {
|
|
43
54
|
if (this._withTangents !== other._withTangents) {
|
|
44
55
|
return false;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { Matrix4 } from "../math/matrix4.js";
|
|
2
|
+
import { Shape } from "../common/shapes.js";
|
|
3
|
+
import { ShapeType } from "../common/shape-type.js";
|
|
4
|
+
import { SceneObject } from "../common/scene-object.js";
|
|
5
|
+
import { FilterBase } from "./filter-base.js";
|
|
6
|
+
export declare class FromSceneObjectFilter<TShape extends Shape> extends FilterBase<TShape> {
|
|
7
|
+
private sceneObjects;
|
|
8
|
+
private shapeType;
|
|
9
|
+
constructor(sceneObjects: SceneObject[], shapeType: ShapeType);
|
|
10
|
+
match(shape: TShape): boolean;
|
|
11
|
+
compareTo(other: FromSceneObjectFilter<TShape>): boolean;
|
|
12
|
+
transform(_matrix: Matrix4): FromSceneObjectFilter<TShape>;
|
|
13
|
+
remap(remap: Map<SceneObject, SceneObject>): FromSceneObjectFilter<TShape>;
|
|
14
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { FilterBase } from "./filter-base.js";
|
|
2
|
+
export class FromSceneObjectFilter extends FilterBase {
|
|
3
|
+
sceneObjects;
|
|
4
|
+
shapeType;
|
|
5
|
+
constructor(sceneObjects, shapeType) {
|
|
6
|
+
super();
|
|
7
|
+
this.sceneObjects = sceneObjects;
|
|
8
|
+
this.shapeType = shapeType;
|
|
9
|
+
}
|
|
10
|
+
match(shape) {
|
|
11
|
+
for (const obj of this.sceneObjects) {
|
|
12
|
+
const subShapes = obj.getShapes().flatMap(s => s.getSubShapes(this.shapeType));
|
|
13
|
+
if (subShapes.some(sub => sub.isSame(shape))) {
|
|
14
|
+
return true;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
return false;
|
|
18
|
+
}
|
|
19
|
+
compareTo(other) {
|
|
20
|
+
if (this.shapeType !== other.shapeType) {
|
|
21
|
+
return false;
|
|
22
|
+
}
|
|
23
|
+
if (this.sceneObjects.length !== other.sceneObjects.length) {
|
|
24
|
+
return false;
|
|
25
|
+
}
|
|
26
|
+
for (let i = 0; i < this.sceneObjects.length; i++) {
|
|
27
|
+
if (!this.sceneObjects[i].compareTo(other.sceneObjects[i])) {
|
|
28
|
+
return false;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
return true;
|
|
32
|
+
}
|
|
33
|
+
transform(_matrix) {
|
|
34
|
+
return new FromSceneObjectFilter(this.sceneObjects, this.shapeType);
|
|
35
|
+
}
|
|
36
|
+
remap(remap) {
|
|
37
|
+
const remapped = this.sceneObjects.map(obj => remap.get(obj) ?? obj);
|
|
38
|
+
return new FromSceneObjectFilter(remapped, this.shapeType);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
@@ -2,9 +2,11 @@ import { SceneObject } from "../common/scene-object.js";
|
|
|
2
2
|
import { Shape } from "../common/shapes.js";
|
|
3
3
|
import { Plane } from "../math/plane.js";
|
|
4
4
|
import { ShapeHistory } from "../common/shape-history-tracker.js";
|
|
5
|
+
import { Profiler } from "../common/profiler.js";
|
|
5
6
|
export declare function fuseWithSceneObjects(sceneObjects: SceneObject[], extrusions: Shape<any>[], opts?: {
|
|
6
7
|
glue?: 'full' | 'shift';
|
|
7
8
|
recordHistoryFor?: SceneObject;
|
|
9
|
+
profiler?: Profiler;
|
|
8
10
|
}): {
|
|
9
11
|
newShapes: Shape<any>[];
|
|
10
12
|
modifiedShapes: any[];
|