fluidcad 0.0.27 → 0.0.29
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/dist/common/profiler.d.ts +12 -0
- package/lib/dist/common/profiler.js +35 -0
- package/lib/dist/common/scene-object.d.ts +47 -0
- package/lib/dist/common/scene-object.js +121 -0
- package/lib/dist/common/shape-factory.d.ts +1 -1
- package/lib/dist/common/shape-history-tracker.d.ts +43 -0
- package/lib/dist/common/shape-history-tracker.js +128 -0
- package/lib/dist/common/shape.js +7 -1
- package/lib/dist/common/solid.js +5 -1
- package/lib/dist/core/2d/aline.d.ts +4 -4
- package/lib/dist/core/2d/aline.js +14 -10
- package/lib/dist/core/2d/arc.d.ts +6 -6
- package/lib/dist/core/2d/arc.js +19 -15
- package/lib/dist/core/2d/circle.d.ts +2 -2
- package/lib/dist/core/2d/circle.js +14 -10
- package/lib/dist/core/2d/ellipse.d.ts +35 -0
- package/lib/dist/core/2d/ellipse.js +65 -0
- package/lib/dist/core/2d/hline.d.ts +4 -4
- package/lib/dist/core/2d/hline.js +14 -10
- package/lib/dist/core/2d/index.d.ts +1 -0
- package/lib/dist/core/2d/index.js +1 -0
- package/lib/dist/core/2d/intersect.d.ts +2 -2
- package/lib/dist/core/2d/intersect.js +7 -3
- package/lib/dist/core/2d/line.d.ts +2 -2
- package/lib/dist/core/2d/line.js +14 -10
- package/lib/dist/core/2d/offset.d.ts +4 -4
- package/lib/dist/core/2d/offset.js +9 -5
- package/lib/dist/core/2d/polygon.d.ts +4 -4
- package/lib/dist/core/2d/polygon.js +24 -20
- package/lib/dist/core/2d/project.d.ts +2 -2
- package/lib/dist/core/2d/project.js +7 -3
- package/lib/dist/core/2d/rect.d.ts +2 -2
- package/lib/dist/core/2d/rect.js +22 -21
- package/lib/dist/core/2d/slot.d.ts +6 -6
- package/lib/dist/core/2d/slot.js +29 -32
- package/lib/dist/core/2d/vline.d.ts +4 -4
- package/lib/dist/core/2d/vline.js +14 -10
- package/lib/dist/core/interfaces.d.ts +8 -0
- package/lib/dist/core/mirror.js +17 -11
- package/lib/dist/core/part.d.ts +3 -1
- package/lib/dist/core/part.js +1 -1
- package/lib/dist/core/rotate.js +4 -1
- package/lib/dist/core/sketch.d.ts +3 -1
- package/lib/dist/core/sketch.js +1 -1
- package/lib/dist/features/2d/ellipse.d.ts +23 -0
- package/lib/dist/features/2d/ellipse.js +75 -0
- package/lib/dist/features/2d/offset.d.ts +3 -0
- package/lib/dist/features/2d/offset.js +27 -3
- package/lib/dist/features/chamfer.js +12 -6
- package/lib/dist/features/common.js +2 -1
- package/lib/dist/features/extrude-base.d.ts +55 -1
- package/lib/dist/features/extrude-base.js +168 -33
- package/lib/dist/features/extrude-to-face.js +13 -2
- package/lib/dist/features/extrude-two-distances.js +45 -25
- package/lib/dist/features/extrude.d.ts +39 -0
- package/lib/dist/features/extrude.js +207 -144
- package/lib/dist/features/fillet.js +3 -4
- package/lib/dist/features/fuse.js +16 -1
- package/lib/dist/features/infinite-extrude.d.ts +1 -0
- package/lib/dist/features/infinite-extrude.js +33 -4
- package/lib/dist/features/loft.js +26 -10
- package/lib/dist/features/revolve.d.ts +31 -0
- package/lib/dist/features/revolve.js +179 -85
- package/lib/dist/features/select.js +2 -1
- package/lib/dist/features/simple-extruder.d.ts +3 -1
- package/lib/dist/features/simple-extruder.js +13 -9
- package/lib/dist/features/subtract.d.ts +2 -2
- package/lib/dist/features/subtract.js +3 -3
- package/lib/dist/features/sweep.d.ts +14 -0
- package/lib/dist/features/sweep.js +93 -69
- package/lib/dist/filters/edge/edge-filter.d.ts +6 -0
- package/lib/dist/filters/edge/edge-filter.js +11 -0
- package/lib/dist/filters/face/face-filter.d.ts +6 -0
- package/lib/dist/filters/face/face-filter.js +11 -0
- package/lib/dist/filters/filter-base.d.ts +7 -1
- package/lib/dist/filters/filter-base.js +8 -0
- package/lib/dist/filters/filter-builder-base.js +11 -0
- package/lib/dist/filters/from-object.d.ts +14 -0
- package/lib/dist/filters/from-object.js +40 -0
- package/lib/dist/helpers/scene-helpers.d.ts +9 -1
- package/lib/dist/helpers/scene-helpers.js +298 -13
- package/lib/dist/oc/boolean-ops.d.ts +29 -3
- package/lib/dist/oc/boolean-ops.js +107 -9
- package/lib/dist/oc/color-transfer.d.ts +37 -0
- package/lib/dist/oc/color-transfer.js +141 -0
- package/lib/dist/oc/edge-ops.d.ts +1 -0
- package/lib/dist/oc/edge-ops.js +17 -0
- package/lib/dist/oc/extrude-ops.d.ts +18 -1
- package/lib/dist/oc/extrude-ops.js +59 -4
- package/lib/dist/oc/fillet-ops.d.ts +5 -3
- package/lib/dist/oc/fillet-ops.js +23 -4
- package/lib/dist/oc/geometry.d.ts +1 -0
- package/lib/dist/oc/geometry.js +27 -0
- package/lib/dist/oc/intersection.js +6 -3
- package/lib/dist/oc/mesh.js +12 -10
- package/lib/dist/oc/shape-ops.d.ts +25 -0
- package/lib/dist/oc/shape-ops.js +131 -12
- package/lib/dist/oc/thin-face-maker.d.ts +0 -1
- package/lib/dist/oc/thin-face-maker.js +2 -20
- package/lib/dist/rendering/render.d.ts +2 -1
- package/lib/dist/rendering/render.js +68 -32
- package/lib/dist/rendering/scene.d.ts +4 -0
- package/lib/dist/tests/common/scene-object-history.test.d.ts +1 -0
- package/lib/dist/tests/common/scene-object-history.test.js +274 -0
- package/lib/dist/tests/common/shape-history-tracker.test.d.ts +1 -0
- package/lib/dist/tests/common/shape-history-tracker.test.js +110 -0
- package/lib/dist/tests/features/2d/circle.test.js +1 -1
- package/lib/dist/tests/features/2d/ellipse.test.d.ts +1 -0
- package/lib/dist/tests/features/2d/ellipse.test.js +100 -0
- package/lib/dist/tests/features/2d/line.test.js +1 -1
- package/lib/dist/tests/features/2d/offset.test.js +1 -1
- package/lib/dist/tests/features/2d/polygon.test.js +2 -2
- package/lib/dist/tests/features/2d/project-regression.test.d.ts +1 -0
- package/lib/dist/tests/features/2d/project-regression.test.js +69 -0
- package/lib/dist/tests/features/2d/project-user-regression.test.d.ts +1 -0
- package/lib/dist/tests/features/2d/project-user-regression.test.js +37 -0
- package/lib/dist/tests/features/2d/rect.test.js +1 -1
- package/lib/dist/tests/features/2d/slot.test.js +1 -1
- package/lib/dist/tests/features/color-lineage.test.d.ts +1 -0
- package/lib/dist/tests/features/color-lineage.test.js +213 -0
- package/lib/dist/tests/features/cut-symmetric-through-all.test.d.ts +1 -0
- package/lib/dist/tests/features/cut-symmetric-through-all.test.js +32 -0
- package/lib/dist/tests/features/extrude-history.test.d.ts +1 -0
- package/lib/dist/tests/features/extrude-history.test.js +248 -0
- package/lib/dist/tests/features/peer-ops-history.test.d.ts +1 -0
- package/lib/dist/tests/features/peer-ops-history.test.js +119 -0
- package/lib/dist/tests/features/subtract.test.js +21 -1
- package/lib/dist/tests/features/thin-revolve.test.js +37 -1
- package/lib/dist/tests/perf/record-fusion-history.bench.test.d.ts +1 -0
- package/lib/dist/tests/perf/record-fusion-history.bench.test.js +77 -0
- package/lib/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +3 -3
- package/ui/dist/assets/{index-gPoNOiIs.css → index-VKkXzLfR.css} +1 -1
- package/ui/dist/assets/{index-55iqIwnj.js → index-VY48_dgc.js} +64 -47
- package/ui/dist/index.html +2 -2
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export type ProfileCategory = {
|
|
2
|
+
category: string;
|
|
3
|
+
durationMs: number;
|
|
4
|
+
};
|
|
5
|
+
export declare class Profiler {
|
|
6
|
+
private categories;
|
|
7
|
+
private stack;
|
|
8
|
+
start(category: string): void;
|
|
9
|
+
end(category: string): void;
|
|
10
|
+
record<T>(category: string, fn: () => T): T;
|
|
11
|
+
getCategories(): ProfileCategory[];
|
|
12
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
export class Profiler {
|
|
2
|
+
categories = new Map();
|
|
3
|
+
stack = [];
|
|
4
|
+
start(category) {
|
|
5
|
+
this.stack.push({ category, startTime: performance.now() });
|
|
6
|
+
}
|
|
7
|
+
end(category) {
|
|
8
|
+
for (let i = this.stack.length - 1; i >= 0; i--) {
|
|
9
|
+
if (this.stack[i].category === category) {
|
|
10
|
+
const entry = this.stack.splice(i, 1)[0];
|
|
11
|
+
const elapsed = performance.now() - entry.startTime;
|
|
12
|
+
const current = this.categories.get(category) || 0;
|
|
13
|
+
this.categories.set(category, current + elapsed);
|
|
14
|
+
this.stack.length = i;
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
record(category, fn) {
|
|
20
|
+
this.start(category);
|
|
21
|
+
try {
|
|
22
|
+
return fn();
|
|
23
|
+
}
|
|
24
|
+
finally {
|
|
25
|
+
this.end(category);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
getCategories() {
|
|
29
|
+
const result = [];
|
|
30
|
+
for (const [category, durationMs] of this.categories.entries()) {
|
|
31
|
+
result.push({ category, durationMs: Math.round(durationMs * 10) / 10 });
|
|
32
|
+
}
|
|
33
|
+
return result;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
@@ -1,13 +1,29 @@
|
|
|
1
1
|
import { Shape, ShapeFilter } from "./shape.js";
|
|
2
|
+
import { Face } from "./face.js";
|
|
3
|
+
import { Edge } from "./edge.js";
|
|
2
4
|
import { Matrix4 } from "../math/matrix4.js";
|
|
3
5
|
import { ISceneObject } from "../core/interfaces.js";
|
|
4
6
|
import { FusionScope, OperationMode } from "../features/extrude-options.js";
|
|
5
7
|
import { ShapeType } from "./shape-type.js";
|
|
8
|
+
import { Profiler } from "./profiler.js";
|
|
6
9
|
export type SourceLocation = {
|
|
7
10
|
filePath: string;
|
|
8
11
|
line: number;
|
|
9
12
|
column: number;
|
|
10
13
|
};
|
|
14
|
+
export type AdditionRecord<T> = {
|
|
15
|
+
shape: T;
|
|
16
|
+
addedBy: SceneObject;
|
|
17
|
+
};
|
|
18
|
+
export type RemovalRecord<T> = {
|
|
19
|
+
shape: T;
|
|
20
|
+
removedBy: SceneObject;
|
|
21
|
+
};
|
|
22
|
+
export type ModificationRecord<T> = {
|
|
23
|
+
sources: T[];
|
|
24
|
+
results: T[];
|
|
25
|
+
modifiedBy: SceneObject;
|
|
26
|
+
};
|
|
11
27
|
export interface Comparable<T> {
|
|
12
28
|
compareTo(other: T): boolean;
|
|
13
29
|
}
|
|
@@ -20,6 +36,7 @@ export type BuildSceneObjectContext = {
|
|
|
20
36
|
getSceneObjectsFromTo(obj: SceneObject, to: SceneObject, type?: string): SceneObject[];
|
|
21
37
|
getTransform(): Matrix4 | null;
|
|
22
38
|
getLastObject(): SceneObject | null;
|
|
39
|
+
getProfiler(): Profiler;
|
|
23
40
|
};
|
|
24
41
|
export declare abstract class SceneObject implements Comparable<SceneObject>, Serializable, ISceneObject {
|
|
25
42
|
private state;
|
|
@@ -74,11 +91,41 @@ export declare abstract class SceneObject implements Comparable<SceneObject>, Se
|
|
|
74
91
|
private set addedShapes(value);
|
|
75
92
|
private get removedShapes();
|
|
76
93
|
private set removedShapes(value);
|
|
94
|
+
private get addedFaces();
|
|
95
|
+
private set addedFaces(value);
|
|
96
|
+
private get modifiedFaces();
|
|
97
|
+
private set modifiedFaces(value);
|
|
98
|
+
private get removedFaces();
|
|
99
|
+
private set removedFaces(value);
|
|
100
|
+
private get addedEdges();
|
|
101
|
+
private set addedEdges(value);
|
|
102
|
+
private get modifiedEdges();
|
|
103
|
+
private set modifiedEdges(value);
|
|
104
|
+
private get removedEdges();
|
|
105
|
+
private set removedEdges(value);
|
|
106
|
+
private get finalShapes();
|
|
107
|
+
private set finalShapes(value);
|
|
77
108
|
getUniqueType(): string;
|
|
78
109
|
addShape(shape: Shape): void;
|
|
79
110
|
addShapes(shapes: Shape[]): void;
|
|
80
111
|
removeShape(shape: Shape, removedBy: SceneObject): void;
|
|
81
112
|
removeShapes(removedBy: SceneObject, force?: boolean): void;
|
|
113
|
+
recordAddedFace(face: Face, addedBy: SceneObject): void;
|
|
114
|
+
recordAddedEdge(edge: Edge, addedBy: SceneObject): void;
|
|
115
|
+
recordModifiedFaces(sources: Face[], results: Face[], modifiedBy: SceneObject): void;
|
|
116
|
+
recordModifiedEdges(sources: Edge[], results: Edge[], modifiedBy: SceneObject): void;
|
|
117
|
+
recordRemovedFace(face: Face, removedBy: SceneObject): void;
|
|
118
|
+
recordRemovedEdge(edge: Edge, removedBy: SceneObject): void;
|
|
119
|
+
private ownsFace;
|
|
120
|
+
private ownsEdge;
|
|
121
|
+
getAddedFaces(scope?: Set<SceneObject>): Face[];
|
|
122
|
+
getModifiedFaces(scope?: Set<SceneObject>): ModificationRecord<Face>[];
|
|
123
|
+
getRemovedFaces(scope?: Set<SceneObject>): Face[];
|
|
124
|
+
getAddedEdges(scope?: Set<SceneObject>): Edge[];
|
|
125
|
+
getModifiedEdges(scope?: Set<SceneObject>): ModificationRecord<Edge>[];
|
|
126
|
+
getRemovedEdges(scope?: Set<SceneObject>): Edge[];
|
|
127
|
+
setFinalShapes(shapes: Shape[]): void;
|
|
128
|
+
getFinalShapes(): Shape[];
|
|
82
129
|
getOwnShapes(filter?: ShapeFilter, scope?: Set<SceneObject>): Shape[];
|
|
83
130
|
getChildShapes(filter?: ShapeFilter, type?: ShapeType): Shape[];
|
|
84
131
|
getShapes(filter?: ShapeFilter, type?: ShapeType): Shape[];
|
|
@@ -21,6 +21,13 @@ export class SceneObject {
|
|
|
21
21
|
this.state = new Map();
|
|
22
22
|
this.state.set('addedShapes', []);
|
|
23
23
|
this.state.set('removedShapes', []);
|
|
24
|
+
this.state.set('addedFaces', []);
|
|
25
|
+
this.state.set('modifiedFaces', []);
|
|
26
|
+
this.state.set('removedFaces', []);
|
|
27
|
+
this.state.set('addedEdges', []);
|
|
28
|
+
this.state.set('modifiedEdges', []);
|
|
29
|
+
this.state.set('removedEdges', []);
|
|
30
|
+
this.state.set('finalShapes', []);
|
|
24
31
|
this._id = randomUUID().toString();
|
|
25
32
|
}
|
|
26
33
|
get id() {
|
|
@@ -208,6 +215,48 @@ export class SceneObject {
|
|
|
208
215
|
set removedShapes(shapes) {
|
|
209
216
|
this.state.set('removedShapes', shapes);
|
|
210
217
|
}
|
|
218
|
+
get addedFaces() {
|
|
219
|
+
return this.state.get('addedFaces');
|
|
220
|
+
}
|
|
221
|
+
set addedFaces(records) {
|
|
222
|
+
this.state.set('addedFaces', records);
|
|
223
|
+
}
|
|
224
|
+
get modifiedFaces() {
|
|
225
|
+
return this.state.get('modifiedFaces');
|
|
226
|
+
}
|
|
227
|
+
set modifiedFaces(records) {
|
|
228
|
+
this.state.set('modifiedFaces', records);
|
|
229
|
+
}
|
|
230
|
+
get removedFaces() {
|
|
231
|
+
return this.state.get('removedFaces');
|
|
232
|
+
}
|
|
233
|
+
set removedFaces(records) {
|
|
234
|
+
this.state.set('removedFaces', records);
|
|
235
|
+
}
|
|
236
|
+
get addedEdges() {
|
|
237
|
+
return this.state.get('addedEdges');
|
|
238
|
+
}
|
|
239
|
+
set addedEdges(records) {
|
|
240
|
+
this.state.set('addedEdges', records);
|
|
241
|
+
}
|
|
242
|
+
get modifiedEdges() {
|
|
243
|
+
return this.state.get('modifiedEdges');
|
|
244
|
+
}
|
|
245
|
+
set modifiedEdges(records) {
|
|
246
|
+
this.state.set('modifiedEdges', records);
|
|
247
|
+
}
|
|
248
|
+
get removedEdges() {
|
|
249
|
+
return this.state.get('removedEdges');
|
|
250
|
+
}
|
|
251
|
+
set removedEdges(records) {
|
|
252
|
+
this.state.set('removedEdges', records);
|
|
253
|
+
}
|
|
254
|
+
get finalShapes() {
|
|
255
|
+
return this.state.get('finalShapes');
|
|
256
|
+
}
|
|
257
|
+
set finalShapes(shapes) {
|
|
258
|
+
this.state.set('finalShapes', shapes);
|
|
259
|
+
}
|
|
211
260
|
getUniqueType() {
|
|
212
261
|
return this.getType();
|
|
213
262
|
}
|
|
@@ -251,6 +300,78 @@ export class SceneObject {
|
|
|
251
300
|
this.removeShape(shape, removedBy);
|
|
252
301
|
}
|
|
253
302
|
}
|
|
303
|
+
recordAddedFace(face, addedBy) {
|
|
304
|
+
this.addedFaces.push({ shape: face, addedBy });
|
|
305
|
+
}
|
|
306
|
+
recordAddedEdge(edge, addedBy) {
|
|
307
|
+
this.addedEdges.push({ shape: edge, addedBy });
|
|
308
|
+
}
|
|
309
|
+
recordModifiedFaces(sources, results, modifiedBy) {
|
|
310
|
+
this.modifiedFaces.push({ sources, results, modifiedBy });
|
|
311
|
+
}
|
|
312
|
+
recordModifiedEdges(sources, results, modifiedBy) {
|
|
313
|
+
this.modifiedEdges.push({ sources, results, modifiedBy });
|
|
314
|
+
}
|
|
315
|
+
recordRemovedFace(face, removedBy) {
|
|
316
|
+
if (this.isContainer()) {
|
|
317
|
+
for (const child of this.children) {
|
|
318
|
+
if (child.ownsFace(face)) {
|
|
319
|
+
child.recordRemovedFace(face, removedBy);
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
return;
|
|
323
|
+
}
|
|
324
|
+
this.removedFaces.push({ shape: face, removedBy });
|
|
325
|
+
}
|
|
326
|
+
recordRemovedEdge(edge, removedBy) {
|
|
327
|
+
if (this.isContainer()) {
|
|
328
|
+
for (const child of this.children) {
|
|
329
|
+
if (child.ownsEdge(edge)) {
|
|
330
|
+
child.recordRemovedEdge(edge, removedBy);
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
return;
|
|
334
|
+
}
|
|
335
|
+
this.removedEdges.push({ shape: edge, removedBy });
|
|
336
|
+
}
|
|
337
|
+
ownsFace(face) {
|
|
338
|
+
return this.addedFaces.some(r => r.shape === face);
|
|
339
|
+
}
|
|
340
|
+
ownsEdge(edge) {
|
|
341
|
+
return this.addedEdges.some(r => r.shape === edge);
|
|
342
|
+
}
|
|
343
|
+
getAddedFaces(scope) {
|
|
344
|
+
return this.addedFaces
|
|
345
|
+
.filter(r => !scope || scope.has(r.addedBy))
|
|
346
|
+
.map(r => r.shape);
|
|
347
|
+
}
|
|
348
|
+
getModifiedFaces(scope) {
|
|
349
|
+
return this.modifiedFaces.filter(r => !scope || scope.has(r.modifiedBy));
|
|
350
|
+
}
|
|
351
|
+
getRemovedFaces(scope) {
|
|
352
|
+
return this.removedFaces
|
|
353
|
+
.filter(r => !scope || scope.has(r.removedBy))
|
|
354
|
+
.map(r => r.shape);
|
|
355
|
+
}
|
|
356
|
+
getAddedEdges(scope) {
|
|
357
|
+
return this.addedEdges
|
|
358
|
+
.filter(r => !scope || scope.has(r.addedBy))
|
|
359
|
+
.map(r => r.shape);
|
|
360
|
+
}
|
|
361
|
+
getModifiedEdges(scope) {
|
|
362
|
+
return this.modifiedEdges.filter(r => !scope || scope.has(r.modifiedBy));
|
|
363
|
+
}
|
|
364
|
+
getRemovedEdges(scope) {
|
|
365
|
+
return this.removedEdges
|
|
366
|
+
.filter(r => !scope || scope.has(r.removedBy))
|
|
367
|
+
.map(r => r.shape);
|
|
368
|
+
}
|
|
369
|
+
setFinalShapes(shapes) {
|
|
370
|
+
this.finalShapes = shapes;
|
|
371
|
+
}
|
|
372
|
+
getFinalShapes() {
|
|
373
|
+
return this.finalShapes;
|
|
374
|
+
}
|
|
254
375
|
getOwnShapes(filter, scope) {
|
|
255
376
|
filter = {
|
|
256
377
|
excludeMeta: filter?.excludeMeta ?? true,
|
|
@@ -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):
|
|
7
|
+
static fromShape(shape: TopoDS_Shape): Solid | Face | Edge | Wire;
|
|
8
8
|
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { BRepBuilderAPI_MakeShape } from "occjs-wrapper";
|
|
2
|
+
import { Face } from "./face.js";
|
|
3
|
+
import { Edge } from "./edge.js";
|
|
4
|
+
import { Shape } from "./shape.js";
|
|
5
|
+
export type ShapeHistoryRecord<T> = {
|
|
6
|
+
sources: T[];
|
|
7
|
+
results: T[];
|
|
8
|
+
};
|
|
9
|
+
export type ShapeHistory = {
|
|
10
|
+
addedFaces: Face[];
|
|
11
|
+
modifiedFaces: ShapeHistoryRecord<Face>[];
|
|
12
|
+
generatedFaces: ShapeHistoryRecord<Face>[];
|
|
13
|
+
removedFaces: Face[];
|
|
14
|
+
addedEdges: Edge[];
|
|
15
|
+
modifiedEdges: ShapeHistoryRecord<Edge>[];
|
|
16
|
+
generatedEdges: ShapeHistoryRecord<Edge>[];
|
|
17
|
+
removedEdges: Edge[];
|
|
18
|
+
};
|
|
19
|
+
export declare class ShapeHistoryTracker {
|
|
20
|
+
/**
|
|
21
|
+
* Remap a list of pre-operation faces through a `ShapeHistory`'s
|
|
22
|
+
* modifications. For each input face:
|
|
23
|
+
* - If it appears as a source in `modifiedFaces`, emit the corresponding
|
|
24
|
+
* result faces (1:N).
|
|
25
|
+
* - Otherwise, pass it through unchanged (it survived the operation with
|
|
26
|
+
* the same TShape pointer).
|
|
27
|
+
*
|
|
28
|
+
* Use this to keep classification arrays (start/end/side/…) valid after a
|
|
29
|
+
* fusion has modified some of their faces.
|
|
30
|
+
*/
|
|
31
|
+
static remapFaces(faces: Face[], history: ShapeHistory): Face[];
|
|
32
|
+
static remapEdges(edges: Edge[], history: ShapeHistory): Edge[];
|
|
33
|
+
/**
|
|
34
|
+
* Collect history for `inputs` against `maker`'s output. When `opts.skipAdded`
|
|
35
|
+
* is set, the added* fields come back empty — callers that compute additions
|
|
36
|
+
* themselves (e.g. `recordFusionHistory` aggregates across all scene shapes)
|
|
37
|
+
* skip the per-call output traversal and per-result claimed-map updates.
|
|
38
|
+
*/
|
|
39
|
+
static collect(maker: BRepBuilderAPI_MakeShape, inputs: Shape[], opts?: {
|
|
40
|
+
skipAdded?: boolean;
|
|
41
|
+
}): ShapeHistory;
|
|
42
|
+
private static collectForType;
|
|
43
|
+
}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import { getOC } from "../oc/init.js";
|
|
2
|
+
import { Explorer } from "../oc/explorer.js";
|
|
3
|
+
import { ShapeOps } from "../oc/shape-ops.js";
|
|
4
|
+
import { Face } from "./face.js";
|
|
5
|
+
import { Edge } from "./edge.js";
|
|
6
|
+
export class ShapeHistoryTracker {
|
|
7
|
+
/**
|
|
8
|
+
* Remap a list of pre-operation faces through a `ShapeHistory`'s
|
|
9
|
+
* modifications. For each input face:
|
|
10
|
+
* - If it appears as a source in `modifiedFaces`, emit the corresponding
|
|
11
|
+
* result faces (1:N).
|
|
12
|
+
* - Otherwise, pass it through unchanged (it survived the operation with
|
|
13
|
+
* the same TShape pointer).
|
|
14
|
+
*
|
|
15
|
+
* Use this to keep classification arrays (start/end/side/…) valid after a
|
|
16
|
+
* fusion has modified some of their faces.
|
|
17
|
+
*/
|
|
18
|
+
static remapFaces(faces, history) {
|
|
19
|
+
const result = [];
|
|
20
|
+
for (const face of faces) {
|
|
21
|
+
const record = history.modifiedFaces.find(m => m.sources.some(s => s.getShape().IsSame(face.getShape())));
|
|
22
|
+
if (record) {
|
|
23
|
+
result.push(...record.results);
|
|
24
|
+
}
|
|
25
|
+
else {
|
|
26
|
+
result.push(face);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
return result;
|
|
30
|
+
}
|
|
31
|
+
static remapEdges(edges, history) {
|
|
32
|
+
const result = [];
|
|
33
|
+
for (const edge of edges) {
|
|
34
|
+
const record = history.modifiedEdges.find(m => m.sources.some(s => s.getShape().IsSame(edge.getShape())));
|
|
35
|
+
if (record) {
|
|
36
|
+
result.push(...record.results);
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
result.push(edge);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return result;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Collect history for `inputs` against `maker`'s output. When `opts.skipAdded`
|
|
46
|
+
* is set, the added* fields come back empty — callers that compute additions
|
|
47
|
+
* themselves (e.g. `recordFusionHistory` aggregates across all scene shapes)
|
|
48
|
+
* skip the per-call output traversal and per-result claimed-map updates.
|
|
49
|
+
*/
|
|
50
|
+
static collect(maker, inputs, opts = {}) {
|
|
51
|
+
const oc = getOC();
|
|
52
|
+
const FACE = oc.TopAbs_ShapeEnum.TopAbs_FACE;
|
|
53
|
+
const EDGE = oc.TopAbs_ShapeEnum.TopAbs_EDGE;
|
|
54
|
+
const skipAdded = opts.skipAdded === true;
|
|
55
|
+
const output = skipAdded ? null : maker.Shape();
|
|
56
|
+
const outputFaces = output ? Explorer.findShapes(output, FACE) : [];
|
|
57
|
+
const outputEdges = output ? Explorer.findShapes(output, EDGE) : [];
|
|
58
|
+
const faces = ShapeHistoryTracker.collectForType(maker, inputs, FACE, outputFaces, (raw) => Face.fromTopoDSFace(Explorer.toFace(raw)), skipAdded);
|
|
59
|
+
const edges = ShapeHistoryTracker.collectForType(maker, inputs, EDGE, outputEdges, (raw) => Edge.fromTopoDSEdge(Explorer.toEdge(raw)), skipAdded);
|
|
60
|
+
return {
|
|
61
|
+
addedFaces: faces.added,
|
|
62
|
+
modifiedFaces: faces.modified,
|
|
63
|
+
generatedFaces: faces.generated,
|
|
64
|
+
removedFaces: faces.removed,
|
|
65
|
+
addedEdges: edges.added,
|
|
66
|
+
modifiedEdges: edges.modified,
|
|
67
|
+
generatedEdges: edges.generated,
|
|
68
|
+
removedEdges: edges.removed,
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
static collectForType(maker, inputs, type, outputRaws, wrap, skipAdded) {
|
|
72
|
+
const oc = getOC();
|
|
73
|
+
const modified = [];
|
|
74
|
+
const generated = [];
|
|
75
|
+
const removed = [];
|
|
76
|
+
// Track which output raws are claimed by a Modified/Generated record so the
|
|
77
|
+
// remaining outputs can be reported as pure additions. When `skipAdded`,
|
|
78
|
+
// we don't compute additions, so skip the bookkeeping entirely.
|
|
79
|
+
const claimed = skipAdded ? null : new oc.TopTools_MapOfShape();
|
|
80
|
+
const isOfType = (raw) => raw.ShapeType() === type;
|
|
81
|
+
for (const input of inputs) {
|
|
82
|
+
const inputRaws = Explorer.findShapes(input.getShape(), type);
|
|
83
|
+
for (const inputRaw of inputRaws) {
|
|
84
|
+
const modifiedRaws = ShapeOps.shapeListToArray(maker.Modified(inputRaw)).filter(isOfType);
|
|
85
|
+
const generatedRaws = ShapeOps.shapeListToArray(maker.Generated(inputRaw)).filter(isOfType);
|
|
86
|
+
if (modifiedRaws.length > 0) {
|
|
87
|
+
modified.push({
|
|
88
|
+
sources: [wrap(inputRaw)],
|
|
89
|
+
results: modifiedRaws.map(wrap),
|
|
90
|
+
});
|
|
91
|
+
if (claimed) {
|
|
92
|
+
for (const r of modifiedRaws) {
|
|
93
|
+
claimed.Add(r);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
if (generatedRaws.length > 0) {
|
|
98
|
+
generated.push({
|
|
99
|
+
sources: [wrap(inputRaw)],
|
|
100
|
+
results: generatedRaws.map(wrap),
|
|
101
|
+
});
|
|
102
|
+
if (claimed) {
|
|
103
|
+
for (const r of generatedRaws) {
|
|
104
|
+
claimed.Add(r);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
// IsDeleted is only meaningful when the input has no successor. If
|
|
109
|
+
// Modified or Generated produced anything, that record already
|
|
110
|
+
// captures its fate — skip the (relatively expensive) IsDeleted call.
|
|
111
|
+
if (modifiedRaws.length === 0 && generatedRaws.length === 0
|
|
112
|
+
&& maker.IsDeleted(inputRaw)) {
|
|
113
|
+
removed.push(wrap(inputRaw));
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
const added = [];
|
|
118
|
+
if (claimed) {
|
|
119
|
+
for (const raw of outputRaws) {
|
|
120
|
+
if (!claimed.Contains(raw)) {
|
|
121
|
+
added.push(wrap(raw));
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
claimed.delete();
|
|
125
|
+
}
|
|
126
|
+
return { added, modified, generated, removed };
|
|
127
|
+
}
|
|
128
|
+
}
|
package/lib/dist/common/shape.js
CHANGED
|
@@ -87,7 +87,13 @@ export class Shape {
|
|
|
87
87
|
if (this.isVertex()) {
|
|
88
88
|
throw new Error("Cannot set color on vertex shape");
|
|
89
89
|
}
|
|
90
|
-
this.colorMap.
|
|
90
|
+
const existing = this.colorMap.findIndex(c => c.shape.IsSame(face));
|
|
91
|
+
if (existing >= 0) {
|
|
92
|
+
this.colorMap[existing] = { shape: face, color };
|
|
93
|
+
}
|
|
94
|
+
else {
|
|
95
|
+
this.colorMap.push({ shape: face, color });
|
|
96
|
+
}
|
|
91
97
|
}
|
|
92
98
|
getColor(face) {
|
|
93
99
|
const entry = this.colorMap.find(c => c.shape.IsSame(face));
|
package/lib/dist/common/solid.js
CHANGED
|
@@ -60,7 +60,11 @@ export class Solid extends Shape {
|
|
|
60
60
|
return null;
|
|
61
61
|
}
|
|
62
62
|
copy() {
|
|
63
|
-
|
|
63
|
+
const copied = new Solid(this.getShape());
|
|
64
|
+
for (const entry of this.colorMap) {
|
|
65
|
+
copied.colorMap.push({ shape: entry.shape, color: entry.color });
|
|
66
|
+
}
|
|
67
|
+
return copied;
|
|
64
68
|
}
|
|
65
69
|
static fromTopoDSSolid(solid) {
|
|
66
70
|
return new Solid(solid);
|
|
@@ -10,19 +10,19 @@ interface ALineFunction {
|
|
|
10
10
|
(length: number, angle: number, centered?: boolean): IGeometry;
|
|
11
11
|
/**
|
|
12
12
|
* Draws a line at the given angle on a specific plane.
|
|
13
|
+
* @param targetPlane - The plane to draw on
|
|
13
14
|
* @param length - The line length
|
|
14
15
|
* @param angle - The angle in degrees
|
|
15
|
-
* @param targetPlane - The plane to draw on
|
|
16
16
|
*/
|
|
17
|
-
(
|
|
17
|
+
(targetPlane: PlaneLike | ISceneObject, length: number, angle: number): IGeometry;
|
|
18
18
|
/**
|
|
19
19
|
* Draws a centered line at the given angle on a specific plane.
|
|
20
|
+
* @param targetPlane - The plane to draw on
|
|
20
21
|
* @param length - The line length
|
|
21
22
|
* @param angle - The angle in degrees
|
|
22
23
|
* @param centered - Whether to center the line on the current position
|
|
23
|
-
* @param targetPlane - The plane to draw on
|
|
24
24
|
*/
|
|
25
|
-
(length: number, angle: number, centered: boolean
|
|
25
|
+
(targetPlane: PlaneLike | ISceneObject, length: number, angle: number, centered: boolean): IGeometry;
|
|
26
26
|
}
|
|
27
27
|
declare const _default: ALineFunction;
|
|
28
28
|
export default _default;
|
|
@@ -6,18 +6,22 @@ import { resolvePlane } from "../../helpers/resolve.js";
|
|
|
6
6
|
function build(context) {
|
|
7
7
|
return function line() {
|
|
8
8
|
let planeObj = null;
|
|
9
|
-
let
|
|
10
|
-
// Detect plane as
|
|
11
|
-
if (
|
|
12
|
-
const
|
|
13
|
-
if (isPlaneLike(
|
|
14
|
-
|
|
15
|
-
|
|
9
|
+
let argOffset = 0;
|
|
10
|
+
// Detect plane as first argument (only valid outside a sketch)
|
|
11
|
+
if (arguments.length > 0) {
|
|
12
|
+
const firstArg = arguments[0];
|
|
13
|
+
if (isPlaneLike(firstArg) || firstArg instanceof SceneObject) {
|
|
14
|
+
if (context.getActiveSketch() !== null) {
|
|
15
|
+
throw new Error("aLine(plane, ...) cannot be used inside a sketch. Use aLine(...) instead.");
|
|
16
|
+
}
|
|
17
|
+
planeObj = resolvePlane(firstArg, context);
|
|
18
|
+
argOffset = 1;
|
|
16
19
|
}
|
|
17
20
|
}
|
|
18
|
-
const
|
|
19
|
-
const
|
|
20
|
-
const
|
|
21
|
+
const argCount = arguments.length - argOffset;
|
|
22
|
+
const length = arguments[argOffset];
|
|
23
|
+
const angle = arguments[argOffset + 1];
|
|
24
|
+
const centered = argCount >= 3 ? arguments[argOffset + 2] : false;
|
|
21
25
|
const aline = new AngledLine(length, angle, centered, planeObj);
|
|
22
26
|
context.addSceneObject(aline);
|
|
23
27
|
return aline;
|
|
@@ -26,25 +26,25 @@ interface ArcFunction {
|
|
|
26
26
|
(radius: number, startAngle?: number, endAngle?: number): IArcAngles;
|
|
27
27
|
/**
|
|
28
28
|
* Draws an arc to an end point on a specific plane.
|
|
29
|
-
* @param endPoint - The end point of the arc
|
|
30
29
|
* @param targetPlane - The plane to draw on
|
|
30
|
+
* @param endPoint - The end point of the arc
|
|
31
31
|
*/
|
|
32
|
-
(
|
|
32
|
+
(targetPlane: PlaneLike | ISceneObject, endPoint: Point2DLike): IArcPoints;
|
|
33
33
|
/**
|
|
34
34
|
* Draws an arc between two points on a specific plane.
|
|
35
|
+
* @param targetPlane - The plane to draw on
|
|
35
36
|
* @param startPoint - The start point of the arc
|
|
36
37
|
* @param endPoint - The end point of the arc
|
|
37
|
-
* @param targetPlane - The plane to draw on
|
|
38
38
|
*/
|
|
39
|
-
(
|
|
39
|
+
(targetPlane: PlaneLike | ISceneObject, startPoint: Point2DLike, endPoint: Point2DLike): IArcPoints;
|
|
40
40
|
/**
|
|
41
41
|
* Draws an arc by radius and angle range on a specific plane.
|
|
42
|
+
* @param targetPlane - The plane to draw on
|
|
42
43
|
* @param radius - The arc radius
|
|
43
44
|
* @param startAngle - The start angle in degrees
|
|
44
45
|
* @param endAngle - The end angle in degrees
|
|
45
|
-
* @param targetPlane - The plane to draw on
|
|
46
46
|
*/
|
|
47
|
-
(radius: number, startAngle: number, endAngle: number
|
|
47
|
+
(targetPlane: PlaneLike | ISceneObject, radius: number, startAngle: number, endAngle: number): IArcAngles;
|
|
48
48
|
}
|
|
49
49
|
declare const _default: ArcFunction;
|
|
50
50
|
export default _default;
|
package/lib/dist/core/2d/arc.js
CHANGED
|
@@ -8,34 +8,38 @@ import { resolvePlane } from "../../helpers/resolve.js";
|
|
|
8
8
|
function build(context) {
|
|
9
9
|
return function arc() {
|
|
10
10
|
let planeObj = null;
|
|
11
|
-
let
|
|
12
|
-
// Detect plane as
|
|
13
|
-
if (
|
|
14
|
-
const
|
|
15
|
-
if (isPlaneLike(
|
|
16
|
-
|
|
17
|
-
|
|
11
|
+
let argOffset = 0;
|
|
12
|
+
// Detect plane as first argument (only valid outside a sketch)
|
|
13
|
+
if (arguments.length > 0) {
|
|
14
|
+
const firstArg = arguments[0];
|
|
15
|
+
if (isPlaneLike(firstArg) || (firstArg instanceof SceneObject && !isPoint2DLike(firstArg))) {
|
|
16
|
+
if (context.getActiveSketch() !== null) {
|
|
17
|
+
throw new Error("arc(plane, ...) cannot be used inside a sketch. Use arc(...) instead.");
|
|
18
|
+
}
|
|
19
|
+
planeObj = resolvePlane(firstArg, context);
|
|
20
|
+
argOffset = 1;
|
|
18
21
|
}
|
|
19
22
|
}
|
|
23
|
+
const argCount = arguments.length - argOffset;
|
|
20
24
|
// (startPoint, endPoint) — two Point2DLike args, default center = current position
|
|
21
|
-
if (argCount >= 2 && isPoint2DLike(arguments[
|
|
22
|
-
const start = normalizePoint2D(arguments[
|
|
23
|
-
const end = normalizePoint2D(arguments[1]);
|
|
25
|
+
if (argCount >= 2 && isPoint2DLike(arguments[argOffset]) && isPoint2DLike(arguments[argOffset + 1])) {
|
|
26
|
+
const start = normalizePoint2D(arguments[argOffset]);
|
|
27
|
+
const end = normalizePoint2D(arguments[argOffset + 1]);
|
|
24
28
|
const arcObj = Arc.twoPoints(start, end, planeObj);
|
|
25
29
|
context.addSceneObject(arcObj);
|
|
26
30
|
return arcObj;
|
|
27
31
|
}
|
|
28
32
|
// (endPoint) — single Point2DLike arg
|
|
29
|
-
if (isPoint2DLike(arguments[
|
|
30
|
-
const end = normalizePoint2D(arguments[
|
|
33
|
+
if (isPoint2DLike(arguments[argOffset])) {
|
|
34
|
+
const end = normalizePoint2D(arguments[argOffset]);
|
|
31
35
|
const arcObj = Arc.toPoint(end, planeObj);
|
|
32
36
|
context.addSceneObject(arcObj);
|
|
33
37
|
return arcObj;
|
|
34
38
|
}
|
|
35
39
|
// (radius, startAngle?, endAngle?) — all numeric args
|
|
36
|
-
const radius = arguments[
|
|
37
|
-
const startAngle = arguments[1] || 0;
|
|
38
|
-
const endAngle = argCount >= 3 ? arguments[2] : 180;
|
|
40
|
+
const radius = arguments[argOffset] || 100;
|
|
41
|
+
const startAngle = arguments[argOffset + 1] || 0;
|
|
42
|
+
const endAngle = argCount >= 3 ? arguments[argOffset + 2] : 180;
|
|
39
43
|
const arcObj = Arc.fromAngles(radius, startAngle, endAngle, planeObj);
|
|
40
44
|
context.addSceneObject(arcObj);
|
|
41
45
|
return arcObj;
|
|
@@ -15,10 +15,10 @@ interface CircleFunction {
|
|
|
15
15
|
(diameter?: number): IExtrudableGeometry;
|
|
16
16
|
/**
|
|
17
17
|
* Draws a circle with a given diameter on a specific plane.
|
|
18
|
-
* @param diameter - The circle diameter
|
|
19
18
|
* @param targetPlane - The plane to draw on
|
|
19
|
+
* @param diameter - The circle diameter
|
|
20
20
|
*/
|
|
21
|
-
(
|
|
21
|
+
(targetPlane: PlaneLike | ISceneObject, diameter: number): IExtrudableGeometry;
|
|
22
22
|
}
|
|
23
23
|
declare const _default: CircleFunction;
|
|
24
24
|
export default _default;
|