fluidcad 0.0.30 → 0.0.32
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/build-error.d.ts +13 -0
- package/lib/dist/common/build-error.js +18 -0
- package/lib/dist/common/describe-error.d.ts +6 -0
- package/lib/dist/common/describe-error.js +26 -0
- package/lib/dist/common/operand-check.d.ts +19 -0
- package/lib/dist/common/operand-check.js +38 -0
- package/lib/dist/common/scene-object.d.ts +8 -0
- package/lib/dist/common/scene-object.js +10 -0
- package/lib/dist/common/shape-factory.d.ts +1 -1
- package/lib/dist/core/2d/arc.d.ts +4 -2
- package/lib/dist/core/2d/hmove.d.ts +8 -1
- package/lib/dist/core/2d/hmove.js +6 -2
- package/lib/dist/core/2d/pmove.d.ts +13 -3
- package/lib/dist/core/2d/pmove.js +6 -2
- package/lib/dist/core/2d/vmove.d.ts +8 -1
- package/lib/dist/core/2d/vmove.js +8 -4
- package/lib/dist/core/extrude.d.ts +17 -4
- package/lib/dist/core/extrude.js +8 -6
- package/lib/dist/core/interfaces.d.ts +16 -6
- package/lib/dist/core/mirror.d.ts +5 -5
- package/lib/dist/features/2d/aline.js +6 -2
- package/lib/dist/features/2d/arc.d.ts +3 -0
- package/lib/dist/features/2d/arc.js +28 -1
- package/lib/dist/features/2d/hline.js +5 -1
- package/lib/dist/features/2d/hmove.d.ts +2 -2
- package/lib/dist/features/2d/hmove.js +32 -7
- package/lib/dist/features/2d/intersect.js +17 -10
- package/lib/dist/features/2d/line.d.ts +2 -0
- package/lib/dist/features/2d/line.js +4 -0
- package/lib/dist/features/2d/pmove.d.ts +2 -2
- package/lib/dist/features/2d/pmove.js +47 -7
- package/lib/dist/features/2d/projection.d.ts +1 -1
- package/lib/dist/features/2d/projection.js +25 -15
- package/lib/dist/features/2d/sketch.d.ts +2 -2
- package/lib/dist/features/2d/sketch.js +10 -4
- package/lib/dist/features/2d/tarc-to-point.js +0 -3
- package/lib/dist/features/2d/tarc.js +0 -3
- package/lib/dist/features/2d/tline.js +0 -3
- package/lib/dist/features/2d/vline.js +5 -1
- package/lib/dist/features/2d/vmove.d.ts +2 -2
- package/lib/dist/features/2d/vmove.js +32 -7
- package/lib/dist/features/axis-from-edge.d.ts +1 -0
- package/lib/dist/features/axis-from-edge.js +8 -0
- package/lib/dist/features/chamfer.d.ts +1 -0
- package/lib/dist/features/chamfer.js +6 -0
- package/lib/dist/features/color.d.ts +1 -0
- package/lib/dist/features/color.js +6 -0
- package/lib/dist/features/common.d.ts +1 -0
- package/lib/dist/features/common.js +9 -0
- package/lib/dist/features/common2d.d.ts +1 -0
- package/lib/dist/features/common2d.js +9 -0
- package/lib/dist/features/draft.d.ts +1 -0
- package/lib/dist/features/draft.js +6 -0
- package/lib/dist/features/extrude-to-face.d.ts +5 -1
- package/lib/dist/features/extrude-to-face.js +50 -8
- package/lib/dist/features/extrude.js +19 -28
- package/lib/dist/features/fillet.d.ts +1 -0
- package/lib/dist/features/fillet.js +6 -0
- package/lib/dist/features/fillet2d.d.ts +1 -0
- package/lib/dist/features/fillet2d.js +9 -0
- package/lib/dist/features/fuse.d.ts +1 -0
- package/lib/dist/features/fuse.js +6 -0
- package/lib/dist/features/fuse2d.d.ts +1 -0
- package/lib/dist/features/fuse2d.js +9 -0
- package/lib/dist/features/loft.d.ts +1 -0
- package/lib/dist/features/loft.js +6 -0
- package/lib/dist/features/mirror-shape.d.ts +1 -0
- package/lib/dist/features/mirror-shape.js +28 -8
- package/lib/dist/features/plane-from-object.d.ts +1 -0
- package/lib/dist/features/plane-from-object.js +8 -0
- package/lib/dist/features/rotate.d.ts +1 -0
- package/lib/dist/features/rotate.js +11 -2
- package/lib/dist/features/select.d.ts +1 -0
- package/lib/dist/features/select.js +40 -12
- package/lib/dist/features/shell.d.ts +1 -0
- package/lib/dist/features/shell.js +6 -0
- package/lib/dist/features/simple-extruder.js +6 -3
- package/lib/dist/features/subtract.d.ts +1 -0
- package/lib/dist/features/subtract.js +5 -0
- package/lib/dist/features/subtract2d.d.ts +1 -0
- package/lib/dist/features/subtract2d.js +5 -0
- package/lib/dist/features/sweep.d.ts +1 -0
- package/lib/dist/features/sweep.js +4 -0
- package/lib/dist/features/translate.d.ts +1 -0
- package/lib/dist/features/translate.js +9 -0
- package/lib/dist/filters/face/above-below.d.ts +20 -0
- package/lib/dist/filters/face/above-below.js +57 -0
- package/lib/dist/filters/face/face-filter.d.ts +26 -0
- package/lib/dist/filters/face/face-filter.js +64 -0
- package/lib/dist/filters/face/planar-filter.d.ts +15 -0
- package/lib/dist/filters/face/planar-filter.js +30 -0
- package/lib/dist/filters/from-object.d.ts +1 -0
- package/lib/dist/filters/from-object.js +3 -0
- package/lib/dist/oc/boolean-ops.d.ts +2 -2
- package/lib/dist/oc/boolean-ops.js +8 -3
- package/lib/dist/oc/edge-ops.d.ts +17 -0
- package/lib/dist/oc/edge-ops.js +60 -0
- package/lib/dist/oc/face-maker2.d.ts +8 -0
- package/lib/dist/oc/face-maker2.js +42 -1
- package/lib/dist/oc/face-ops.d.ts +6 -1
- package/lib/dist/oc/face-ops.js +3 -2
- package/lib/dist/oc/face-query.js +19 -15
- package/lib/dist/oc/ray-intersect.d.ts +3 -2
- package/lib/dist/oc/ray-intersect.js +2 -4
- package/lib/dist/oc/shell-ops.js +15 -2
- package/lib/dist/oc/thin-face-maker.d.ts +15 -0
- package/lib/dist/oc/thin-face-maker.js +48 -7
- package/lib/dist/oc/wire-ops.d.ts +14 -0
- package/lib/dist/oc/wire-ops.js +38 -0
- package/lib/dist/rendering/render.js +6 -4
- package/lib/dist/tests/common/describe-error.test.d.ts +1 -0
- package/lib/dist/tests/common/describe-error.test.js +36 -0
- package/lib/dist/tests/features/2d/intersect.test.js +43 -0
- package/lib/dist/tests/features/2d/move.test.js +72 -1
- package/lib/dist/tests/features/2d/project-regression.test.js +35 -0
- package/lib/dist/tests/features/color-lineage.test.js +24 -0
- package/lib/dist/tests/features/cut.test.js +40 -0
- package/lib/dist/tests/features/cylinder-curve-filter.test.d.ts +1 -0
- package/lib/dist/tests/features/cylinder-curve-filter.test.js +99 -0
- package/lib/dist/tests/features/extrude-to-face.test.js +52 -0
- package/lib/dist/tests/features/extrude.test.js +46 -8
- package/lib/dist/tests/features/mirror.test.js +74 -0
- package/lib/dist/tests/features/select.test.js +141 -0
- package/lib/dist/tests/features/subtract-consumed-input.test.d.ts +1 -0
- package/lib/dist/tests/features/subtract-consumed-input.test.js +28 -0
- package/lib/dist/tests/features/thin-extrude-offset-fix.test.d.ts +1 -0
- package/lib/dist/tests/features/thin-extrude-offset-fix.test.js +34 -0
- package/lib/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +2 -3
- package/ui/dist/assets/{index-6Ep4GPxf.js → index-DMw0OYCF.js} +70 -70
- package/ui/dist/assets/index-DR7c2Qk9.css +2 -0
- package/ui/dist/index.html +2 -2
- package/lib/dist/features/infinite-extrude.d.ts +0 -13
- package/lib/dist/features/infinite-extrude.js +0 -79
- package/ui/dist/assets/index-DRKfe6N9.css +0 -2
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Vertex } from "../../common/vertex.js";
|
|
2
2
|
import { SectionOps } from "../../oc/section-ops.js";
|
|
3
|
+
import { WireOps } from "../../oc/wire-ops.js";
|
|
3
4
|
import { ExtrudableGeometryBase } from "./extrudable-base.js";
|
|
4
5
|
export class Intersect extends ExtrudableGeometryBase {
|
|
5
6
|
sourceObjects;
|
|
@@ -11,19 +12,25 @@ export class Intersect extends ExtrudableGeometryBase {
|
|
|
11
12
|
const plane = this.targetPlane?.getPlane() || this.sketch.getPlane();
|
|
12
13
|
const shapes = this.sourceObjects.flatMap(obj => obj.getShapes());
|
|
13
14
|
const transform = context?.getTransform() ?? null;
|
|
14
|
-
|
|
15
|
-
for (
|
|
15
|
+
const allEdges = [];
|
|
16
|
+
for (const shape of shapes) {
|
|
16
17
|
const edges = SectionOps.sectionShapeWithPlane(plane, shape);
|
|
17
|
-
|
|
18
|
-
lastEdge = edge;
|
|
19
|
-
}
|
|
18
|
+
allEdges.push(...edges);
|
|
20
19
|
this.addShapes(edges);
|
|
21
20
|
}
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
21
|
+
// Section across multiple source faces yields an unordered edge set that
|
|
22
|
+
// may form one connected chain, several disjoint chains, or closed loops.
|
|
23
|
+
// Take the first connected group and use its actual chain endpoints —
|
|
24
|
+
// not an arbitrary edge's vertices, which can land on interior junctions.
|
|
25
|
+
if (allEdges.length > 0) {
|
|
26
|
+
const groups = WireOps.groupConnectedEdges(allEdges);
|
|
27
|
+
const endpoints = WireOps.findChainEndpoints(groups[0]);
|
|
28
|
+
if (endpoints) {
|
|
29
|
+
const localStart = plane.worldToLocal(endpoints.start.toPoint());
|
|
30
|
+
const localEnd = plane.worldToLocal(endpoints.end.toPoint());
|
|
31
|
+
this.setState('start', Vertex.fromPoint2D(localStart));
|
|
32
|
+
this.setState('end', Vertex.fromPoint2D(localEnd));
|
|
33
|
+
}
|
|
27
34
|
}
|
|
28
35
|
for (const obj of this.sourceObjects) {
|
|
29
36
|
obj.removeShapes(this);
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { SceneObject } from "../../common/scene-object.js";
|
|
1
2
|
import { LazyVertex } from "../lazy-vertex.js";
|
|
2
3
|
import { PlaneObjectBase } from "../plane-renderable-base.js";
|
|
3
4
|
import { GeometrySceneObject } from "./geometry.js";
|
|
@@ -6,6 +7,7 @@ export declare class LineTo extends GeometrySceneObject {
|
|
|
6
7
|
private targetPlane;
|
|
7
8
|
constructor(endPoint: LazyVertex, targetPlane?: PlaneObjectBase);
|
|
8
9
|
build(): void;
|
|
10
|
+
createCopy(remap: Map<SceneObject, SceneObject>): SceneObject;
|
|
9
11
|
compareTo(other: LineTo): boolean;
|
|
10
12
|
getType(): string;
|
|
11
13
|
getUniqueType(): string;
|
|
@@ -30,6 +30,10 @@ export class LineTo extends GeometrySceneObject {
|
|
|
30
30
|
this.targetPlane.removeShapes(this);
|
|
31
31
|
}
|
|
32
32
|
}
|
|
33
|
+
createCopy(remap) {
|
|
34
|
+
const targetPlane = this.targetPlane ? (remap.get(this.targetPlane) || this.targetPlane) : null;
|
|
35
|
+
return new LineTo(this.endPoint, targetPlane);
|
|
36
|
+
}
|
|
33
37
|
compareTo(other) {
|
|
34
38
|
if (!(other instanceof LineTo)) {
|
|
35
39
|
return false;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { SceneObject } from "../../common/scene-object.js";
|
|
2
2
|
import { GeometrySceneObject } from "./geometry.js";
|
|
3
3
|
export declare class PolarMove extends GeometrySceneObject {
|
|
4
|
-
|
|
4
|
+
radiusOrTarget: number | SceneObject;
|
|
5
5
|
angle: number;
|
|
6
|
-
constructor(
|
|
6
|
+
constructor(radiusOrTarget: number | SceneObject, angle: number);
|
|
7
7
|
getType(): string;
|
|
8
8
|
build(): void;
|
|
9
9
|
getDependencies(): SceneObject[];
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import { Point2D } from "../../math/point.js";
|
|
2
|
+
import { SceneObject } from "../../common/scene-object.js";
|
|
2
3
|
import { GeometrySceneObject } from "./geometry.js";
|
|
4
|
+
import { findNearestRayIntersection } from "../../oc/ray-intersect.js";
|
|
3
5
|
export class PolarMove extends GeometrySceneObject {
|
|
4
|
-
|
|
6
|
+
radiusOrTarget;
|
|
5
7
|
angle;
|
|
6
|
-
constructor(
|
|
8
|
+
constructor(radiusOrTarget, angle) {
|
|
7
9
|
super();
|
|
8
|
-
this.
|
|
10
|
+
this.radiusOrTarget = radiusOrTarget;
|
|
9
11
|
this.angle = angle;
|
|
10
12
|
}
|
|
11
13
|
getType() {
|
|
@@ -13,14 +15,43 @@ export class PolarMove extends GeometrySceneObject {
|
|
|
13
15
|
}
|
|
14
16
|
build() {
|
|
15
17
|
const pos = this.getCurrentPosition();
|
|
16
|
-
const
|
|
18
|
+
const tangent = (this.sketch?.getTangentAt(this) ?? new Point2D(1, 0)).normalize();
|
|
19
|
+
const cos = Math.cos(this.angle);
|
|
20
|
+
const sin = Math.sin(this.angle);
|
|
21
|
+
const direction = new Point2D(cos * tangent.x - sin * tangent.y, sin * tangent.x + cos * tangent.y);
|
|
22
|
+
let newPos;
|
|
23
|
+
if (typeof this.radiusOrTarget === 'number') {
|
|
24
|
+
newPos = new Point2D(pos.x + this.radiusOrTarget * direction.x, pos.y + this.radiusOrTarget * direction.y);
|
|
25
|
+
}
|
|
26
|
+
else {
|
|
27
|
+
const plane = this.sketch.getPlane();
|
|
28
|
+
const hit = findNearestRayIntersection(plane, pos, direction, this.radiusOrTarget);
|
|
29
|
+
if (!hit) {
|
|
30
|
+
throw new Error("Cannot move at the specified angle up to the geometry");
|
|
31
|
+
}
|
|
32
|
+
newPos = hit;
|
|
33
|
+
}
|
|
17
34
|
this.setCurrentPosition(newPos);
|
|
35
|
+
const moveVec = newPos.subtract(pos);
|
|
36
|
+
const moveLen = Math.hypot(moveVec.x, moveVec.y);
|
|
37
|
+
if (moveLen > 1e-12) {
|
|
38
|
+
this.setTangent(new Point2D(moveVec.x / moveLen, moveVec.y / moveLen));
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
this.setTangent(direction);
|
|
42
|
+
}
|
|
18
43
|
}
|
|
19
44
|
getDependencies() {
|
|
45
|
+
if (this.radiusOrTarget instanceof SceneObject) {
|
|
46
|
+
return [this.radiusOrTarget];
|
|
47
|
+
}
|
|
20
48
|
return [];
|
|
21
49
|
}
|
|
22
50
|
createCopy(remap) {
|
|
23
|
-
|
|
51
|
+
const radiusOrTarget = this.radiusOrTarget instanceof SceneObject
|
|
52
|
+
? (remap.get(this.radiusOrTarget) || this.radiusOrTarget)
|
|
53
|
+
: this.radiusOrTarget;
|
|
54
|
+
return new PolarMove(radiusOrTarget, this.angle);
|
|
24
55
|
}
|
|
25
56
|
compareTo(other) {
|
|
26
57
|
if (!(other instanceof PolarMove)) {
|
|
@@ -29,11 +60,20 @@ export class PolarMove extends GeometrySceneObject {
|
|
|
29
60
|
if (!super.compareTo(other)) {
|
|
30
61
|
return false;
|
|
31
62
|
}
|
|
32
|
-
|
|
63
|
+
if (this.angle !== other.angle) {
|
|
64
|
+
return false;
|
|
65
|
+
}
|
|
66
|
+
if (typeof this.radiusOrTarget !== typeof other.radiusOrTarget) {
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
69
|
+
if (this.radiusOrTarget instanceof SceneObject && other.radiusOrTarget instanceof SceneObject) {
|
|
70
|
+
return this.radiusOrTarget.compareTo(other.radiusOrTarget);
|
|
71
|
+
}
|
|
72
|
+
return this.radiusOrTarget === other.radiusOrTarget;
|
|
33
73
|
}
|
|
34
74
|
serialize() {
|
|
35
75
|
return {
|
|
36
|
-
radius: this.
|
|
76
|
+
radius: typeof this.radiusOrTarget === 'number' ? this.radiusOrTarget : null,
|
|
37
77
|
angle: this.angle
|
|
38
78
|
};
|
|
39
79
|
}
|
|
@@ -4,7 +4,7 @@ import { ExtrudableGeometryBase } from "./extrudable-base.js";
|
|
|
4
4
|
export declare class Projection extends ExtrudableGeometryBase {
|
|
5
5
|
private sourceObjects;
|
|
6
6
|
constructor(sourceObjects: SceneObject[], targetPlane?: PlaneObjectBase);
|
|
7
|
-
build(
|
|
7
|
+
build(_context?: BuildSceneObjectContext): void;
|
|
8
8
|
getDependencies(): SceneObject[];
|
|
9
9
|
createCopy(remap: Map<SceneObject, SceneObject>): SceneObject;
|
|
10
10
|
compareTo(other: Projection): boolean;
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { Face } from "../../common/face.js";
|
|
2
2
|
import { Edge } from "../../common/edge.js";
|
|
3
3
|
import { Vertex } from "../../common/vertex.js";
|
|
4
|
+
import { EdgeOps } from "../../oc/edge-ops.js";
|
|
5
|
+
import { WireOps } from "../../oc/wire-ops.js";
|
|
4
6
|
import { ProjectionOps } from "../../oc/intersection.js";
|
|
5
7
|
import { Wire } from "../../common/wire.js";
|
|
6
8
|
import { ExtrudableGeometryBase } from "./extrudable-base.js";
|
|
@@ -10,16 +12,14 @@ export class Projection extends ExtrudableGeometryBase {
|
|
|
10
12
|
super(targetPlane);
|
|
11
13
|
this.sourceObjects = sourceObjects;
|
|
12
14
|
}
|
|
13
|
-
build(
|
|
15
|
+
build(_context) {
|
|
14
16
|
const plane = this.targetPlane?.getPlane() || this.sketch.getPlane();
|
|
15
17
|
const shapes = this.sourceObjects.flatMap(obj => obj.getShapes());
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
// shape = ShapeOps.transform(shape, transform);
|
|
22
|
-
// }
|
|
18
|
+
// Project every source first; collect all resulting wires before any dedup
|
|
19
|
+
// or scene-graph mutation. We need the full set up-front so the General Fuse
|
|
20
|
+
// in unifyCoincident can detect overlaps across sources, not just within one.
|
|
21
|
+
const allWires = [];
|
|
22
|
+
for (const shape of shapes) {
|
|
23
23
|
let wires = [];
|
|
24
24
|
if (shape instanceof Face) {
|
|
25
25
|
wires = ProjectionOps.projectFaceOntoPlane(plane, shape);
|
|
@@ -31,14 +31,24 @@ export class Projection extends ExtrudableGeometryBase {
|
|
|
31
31
|
else if (shape instanceof Edge) {
|
|
32
32
|
wires = ProjectionOps.projectEdgeOntoPlane(plane, shape);
|
|
33
33
|
}
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
34
|
+
allWires.push(...wires);
|
|
35
|
+
}
|
|
36
|
+
// Capture the sketch-cursor endpoints BEFORE dedup. unifyCoincident may
|
|
37
|
+
// split/drop edges and the wire structure is discarded anyway, but the
|
|
38
|
+
// chain endpoints of the first connected group are still the right anchor
|
|
39
|
+
// for the sketch's current position. When multiple disjoint pieces are
|
|
40
|
+
// projected, we use the first as a stable convention.
|
|
41
|
+
const allEdges = allWires.flatMap(w => w.getEdges());
|
|
42
|
+
let endpoints = null;
|
|
43
|
+
if (allEdges.length > 0) {
|
|
44
|
+
const groups = WireOps.groupConnectedEdges(allEdges);
|
|
45
|
+
endpoints = WireOps.findChainEndpoints(groups[0]);
|
|
38
46
|
}
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
47
|
+
const uniqueEdges = EdgeOps.unifyCoincident(allEdges);
|
|
48
|
+
this.addShapes(uniqueEdges);
|
|
49
|
+
if (endpoints) {
|
|
50
|
+
const localStart = plane.worldToLocal(endpoints.start.toPoint());
|
|
51
|
+
const localEnd = plane.worldToLocal(endpoints.end.toPoint());
|
|
42
52
|
this.setState('start', Vertex.fromPoint2D(localStart));
|
|
43
53
|
this.setState('end', Vertex.fromPoint2D(localEnd));
|
|
44
54
|
}
|
|
@@ -12,7 +12,7 @@ export declare class Sketch extends SceneObject implements Extrudable {
|
|
|
12
12
|
isExtrudable(): boolean;
|
|
13
13
|
getPlane(): Plane;
|
|
14
14
|
getStartPoint(): Point2D;
|
|
15
|
-
getTangentAt(currentObj: GeometrySceneObject): Point2D
|
|
15
|
+
getTangentAt(currentObj: GeometrySceneObject): Point2D;
|
|
16
16
|
getPositionAt(currentObj: GeometrySceneObject): Point2D;
|
|
17
17
|
getPreviousPosition(currentObj: GeometrySceneObject, count?: number): Point2D;
|
|
18
18
|
getLastPosition(scope?: Set<SceneObject>): Point2D;
|
|
@@ -24,7 +24,7 @@ export declare class Sketch extends SceneObject implements Extrudable {
|
|
|
24
24
|
getDependencies(): SceneObject[];
|
|
25
25
|
createCopy(remap: Map<SceneObject, SceneObject>): SceneObject;
|
|
26
26
|
compareTo(other: Sketch): boolean;
|
|
27
|
-
getTangent(scope?: Set<SceneObject>): Point2D
|
|
27
|
+
getTangent(scope?: Set<SceneObject>): Point2D;
|
|
28
28
|
getType(): string;
|
|
29
29
|
serialize(scope?: Set<SceneObject>): {
|
|
30
30
|
currentPosition: import("../../math/point.js").Point;
|
|
@@ -32,6 +32,11 @@ export class Sketch extends SceneObject {
|
|
|
32
32
|
const previous = children.slice(0, children.indexOf(currentObj));
|
|
33
33
|
let last = previous[previous.length - 1];
|
|
34
34
|
while (last) {
|
|
35
|
+
if (!(last instanceof GeometrySceneObject)) {
|
|
36
|
+
previous.pop();
|
|
37
|
+
last = previous[previous.length - 1];
|
|
38
|
+
continue;
|
|
39
|
+
}
|
|
35
40
|
const tangent = last.getTangent();
|
|
36
41
|
if (tangent) {
|
|
37
42
|
return tangent;
|
|
@@ -39,7 +44,7 @@ export class Sketch extends SceneObject {
|
|
|
39
44
|
previous.pop();
|
|
40
45
|
last = previous[previous.length - 1];
|
|
41
46
|
}
|
|
42
|
-
return
|
|
47
|
+
return new Point2D(1, 0);
|
|
43
48
|
}
|
|
44
49
|
getPositionAt(currentObj) {
|
|
45
50
|
const children = this.getChildren();
|
|
@@ -94,6 +99,7 @@ export class Sketch extends SceneObject {
|
|
|
94
99
|
}
|
|
95
100
|
}
|
|
96
101
|
build(context) {
|
|
102
|
+
this.setState('tangent', new Point2D(1, 0));
|
|
97
103
|
this.planeObj.removeShapes(this);
|
|
98
104
|
const source = this.getCloneSource();
|
|
99
105
|
const transform = context?.getTransform();
|
|
@@ -174,7 +180,7 @@ export class Sketch extends SceneObject {
|
|
|
174
180
|
children = children.filter(c => scope.has(c));
|
|
175
181
|
}
|
|
176
182
|
if (children.length === 0) {
|
|
177
|
-
return
|
|
183
|
+
return new Point2D(1, 0);
|
|
178
184
|
}
|
|
179
185
|
let last = children[children.length - 1];
|
|
180
186
|
while (last) {
|
|
@@ -190,7 +196,7 @@ export class Sketch extends SceneObject {
|
|
|
190
196
|
children.pop();
|
|
191
197
|
last = children[children.length - 1];
|
|
192
198
|
}
|
|
193
|
-
return
|
|
199
|
+
return new Point2D(1, 0);
|
|
194
200
|
}
|
|
195
201
|
getType() {
|
|
196
202
|
return "sketch";
|
|
@@ -200,7 +206,7 @@ export class Sketch extends SceneObject {
|
|
|
200
206
|
const tangent = this.getTangent(scope);
|
|
201
207
|
return {
|
|
202
208
|
currentPosition: plane.localToWorld(this.getLastPosition(scope)),
|
|
203
|
-
currentTangent:
|
|
209
|
+
currentTangent: plane.localToWorld(tangent),
|
|
204
210
|
plane: this.planeObj.serialize(),
|
|
205
211
|
};
|
|
206
212
|
}
|
|
@@ -10,9 +10,6 @@ export class TangentArcToPoint extends GeometrySceneObject {
|
|
|
10
10
|
}
|
|
11
11
|
build() {
|
|
12
12
|
const tangent = this.sketch.getTangentAt(this);
|
|
13
|
-
if (!tangent) {
|
|
14
|
-
throw new Error('TangentArcToPoint requires a previous sibling with a tangent');
|
|
15
|
-
}
|
|
16
13
|
const plane = this.sketch.getPlane();
|
|
17
14
|
const startPoint = this.getCurrentPosition();
|
|
18
15
|
const targetPoint = this.endPoint.asPoint2D();
|
|
@@ -13,9 +13,6 @@ export class TangentArc extends GeometrySceneObject {
|
|
|
13
13
|
}
|
|
14
14
|
build() {
|
|
15
15
|
const tangent = this.sketch.getTangentAt(this);
|
|
16
|
-
if (!tangent) {
|
|
17
|
-
throw new Error('TangentArc requires a previous sibling with a tangent');
|
|
18
|
-
}
|
|
19
16
|
const plane = this.sketch.getPlane();
|
|
20
17
|
// Negative radius flips the sweep direction.
|
|
21
18
|
const radius = Math.abs(this.radius);
|
|
@@ -9,9 +9,6 @@ export class TangentLine extends GeometrySceneObject {
|
|
|
9
9
|
}
|
|
10
10
|
build() {
|
|
11
11
|
const tangent = this.sketch.getTangentAt(this);
|
|
12
|
-
if (!tangent) {
|
|
13
|
-
throw new Error('TangentLine requires a previous sibling with a tangent');
|
|
14
|
-
}
|
|
15
12
|
const plane = this.sketch.getPlane();
|
|
16
13
|
const startPoint = this.getCurrentPosition();
|
|
17
14
|
const start = plane.localToWorld(startPoint);
|
|
@@ -38,7 +38,11 @@ export class VerticalLine extends GeometrySceneObject {
|
|
|
38
38
|
throw new Error('vLine: .centered() cannot be combined with a target geometry');
|
|
39
39
|
}
|
|
40
40
|
startPoint = currentPos;
|
|
41
|
-
|
|
41
|
+
const hit = findNearestRayIntersection(plane, startPoint, new Point2D(0, 1), this.distanceOrTarget);
|
|
42
|
+
if (!hit) {
|
|
43
|
+
throw new Error("Line does not intersect target geometry");
|
|
44
|
+
}
|
|
45
|
+
endPoint = hit;
|
|
42
46
|
signedLength = endPoint.y - startPoint.y;
|
|
43
47
|
}
|
|
44
48
|
const start = plane.localToWorld(startPoint);
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { SceneObject } from "../../common/scene-object.js";
|
|
2
2
|
import { GeometrySceneObject } from "./geometry.js";
|
|
3
3
|
export declare class VMove extends GeometrySceneObject {
|
|
4
|
-
|
|
5
|
-
constructor(
|
|
4
|
+
distanceOrTarget: number | SceneObject;
|
|
5
|
+
constructor(distanceOrTarget: number | SceneObject);
|
|
6
6
|
getType(): string;
|
|
7
7
|
build(): void;
|
|
8
8
|
getDependencies(): SceneObject[];
|
|
@@ -1,24 +1,43 @@
|
|
|
1
1
|
import { Point2D } from "../../math/point.js";
|
|
2
|
+
import { SceneObject } from "../../common/scene-object.js";
|
|
2
3
|
import { GeometrySceneObject } from "./geometry.js";
|
|
4
|
+
import { findNearestRayIntersection } from "../../oc/ray-intersect.js";
|
|
3
5
|
export class VMove extends GeometrySceneObject {
|
|
4
|
-
|
|
5
|
-
constructor(
|
|
6
|
+
distanceOrTarget;
|
|
7
|
+
constructor(distanceOrTarget) {
|
|
6
8
|
super();
|
|
7
|
-
this.
|
|
9
|
+
this.distanceOrTarget = distanceOrTarget;
|
|
8
10
|
}
|
|
9
11
|
getType() {
|
|
10
12
|
return 'vmove';
|
|
11
13
|
}
|
|
12
14
|
build() {
|
|
13
15
|
const pos = this.getCurrentPosition();
|
|
14
|
-
|
|
16
|
+
let newPos;
|
|
17
|
+
if (typeof this.distanceOrTarget === 'number') {
|
|
18
|
+
newPos = new Point2D(pos.x, pos.y + this.distanceOrTarget);
|
|
19
|
+
}
|
|
20
|
+
else {
|
|
21
|
+
const plane = this.sketch.getPlane();
|
|
22
|
+
const hit = findNearestRayIntersection(plane, pos, new Point2D(0, 1), this.distanceOrTarget);
|
|
23
|
+
if (!hit) {
|
|
24
|
+
throw new Error("Cannot move vertically up to the specified geometry");
|
|
25
|
+
}
|
|
26
|
+
newPos = hit;
|
|
27
|
+
}
|
|
15
28
|
this.setCurrentPosition(newPos);
|
|
16
29
|
}
|
|
17
30
|
getDependencies() {
|
|
31
|
+
if (this.distanceOrTarget instanceof SceneObject) {
|
|
32
|
+
return [this.distanceOrTarget];
|
|
33
|
+
}
|
|
18
34
|
return [];
|
|
19
35
|
}
|
|
20
36
|
createCopy(remap) {
|
|
21
|
-
|
|
37
|
+
const distanceOrTarget = this.distanceOrTarget instanceof SceneObject
|
|
38
|
+
? (remap.get(this.distanceOrTarget) || this.distanceOrTarget)
|
|
39
|
+
: this.distanceOrTarget;
|
|
40
|
+
return new VMove(distanceOrTarget);
|
|
22
41
|
}
|
|
23
42
|
compareTo(other) {
|
|
24
43
|
if (!(other instanceof VMove)) {
|
|
@@ -27,11 +46,17 @@ export class VMove extends GeometrySceneObject {
|
|
|
27
46
|
if (!super.compareTo(other)) {
|
|
28
47
|
return false;
|
|
29
48
|
}
|
|
30
|
-
|
|
49
|
+
if (typeof this.distanceOrTarget !== typeof other.distanceOrTarget) {
|
|
50
|
+
return false;
|
|
51
|
+
}
|
|
52
|
+
if (this.distanceOrTarget instanceof SceneObject && other.distanceOrTarget instanceof SceneObject) {
|
|
53
|
+
return this.distanceOrTarget.compareTo(other.distanceOrTarget);
|
|
54
|
+
}
|
|
55
|
+
return this.distanceOrTarget === other.distanceOrTarget;
|
|
31
56
|
}
|
|
32
57
|
serialize() {
|
|
33
58
|
return {
|
|
34
|
-
distance: this.
|
|
59
|
+
distance: typeof this.distanceOrTarget === 'number' ? this.distanceOrTarget : null
|
|
35
60
|
};
|
|
36
61
|
}
|
|
37
62
|
}
|
|
@@ -5,6 +5,7 @@ export declare class AxisFromEdge extends AxisObjectBase {
|
|
|
5
5
|
private sourceObject;
|
|
6
6
|
private options?;
|
|
7
7
|
constructor(sourceObject: SceneObject, options?: AxisTransformOptions);
|
|
8
|
+
validate(): void;
|
|
8
9
|
build(): void;
|
|
9
10
|
compareTo(other: AxisFromEdge): boolean;
|
|
10
11
|
getUniqueType(): string;
|
|
@@ -2,6 +2,7 @@ import { SelectSceneObject } from "./select.js";
|
|
|
2
2
|
import { AxisObjectBase } from "./axis-renderable-base.js";
|
|
3
3
|
import { EdgeOps } from "../oc/edge-ops.js";
|
|
4
4
|
import { SceneObject } from "../common/scene-object.js";
|
|
5
|
+
import { requireShapes } from "../common/operand-check.js";
|
|
5
6
|
export class AxisFromEdge extends AxisObjectBase {
|
|
6
7
|
sourceObject;
|
|
7
8
|
options;
|
|
@@ -10,6 +11,13 @@ export class AxisFromEdge extends AxisObjectBase {
|
|
|
10
11
|
this.sourceObject = sourceObject;
|
|
11
12
|
this.options = options;
|
|
12
13
|
}
|
|
14
|
+
validate() {
|
|
15
|
+
// AxisObjectBase sources expose the axis directly — no shapes required.
|
|
16
|
+
if (this.sourceObject instanceof AxisObjectBase) {
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
requireShapes(this.sourceObject, "source", "axis");
|
|
20
|
+
}
|
|
13
21
|
build() {
|
|
14
22
|
let axis;
|
|
15
23
|
if (this.sourceObject instanceof SelectSceneObject) {
|
|
@@ -6,6 +6,7 @@ export declare class Chamfer extends SceneObject {
|
|
|
6
6
|
private _selections;
|
|
7
7
|
constructor(distance: number, distance2: number, isAngle?: boolean, ...selections: SceneObject[]);
|
|
8
8
|
get selections(): SceneObject[];
|
|
9
|
+
validate(): void;
|
|
9
10
|
build(context: BuildSceneObjectContext): void;
|
|
10
11
|
getDependencies(): SceneObject[];
|
|
11
12
|
createCopy(remap: Map<SceneObject, SceneObject>): SceneObject;
|
|
@@ -3,6 +3,7 @@ import { FilletOps } from "../oc/fillet-ops.js";
|
|
|
3
3
|
import { Explorer } from "../oc/explorer.js";
|
|
4
4
|
import { ShapeOps } from "../oc/shape-ops.js";
|
|
5
5
|
import { ColorTransfer } from "../oc/color-transfer.js";
|
|
6
|
+
import { requireShapes } from "../common/operand-check.js";
|
|
6
7
|
export class Chamfer extends SceneObject {
|
|
7
8
|
distance;
|
|
8
9
|
distance2;
|
|
@@ -18,6 +19,11 @@ export class Chamfer extends SceneObject {
|
|
|
18
19
|
get selections() {
|
|
19
20
|
return this._selections;
|
|
20
21
|
}
|
|
22
|
+
validate() {
|
|
23
|
+
for (let i = 0; i < this._selections.length; i++) {
|
|
24
|
+
requireShapes(this._selections[i], `edge selection ${i + 1}`, "chamfer");
|
|
25
|
+
}
|
|
26
|
+
}
|
|
21
27
|
build(context) {
|
|
22
28
|
let sceneObjects;
|
|
23
29
|
sceneObjects = new Map();
|
|
@@ -4,6 +4,7 @@ export declare class Color extends SceneObject {
|
|
|
4
4
|
private _selection;
|
|
5
5
|
constructor(color: string, selection?: SceneObject);
|
|
6
6
|
get selection(): SceneObject;
|
|
7
|
+
validate(): void;
|
|
7
8
|
build(context: BuildSceneObjectContext): void;
|
|
8
9
|
createCopy(remap: Map<SceneObject, SceneObject>): SceneObject;
|
|
9
10
|
compareTo(other: Color): boolean;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { SceneObject } from "../common/scene-object.js";
|
|
2
2
|
import { SelectSceneObject } from "./select.js";
|
|
3
|
+
import { requireShapes } from "../common/operand-check.js";
|
|
3
4
|
import cssColorNames from "color-name";
|
|
4
5
|
function toHex(color) {
|
|
5
6
|
if (color.startsWith('#')) {
|
|
@@ -23,6 +24,11 @@ export class Color extends SceneObject {
|
|
|
23
24
|
get selection() {
|
|
24
25
|
return this._selection;
|
|
25
26
|
}
|
|
27
|
+
validate() {
|
|
28
|
+
if (this._selection) {
|
|
29
|
+
requireShapes(this._selection, "selection", "color");
|
|
30
|
+
}
|
|
31
|
+
}
|
|
26
32
|
build(context) {
|
|
27
33
|
const sceneObjects = context.getSceneObjects();
|
|
28
34
|
const objShapeMap = new Map();
|
|
@@ -5,6 +5,7 @@ export declare class Common extends SceneObject {
|
|
|
5
5
|
constructor(...objects: SceneObject[]);
|
|
6
6
|
keepOriginal(value?: boolean): this;
|
|
7
7
|
get sceneObjects(): SceneObject[];
|
|
8
|
+
validate(): void;
|
|
8
9
|
build(context: BuildSceneObjectContext): void;
|
|
9
10
|
compareTo(other: Common): boolean;
|
|
10
11
|
getType(): string;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { SceneObject } from "../common/scene-object.js";
|
|
2
2
|
import { BooleanOps } from "../oc/boolean-ops.js";
|
|
3
|
+
import { requireShapes } from "../common/operand-check.js";
|
|
3
4
|
export class Common extends SceneObject {
|
|
4
5
|
_sceneObjects = [];
|
|
5
6
|
_keepOriginal = false;
|
|
@@ -14,6 +15,14 @@ export class Common extends SceneObject {
|
|
|
14
15
|
get sceneObjects() {
|
|
15
16
|
return this._sceneObjects;
|
|
16
17
|
}
|
|
18
|
+
validate() {
|
|
19
|
+
// Scene-wide mode (no explicit operands) has nothing to fault — let build
|
|
20
|
+
// pick up whatever is in the scene. Only validate when the user named
|
|
21
|
+
// specific operands.
|
|
22
|
+
for (let i = 0; i < this._sceneObjects.length; i++) {
|
|
23
|
+
requireShapes(this._sceneObjects[i], `operand ${i + 1}`, "common");
|
|
24
|
+
}
|
|
25
|
+
}
|
|
17
26
|
build(context) {
|
|
18
27
|
const p = context.getProfiler();
|
|
19
28
|
let sceneObjects = this.sceneObjects;
|
|
@@ -6,6 +6,7 @@ export declare class Common2D extends GeometrySceneObject {
|
|
|
6
6
|
constructor(...targets: GeometrySceneObject[]);
|
|
7
7
|
keepOriginal(value?: boolean): this;
|
|
8
8
|
get targetObjects(): GeometrySceneObject[] | null;
|
|
9
|
+
validate(): void;
|
|
9
10
|
build(context: BuildSceneObjectContext): void;
|
|
10
11
|
getDependencies(): SceneObject[];
|
|
11
12
|
createCopy(remap: Map<SceneObject, SceneObject>): SceneObject;
|
|
@@ -3,6 +3,7 @@ import { Edge } from "../common/edge.js";
|
|
|
3
3
|
import { GeometrySceneObject } from "./2d/geometry.js";
|
|
4
4
|
import { BooleanOps } from "../oc/boolean-ops.js";
|
|
5
5
|
import { FaceMaker2 } from "../oc/face-maker2.js";
|
|
6
|
+
import { requireShapes } from "../common/operand-check.js";
|
|
6
7
|
export class Common2D extends GeometrySceneObject {
|
|
7
8
|
_targetObjects = null;
|
|
8
9
|
_keepOriginal = false;
|
|
@@ -17,6 +18,14 @@ export class Common2D extends GeometrySceneObject {
|
|
|
17
18
|
get targetObjects() {
|
|
18
19
|
return this._targetObjects;
|
|
19
20
|
}
|
|
21
|
+
validate() {
|
|
22
|
+
if (!this._targetObjects) {
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
for (let i = 0; i < this._targetObjects.length; i++) {
|
|
26
|
+
requireShapes(this._targetObjects[i], `operand ${i + 1}`, "common2d");
|
|
27
|
+
}
|
|
28
|
+
}
|
|
20
29
|
build(context) {
|
|
21
30
|
let sourceEdges;
|
|
22
31
|
if (this._targetObjects === null) {
|
|
@@ -4,6 +4,7 @@ export declare class Draft extends SceneObject implements IDraft {
|
|
|
4
4
|
private angle;
|
|
5
5
|
private _selections;
|
|
6
6
|
constructor(angle: number, selections: SceneObject[]);
|
|
7
|
+
validate(): void;
|
|
7
8
|
build(context: BuildSceneObjectContext): void;
|
|
8
9
|
compareTo(other: SceneObject): boolean;
|
|
9
10
|
getDependencies(): SceneObject[];
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { SceneObject } from "../common/scene-object.js";
|
|
2
2
|
import { DraftOps } from "../oc/draft-ops.js";
|
|
3
|
+
import { requireShapes } from "../common/operand-check.js";
|
|
3
4
|
export class Draft extends SceneObject {
|
|
4
5
|
angle;
|
|
5
6
|
_selections = [];
|
|
@@ -8,6 +9,11 @@ export class Draft extends SceneObject {
|
|
|
8
9
|
this.angle = angle;
|
|
9
10
|
this._selections = selections;
|
|
10
11
|
}
|
|
12
|
+
validate() {
|
|
13
|
+
for (let i = 0; i < this._selections.length; i++) {
|
|
14
|
+
requireShapes(this._selections[i], `selection ${i + 1}`, "draft");
|
|
15
|
+
}
|
|
16
|
+
}
|
|
11
17
|
build(context) {
|
|
12
18
|
const shapeObjMap = new Map();
|
|
13
19
|
for (const obj of context.getSceneObjects()) {
|