fluidcad 0.0.26 → 0.0.27
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/shape-factory.d.ts +1 -1
- package/lib/dist/common/shapes.d.ts +0 -1
- package/lib/dist/common/shapes.js +0 -1
- package/lib/dist/core/extrude.d.ts +12 -13
- package/lib/dist/core/extrude.js +19 -1
- package/lib/dist/core/part.d.ts +2 -1
- package/lib/dist/core/part.js +4 -1
- package/lib/dist/core/sketch.d.ts +4 -3
- package/lib/dist/core/sketch.js +4 -1
- package/lib/dist/features/extrude-base.d.ts +7 -1
- package/lib/dist/features/extrude-base.js +36 -3
- package/lib/dist/features/extrude-to-face.d.ts +1 -1
- package/lib/dist/features/extrude-to-face.js +29 -17
- package/lib/dist/features/extrude-two-distances.d.ts +1 -1
- package/lib/dist/features/extrude-two-distances.js +23 -12
- package/lib/dist/features/extrude.d.ts +1 -1
- package/lib/dist/features/extrude.js +47 -15
- package/lib/dist/features/mirror-shape.d.ts +1 -3
- package/lib/dist/features/mirror-shape.js +2 -1
- package/lib/dist/features/revolve.js +4 -2
- package/lib/dist/features/rotate.js +1 -0
- package/lib/dist/features/simple-extruder.js +5 -0
- package/lib/dist/features/translate.js +3 -1
- package/lib/dist/filters/face/face-filter.d.ts +12 -0
- package/lib/dist/filters/face/face-filter.js +21 -0
- package/lib/dist/filters/face/torus-filter.d.ts +19 -0
- package/lib/dist/filters/face/torus-filter.js +38 -0
- package/lib/dist/helpers/scene-helpers.d.ts +3 -1
- package/lib/dist/helpers/scene-helpers.js +6 -3
- package/lib/dist/index.d.ts +1 -0
- package/lib/dist/oc/boolean-ops.d.ts +5 -3
- package/lib/dist/oc/boolean-ops.js +15 -2
- package/lib/dist/oc/face-ops.d.ts +0 -1
- package/lib/dist/oc/face-ops.js +0 -13
- package/lib/dist/oc/face-query.d.ts +2 -0
- package/lib/dist/oc/face-query.js +30 -0
- package/lib/dist/oc/fillet-ops.js +84 -66
- package/lib/dist/oc/mesh.d.ts +25 -2
- package/lib/dist/oc/mesh.js +112 -35
- package/lib/dist/oc/shape-ops.d.ts +1 -21
- package/lib/dist/oc/shape-ops.js +0 -103
- package/lib/dist/rendering/mesh-transform.js +17 -1
- package/lib/dist/rendering/render-solid.js +19 -6
- package/lib/dist/rendering/render-wire.js +2 -0
- package/lib/dist/rendering/render.d.ts +12 -2
- package/lib/dist/rendering/render.js +195 -220
- package/lib/dist/scene-manager.d.ts +2 -0
- package/lib/dist/scene-manager.js +4 -3
- package/lib/dist/tests/features/extrude.test.js +71 -0
- package/lib/dist/tests/features/fillet2d.test.js +16 -1
- package/lib/dist/tests/features/select.test.js +50 -0
- package/lib/dist/tests/setup.js +3 -2
- package/lib/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +3 -3
- package/ui/dist/assets/{index-BeLxRMCv.js → index-55iqIwnj.js} +37 -37
- package/ui/dist/index.html +1 -1
- package/lib/dist/common/solid-face.d.ts +0 -9
- package/lib/dist/common/solid-face.js +0 -22
|
@@ -4,5 +4,5 @@ import { Wire } from "./wire.js";
|
|
|
4
4
|
import { Face } from "./face.js";
|
|
5
5
|
import { Edge } from "./edge.js";
|
|
6
6
|
export declare class ShapeFactory {
|
|
7
|
-
static fromShape(shape: TopoDS_Shape): Wire | Edge |
|
|
7
|
+
static fromShape(shape: TopoDS_Shape): Wire | Edge | Face | Solid;
|
|
8
8
|
}
|
|
@@ -2,45 +2,44 @@ import { IExtrude, ISceneObject } from "./interfaces.js";
|
|
|
2
2
|
interface ExtrudeFunction {
|
|
3
3
|
/**
|
|
4
4
|
* Extrudes the last sketch with a default distance.
|
|
5
|
-
* @param target - The sketch to extrude
|
|
5
|
+
* @param target - The sketch or face-bearing scene object to extrude
|
|
6
6
|
*/
|
|
7
7
|
(target?: ISceneObject): IExtrude;
|
|
8
8
|
/**
|
|
9
|
-
* Extrudes
|
|
9
|
+
* Extrudes by a given distance.
|
|
10
10
|
* @param distance - The extrusion distance
|
|
11
|
-
* @param target - The sketch to extrude
|
|
11
|
+
* @param target - The sketch or face-bearing scene object to extrude
|
|
12
12
|
*/
|
|
13
13
|
(distance: number, target?: ISceneObject): IExtrude;
|
|
14
14
|
/**
|
|
15
|
-
* Extrudes
|
|
15
|
+
* Extrudes between two distances.
|
|
16
16
|
* @param distance1 - The first extrusion distance
|
|
17
17
|
* @param distance2 - The second extrusion distance
|
|
18
|
-
* @param target - The sketch to extrude
|
|
19
18
|
*/
|
|
20
19
|
(distance1: number, distance2: number): IExtrude;
|
|
21
20
|
/**
|
|
22
|
-
* Extrudes
|
|
21
|
+
* Extrudes between two distances.
|
|
23
22
|
* @param distance1 - The first extrusion distance
|
|
24
23
|
* @param distance2 - The second extrusion distance
|
|
25
|
-
* @param target - The sketch to extrude
|
|
24
|
+
* @param target - The sketch or face-bearing scene object to extrude
|
|
26
25
|
*/
|
|
27
26
|
(distance1: number, distance2: number, target: ISceneObject): IExtrude;
|
|
28
27
|
/**
|
|
29
|
-
* Extrudes
|
|
28
|
+
* Extrudes up to a specific face.
|
|
30
29
|
* @param face - A face selection to extrude up to
|
|
31
|
-
* @param target - The sketch to extrude
|
|
30
|
+
* @param target - The sketch or face-bearing scene object to extrude
|
|
32
31
|
*/
|
|
33
32
|
(face: ISceneObject, target?: ISceneObject): IExtrude;
|
|
34
33
|
/**
|
|
35
|
-
* Extrudes
|
|
34
|
+
* Extrudes up to the first intersecting face.
|
|
36
35
|
* @param face - The literal `'first-face'`
|
|
37
|
-
* @param target - The sketch to extrude
|
|
36
|
+
* @param target - The sketch or face-bearing scene object to extrude
|
|
38
37
|
*/
|
|
39
38
|
(face: 'first-face', target?: ISceneObject): IExtrude;
|
|
40
39
|
/**
|
|
41
|
-
* Extrudes
|
|
40
|
+
* Extrudes up to the last intersecting face.
|
|
42
41
|
* @param face - The literal `'last-face'`
|
|
43
|
-
* @param target - The sketch to extrude
|
|
42
|
+
* @param target - The sketch or face-bearing scene object to extrude
|
|
44
43
|
*/
|
|
45
44
|
(face: 'last-face', target?: ISceneObject): IExtrude;
|
|
46
45
|
}
|
package/lib/dist/core/extrude.js
CHANGED
|
@@ -3,9 +3,22 @@ import { registerBuilder } from "../index.js";
|
|
|
3
3
|
import { Extrude } from "../features/extrude.js";
|
|
4
4
|
import { ExtrudeTwoDistances } from "../features/extrude-two-distances.js";
|
|
5
5
|
import { ExtrudeToFace } from "../features/extrude-to-face.js";
|
|
6
|
+
import { SelectSceneObject } from "../features/select.js";
|
|
6
7
|
function isExtrudable(obj) {
|
|
7
8
|
return obj instanceof SceneObject && obj.isExtrudable();
|
|
8
9
|
}
|
|
10
|
+
function isFaceSource(obj) {
|
|
11
|
+
if (!(obj instanceof SceneObject)) {
|
|
12
|
+
return false;
|
|
13
|
+
}
|
|
14
|
+
if (isExtrudable(obj)) {
|
|
15
|
+
return false;
|
|
16
|
+
}
|
|
17
|
+
if (obj instanceof SelectSceneObject) {
|
|
18
|
+
return obj.shapeType() === 'face';
|
|
19
|
+
}
|
|
20
|
+
return true;
|
|
21
|
+
}
|
|
9
22
|
function build(context) {
|
|
10
23
|
function doExtrude(params, extrudable) {
|
|
11
24
|
const defaultDistance = 25;
|
|
@@ -41,8 +54,13 @@ function build(context) {
|
|
|
41
54
|
return function extrude() {
|
|
42
55
|
const args = [...arguments];
|
|
43
56
|
let extrudable;
|
|
44
|
-
|
|
57
|
+
const last = args.length > 0 ? args[args.length - 1] : undefined;
|
|
58
|
+
if (last !== undefined && isExtrudable(last)) {
|
|
59
|
+
extrudable = args.pop();
|
|
60
|
+
}
|
|
61
|
+
else if (last !== undefined && args.length >= 2 && isFaceSource(last)) {
|
|
45
62
|
extrudable = args.pop();
|
|
63
|
+
context.addSceneObject(extrudable);
|
|
46
64
|
}
|
|
47
65
|
else {
|
|
48
66
|
extrudable = context.getLastExtrudable() || undefined;
|
package/lib/dist/core/part.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
1
|
import { ISceneObject } from "./interfaces.js";
|
|
2
|
-
|
|
2
|
+
type Extend<T> = T extends object ? T : {};
|
|
3
|
+
declare function part<T>(name: string, callback: () => T): ISceneObject & Extend<T>;
|
|
3
4
|
export default part;
|
package/lib/dist/core/part.js
CHANGED
|
@@ -12,8 +12,11 @@ function part(name, callback) {
|
|
|
12
12
|
partObj.setSourceLocation(sourceLocation);
|
|
13
13
|
}
|
|
14
14
|
scene.startProgressiveContainer(partObj);
|
|
15
|
-
callback();
|
|
15
|
+
const extensions = callback();
|
|
16
16
|
scene.endProgressiveContainer();
|
|
17
|
+
if (extensions && typeof extensions === 'object') {
|
|
18
|
+
Object.assign(partObj, extensions);
|
|
19
|
+
}
|
|
17
20
|
return partObj;
|
|
18
21
|
}
|
|
19
22
|
export default part;
|
|
@@ -1,24 +1,25 @@
|
|
|
1
1
|
import { PlaneLike } from "../math/plane.js";
|
|
2
2
|
import { IPlane, ISceneObject } from "./interfaces.js";
|
|
3
|
+
type Extend<T> = T extends object ? T : {};
|
|
3
4
|
interface SketchFunction {
|
|
4
5
|
/**
|
|
5
6
|
* Draws 2D geometry on a standard plane.
|
|
6
7
|
* @param plane - The plane to sketch on
|
|
7
8
|
* @param sketcher - Callback containing sketch operations
|
|
8
9
|
*/
|
|
9
|
-
(plane: PlaneLike, sketcher: () =>
|
|
10
|
+
<T>(plane: PlaneLike, sketcher: () => T): ISceneObject & Extend<T>;
|
|
10
11
|
/**
|
|
11
12
|
* Draws 2D geometry on a face selection.
|
|
12
13
|
* @param face - The face to sketch on
|
|
13
14
|
* @param sketcher - Callback containing sketch operations
|
|
14
15
|
*/
|
|
15
|
-
(face: ISceneObject, sketcher: () =>
|
|
16
|
+
<T>(face: ISceneObject, sketcher: () => T): ISceneObject & Extend<T>;
|
|
16
17
|
/**
|
|
17
18
|
* Draws 2D geometry on an existing Plane object.
|
|
18
19
|
* @param plane - The Plane object to sketch on
|
|
19
20
|
* @param sketcher - Callback containing sketch operations
|
|
20
21
|
*/
|
|
21
|
-
(plane: IPlane, sketcher: () =>
|
|
22
|
+
<T>(plane: IPlane, sketcher: () => T): ISceneObject & Extend<T>;
|
|
22
23
|
}
|
|
23
24
|
declare const _default: SketchFunction;
|
|
24
25
|
export default _default;
|
package/lib/dist/core/sketch.js
CHANGED
|
@@ -26,8 +26,11 @@ function build(context) {
|
|
|
26
26
|
}
|
|
27
27
|
const sketch = new Sketch(planeObj);
|
|
28
28
|
context.startProgressiveContainer(sketch);
|
|
29
|
-
sketcher();
|
|
29
|
+
const extensions = sketcher();
|
|
30
30
|
context.endProgressiveContainer();
|
|
31
|
+
if (extensions && typeof extensions === 'object') {
|
|
32
|
+
Object.assign(sketch, extensions);
|
|
33
|
+
}
|
|
31
34
|
return sketch;
|
|
32
35
|
};
|
|
33
36
|
}
|
|
@@ -10,14 +10,20 @@ import { FaceFilterBuilder } from "../filters/face/face-filter.js";
|
|
|
10
10
|
import { EdgeFilterBuilder } from "../filters/edge/edge-filter.js";
|
|
11
11
|
export declare abstract class ExtrudeBase extends SceneObject implements IExtrude {
|
|
12
12
|
protected _extrudable: Extrudable | null;
|
|
13
|
+
protected _faceSource: SceneObject | null;
|
|
13
14
|
protected _draft?: number | [number, number];
|
|
14
15
|
protected _endOffset?: number;
|
|
15
16
|
protected _drill?: boolean;
|
|
16
17
|
protected _picking: boolean;
|
|
17
18
|
protected _pickPoints: LazyVertex[];
|
|
18
19
|
protected _thin?: [number] | [number, number];
|
|
19
|
-
constructor(
|
|
20
|
+
constructor(source?: Extrudable | SceneObject);
|
|
20
21
|
get extrudable(): Extrudable;
|
|
22
|
+
get faceSource(): SceneObject | null;
|
|
23
|
+
isFaceSourced(): boolean;
|
|
24
|
+
getSource(): SceneObject | null;
|
|
25
|
+
getSourcePlane(): Plane | null;
|
|
26
|
+
getSourceFaces(): Face[];
|
|
21
27
|
startFaces(...args: number[] | FaceFilterBuilder[]): SceneObject;
|
|
22
28
|
endFaces(...args: number[] | FaceFilterBuilder[]): SceneObject;
|
|
23
29
|
startEdges(...args: number[] | EdgeFilterBuilder[]): SceneObject;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { Face } from "../common/face.js";
|
|
1
2
|
import { SceneObject } from "../common/scene-object.js";
|
|
2
3
|
import { LazySelectionSceneObject } from "./lazy-scene-object.js";
|
|
3
4
|
import { normalizePoint2D } from "../helpers/normalize.js";
|
|
@@ -9,19 +10,51 @@ import { ShapeFilter } from "../filters/filter.js";
|
|
|
9
10
|
import { EdgeOps } from "../oc/edge-ops.js";
|
|
10
11
|
export class ExtrudeBase extends SceneObject {
|
|
11
12
|
_extrudable = null;
|
|
13
|
+
_faceSource = null;
|
|
12
14
|
_draft;
|
|
13
15
|
_endOffset;
|
|
14
16
|
_drill = true;
|
|
15
17
|
_picking = false;
|
|
16
18
|
_pickPoints = [];
|
|
17
19
|
_thin;
|
|
18
|
-
constructor(
|
|
20
|
+
constructor(source) {
|
|
19
21
|
super();
|
|
20
|
-
|
|
22
|
+
if (source) {
|
|
23
|
+
if (source.isExtrudable()) {
|
|
24
|
+
this._extrudable = source;
|
|
25
|
+
}
|
|
26
|
+
else {
|
|
27
|
+
this._faceSource = source;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
21
30
|
}
|
|
22
31
|
get extrudable() {
|
|
23
32
|
return this._extrudable;
|
|
24
33
|
}
|
|
34
|
+
get faceSource() {
|
|
35
|
+
return this._faceSource;
|
|
36
|
+
}
|
|
37
|
+
isFaceSourced() {
|
|
38
|
+
return this._faceSource !== null;
|
|
39
|
+
}
|
|
40
|
+
getSource() {
|
|
41
|
+
return this._extrudable ?? this._faceSource;
|
|
42
|
+
}
|
|
43
|
+
getSourcePlane() {
|
|
44
|
+
if (this._extrudable) {
|
|
45
|
+
return this._extrudable.getPlane();
|
|
46
|
+
}
|
|
47
|
+
const faces = this.getSourceFaces();
|
|
48
|
+
return faces.length > 0 ? faces[0].getPlane() : null;
|
|
49
|
+
}
|
|
50
|
+
getSourceFaces() {
|
|
51
|
+
if (!this._faceSource) {
|
|
52
|
+
return [];
|
|
53
|
+
}
|
|
54
|
+
return this._faceSource.getShapes()
|
|
55
|
+
.flatMap(s => s.getSubShapes('face'))
|
|
56
|
+
.filter((f) => f instanceof Face);
|
|
57
|
+
}
|
|
25
58
|
startFaces(...args) {
|
|
26
59
|
const suffix = this.buildSuffix('start-faces', args);
|
|
27
60
|
return new LazySelectionSceneObject(`${this.generateUniqueName(suffix)}`, (parent) => {
|
|
@@ -230,7 +263,7 @@ export class ExtrudeBase extends SceneObject {
|
|
|
230
263
|
return this._thin;
|
|
231
264
|
}
|
|
232
265
|
serializePickFields() {
|
|
233
|
-
const plane = this.
|
|
266
|
+
const plane = this.getSourcePlane();
|
|
234
267
|
return {
|
|
235
268
|
picking: this.isPicking() || undefined,
|
|
236
269
|
pickPoints: this.isPicking()
|
|
@@ -4,7 +4,7 @@ import { Extrudable } from "../helpers/types.js";
|
|
|
4
4
|
import { Point } from "../math/point.js";
|
|
5
5
|
export declare class ExtrudeToFace extends ExtrudeBase {
|
|
6
6
|
face: SceneObject | 'first-face' | 'last-face';
|
|
7
|
-
constructor(face: SceneObject | 'first-face' | 'last-face',
|
|
7
|
+
constructor(face: SceneObject | 'first-face' | 'last-face', source?: Extrudable | SceneObject);
|
|
8
8
|
build(context: BuildSceneObjectContext): void;
|
|
9
9
|
private createAdvancedExtrude;
|
|
10
10
|
private resizePlanarFace;
|
|
@@ -13,14 +13,14 @@ import { ThinFaceMaker } from "../oc/thin-face-maker.js";
|
|
|
13
13
|
import { Point } from "../math/point.js";
|
|
14
14
|
export class ExtrudeToFace extends ExtrudeBase {
|
|
15
15
|
face;
|
|
16
|
-
constructor(face,
|
|
17
|
-
super(
|
|
16
|
+
constructor(face, source) {
|
|
17
|
+
super(source);
|
|
18
18
|
this.face = face;
|
|
19
19
|
}
|
|
20
20
|
build(context) {
|
|
21
21
|
const allSceneObjects = context.getSceneObjects();
|
|
22
22
|
const sceneObjects = this.resolveFusionScope(allSceneObjects);
|
|
23
|
-
const plane = this.
|
|
23
|
+
const plane = this.getSourcePlane();
|
|
24
24
|
const pickedFaces = this.resolvePickedFaces(plane);
|
|
25
25
|
if (pickedFaces !== null && pickedFaces.length === 0) {
|
|
26
26
|
return;
|
|
@@ -35,7 +35,13 @@ export class ExtrudeToFace extends ExtrudeBase {
|
|
|
35
35
|
let faces;
|
|
36
36
|
let inwardEdges;
|
|
37
37
|
let outwardEdges;
|
|
38
|
-
if (this.
|
|
38
|
+
if (this.isFaceSourced()) {
|
|
39
|
+
if (this.isThin()) {
|
|
40
|
+
throw new Error("thin() is not supported with a face-sourced extrude");
|
|
41
|
+
}
|
|
42
|
+
faces = pickedFaces ?? this.getSourceFaces();
|
|
43
|
+
}
|
|
44
|
+
else if (this.isThin()) {
|
|
39
45
|
const thinResult = ThinFaceMaker.make(this.extrudable.getGeometries(), plane, this._thin[0], this._thin[1]);
|
|
40
46
|
faces = thinResult.faces;
|
|
41
47
|
inwardEdges = thinResult.inwardEdges;
|
|
@@ -79,7 +85,7 @@ export class ExtrudeToFace extends ExtrudeBase {
|
|
|
79
85
|
this.setState('side-faces', allSideFaces);
|
|
80
86
|
this.setState('internal-faces', allInternalFaces);
|
|
81
87
|
this.setState('cap-faces', allCapFaces);
|
|
82
|
-
this.
|
|
88
|
+
this.getSource()?.removeShapes(this);
|
|
83
89
|
if (this.face instanceof SceneObject) {
|
|
84
90
|
this.face.removeShapes(this);
|
|
85
91
|
}
|
|
@@ -128,7 +134,7 @@ export class ExtrudeToFace extends ExtrudeBase {
|
|
|
128
134
|
resizePlanarFace(targetFace) {
|
|
129
135
|
const endOffset = this.getEndOffset();
|
|
130
136
|
if (endOffset) {
|
|
131
|
-
const dir = this.
|
|
137
|
+
const dir = this.getSourcePlane().normal.reverse();
|
|
132
138
|
return FaceQuery.makeInfinitePlanarFace(targetFace, endOffset, dir);
|
|
133
139
|
}
|
|
134
140
|
return FaceQuery.makeInfinitePlanarFace(targetFace);
|
|
@@ -165,7 +171,7 @@ export class ExtrudeToFace extends ExtrudeBase {
|
|
|
165
171
|
}
|
|
166
172
|
splitShapesByFace(extrusions, targetFace) {
|
|
167
173
|
const result = [];
|
|
168
|
-
const sourcePlane = this.
|
|
174
|
+
const sourcePlane = this.getSourcePlane();
|
|
169
175
|
for (const shape of extrusions) {
|
|
170
176
|
const solids = BooleanOps.splitShape(shape, targetFace);
|
|
171
177
|
if (solids.length === 1) {
|
|
@@ -221,10 +227,11 @@ export class ExtrudeToFace extends ExtrudeBase {
|
|
|
221
227
|
}
|
|
222
228
|
}
|
|
223
229
|
getFirstOrLastFace(sceneObjects, mode) {
|
|
224
|
-
const plane = this.
|
|
230
|
+
const plane = this.getSourcePlane();
|
|
231
|
+
const source = this.getSource();
|
|
225
232
|
const allFaces = [];
|
|
226
233
|
for (const obj of sceneObjects) {
|
|
227
|
-
if (obj ===
|
|
234
|
+
if (obj === source) {
|
|
228
235
|
continue;
|
|
229
236
|
}
|
|
230
237
|
for (const shape of obj.getShapes()) {
|
|
@@ -242,8 +249,9 @@ export class ExtrudeToFace extends ExtrudeBase {
|
|
|
242
249
|
}
|
|
243
250
|
getDependencies() {
|
|
244
251
|
const deps = [];
|
|
245
|
-
|
|
246
|
-
|
|
252
|
+
const source = this.getSource();
|
|
253
|
+
if (source) {
|
|
254
|
+
deps.push(source);
|
|
247
255
|
}
|
|
248
256
|
if (this.face instanceof SceneObject) {
|
|
249
257
|
deps.push(this.face);
|
|
@@ -254,10 +262,9 @@ export class ExtrudeToFace extends ExtrudeBase {
|
|
|
254
262
|
const newFace = this.face instanceof SceneObject
|
|
255
263
|
? (remap.get(this.face) || this.face)
|
|
256
264
|
: this.face;
|
|
257
|
-
const
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
return new ExtrudeToFace(newFace, extrudable).syncWith(this);
|
|
265
|
+
const source = this.getSource();
|
|
266
|
+
const remapped = source ? (remap.get(source) || source) : undefined;
|
|
267
|
+
return new ExtrudeToFace(newFace, remapped).syncWith(this);
|
|
261
268
|
}
|
|
262
269
|
compareTo(other) {
|
|
263
270
|
if (!(other instanceof ExtrudeToFace)) {
|
|
@@ -266,7 +273,12 @@ export class ExtrudeToFace extends ExtrudeBase {
|
|
|
266
273
|
if (!super.compareTo(other)) {
|
|
267
274
|
return false;
|
|
268
275
|
}
|
|
269
|
-
|
|
276
|
+
const thisSource = this.getSource();
|
|
277
|
+
const otherSource = other.getSource();
|
|
278
|
+
if (!thisSource !== !otherSource) {
|
|
279
|
+
return false;
|
|
280
|
+
}
|
|
281
|
+
if (thisSource && otherSource && !thisSource.compareTo(otherSource)) {
|
|
270
282
|
return false;
|
|
271
283
|
}
|
|
272
284
|
if (typeof (this.face) !== typeof (other.face)) {
|
|
@@ -289,7 +301,7 @@ export class ExtrudeToFace extends ExtrudeBase {
|
|
|
289
301
|
serialize() {
|
|
290
302
|
return {
|
|
291
303
|
sheptType: 'wire',
|
|
292
|
-
extrudable: this.
|
|
304
|
+
extrudable: this.getSource()?.serialize(),
|
|
293
305
|
draft: this.getDraft(),
|
|
294
306
|
endOffset: this.getEndOffset(),
|
|
295
307
|
face: typeof (this.face) === 'string' ? this.face : 'selection',
|
|
@@ -4,7 +4,7 @@ import { Extrudable } from "../helpers/types.js";
|
|
|
4
4
|
export declare class ExtrudeTwoDistances extends ExtrudeBase {
|
|
5
5
|
distance1: number;
|
|
6
6
|
distance2: number;
|
|
7
|
-
constructor(distance1: number, distance2: number,
|
|
7
|
+
constructor(distance1: number, distance2: number, source?: Extrudable | SceneObject);
|
|
8
8
|
build(context: BuildSceneObjectContext): void;
|
|
9
9
|
getDependencies(): SceneObject[];
|
|
10
10
|
createCopy(remap: Map<SceneObject, SceneObject>): SceneObject;
|
|
@@ -9,14 +9,14 @@ import { ThinFaceMaker } from "../oc/thin-face-maker.js";
|
|
|
9
9
|
export class ExtrudeTwoDistances extends ExtrudeBase {
|
|
10
10
|
distance1;
|
|
11
11
|
distance2;
|
|
12
|
-
constructor(distance1, distance2,
|
|
13
|
-
super(
|
|
12
|
+
constructor(distance1, distance2, source) {
|
|
13
|
+
super(source);
|
|
14
14
|
this.distance1 = distance1;
|
|
15
15
|
this.distance2 = distance2;
|
|
16
16
|
}
|
|
17
17
|
build(context) {
|
|
18
18
|
const sceneObjects = this.resolveFusionScope(context.getSceneObjects());
|
|
19
|
-
const plane = this.
|
|
19
|
+
const plane = this.getSourcePlane();
|
|
20
20
|
const pickedFaces = this.resolvePickedFaces(plane);
|
|
21
21
|
if (pickedFaces !== null && pickedFaces.length === 0) {
|
|
22
22
|
return;
|
|
@@ -24,7 +24,13 @@ export class ExtrudeTwoDistances extends ExtrudeBase {
|
|
|
24
24
|
let faces;
|
|
25
25
|
let inwardEdges;
|
|
26
26
|
let outwardEdges;
|
|
27
|
-
if (this.
|
|
27
|
+
if (this.isFaceSourced()) {
|
|
28
|
+
if (this.isThin()) {
|
|
29
|
+
throw new Error("thin() is not supported with a face-sourced extrude");
|
|
30
|
+
}
|
|
31
|
+
faces = pickedFaces ?? this.getSourceFaces();
|
|
32
|
+
}
|
|
33
|
+
else if (this.isThin()) {
|
|
28
34
|
const thinResult = ThinFaceMaker.make(this.extrudable.getGeometries(), plane, this._thin[0], this._thin[1]);
|
|
29
35
|
faces = thinResult.faces;
|
|
30
36
|
inwardEdges = thinResult.inwardEdges;
|
|
@@ -112,7 +118,7 @@ export class ExtrudeTwoDistances extends ExtrudeBase {
|
|
|
112
118
|
this.setState('side-faces', sideFaces);
|
|
113
119
|
this.setState('internal-faces', internalFaces);
|
|
114
120
|
this.setState('cap-faces', capFaces);
|
|
115
|
-
this.
|
|
121
|
+
this.getSource()?.removeShapes(this);
|
|
116
122
|
if (this._operationMode === 'remove') {
|
|
117
123
|
const scope = this.resolveFusionScope(context.getSceneObjects());
|
|
118
124
|
cutWithSceneObjects(scope, extrusions, plane, this.distance1 + this.distance2, this);
|
|
@@ -132,13 +138,13 @@ export class ExtrudeTwoDistances extends ExtrudeBase {
|
|
|
132
138
|
this.addShapes(fusionResult.newShapes);
|
|
133
139
|
}
|
|
134
140
|
getDependencies() {
|
|
135
|
-
|
|
141
|
+
const source = this.getSource();
|
|
142
|
+
return source ? [source] : [];
|
|
136
143
|
}
|
|
137
144
|
createCopy(remap) {
|
|
138
|
-
const
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
return new ExtrudeTwoDistances(this.distance1, this.distance2, extrudable).syncWith(this);
|
|
145
|
+
const source = this.getSource();
|
|
146
|
+
const remapped = source ? (remap.get(source) || source) : undefined;
|
|
147
|
+
return new ExtrudeTwoDistances(this.distance1, this.distance2, remapped).syncWith(this);
|
|
142
148
|
}
|
|
143
149
|
compareTo(other) {
|
|
144
150
|
if (!(other instanceof ExtrudeTwoDistances)) {
|
|
@@ -150,7 +156,12 @@ export class ExtrudeTwoDistances extends ExtrudeBase {
|
|
|
150
156
|
if (this.distance1 !== other.distance1 || this.distance2 !== other.distance2) {
|
|
151
157
|
return false;
|
|
152
158
|
}
|
|
153
|
-
|
|
159
|
+
const thisSource = this.getSource();
|
|
160
|
+
const otherSource = other.getSource();
|
|
161
|
+
if (!thisSource !== !otherSource) {
|
|
162
|
+
return false;
|
|
163
|
+
}
|
|
164
|
+
if (thisSource && otherSource && !thisSource.compareTo(otherSource)) {
|
|
154
165
|
return false;
|
|
155
166
|
}
|
|
156
167
|
return true;
|
|
@@ -163,7 +174,7 @@ export class ExtrudeTwoDistances extends ExtrudeBase {
|
|
|
163
174
|
}
|
|
164
175
|
serialize() {
|
|
165
176
|
return {
|
|
166
|
-
extrudable: this.
|
|
177
|
+
extrudable: this.getSource()?.serialize(),
|
|
167
178
|
distance1: this.distance1,
|
|
168
179
|
distance2: this.distance2,
|
|
169
180
|
operationMode: this._operationMode !== 'add' ? this._operationMode : undefined,
|
|
@@ -3,7 +3,7 @@ import { Extrudable } from "../helpers/types.js";
|
|
|
3
3
|
import { ExtrudeBase } from "./extrude-base.js";
|
|
4
4
|
export declare class Extrude extends ExtrudeBase {
|
|
5
5
|
distance: number;
|
|
6
|
-
constructor(distance: number,
|
|
6
|
+
constructor(distance: number, source?: Extrudable | SceneObject);
|
|
7
7
|
build(context: BuildSceneObjectContext): void;
|
|
8
8
|
private buildAdd;
|
|
9
9
|
private buildSymmetric;
|
|
@@ -9,20 +9,32 @@ import { ExtrudeThroughAll } from "./infinite-extrude.js";
|
|
|
9
9
|
import { ThinFaceMaker } from "../oc/thin-face-maker.js";
|
|
10
10
|
export class Extrude extends ExtrudeBase {
|
|
11
11
|
distance;
|
|
12
|
-
constructor(distance,
|
|
13
|
-
super(
|
|
12
|
+
constructor(distance, source) {
|
|
13
|
+
super(source);
|
|
14
14
|
this.distance = distance;
|
|
15
15
|
}
|
|
16
16
|
build(context) {
|
|
17
|
-
const
|
|
17
|
+
const tBuild = performance.now();
|
|
18
|
+
let t = performance.now();
|
|
19
|
+
const plane = this.getSourcePlane();
|
|
20
|
+
console.log(`[perf] Extrude.getSourcePlane: ${(performance.now() - t).toFixed(1)} ms`);
|
|
21
|
+
t = performance.now();
|
|
18
22
|
const pickedFaces = this.resolvePickedFaces(plane);
|
|
23
|
+
console.log(`[perf] Extrude.resolvePickedFaces: ${(performance.now() - t).toFixed(1)} ms`);
|
|
19
24
|
if (pickedFaces !== null && pickedFaces.length === 0) {
|
|
20
25
|
return;
|
|
21
26
|
}
|
|
22
27
|
let faces;
|
|
23
28
|
let inwardEdges;
|
|
24
29
|
let outwardEdges;
|
|
25
|
-
|
|
30
|
+
t = performance.now();
|
|
31
|
+
if (this.isFaceSourced()) {
|
|
32
|
+
if (this.isThin()) {
|
|
33
|
+
throw new Error("thin() is not supported with a face-sourced extrude");
|
|
34
|
+
}
|
|
35
|
+
faces = pickedFaces ?? this.getSourceFaces();
|
|
36
|
+
}
|
|
37
|
+
else if (this.isThin()) {
|
|
26
38
|
const thinResult = ThinFaceMaker.make(this.extrudable.getGeometries(), plane, this._thin[0], this._thin[1]);
|
|
27
39
|
faces = thinResult.faces;
|
|
28
40
|
inwardEdges = thinResult.inwardEdges;
|
|
@@ -31,6 +43,7 @@ export class Extrude extends ExtrudeBase {
|
|
|
31
43
|
else {
|
|
32
44
|
faces = pickedFaces ?? FaceMaker2.getRegions(this.extrudable.getGeometries(), plane, this.getDrill());
|
|
33
45
|
}
|
|
46
|
+
console.log(`[perf] Extrude.resolveFaces (faces=${faces.length}, faceSourced=${this.isFaceSourced()}): ${(performance.now() - t).toFixed(1)} ms`);
|
|
34
47
|
if (this._operationMode === 'remove') {
|
|
35
48
|
this.buildRemove(faces, plane, context);
|
|
36
49
|
}
|
|
@@ -40,11 +53,16 @@ export class Extrude extends ExtrudeBase {
|
|
|
40
53
|
else {
|
|
41
54
|
this.buildAdd(faces, plane, context, inwardEdges, outwardEdges);
|
|
42
55
|
}
|
|
56
|
+
console.log(`[perf] Extrude.build TOTAL: ${(performance.now() - tBuild).toFixed(1)} ms`);
|
|
43
57
|
}
|
|
44
58
|
buildAdd(faces, plane, context, inwardEdges, outwardEdges) {
|
|
59
|
+
let t = performance.now();
|
|
45
60
|
const sceneObjects = this.resolveFusionScope(context.getSceneObjects());
|
|
61
|
+
console.log(`[perf] Extrude.buildAdd.resolveFusionScope (n=${sceneObjects.length}): ${(performance.now() - t).toFixed(1)} ms`);
|
|
62
|
+
t = performance.now();
|
|
46
63
|
const extruder = new Extruder(faces, plane, this.distance, this.getDraft(), this.getEndOffset());
|
|
47
64
|
let extrusions = extruder.extrude();
|
|
65
|
+
console.log(`[perf] Extrude.buildAdd.extruder.extrude (extrusions=${extrusions.length}): ${(performance.now() - t).toFixed(1)} ms`);
|
|
48
66
|
let sideFaces = extruder.getSideFaces();
|
|
49
67
|
let internalFaces = extruder.getInternalFaces();
|
|
50
68
|
let capFaces = [];
|
|
@@ -59,12 +77,15 @@ export class Extrude extends ExtrudeBase {
|
|
|
59
77
|
this.setState('side-faces', sideFaces);
|
|
60
78
|
this.setState('internal-faces', internalFaces);
|
|
61
79
|
this.setState('cap-faces', capFaces);
|
|
62
|
-
this.
|
|
80
|
+
this.getSource()?.removeShapes(this);
|
|
81
|
+
console.log("Extrusions before fusion:", extrusions.length);
|
|
63
82
|
if (extrusions.length === 0 || sceneObjects.length === 0) {
|
|
64
83
|
this.addShapes(extrusions);
|
|
65
84
|
return;
|
|
66
85
|
}
|
|
67
|
-
const
|
|
86
|
+
const tFuse = performance.now();
|
|
87
|
+
const fusionResult = fuseWithSceneObjects(sceneObjects, extrusions, this.isFaceSourced() ? { glue: 'full' } : undefined);
|
|
88
|
+
console.log(`[perf] Extrude.buildAdd.fuseWithSceneObjects: ${(performance.now() - tFuse).toFixed(1)} ms`);
|
|
68
89
|
for (const modifiedShape of fusionResult.modifiedShapes) {
|
|
69
90
|
if (!modifiedShape.object) {
|
|
70
91
|
continue;
|
|
@@ -158,7 +179,7 @@ export class Extrude extends ExtrudeBase {
|
|
|
158
179
|
this.setState('side-faces', sideFaces);
|
|
159
180
|
this.setState('internal-faces', internalFaces);
|
|
160
181
|
this.setState('cap-faces', capFaces);
|
|
161
|
-
this.
|
|
182
|
+
this.getSource()?.removeShapes(this);
|
|
162
183
|
if (extrusions.length === 0 || sceneObjects.length === 0) {
|
|
163
184
|
this.addShapes(extrusions);
|
|
164
185
|
return;
|
|
@@ -179,6 +200,9 @@ export class Extrude extends ExtrudeBase {
|
|
|
179
200
|
if (this._symmetric) {
|
|
180
201
|
// Symmetric cut: create tool centered on sketch plane
|
|
181
202
|
if (isThroughAll) {
|
|
203
|
+
if (this.isFaceSourced()) {
|
|
204
|
+
throw new Error("through-all is not supported with a face-sourced extrude");
|
|
205
|
+
}
|
|
182
206
|
const extrudeThroughAll = new ExtrudeThroughAll(this.extrudable, true, true, faces);
|
|
183
207
|
toolShapes = extrudeThroughAll.build();
|
|
184
208
|
}
|
|
@@ -193,6 +217,9 @@ export class Extrude extends ExtrudeBase {
|
|
|
193
217
|
}
|
|
194
218
|
}
|
|
195
219
|
else if (isThroughAll) {
|
|
220
|
+
if (this.isFaceSourced()) {
|
|
221
|
+
throw new Error("through-all is not supported with a face-sourced extrude");
|
|
222
|
+
}
|
|
196
223
|
const extrudeThroughAll = new ExtrudeThroughAll(this.extrudable, false, true, faces);
|
|
197
224
|
toolShapes = extrudeThroughAll.build();
|
|
198
225
|
}
|
|
@@ -201,17 +228,17 @@ export class Extrude extends ExtrudeBase {
|
|
|
201
228
|
const extruder = new Extruder(faces, plane, distance, this.getDraft(), this.getEndOffset());
|
|
202
229
|
toolShapes = extruder.extrude();
|
|
203
230
|
}
|
|
204
|
-
this.
|
|
231
|
+
this.getSource()?.removeShapes(this);
|
|
205
232
|
cutWithSceneObjects(scope, toolShapes, plane, this.distance, this);
|
|
206
233
|
}
|
|
207
234
|
getDependencies() {
|
|
208
|
-
|
|
235
|
+
const source = this.getSource();
|
|
236
|
+
return source ? [source] : [];
|
|
209
237
|
}
|
|
210
238
|
createCopy(remap) {
|
|
211
|
-
const
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
return new Extrude(this.distance, extrudable).syncWith(this);
|
|
239
|
+
const source = this.getSource();
|
|
240
|
+
const remapped = source ? (remap.get(source) || source) : undefined;
|
|
241
|
+
return new Extrude(this.distance, remapped).syncWith(this);
|
|
215
242
|
}
|
|
216
243
|
compareTo(other) {
|
|
217
244
|
if (!(other instanceof Extrude)) {
|
|
@@ -220,7 +247,12 @@ export class Extrude extends ExtrudeBase {
|
|
|
220
247
|
if (!super.compareTo(other)) {
|
|
221
248
|
return false;
|
|
222
249
|
}
|
|
223
|
-
|
|
250
|
+
const thisSource = this.getSource();
|
|
251
|
+
const otherSource = other.getSource();
|
|
252
|
+
if (!thisSource !== !otherSource) {
|
|
253
|
+
return false;
|
|
254
|
+
}
|
|
255
|
+
if (thisSource && otherSource && !thisSource.compareTo(otherSource)) {
|
|
224
256
|
return false;
|
|
225
257
|
}
|
|
226
258
|
if (this.distance !== other.distance) {
|
|
@@ -242,7 +274,7 @@ export class Extrude extends ExtrudeBase {
|
|
|
242
274
|
}
|
|
243
275
|
serialize() {
|
|
244
276
|
return {
|
|
245
|
-
extrudable: this.
|
|
277
|
+
extrudable: this.getSource()?.serialize(),
|
|
246
278
|
distance: this.distance,
|
|
247
279
|
operationMode: this._operationMode !== 'add' ? this._operationMode : undefined,
|
|
248
280
|
symmetric: this._symmetric || undefined,
|