fluidcad 0.0.7 → 0.0.9
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/bin/fluidcad.js +16 -0
- package/lib/dist/core/2d/arc.d.ts +15 -0
- package/lib/dist/core/2d/arc.js +10 -0
- package/lib/dist/core/2d/index.d.ts +0 -1
- package/lib/dist/core/2d/index.js +0 -1
- package/lib/dist/core/2d/tarc.d.ts +26 -2
- package/lib/dist/core/2d/tcircle.d.ts +26 -2
- package/lib/dist/core/2d/tline.d.ts +26 -6
- package/lib/dist/core/axis.d.ts +11 -4
- package/lib/dist/core/chamfer.d.ts +6 -6
- package/lib/dist/core/chamfer.js +12 -9
- package/lib/dist/core/cut.d.ts +27 -6
- package/lib/dist/core/extrude.d.ts +15 -3
- package/lib/dist/core/plane.d.ts +11 -4
- package/lib/dist/core/repeat.d.ts +16 -1
- package/lib/dist/core/repeat.js +39 -3
- package/lib/dist/core/sketch.d.ts +9 -3
- package/lib/dist/core/subtract.d.ts +5 -4
- package/lib/dist/core/subtract.js +9 -2
- package/lib/dist/features/2d/arc-three-points.d.ts +19 -0
- package/lib/dist/features/2d/arc-three-points.js +75 -0
- package/lib/dist/features/2d/constraints/geometry-qualifier.d.ts +16 -0
- package/lib/dist/features/2d/constraints/geometry-qualifier.js +16 -0
- package/lib/dist/features/2d/offset.js +10 -0
- package/lib/dist/features/2d/projection.js +9 -0
- package/lib/dist/features/2d/rect.js +19 -16
- package/lib/dist/features/chamfer.d.ts +4 -4
- package/lib/dist/features/chamfer.js +33 -15
- package/lib/dist/features/common2d.js +26 -8
- package/lib/dist/features/fuse2d.js +24 -6
- package/lib/dist/features/repeat-matrix.d.ts +14 -0
- package/lib/dist/features/repeat-matrix.js +41 -0
- package/lib/dist/features/select.d.ts +1 -0
- package/lib/dist/features/select.js +19 -0
- package/lib/dist/features/subtract2d.d.ts +14 -0
- package/lib/dist/features/subtract2d.js +80 -0
- package/lib/dist/filters/edge/belongs-to-face.d.ts +22 -0
- package/lib/dist/filters/edge/belongs-to-face.js +67 -0
- package/lib/dist/filters/edge/belongs-to-object.d.ts +18 -0
- package/lib/dist/filters/edge/belongs-to-object.js +37 -0
- package/lib/dist/filters/edge/edge-filter.d.ts +88 -3
- package/lib/dist/filters/edge/edge-filter.js +101 -4
- package/lib/dist/filters/edge/line-filter.d.ts +4 -1
- package/lib/dist/filters/edge/line-filter.js +14 -7
- package/lib/dist/filters/face/edge-count.d.ts +17 -0
- package/lib/dist/filters/face/edge-count.js +33 -0
- package/lib/dist/filters/face/face-filter.d.ts +93 -0
- package/lib/dist/filters/face/face-filter.js +112 -0
- package/lib/dist/filters/face/has-edge.d.ts +18 -0
- package/lib/dist/filters/face/has-edge.js +59 -0
- package/lib/dist/filters/face/has-object.d.ts +18 -0
- package/lib/dist/filters/face/has-object.js +37 -0
- package/lib/dist/filters/index.d.ts +6 -0
- package/lib/dist/filters/index.js +6 -0
- package/lib/dist/index.js +1 -1
- package/lib/dist/oc/edge-query.d.ts +2 -2
- package/lib/dist/oc/edge-query.js +13 -4
- package/lib/dist/tests/features/2d/arc.test.js +15 -1
- package/lib/dist/tests/features/select.test.js +249 -0
- package/lib/dist/tests/features/subtract2d.test.d.ts +1 -0
- package/lib/dist/tests/features/subtract2d.test.js +63 -0
- package/lib/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +3 -2
- package/server/dist/fluidcad-server.js +3 -2
- package/server/dist/index.js +2 -1
- package/server/dist/normalize-path.d.ts +6 -0
- package/server/dist/normalize-path.js +8 -0
- package/server/dist/vite-manager.js +3 -2
- package/lib/dist/core/2d/wire.d.ts +0 -11
- package/lib/dist/core/2d/wire.js +0 -29
- package/lib/dist/features/2d/wire.d.ts +0 -12
- package/lib/dist/features/2d/wire.js +0 -76
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { Vertex } from "../../common/vertex.js";
|
|
2
|
+
import { Geometry } from "../../oc/geometry.js";
|
|
3
|
+
import { Point2D } from "../../math/point.js";
|
|
4
|
+
import { GeometrySceneObject } from "./geometry.js";
|
|
5
|
+
export class ArcThreePoints extends GeometrySceneObject {
|
|
6
|
+
startPoint;
|
|
7
|
+
endPoint;
|
|
8
|
+
center;
|
|
9
|
+
targetPlane;
|
|
10
|
+
constructor(startPoint, endPoint, center, targetPlane = null) {
|
|
11
|
+
super();
|
|
12
|
+
this.startPoint = startPoint;
|
|
13
|
+
this.endPoint = endPoint;
|
|
14
|
+
this.center = center;
|
|
15
|
+
this.targetPlane = targetPlane;
|
|
16
|
+
}
|
|
17
|
+
build() {
|
|
18
|
+
const plane = this.targetPlane?.getPlane() || this.sketch.getPlane();
|
|
19
|
+
const startPt = this.startPoint.asPoint2D();
|
|
20
|
+
const endPt = this.endPoint.asPoint2D();
|
|
21
|
+
const centerPt = this.center.asPoint2D();
|
|
22
|
+
const dx = startPt.x - centerPt.x;
|
|
23
|
+
const dy = startPt.y - centerPt.y;
|
|
24
|
+
const radius = Math.sqrt(dx * dx + dy * dy);
|
|
25
|
+
const endAngle = Math.atan2(endPt.y - centerPt.y, endPt.x - centerPt.x);
|
|
26
|
+
const center = plane.localToWorld(centerPt);
|
|
27
|
+
const start = plane.localToWorld(startPt);
|
|
28
|
+
const end = plane.localToWorld(endPt);
|
|
29
|
+
const arc = Geometry.makeArc(center, radius, plane.normal, start, end);
|
|
30
|
+
const edge = Geometry.makeEdgeFromCurve(arc);
|
|
31
|
+
// Tangent at end: perpendicular to radius direction at end point (CCW)
|
|
32
|
+
const tx = -Math.sin(endAngle);
|
|
33
|
+
const ty = Math.cos(endAngle);
|
|
34
|
+
this.setTangent(new Point2D(tx, ty));
|
|
35
|
+
this.setState('start', Vertex.fromPoint2D(startPt));
|
|
36
|
+
this.setState('end', Vertex.fromPoint2D(endPt));
|
|
37
|
+
this.addShape(edge);
|
|
38
|
+
if (this.sketch) {
|
|
39
|
+
this.setCurrentPosition(endPt);
|
|
40
|
+
}
|
|
41
|
+
if (this.targetPlane) {
|
|
42
|
+
this.targetPlane.removeShapes(this);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
compareTo(other) {
|
|
46
|
+
if (!(other instanceof ArcThreePoints)) {
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
if (!super.compareTo(other)) {
|
|
50
|
+
return false;
|
|
51
|
+
}
|
|
52
|
+
if (this.targetPlane?.constructor !== other.targetPlane?.constructor) {
|
|
53
|
+
return false;
|
|
54
|
+
}
|
|
55
|
+
if (this.targetPlane && other.targetPlane && !this.targetPlane.compareTo(other.targetPlane)) {
|
|
56
|
+
return false;
|
|
57
|
+
}
|
|
58
|
+
return this.startPoint.compareTo(other.startPoint) &&
|
|
59
|
+
this.endPoint.compareTo(other.endPoint) &&
|
|
60
|
+
this.center.compareTo(other.center);
|
|
61
|
+
}
|
|
62
|
+
getType() {
|
|
63
|
+
return 'arc';
|
|
64
|
+
}
|
|
65
|
+
getUniqueType() {
|
|
66
|
+
return 'arc-three-points';
|
|
67
|
+
}
|
|
68
|
+
serialize() {
|
|
69
|
+
return {
|
|
70
|
+
startPoint: this.startPoint.serialize(),
|
|
71
|
+
endPoint: this.endPoint.serialize(),
|
|
72
|
+
center: this.center.serialize()
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
}
|
|
@@ -1,6 +1,22 @@
|
|
|
1
1
|
import { ISceneObject } from "../../../core/interfaces.js";
|
|
2
2
|
import { QualifiedSceneObject } from "./qualified-geometry.js";
|
|
3
|
+
/**
|
|
4
|
+
* Qualifies a geometry as being on the outside of the constraining object.
|
|
5
|
+
* @param sceneObject - The geometry to qualify.
|
|
6
|
+
*/
|
|
3
7
|
export declare function outside(sceneObject: ISceneObject): QualifiedSceneObject;
|
|
8
|
+
/**
|
|
9
|
+
* Qualifies a geometry as being enclosed by the constraining object.
|
|
10
|
+
* @param sceneObject - The geometry to qualify.
|
|
11
|
+
*/
|
|
4
12
|
export declare function enclosed(sceneObject: ISceneObject): QualifiedSceneObject;
|
|
13
|
+
/**
|
|
14
|
+
* Qualifies a geometry as enclosing the constraining object.
|
|
15
|
+
* @param sceneObject - The geometry to qualify.
|
|
16
|
+
*/
|
|
5
17
|
export declare function enclosing(sceneObject: ISceneObject): QualifiedSceneObject;
|
|
18
|
+
/**
|
|
19
|
+
* Removes any existing constraint qualification from a geometry.
|
|
20
|
+
* @param sceneObject - The geometry to unqualify.
|
|
21
|
+
*/
|
|
6
22
|
export declare function unqualified(sceneObject: ISceneObject): QualifiedSceneObject;
|
|
@@ -1,13 +1,29 @@
|
|
|
1
1
|
import { QualifiedSceneObject } from "./qualified-geometry.js";
|
|
2
|
+
/**
|
|
3
|
+
* Qualifies a geometry as being on the outside of the constraining object.
|
|
4
|
+
* @param sceneObject - The geometry to qualify.
|
|
5
|
+
*/
|
|
2
6
|
export function outside(sceneObject) {
|
|
3
7
|
return new QualifiedSceneObject(sceneObject, 'outside');
|
|
4
8
|
}
|
|
9
|
+
/**
|
|
10
|
+
* Qualifies a geometry as being enclosed by the constraining object.
|
|
11
|
+
* @param sceneObject - The geometry to qualify.
|
|
12
|
+
*/
|
|
5
13
|
export function enclosed(sceneObject) {
|
|
6
14
|
return new QualifiedSceneObject(sceneObject, 'enclosed');
|
|
7
15
|
}
|
|
16
|
+
/**
|
|
17
|
+
* Qualifies a geometry as enclosing the constraining object.
|
|
18
|
+
* @param sceneObject - The geometry to qualify.
|
|
19
|
+
*/
|
|
8
20
|
export function enclosing(sceneObject) {
|
|
9
21
|
return new QualifiedSceneObject(sceneObject, 'enclosing');
|
|
10
22
|
}
|
|
23
|
+
/**
|
|
24
|
+
* Removes any existing constraint qualification from a geometry.
|
|
25
|
+
* @param sceneObject - The geometry to unqualify.
|
|
26
|
+
*/
|
|
11
27
|
export function unqualified(sceneObject) {
|
|
12
28
|
return new QualifiedSceneObject(sceneObject, 'unqualified');
|
|
13
29
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { WireOps } from "../../oc/wire-ops.js";
|
|
2
2
|
import { Edge } from "../../common/edge.js";
|
|
3
|
+
import { Vertex } from "../../common/vertex.js";
|
|
3
4
|
import { Wire } from "../../common/wire.js";
|
|
4
5
|
import { ExtrudableGeometryBase } from "./extrudable-base.js";
|
|
5
6
|
export class Offset extends ExtrudableGeometryBase {
|
|
@@ -44,9 +45,11 @@ export class Offset extends ExtrudableGeometryBase {
|
|
|
44
45
|
edges: new Map(group.map(edge => [edge, sourceObjects.get(edge)]))
|
|
45
46
|
});
|
|
46
47
|
}
|
|
48
|
+
let lastOffsetWire = null;
|
|
47
49
|
for (const wireInfo of wires) {
|
|
48
50
|
const isOpen = !wireInfo.wire.isClosed();
|
|
49
51
|
const offsetWire = WireOps.offsetWire(wireInfo.wire, this.distance, isOpen);
|
|
52
|
+
lastOffsetWire = offsetWire;
|
|
50
53
|
const edges = offsetWire.getEdges();
|
|
51
54
|
for (const edge of edges) {
|
|
52
55
|
this.addShape(edge);
|
|
@@ -57,6 +60,13 @@ export class Offset extends ExtrudableGeometryBase {
|
|
|
57
60
|
}
|
|
58
61
|
}
|
|
59
62
|
}
|
|
63
|
+
if (lastOffsetWire) {
|
|
64
|
+
const plane = this.getPlane();
|
|
65
|
+
const localStart = plane.worldToLocal(lastOffsetWire.getFirstVertex().toPoint());
|
|
66
|
+
const localEnd = plane.worldToLocal(lastOffsetWire.getLastVertex().toPoint());
|
|
67
|
+
this.setState('start', Vertex.fromPoint2D(localStart));
|
|
68
|
+
this.setState('end', Vertex.fromPoint2D(localEnd));
|
|
69
|
+
}
|
|
60
70
|
}
|
|
61
71
|
getDependencies() {
|
|
62
72
|
const deps = [];
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Face } from "../../common/face.js";
|
|
2
2
|
import { ShapeOps } from "../../oc/shape-ops.js";
|
|
3
3
|
import { Edge } from "../../common/edge.js";
|
|
4
|
+
import { Vertex } from "../../common/vertex.js";
|
|
4
5
|
import { ProjectionOps } from "../../oc/intersection.js";
|
|
5
6
|
import { Wire } from "../../common/wire.js";
|
|
6
7
|
import { ExtrudableGeometryBase } from "./extrudable-base.js";
|
|
@@ -14,6 +15,7 @@ export class Projection extends ExtrudableGeometryBase {
|
|
|
14
15
|
const plane = this.targetPlane?.getPlane() || this.sketch.getPlane();
|
|
15
16
|
const shapes = this.sourceObjects.flatMap(obj => obj.getShapes());
|
|
16
17
|
const transform = context?.getTransform() ?? null;
|
|
18
|
+
let lastWire = null;
|
|
17
19
|
console.log('Projection: building with shapes:', shapes.length);
|
|
18
20
|
for (let shape of shapes) {
|
|
19
21
|
if (transform) {
|
|
@@ -31,9 +33,16 @@ export class Projection extends ExtrudableGeometryBase {
|
|
|
31
33
|
wires = ProjectionOps.projectEdgeOntoPlane(plane, shape);
|
|
32
34
|
}
|
|
33
35
|
for (const wire of wires) {
|
|
36
|
+
lastWire = wire;
|
|
34
37
|
this.addShapes(wire.getEdges());
|
|
35
38
|
}
|
|
36
39
|
}
|
|
40
|
+
if (lastWire) {
|
|
41
|
+
const localStart = plane.worldToLocal(lastWire.getFirstVertex().toPoint());
|
|
42
|
+
const localEnd = plane.worldToLocal(lastWire.getLastVertex().toPoint());
|
|
43
|
+
this.setState('start', Vertex.fromPoint2D(localStart));
|
|
44
|
+
this.setState('end', Vertex.fromPoint2D(localEnd));
|
|
45
|
+
}
|
|
37
46
|
for (const obj of this.sourceObjects) {
|
|
38
47
|
obj.removeShapes(this);
|
|
39
48
|
}
|
|
@@ -77,41 +77,44 @@ export class Rect extends ExtrudableGeometryBase {
|
|
|
77
77
|
const [bottomLeftRadius, bottomRightRadius, topRightRadius, topLeftRadius] = radius;
|
|
78
78
|
const bottomLeft = start;
|
|
79
79
|
const topRight = new Point2D(bottomLeft.x + this.width, bottomLeft.y + this.height);
|
|
80
|
-
const
|
|
81
|
-
const
|
|
82
|
-
const
|
|
83
|
-
const
|
|
84
|
-
const
|
|
85
|
-
const
|
|
86
|
-
const
|
|
87
|
-
const
|
|
88
|
-
const
|
|
89
|
-
const
|
|
90
|
-
const
|
|
91
|
-
const
|
|
80
|
+
const signW = Math.sign(this.width);
|
|
81
|
+
const signH = Math.sign(this.height);
|
|
82
|
+
const bottomLeftArcCenter = new Point2D(bottomLeft.x + bottomLeftRadius * signW, bottomLeft.y + bottomLeftRadius * signH);
|
|
83
|
+
const bottomRightArcCenter = new Point2D(topRight.x - bottomRightRadius * signW, bottomLeft.y + bottomRightRadius * signH);
|
|
84
|
+
const topRightArcCenter = new Point2D(topRight.x - topRightRadius * signW, topRight.y - topRightRadius * signH);
|
|
85
|
+
const topLeftArcCenter = new Point2D(bottomLeft.x + topLeftRadius * signW, topRight.y - topLeftRadius * signH);
|
|
86
|
+
const bottomLineStart = new Point2D(bottomLeft.x + bottomLeftRadius * signW, bottomLeft.y);
|
|
87
|
+
const bottomLineEnd = new Point2D(topRight.x - bottomRightRadius * signW, bottomLeft.y);
|
|
88
|
+
const rightLineStart = new Point2D(topRight.x, bottomLeft.y + bottomRightRadius * signH);
|
|
89
|
+
const rightLineEnd = new Point2D(topRight.x, topRight.y - topRightRadius * signH);
|
|
90
|
+
const topLineStart = new Point2D(topRight.x - topRightRadius * signW, topRight.y);
|
|
91
|
+
const topLineEnd = new Point2D(bottomLeft.x + topLeftRadius * signW, topRight.y);
|
|
92
|
+
const leftLineStart = new Point2D(bottomLeft.x, topRight.y - topLeftRadius * signH);
|
|
93
|
+
const leftLineEnd = new Point2D(bottomLeft.x, bottomLeft.y + bottomLeftRadius * signH);
|
|
92
94
|
const localToWorld = plane.localToWorld.bind(plane);
|
|
95
|
+
const arcNormal = signW * signH < 0 ? plane.normal.negate() : plane.normal;
|
|
93
96
|
const bottomLineSegment = Geometry.makeSegment(localToWorld(bottomLineStart), localToWorld(bottomLineEnd));
|
|
94
97
|
const rightLineSegment = Geometry.makeSegment(localToWorld(rightLineStart), localToWorld(rightLineEnd));
|
|
95
98
|
const topLineSegment = Geometry.makeSegment(localToWorld(topLineStart), localToWorld(topLineEnd));
|
|
96
99
|
const leftLineSegment = Geometry.makeSegment(localToWorld(leftLineStart), localToWorld(leftLineEnd));
|
|
97
100
|
let bottomRightArcEdge = null;
|
|
98
101
|
if (bottomRightRadius > 0) {
|
|
99
|
-
const arc = Geometry.makeArc(localToWorld(bottomRightArcCenter), bottomRightRadius,
|
|
102
|
+
const arc = Geometry.makeArc(localToWorld(bottomRightArcCenter), bottomRightRadius, arcNormal, localToWorld(bottomLineEnd), localToWorld(rightLineStart));
|
|
100
103
|
bottomRightArcEdge = Geometry.makeEdgeFromCurve(arc);
|
|
101
104
|
}
|
|
102
105
|
let topRightArcEdge = null;
|
|
103
106
|
if (topRightRadius > 0) {
|
|
104
|
-
const arc = Geometry.makeArc(localToWorld(topRightArcCenter), topRightRadius,
|
|
107
|
+
const arc = Geometry.makeArc(localToWorld(topRightArcCenter), topRightRadius, arcNormal, localToWorld(rightLineEnd), localToWorld(topLineStart));
|
|
105
108
|
topRightArcEdge = Geometry.makeEdgeFromCurve(arc);
|
|
106
109
|
}
|
|
107
110
|
let topLeftArcEdge = null;
|
|
108
111
|
if (topLeftRadius > 0) {
|
|
109
|
-
const arc = Geometry.makeArc(localToWorld(topLeftArcCenter), topLeftRadius,
|
|
112
|
+
const arc = Geometry.makeArc(localToWorld(topLeftArcCenter), topLeftRadius, arcNormal, localToWorld(topLineEnd), localToWorld(leftLineStart));
|
|
110
113
|
topLeftArcEdge = Geometry.makeEdgeFromCurve(arc);
|
|
111
114
|
}
|
|
112
115
|
let bottomLeftArcEdge = null;
|
|
113
116
|
if (bottomLeftRadius > 0) {
|
|
114
|
-
const arc = Geometry.makeArc(localToWorld(bottomLeftArcCenter), bottomLeftRadius,
|
|
117
|
+
const arc = Geometry.makeArc(localToWorld(bottomLeftArcCenter), bottomLeftRadius, arcNormal, localToWorld(leftLineEnd), localToWorld(bottomLineStart));
|
|
115
118
|
bottomLeftArcEdge = Geometry.makeEdgeFromCurve(arc);
|
|
116
119
|
}
|
|
117
120
|
const bottomEdge = Geometry.makeEdge(bottomLineSegment);
|
|
@@ -3,16 +3,16 @@ export declare class Chamfer extends SceneObject {
|
|
|
3
3
|
private distance;
|
|
4
4
|
private distance2;
|
|
5
5
|
private isAngle;
|
|
6
|
-
private
|
|
7
|
-
constructor(distance: number, distance2: number, isAngle?: boolean,
|
|
8
|
-
get
|
|
6
|
+
private _selections;
|
|
7
|
+
constructor(distance: number, distance2: number, isAngle?: boolean, ...selections: SceneObject[]);
|
|
8
|
+
get selections(): SceneObject[];
|
|
9
9
|
build(context: BuildSceneObjectContext): void;
|
|
10
10
|
getDependencies(): SceneObject[];
|
|
11
11
|
createCopy(remap: Map<SceneObject, SceneObject>): SceneObject;
|
|
12
12
|
compareTo(other: SceneObject): boolean;
|
|
13
13
|
getType(): string;
|
|
14
14
|
serialize(): {
|
|
15
|
-
edges: any;
|
|
15
|
+
edges: any[];
|
|
16
16
|
distance: number;
|
|
17
17
|
distance2: number;
|
|
18
18
|
isAngle: boolean;
|
|
@@ -6,16 +6,16 @@ export class Chamfer extends SceneObject {
|
|
|
6
6
|
distance;
|
|
7
7
|
distance2;
|
|
8
8
|
isAngle;
|
|
9
|
-
|
|
10
|
-
constructor(distance, distance2, isAngle = false,
|
|
9
|
+
_selections = [];
|
|
10
|
+
constructor(distance, distance2, isAngle = false, ...selections) {
|
|
11
11
|
super();
|
|
12
12
|
this.distance = distance;
|
|
13
13
|
this.distance2 = distance2;
|
|
14
14
|
this.isAngle = isAngle;
|
|
15
|
-
this.
|
|
15
|
+
this._selections = selections;
|
|
16
16
|
}
|
|
17
|
-
get
|
|
18
|
-
return this.
|
|
17
|
+
get selections() {
|
|
18
|
+
return this._selections;
|
|
19
19
|
}
|
|
20
20
|
build(context) {
|
|
21
21
|
let sceneObjects;
|
|
@@ -26,8 +26,18 @@ export class Chamfer extends SceneObject {
|
|
|
26
26
|
sceneObjects.set(obj, shapes);
|
|
27
27
|
}
|
|
28
28
|
}
|
|
29
|
-
|
|
30
|
-
|
|
29
|
+
let edges = [];
|
|
30
|
+
for (const selection of this.selections) {
|
|
31
|
+
const allEdgeShapes = selection.getShapes();
|
|
32
|
+
for (const shape of allEdgeShapes) {
|
|
33
|
+
if (shape.isEdge()) {
|
|
34
|
+
edges.push(shape);
|
|
35
|
+
}
|
|
36
|
+
else {
|
|
37
|
+
edges.push(...Explorer.findEdgesWrapped(shape));
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
31
41
|
const newShapes = [];
|
|
32
42
|
const shapeObjectMap = new Map();
|
|
33
43
|
for (const [obj, shapes] of sceneObjects) {
|
|
@@ -82,17 +92,20 @@ export class Chamfer extends SceneObject {
|
|
|
82
92
|
continue;
|
|
83
93
|
}
|
|
84
94
|
}
|
|
85
|
-
this.
|
|
95
|
+
for (const selection of this.selections) {
|
|
96
|
+
const shapes = selection.getShapes();
|
|
97
|
+
for (const shape of shapes) {
|
|
98
|
+
selection.removeShape(shape, this);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
86
101
|
this.addShapes(newShapes);
|
|
87
102
|
}
|
|
88
103
|
getDependencies() {
|
|
89
|
-
return
|
|
104
|
+
return [...this.selections];
|
|
90
105
|
}
|
|
91
106
|
createCopy(remap) {
|
|
92
|
-
const
|
|
93
|
-
|
|
94
|
-
: undefined;
|
|
95
|
-
return new Chamfer(this.distance, this.distance2, this.isAngle, selection);
|
|
107
|
+
const selections = this.selections.map(s => remap.get(s) || s);
|
|
108
|
+
return new Chamfer(this.distance, this.distance2, this.isAngle, ...selections);
|
|
96
109
|
}
|
|
97
110
|
compareTo(other) {
|
|
98
111
|
if (!(other instanceof Chamfer)) {
|
|
@@ -110,9 +123,14 @@ export class Chamfer extends SceneObject {
|
|
|
110
123
|
if (this.isAngle !== other.isAngle) {
|
|
111
124
|
return false;
|
|
112
125
|
}
|
|
113
|
-
if (
|
|
126
|
+
if (this.selections.length !== other.selections.length) {
|
|
114
127
|
return false;
|
|
115
128
|
}
|
|
129
|
+
for (let i = 0; i < this.selections.length; i++) {
|
|
130
|
+
if (!this.selections[i].compareTo(other.selections[i])) {
|
|
131
|
+
return false;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
116
134
|
return true;
|
|
117
135
|
}
|
|
118
136
|
getType() {
|
|
@@ -120,7 +138,7 @@ export class Chamfer extends SceneObject {
|
|
|
120
138
|
}
|
|
121
139
|
serialize() {
|
|
122
140
|
return {
|
|
123
|
-
edges: this.
|
|
141
|
+
edges: this.selections.map(s => s.serialize()),
|
|
124
142
|
distance: this.distance,
|
|
125
143
|
distance2: this.distance2,
|
|
126
144
|
isAngle: this.isAngle
|
|
@@ -2,8 +2,7 @@ import { Wire } from "../common/wire.js";
|
|
|
2
2
|
import { Edge } from "../common/edge.js";
|
|
3
3
|
import { GeometrySceneObject } from "./2d/geometry.js";
|
|
4
4
|
import { BooleanOps } from "../oc/boolean-ops.js";
|
|
5
|
-
import {
|
|
6
|
-
import { WireOps } from "../oc/wire-ops.js";
|
|
5
|
+
import { FaceMaker2 } from "../oc/face-maker2.js";
|
|
7
6
|
export class Common2D extends GeometrySceneObject {
|
|
8
7
|
_targetObjects = null;
|
|
9
8
|
_keepOriginal = false;
|
|
@@ -38,20 +37,39 @@ export class Common2D extends GeometrySceneObject {
|
|
|
38
37
|
}
|
|
39
38
|
}
|
|
40
39
|
}
|
|
41
|
-
const
|
|
42
|
-
|
|
43
|
-
const
|
|
40
|
+
const plane = this.sketch.getPlane();
|
|
41
|
+
// Group edges by owner
|
|
42
|
+
const ownerToEdges = new Map();
|
|
43
|
+
for (const [edge, owner] of sourceEdges) {
|
|
44
|
+
if (!ownerToEdges.has(owner)) {
|
|
45
|
+
ownerToEdges.set(owner, []);
|
|
46
|
+
}
|
|
47
|
+
ownerToEdges.get(owner).push(edge);
|
|
48
|
+
}
|
|
49
|
+
// Convert each owner's edges to faces via FaceMaker2
|
|
50
|
+
const faces = [];
|
|
51
|
+
const processedOwners = new Set();
|
|
52
|
+
for (const [owner, edges] of ownerToEdges) {
|
|
53
|
+
const ownerFaces = FaceMaker2.getRegions(edges, plane);
|
|
54
|
+
if (ownerFaces.length > 0) {
|
|
55
|
+
faces.push(...ownerFaces);
|
|
56
|
+
processedOwners.add(owner);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
if (faces.length === 0) {
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
44
62
|
const { newShapes } = BooleanOps.common(faces);
|
|
45
63
|
if (newShapes.length === 0) {
|
|
46
64
|
return;
|
|
47
65
|
}
|
|
48
66
|
const newEdges = newShapes.flatMap((face) => face.getEdges());
|
|
49
67
|
if (!this._keepOriginal) {
|
|
50
|
-
for (const [
|
|
51
|
-
if (!
|
|
68
|
+
for (const [edge, owner] of sourceEdges) {
|
|
69
|
+
if (!processedOwners.has(owner)) {
|
|
52
70
|
continue;
|
|
53
71
|
}
|
|
54
|
-
owner.removeShape(
|
|
72
|
+
owner.removeShape(edge, this);
|
|
55
73
|
}
|
|
56
74
|
}
|
|
57
75
|
this.addShapes(newEdges);
|
|
@@ -2,8 +2,7 @@ import { Wire } from "../common/wire.js";
|
|
|
2
2
|
import { Edge } from "../common/edge.js";
|
|
3
3
|
import { GeometrySceneObject } from "./2d/geometry.js";
|
|
4
4
|
import { BooleanOps } from "../oc/boolean-ops.js";
|
|
5
|
-
import {
|
|
6
|
-
import { FaceOps } from "../oc/face-ops.js";
|
|
5
|
+
import { FaceMaker2 } from "../oc/face-maker2.js";
|
|
7
6
|
export class Fuse2D extends GeometrySceneObject {
|
|
8
7
|
_targetObjects = null;
|
|
9
8
|
constructor(...targets) {
|
|
@@ -33,16 +32,35 @@ export class Fuse2D extends GeometrySceneObject {
|
|
|
33
32
|
}
|
|
34
33
|
}
|
|
35
34
|
}
|
|
36
|
-
const
|
|
37
|
-
|
|
38
|
-
const
|
|
35
|
+
const plane = this.sketch.getPlane();
|
|
36
|
+
// Group edges by owner
|
|
37
|
+
const ownerToEdges = new Map();
|
|
38
|
+
for (const [edge, owner] of sourceEdges) {
|
|
39
|
+
if (!ownerToEdges.has(owner)) {
|
|
40
|
+
ownerToEdges.set(owner, []);
|
|
41
|
+
}
|
|
42
|
+
ownerToEdges.get(owner).push(edge);
|
|
43
|
+
}
|
|
44
|
+
// Convert each owner's edges to faces via FaceMaker2
|
|
45
|
+
const faces = [];
|
|
46
|
+
const processedOwners = new Set();
|
|
47
|
+
for (const [owner, edges] of ownerToEdges) {
|
|
48
|
+
const ownerFaces = FaceMaker2.getRegions(edges, plane);
|
|
49
|
+
if (ownerFaces.length > 0) {
|
|
50
|
+
faces.push(...ownerFaces);
|
|
51
|
+
processedOwners.add(owner);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
if (faces.length === 0) {
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
39
57
|
const { newShapes } = BooleanOps.fuseFaces(faces);
|
|
40
58
|
if (newShapes.length === 0) {
|
|
41
59
|
return;
|
|
42
60
|
}
|
|
43
61
|
const newEdges = newShapes.flatMap((face) => face.getEdges());
|
|
44
62
|
for (const [edge, owner] of sourceEdges) {
|
|
45
|
-
if (!
|
|
63
|
+
if (!processedOwners.has(owner)) {
|
|
46
64
|
continue;
|
|
47
65
|
}
|
|
48
66
|
owner.removeShape(edge, this);
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { BuildSceneObjectContext, SceneObject } from "../common/scene-object.js";
|
|
2
|
+
import { Matrix4 } from "../math/matrix4.js";
|
|
3
|
+
export declare class RepeatMatrix extends SceneObject {
|
|
4
|
+
private _matrix;
|
|
5
|
+
targetObjects: SceneObject[];
|
|
6
|
+
constructor(_matrix: Matrix4, targetObjects: SceneObject[]);
|
|
7
|
+
getTransformMatrix(): Matrix4 | null;
|
|
8
|
+
isContainer(): boolean;
|
|
9
|
+
build(context: BuildSceneObjectContext): void;
|
|
10
|
+
compareTo(other: RepeatMatrix): boolean;
|
|
11
|
+
getType(): string;
|
|
12
|
+
getUniqueType(): string;
|
|
13
|
+
serialize(): {};
|
|
14
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { SceneObject } from "../common/scene-object.js";
|
|
2
|
+
export class RepeatMatrix extends SceneObject {
|
|
3
|
+
_matrix;
|
|
4
|
+
targetObjects;
|
|
5
|
+
constructor(_matrix, targetObjects) {
|
|
6
|
+
super();
|
|
7
|
+
this._matrix = _matrix;
|
|
8
|
+
this.targetObjects = targetObjects;
|
|
9
|
+
this.setAlwaysVisible();
|
|
10
|
+
}
|
|
11
|
+
getTransformMatrix() {
|
|
12
|
+
return this._matrix;
|
|
13
|
+
}
|
|
14
|
+
isContainer() {
|
|
15
|
+
return true;
|
|
16
|
+
}
|
|
17
|
+
build(context) {
|
|
18
|
+
this.saveShapesSnapshot(context);
|
|
19
|
+
}
|
|
20
|
+
compareTo(other) {
|
|
21
|
+
if (!(other instanceof RepeatMatrix)) {
|
|
22
|
+
return false;
|
|
23
|
+
}
|
|
24
|
+
if (!super.compareTo(other)) {
|
|
25
|
+
return false;
|
|
26
|
+
}
|
|
27
|
+
if (!this._matrix.equals(other._matrix)) {
|
|
28
|
+
return false;
|
|
29
|
+
}
|
|
30
|
+
return true;
|
|
31
|
+
}
|
|
32
|
+
getType() {
|
|
33
|
+
return "repeat-matrix";
|
|
34
|
+
}
|
|
35
|
+
getUniqueType() {
|
|
36
|
+
return "repeat-matrix";
|
|
37
|
+
}
|
|
38
|
+
serialize() {
|
|
39
|
+
return {};
|
|
40
|
+
}
|
|
41
|
+
}
|
|
@@ -15,6 +15,7 @@ export declare class SelectSceneObject extends SceneObject implements ISelect {
|
|
|
15
15
|
getDependencies(): SceneObject[];
|
|
16
16
|
createCopy(remap: Map<SceneObject, SceneObject>): SceneObject;
|
|
17
17
|
transform(matrix: Matrix4): SelectSceneObject;
|
|
18
|
+
private injectScopeFaces;
|
|
18
19
|
applyFilters(shapes: Shape[], filters: FilterBuilderBase<Shape>[]): Shape[];
|
|
19
20
|
compareTo(other: SelectSceneObject): boolean;
|
|
20
21
|
shapeType(): string;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { FaceFilterBuilder } from "../filters/face/face-filter.js";
|
|
2
2
|
import { ShapeFilter } from "../filters/filter.js";
|
|
3
3
|
import { SceneObject } from "../common/scene-object.js";
|
|
4
|
+
import { BelongsToFaceFilter, NotBelongsToFaceFilter } from "../filters/edge/belongs-to-face.js";
|
|
4
5
|
export class SelectSceneObject extends SceneObject {
|
|
5
6
|
filters;
|
|
6
7
|
constraintObject;
|
|
@@ -32,6 +33,9 @@ export class SelectSceneObject extends SceneObject {
|
|
|
32
33
|
}
|
|
33
34
|
}
|
|
34
35
|
const allShapes = this.constraintObject ? this.constraintObject.getShapes() : this.getAllShapes(sceneObjects, excludedObjects);
|
|
36
|
+
if (this.type === "edge") {
|
|
37
|
+
this.injectScopeFaces(filters, sceneObjects);
|
|
38
|
+
}
|
|
35
39
|
const filteredShapes = this.applyFilters(allShapes, filters);
|
|
36
40
|
console.log(`SelectSceneObject: shapes after filtering: ${filteredShapes[0]}`);
|
|
37
41
|
this.addShapes(filteredShapes);
|
|
@@ -64,6 +68,21 @@ export class SelectSceneObject extends SceneObject {
|
|
|
64
68
|
console.log('SelectSceneObject: transform applied to selection filters.', mirroredFilters);
|
|
65
69
|
return new SelectSceneObject(mirroredFilters, this.constraintObject);
|
|
66
70
|
}
|
|
71
|
+
injectScopeFaces(filters, sceneObjects) {
|
|
72
|
+
let scopeFaces = null;
|
|
73
|
+
for (const builder of filters) {
|
|
74
|
+
for (const filter of builder.getFilters()) {
|
|
75
|
+
if (filter instanceof BelongsToFaceFilter || filter instanceof NotBelongsToFaceFilter) {
|
|
76
|
+
if (!scopeFaces) {
|
|
77
|
+
scopeFaces = this.constraintObject
|
|
78
|
+
? this.constraintObject.getShapes().flatMap(s => s.getSubShapes("face"))
|
|
79
|
+
: sceneObjects.flatMap(obj => obj.getShapes({}, 'solid').flatMap(s => s.getSubShapes("face")));
|
|
80
|
+
}
|
|
81
|
+
filter.setScopeFaces(scopeFaces);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
67
86
|
applyFilters(shapes, filters) {
|
|
68
87
|
const shapeFilter = new ShapeFilter(shapes, ...filters);
|
|
69
88
|
return shapeFilter.apply();
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { BuildSceneObjectContext, SceneObject } from "../common/scene-object.js";
|
|
2
|
+
import { GeometrySceneObject } from "./2d/geometry.js";
|
|
3
|
+
export declare class Subtract2D extends GeometrySceneObject {
|
|
4
|
+
target1: GeometrySceneObject;
|
|
5
|
+
target2: GeometrySceneObject;
|
|
6
|
+
constructor(target1: GeometrySceneObject, target2: GeometrySceneObject);
|
|
7
|
+
private collectEdges;
|
|
8
|
+
build(context: BuildSceneObjectContext): void;
|
|
9
|
+
getDependencies(): SceneObject[];
|
|
10
|
+
createCopy(remap: Map<SceneObject, SceneObject>): SceneObject;
|
|
11
|
+
compareTo(other: Subtract2D): boolean;
|
|
12
|
+
getType(): string;
|
|
13
|
+
serialize(): {};
|
|
14
|
+
}
|