fluidcad 0.0.7 → 0.0.8

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.
Files changed (66) hide show
  1. package/bin/fluidcad.js +16 -0
  2. package/lib/dist/core/2d/arc.d.ts +15 -0
  3. package/lib/dist/core/2d/arc.js +10 -0
  4. package/lib/dist/core/2d/index.d.ts +0 -1
  5. package/lib/dist/core/2d/index.js +0 -1
  6. package/lib/dist/core/2d/tarc.d.ts +26 -2
  7. package/lib/dist/core/2d/tcircle.d.ts +26 -2
  8. package/lib/dist/core/2d/tline.d.ts +26 -6
  9. package/lib/dist/core/axis.d.ts +11 -4
  10. package/lib/dist/core/chamfer.d.ts +6 -6
  11. package/lib/dist/core/chamfer.js +12 -9
  12. package/lib/dist/core/cut.d.ts +27 -6
  13. package/lib/dist/core/extrude.d.ts +15 -3
  14. package/lib/dist/core/plane.d.ts +11 -4
  15. package/lib/dist/core/repeat.d.ts +16 -1
  16. package/lib/dist/core/repeat.js +39 -3
  17. package/lib/dist/core/sketch.d.ts +9 -3
  18. package/lib/dist/core/subtract.d.ts +5 -4
  19. package/lib/dist/core/subtract.js +9 -2
  20. package/lib/dist/features/2d/arc-three-points.d.ts +19 -0
  21. package/lib/dist/features/2d/arc-three-points.js +75 -0
  22. package/lib/dist/features/2d/constraints/geometry-qualifier.d.ts +16 -0
  23. package/lib/dist/features/2d/constraints/geometry-qualifier.js +16 -0
  24. package/lib/dist/features/2d/offset.js +10 -0
  25. package/lib/dist/features/2d/projection.js +9 -0
  26. package/lib/dist/features/2d/rect.js +19 -16
  27. package/lib/dist/features/chamfer.d.ts +4 -4
  28. package/lib/dist/features/chamfer.js +33 -15
  29. package/lib/dist/features/common2d.js +26 -8
  30. package/lib/dist/features/fuse2d.js +24 -6
  31. package/lib/dist/features/repeat-matrix.d.ts +14 -0
  32. package/lib/dist/features/repeat-matrix.js +41 -0
  33. package/lib/dist/features/select.d.ts +1 -0
  34. package/lib/dist/features/select.js +19 -0
  35. package/lib/dist/features/subtract2d.d.ts +14 -0
  36. package/lib/dist/features/subtract2d.js +80 -0
  37. package/lib/dist/filters/edge/belongs-to-face.d.ts +22 -0
  38. package/lib/dist/filters/edge/belongs-to-face.js +67 -0
  39. package/lib/dist/filters/edge/belongs-to-object.d.ts +18 -0
  40. package/lib/dist/filters/edge/belongs-to-object.js +37 -0
  41. package/lib/dist/filters/edge/edge-filter.d.ts +88 -3
  42. package/lib/dist/filters/edge/edge-filter.js +101 -4
  43. package/lib/dist/filters/edge/line-filter.d.ts +4 -1
  44. package/lib/dist/filters/edge/line-filter.js +14 -7
  45. package/lib/dist/filters/face/edge-count.d.ts +17 -0
  46. package/lib/dist/filters/face/edge-count.js +33 -0
  47. package/lib/dist/filters/face/face-filter.d.ts +93 -0
  48. package/lib/dist/filters/face/face-filter.js +112 -0
  49. package/lib/dist/filters/face/has-edge.d.ts +18 -0
  50. package/lib/dist/filters/face/has-edge.js +59 -0
  51. package/lib/dist/filters/face/has-object.d.ts +18 -0
  52. package/lib/dist/filters/face/has-object.js +37 -0
  53. package/lib/dist/filters/index.d.ts +6 -0
  54. package/lib/dist/filters/index.js +6 -0
  55. package/lib/dist/oc/edge-query.d.ts +2 -2
  56. package/lib/dist/oc/edge-query.js +13 -4
  57. package/lib/dist/tests/features/2d/arc.test.js +15 -1
  58. package/lib/dist/tests/features/select.test.js +249 -0
  59. package/lib/dist/tests/features/subtract2d.test.d.ts +1 -0
  60. package/lib/dist/tests/features/subtract2d.test.js +63 -0
  61. package/lib/dist/tsconfig.tsbuildinfo +1 -1
  62. package/package.json +3 -2
  63. package/lib/dist/core/2d/wire.d.ts +0 -11
  64. package/lib/dist/core/2d/wire.js +0 -29
  65. package/lib/dist/features/2d/wire.d.ts +0 -12
  66. package/lib/dist/features/2d/wire.js +0 -76
@@ -2,20 +2,113 @@ import { PlaneLike } from "../../math/plane.js";
2
2
  import { Face } from "../../common/shapes.js";
3
3
  import { FilterBuilderBase } from "../filter-builder-base.js";
4
4
  import { PlaneObjectBase } from "../../features/plane-renderable-base.js";
5
+ import { EdgeFilterBuilder } from "../edge/edge-filter.js";
6
+ import { ISceneObject } from "../../core/interfaces.js";
5
7
  export declare class FaceFilterBuilder extends FilterBuilderBase<Face> {
6
8
  constructor();
9
+ /**
10
+ * Selects the face at the given index.
11
+ * @param index - Zero-based face index.
12
+ * @param shapes - The face array to index into.
13
+ * @param originalShapes - Optional original face array before filtering.
14
+ */
7
15
  atIndex(index: number, shapes: Face[], originalShapes?: Face[]): this;
16
+ /**
17
+ * Excludes the face at the given index.
18
+ * @param index - Zero-based face index to exclude.
19
+ * @param shapes - The face array to index into.
20
+ * @param originalShapes - Optional original face array before filtering.
21
+ */
8
22
  notAtIndex(index: number, shapes: Face[], originalShapes?: Face[]): this;
23
+ /**
24
+ * Selects faces that lie on the given plane.
25
+ * @param plane - The reference plane.
26
+ * @param offset - Optional distance to offset the plane before matching.
27
+ */
9
28
  onPlane(plane: PlaneLike | PlaneObjectBase, offset?: number): this;
29
+ /**
30
+ * Excludes faces that lie on the given plane.
31
+ * @param plane - The reference plane.
32
+ * @param offset - Optional distance to offset the plane before matching.
33
+ */
10
34
  notOnPlane(plane: PlaneLike | PlaneObjectBase, offset?: number): this;
35
+ /**
36
+ * Selects circular (flat, disc-shaped) faces, optionally matching a specific diameter.
37
+ * @param diameter - Optional diameter to match.
38
+ */
11
39
  circle(diameter?: number): this;
40
+ /**
41
+ * Excludes circular (flat, disc-shaped) faces, optionally matching a specific diameter.
42
+ * @param diameter - Optional diameter to exclude.
43
+ */
12
44
  notCircle(diameter?: number): this;
45
+ /**
46
+ * Selects cylindrical faces, optionally matching a specific diameter.
47
+ * @param diameter - Optional diameter to match.
48
+ */
13
49
  cylinder(diameter?: number): this;
50
+ /**
51
+ * Excludes cylindrical faces, optionally matching a specific diameter.
52
+ * @param diameter - Optional diameter to exclude.
53
+ */
14
54
  notCylinder(diameter?: number): this;
55
+ /**
56
+ * Selects faces bounded by cylindrical curves, optionally matching a specific diameter.
57
+ * @param diameter - Optional diameter to match.
58
+ */
15
59
  cylinderCurve(diameter?: number): this;
60
+ /**
61
+ * Excludes faces bounded by cylindrical curves, optionally matching a specific diameter.
62
+ * @param diameter - Optional diameter to exclude.
63
+ */
16
64
  notCylinderCurve(diameter?: number): this;
65
+ /**
66
+ * Selects faces whose normal is parallel to the given plane.
67
+ * @param plane - The reference plane.
68
+ */
17
69
  parallelTo(plane: PlaneLike | PlaneObjectBase): this;
70
+ /**
71
+ * Excludes faces whose normal is parallel to the given plane.
72
+ * @param plane - The reference plane.
73
+ */
18
74
  notParallelTo(plane: PlaneLike | PlaneObjectBase): this;
75
+ /**
76
+ * Selects conical faces.
77
+ */
19
78
  cone(): this;
79
+ /**
80
+ * Excludes conical faces.
81
+ */
20
82
  notCone(): this;
83
+ /**
84
+ * Selects faces that share an edge with the given scene object.
85
+ * @param sceneObject - A scene object whose edges are matched against.
86
+ */
87
+ hasEdge(sceneObject: ISceneObject): this;
88
+ /**
89
+ * Selects faces that have edges matching all of the given edge filters.
90
+ * Each edge filter builder must match at least one edge of the face.
91
+ * @param edgeFilters - One or more edge filter builders. All must be satisfied.
92
+ */
93
+ hasEdge(...edgeFilters: EdgeFilterBuilder[]): this;
94
+ /**
95
+ * Excludes faces that share an edge with the given scene object.
96
+ * @param sceneObject - A scene object whose edges are matched against.
97
+ */
98
+ notHasEdge(sceneObject: ISceneObject): this;
99
+ /**
100
+ * Excludes faces that have edges matching all of the given edge filters.
101
+ * @param edgeFilters - One or more edge filter builders. If all are satisfied, the face is excluded.
102
+ */
103
+ notHasEdge(...edgeFilters: EdgeFilterBuilder[]): this;
104
+ /**
105
+ * Selects faces with exactly the given number of edges.
106
+ * @param count - The exact number of edges to match.
107
+ */
108
+ edgeCount(count: number): this;
109
+ /**
110
+ * Excludes faces with the given number of edges.
111
+ * @param count - The number of edges to exclude.
112
+ */
113
+ notEdgeCount(count: number): this;
21
114
  }
@@ -9,20 +9,41 @@ import { NotParallelFilter, ParallelFilter } from "./parallel.js";
9
9
  import { PlaneObject } from "../../features/plane.js";
10
10
  import { PlaneObjectBase } from "../../features/plane-renderable-base.js";
11
11
  import { AtIndexFilter, NotAtIndexFilter } from "./at-index.js";
12
+ import { HasEdgeFilter, NotHasEdgeFilter } from "./has-edge.js";
13
+ import { HasEdgeFromSceneObjectFilter, NotHasEdgeFromSceneObjectFilter } from "./has-object.js";
14
+ import { EdgeCountFilter, NotEdgeCountFilter } from "./edge-count.js";
15
+ import { SceneObject } from "../../common/scene-object.js";
12
16
  export class FaceFilterBuilder extends FilterBuilderBase {
13
17
  constructor() {
14
18
  super();
15
19
  }
20
+ /**
21
+ * Selects the face at the given index.
22
+ * @param index - Zero-based face index.
23
+ * @param shapes - The face array to index into.
24
+ * @param originalShapes - Optional original face array before filtering.
25
+ */
16
26
  atIndex(index, shapes, originalShapes) {
17
27
  const filter = new AtIndexFilter(index, shapes, originalShapes);
18
28
  this.filters.push(filter);
19
29
  return this;
20
30
  }
31
+ /**
32
+ * Excludes the face at the given index.
33
+ * @param index - Zero-based face index to exclude.
34
+ * @param shapes - The face array to index into.
35
+ * @param originalShapes - Optional original face array before filtering.
36
+ */
21
37
  notAtIndex(index, shapes, originalShapes) {
22
38
  const filter = new NotAtIndexFilter(index, shapes, originalShapes);
23
39
  this.filters.push(filter);
24
40
  return this;
25
41
  }
42
+ /**
43
+ * Selects faces that lie on the given plane.
44
+ * @param plane - The reference plane.
45
+ * @param offset - Optional distance to offset the plane before matching.
46
+ */
26
47
  onPlane(plane, offset = 0) {
27
48
  if (!plane) {
28
49
  throw new Error('Plane is required');
@@ -42,6 +63,11 @@ export class FaceFilterBuilder extends FilterBuilderBase {
42
63
  this.filters.push(filter);
43
64
  return this;
44
65
  }
66
+ /**
67
+ * Excludes faces that lie on the given plane.
68
+ * @param plane - The reference plane.
69
+ * @param offset - Optional distance to offset the plane before matching.
70
+ */
45
71
  notOnPlane(plane, offset = 0) {
46
72
  if (!plane) {
47
73
  throw new Error('Plane is required');
@@ -61,36 +87,64 @@ export class FaceFilterBuilder extends FilterBuilderBase {
61
87
  this.filters.push(filter);
62
88
  return this;
63
89
  }
90
+ /**
91
+ * Selects circular (flat, disc-shaped) faces, optionally matching a specific diameter.
92
+ * @param diameter - Optional diameter to match.
93
+ */
64
94
  circle(diameter) {
65
95
  const filter = new CircleFilter(diameter);
66
96
  this.filters.push(filter);
67
97
  return this;
68
98
  }
99
+ /**
100
+ * Excludes circular (flat, disc-shaped) faces, optionally matching a specific diameter.
101
+ * @param diameter - Optional diameter to exclude.
102
+ */
69
103
  notCircle(diameter) {
70
104
  const filter = new NotCircleFilter(diameter);
71
105
  this.filters.push(filter);
72
106
  return this;
73
107
  }
108
+ /**
109
+ * Selects cylindrical faces, optionally matching a specific diameter.
110
+ * @param diameter - Optional diameter to match.
111
+ */
74
112
  cylinder(diameter) {
75
113
  const filter = new CylinderFilter(diameter);
76
114
  this.filters.push(filter);
77
115
  return this;
78
116
  }
117
+ /**
118
+ * Excludes cylindrical faces, optionally matching a specific diameter.
119
+ * @param diameter - Optional diameter to exclude.
120
+ */
79
121
  notCylinder(diameter) {
80
122
  const filter = new NotCylinderFilter(diameter);
81
123
  this.filters.push(filter);
82
124
  return this;
83
125
  }
126
+ /**
127
+ * Selects faces bounded by cylindrical curves, optionally matching a specific diameter.
128
+ * @param diameter - Optional diameter to match.
129
+ */
84
130
  cylinderCurve(diameter) {
85
131
  const filter = new CylinderCurveFilter(diameter);
86
132
  this.filters.push(filter);
87
133
  return this;
88
134
  }
135
+ /**
136
+ * Excludes faces bounded by cylindrical curves, optionally matching a specific diameter.
137
+ * @param diameter - Optional diameter to exclude.
138
+ */
89
139
  notCylinderCurve(diameter) {
90
140
  const filter = new NotCylinderCurveFilter(diameter);
91
141
  this.filters.push(filter);
92
142
  return this;
93
143
  }
144
+ /**
145
+ * Selects faces whose normal is parallel to the given plane.
146
+ * @param plane - The reference plane.
147
+ */
94
148
  parallelTo(plane) {
95
149
  if (!plane) {
96
150
  throw new Error('Plane is required');
@@ -106,6 +160,10 @@ export class FaceFilterBuilder extends FilterBuilderBase {
106
160
  this.filters.push(filter);
107
161
  return this;
108
162
  }
163
+ /**
164
+ * Excludes faces whose normal is parallel to the given plane.
165
+ * @param plane - The reference plane.
166
+ */
109
167
  notParallelTo(plane) {
110
168
  if (!plane) {
111
169
  throw new Error('Plane is required');
@@ -121,14 +179,68 @@ export class FaceFilterBuilder extends FilterBuilderBase {
121
179
  this.filters.push(filter);
122
180
  return this;
123
181
  }
182
+ /**
183
+ * Selects conical faces.
184
+ */
124
185
  cone() {
125
186
  const filter = new ConeFilter();
126
187
  this.filters.push(filter);
127
188
  return this;
128
189
  }
190
+ /**
191
+ * Excludes conical faces.
192
+ */
129
193
  notCone() {
130
194
  const filter = new NotConeFilter();
131
195
  this.filters.push(filter);
132
196
  return this;
133
197
  }
198
+ hasEdge(...args) {
199
+ const filterBuilders = [];
200
+ for (const arg of args) {
201
+ if (arg instanceof SceneObject) {
202
+ this.filters.push(new HasEdgeFromSceneObjectFilter(arg));
203
+ }
204
+ else {
205
+ filterBuilders.push(arg);
206
+ }
207
+ }
208
+ if (filterBuilders.length > 0) {
209
+ this.filters.push(new HasEdgeFilter(filterBuilders));
210
+ }
211
+ return this;
212
+ }
213
+ notHasEdge(...args) {
214
+ const filterBuilders = [];
215
+ for (const arg of args) {
216
+ if (arg instanceof SceneObject) {
217
+ this.filters.push(new NotHasEdgeFromSceneObjectFilter(arg));
218
+ }
219
+ else {
220
+ filterBuilders.push(arg);
221
+ }
222
+ }
223
+ if (filterBuilders.length > 0) {
224
+ this.filters.push(new NotHasEdgeFilter(filterBuilders));
225
+ }
226
+ return this;
227
+ }
228
+ /**
229
+ * Selects faces with exactly the given number of edges.
230
+ * @param count - The exact number of edges to match.
231
+ */
232
+ edgeCount(count) {
233
+ const filter = new EdgeCountFilter(count);
234
+ this.filters.push(filter);
235
+ return this;
236
+ }
237
+ /**
238
+ * Excludes faces with the given number of edges.
239
+ * @param count - The number of edges to exclude.
240
+ */
241
+ notEdgeCount(count) {
242
+ const filter = new NotEdgeCountFilter(count);
243
+ this.filters.push(filter);
244
+ return this;
245
+ }
134
246
  }
@@ -0,0 +1,18 @@
1
+ import { Matrix4 } from "../../math/matrix4.js";
2
+ import { Edge, Face } from "../../common/shapes.js";
3
+ import { FilterBase } from "../filter-base.js";
4
+ import { FilterBuilderBase } from "../filter-builder-base.js";
5
+ export declare class HasEdgeFilter extends FilterBase<Face> {
6
+ private edgeFilterBuilders;
7
+ constructor(edgeFilterBuilders: FilterBuilderBase<Edge>[]);
8
+ match(shape: Face): boolean;
9
+ compareTo(other: HasEdgeFilter): boolean;
10
+ transform(matrix: Matrix4): HasEdgeFilter;
11
+ }
12
+ export declare class NotHasEdgeFilter extends FilterBase<Face> {
13
+ private edgeFilterBuilders;
14
+ constructor(edgeFilterBuilders: FilterBuilderBase<Edge>[]);
15
+ match(shape: Face): boolean;
16
+ compareTo(other: NotHasEdgeFilter): boolean;
17
+ transform(matrix: Matrix4): NotHasEdgeFilter;
18
+ }
@@ -0,0 +1,59 @@
1
+ import { FilterBase } from "../filter-base.js";
2
+ export class HasEdgeFilter extends FilterBase {
3
+ edgeFilterBuilders;
4
+ constructor(edgeFilterBuilders) {
5
+ super();
6
+ this.edgeFilterBuilders = edgeFilterBuilders;
7
+ }
8
+ match(shape) {
9
+ const edges = shape.getEdges();
10
+ return this.edgeFilterBuilders.every(builder => {
11
+ const filters = builder.getFilters();
12
+ return edges.some(edge => filters.every(f => f.match(edge)));
13
+ });
14
+ }
15
+ compareTo(other) {
16
+ if (this.edgeFilterBuilders.length !== other.edgeFilterBuilders.length) {
17
+ return false;
18
+ }
19
+ for (let i = 0; i < this.edgeFilterBuilders.length; i++) {
20
+ if (!this.edgeFilterBuilders[i].equals(other.edgeFilterBuilders[i])) {
21
+ return false;
22
+ }
23
+ }
24
+ return true;
25
+ }
26
+ transform(matrix) {
27
+ const transformed = this.edgeFilterBuilders.map(builder => builder.transform(matrix));
28
+ return new HasEdgeFilter(transformed);
29
+ }
30
+ }
31
+ export class NotHasEdgeFilter extends FilterBase {
32
+ edgeFilterBuilders;
33
+ constructor(edgeFilterBuilders) {
34
+ super();
35
+ this.edgeFilterBuilders = edgeFilterBuilders;
36
+ }
37
+ match(shape) {
38
+ const edges = shape.getEdges();
39
+ return !this.edgeFilterBuilders.every(builder => {
40
+ const filters = builder.getFilters();
41
+ return edges.some(edge => filters.every(f => f.match(edge)));
42
+ });
43
+ }
44
+ compareTo(other) {
45
+ if (this.edgeFilterBuilders.length !== other.edgeFilterBuilders.length) {
46
+ return false;
47
+ }
48
+ for (let i = 0; i < this.edgeFilterBuilders.length; i++) {
49
+ if (!this.edgeFilterBuilders[i].equals(other.edgeFilterBuilders[i])) {
50
+ return false;
51
+ }
52
+ }
53
+ return true;
54
+ }
55
+ transform(matrix) {
56
+ const transformed = this.edgeFilterBuilders.map(builder => builder.transform(matrix));
57
+ return new NotHasEdgeFilter(transformed);
58
+ }
59
+ }
@@ -0,0 +1,18 @@
1
+ import { Matrix4 } from "../../math/matrix4.js";
2
+ import { Face } from "../../common/shapes.js";
3
+ import { FilterBase } from "../filter-base.js";
4
+ import { SceneObject } from "../../common/scene-object.js";
5
+ export declare class HasEdgeFromSceneObjectFilter extends FilterBase<Face> {
6
+ private sceneObject;
7
+ constructor(sceneObject: SceneObject);
8
+ match(shape: Face): boolean;
9
+ compareTo(other: HasEdgeFromSceneObjectFilter): boolean;
10
+ transform(_matrix: Matrix4): HasEdgeFromSceneObjectFilter;
11
+ }
12
+ export declare class NotHasEdgeFromSceneObjectFilter extends FilterBase<Face> {
13
+ private sceneObject;
14
+ constructor(sceneObject: SceneObject);
15
+ match(shape: Face): boolean;
16
+ compareTo(other: NotHasEdgeFromSceneObjectFilter): boolean;
17
+ transform(_matrix: Matrix4): NotHasEdgeFromSceneObjectFilter;
18
+ }
@@ -0,0 +1,37 @@
1
+ import { FilterBase } from "../filter-base.js";
2
+ export class HasEdgeFromSceneObjectFilter extends FilterBase {
3
+ sceneObject;
4
+ constructor(sceneObject) {
5
+ super();
6
+ this.sceneObject = sceneObject;
7
+ }
8
+ match(shape) {
9
+ const objectEdges = this.sceneObject.getShapes()
10
+ .flatMap(s => s.getSubShapes("edge"));
11
+ return objectEdges.some(objEdge => shape.hasEdge(objEdge.getShape()) !== null);
12
+ }
13
+ compareTo(other) {
14
+ return this.sceneObject.compareTo(other.sceneObject);
15
+ }
16
+ transform(_matrix) {
17
+ return new HasEdgeFromSceneObjectFilter(this.sceneObject);
18
+ }
19
+ }
20
+ export class NotHasEdgeFromSceneObjectFilter extends FilterBase {
21
+ sceneObject;
22
+ constructor(sceneObject) {
23
+ super();
24
+ this.sceneObject = sceneObject;
25
+ }
26
+ match(shape) {
27
+ const objectEdges = this.sceneObject.getShapes()
28
+ .flatMap(s => s.getSubShapes("edge"));
29
+ return !objectEdges.some(objEdge => shape.hasEdge(objEdge.getShape()) !== null);
30
+ }
31
+ compareTo(other) {
32
+ return this.sceneObject.compareTo(other.sceneObject);
33
+ }
34
+ transform(_matrix) {
35
+ return new NotHasEdgeFromSceneObjectFilter(this.sceneObject);
36
+ }
37
+ }
@@ -1,4 +1,10 @@
1
1
  import { FaceFilterBuilder } from './face/face-filter.js';
2
2
  import { EdgeFilterBuilder } from './edge/edge-filter.js';
3
+ /**
4
+ * Creates a new face filter builder for selecting faces by geometric properties.
5
+ */
3
6
  export declare function face(): FaceFilterBuilder;
7
+ /**
8
+ * Creates a new edge filter builder for selecting edges by geometric properties.
9
+ */
4
10
  export declare function edge(): EdgeFilterBuilder;
@@ -1,8 +1,14 @@
1
1
  import { FaceFilterBuilder } from './face/face-filter.js';
2
2
  import { EdgeFilterBuilder } from './edge/edge-filter.js';
3
+ /**
4
+ * Creates a new face filter builder for selecting faces by geometric properties.
5
+ */
3
6
  export function face() {
4
7
  return new FaceFilterBuilder();
5
8
  }
9
+ /**
10
+ * Creates a new edge filter builder for selecting edges by geometric properties.
11
+ */
6
12
  export function edge() {
7
13
  return new EdgeFilterBuilder();
8
14
  }
@@ -7,7 +7,7 @@ import { Edge } from "../common/edge.js";
7
7
  export declare class EdgeQuery {
8
8
  static isCircleEdge(edge: Shape, diameter?: number): boolean;
9
9
  static isArcEdge(edge: Shape, radius?: number): boolean;
10
- static isLineEdge(edge: Shape): boolean;
10
+ static isLineEdge(edge: Shape, length?: number): boolean;
11
11
  static isEdgeOnPlane(edge: Shape, plane: Plane): boolean;
12
12
  static isEdgeParallelToPlane(edge: Shape, planeNormal: Vector3d): boolean;
13
13
  static isEdgeAlignedWithNormal(edge: Shape, planeNormal: Vector3d): boolean;
@@ -25,7 +25,7 @@ export declare class EdgeQuery {
25
25
  };
26
26
  static isCircleEdgeRaw(edge: TopoDS_Shape, diameter?: number): boolean;
27
27
  static isArcEdgeRaw(edge: TopoDS_Shape, radius?: number): boolean;
28
- static isLineEdgeRaw(edge: TopoDS_Shape): boolean;
28
+ static isLineEdgeRaw(edge: TopoDS_Shape, length?: number): boolean;
29
29
  static isEdgeOnPlaneRaw(edge: TopoDS_Shape, plane: gp_Pln): boolean;
30
30
  static isEdgeParallelToPlaneRaw(edge: TopoDS_Shape, planeNormal: gp_Vec): boolean;
31
31
  static isEdgeAlignedWithNormalRaw(edge: TopoDS_Shape, planeNormal: gp_Vec): boolean;
@@ -10,8 +10,8 @@ export class EdgeQuery {
10
10
  static isArcEdge(edge, radius) {
11
11
  return EdgeQuery.isArcEdgeRaw(edge.getShape(), radius);
12
12
  }
13
- static isLineEdge(edge) {
14
- return EdgeQuery.isLineEdgeRaw(edge.getShape());
13
+ static isLineEdge(edge, length) {
14
+ return EdgeQuery.isLineEdgeRaw(edge.getShape(), length);
15
15
  }
16
16
  static isEdgeOnPlane(edge, plane) {
17
17
  const [gpPln, dispose] = Convert.toGpPln(plane);
@@ -93,13 +93,22 @@ export class EdgeQuery {
93
93
  curveAdaptor.delete();
94
94
  return Math.abs(r - radius) <= oc.Precision.Confusion();
95
95
  }
96
- static isLineEdgeRaw(edge) {
96
+ static isLineEdgeRaw(edge, length) {
97
97
  const oc = getOC();
98
98
  const ocEdge = oc.TopoDS.Edge(edge);
99
99
  const curveAdaptor = new oc.BRepAdaptor_Curve(ocEdge);
100
100
  const curveType = curveAdaptor.GetType();
101
+ if (curveType !== oc.GeomAbs_CurveType.GeomAbs_Line) {
102
+ curveAdaptor.delete();
103
+ return false;
104
+ }
105
+ if (length === undefined) {
106
+ curveAdaptor.delete();
107
+ return true;
108
+ }
109
+ const edgeLength = Math.abs(curveAdaptor.LastParameter() - curveAdaptor.FirstParameter());
101
110
  curveAdaptor.delete();
102
- return curveType === oc.GeomAbs_CurveType.GeomAbs_Line;
111
+ return Math.abs(edgeLength - length) <= oc.Precision.Confusion();
103
112
  }
104
113
  static isEdgeOnPlaneRaw(edge, plane) {
105
114
  const oc = getOC();
@@ -2,7 +2,7 @@ import { describe, it, expect } from "vitest";
2
2
  import { setupOC, render } from "../../setup.js";
3
3
  import sketch from "../../../core/sketch.js";
4
4
  import extrude from "../../../core/extrude.js";
5
- import { arc, hLine, vLine } from "../../../core/2d/index.js";
5
+ import { arc, hLine, vLine, line } from "../../../core/2d/index.js";
6
6
  import { getEdgesByType } from "../../utils.js";
7
7
  describe("arc", () => {
8
8
  setupOC();
@@ -22,6 +22,20 @@ describe("arc", () => {
22
22
  expect(arcEdges.length).toBeGreaterThan(0);
23
23
  });
24
24
  });
25
+ describe("from three points (start, end, center)", () => {
26
+ it("should create an arc from start to end around a center point", () => {
27
+ sketch("xy", () => {
28
+ arc([0, 0], [20, 0], [10, 0]);
29
+ line([0, 0]);
30
+ });
31
+ const e = extrude(10);
32
+ render();
33
+ expect(e.getShapes()).toHaveLength(1);
34
+ const solid = e.getShapes()[0];
35
+ const arcEdges = getEdgesByType(solid, "arc");
36
+ expect(arcEdges.length).toBeGreaterThan(0);
37
+ });
38
+ });
25
39
  describe("combined with lines", () => {
26
40
  it("should create a shape with straight and curved edges", () => {
27
41
  sketch("xy", () => {