@constructorfleet/sketchforge-engine 1.24.1 → 1.26.0
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/dist/cadFaceMesh.d.ts +31 -0
- package/dist/cadFaceMesh.d.ts.map +1 -0
- package/dist/cadFaceMesh.js +50 -0
- package/dist/cadFaceMesh.js.map +1 -0
- package/dist/cadSolids.d.ts +32 -0
- package/dist/cadSolids.d.ts.map +1 -1
- package/dist/cadSolids.js +45 -12
- package/dist/cadSolids.js.map +1 -1
- package/dist/engine.d.ts.map +1 -1
- package/dist/engine.js +16 -67
- package/dist/engine.js.map +1 -1
- package/dist/faceDraftSegmentLineage.d.ts +2 -37
- package/dist/faceDraftSegmentLineage.d.ts.map +1 -1
- package/dist/faceDraftSegmentLineage.js +6 -190
- package/dist/faceDraftSegmentLineage.js.map +1 -1
- package/dist/serverCadMeasure.d.ts.map +1 -1
- package/dist/serverCadMeasure.js +33 -2
- package/dist/serverCadMeasure.js.map +1 -1
- package/dist/serverCadOperations.d.ts +14 -43
- package/dist/serverCadOperations.d.ts.map +1 -1
- package/dist/serverCadOperations.js +44 -142
- package/dist/serverCadOperations.js.map +1 -1
- package/dist/serverShapeBooleans.js +1 -1
- package/dist/serverShapeBooleans.js.map +1 -1
- package/dist/sketchExtrusionRequest.d.ts.map +1 -1
- package/dist/sketchExtrusionRequest.js +2 -25
- package/dist/sketchExtrusionRequest.js.map +1 -1
- package/dist/sketchExtrusionSolid.d.ts +4 -0
- package/dist/sketchExtrusionSolid.d.ts.map +1 -0
- package/dist/sketchExtrusionSolid.js +36 -0
- package/dist/sketchExtrusionSolid.js.map +1 -0
- package/dist/sketchFaceDraftKernel.d.ts +248 -0
- package/dist/sketchFaceDraftKernel.d.ts.map +1 -0
- package/dist/sketchFaceDraftKernel.js +573 -0
- package/dist/sketchFaceDraftKernel.js.map +1 -0
- package/dist/support/cadModifierTypes.d.ts +45 -0
- package/dist/support/cadModifierTypes.d.ts.map +1 -1
- package/dist/support/i18n/locales/en/messages.json +3 -1
- package/dist/support/lib/operator-configuration.json +11 -0
- package/dist/workplaneShapes.d.ts +6 -0
- package/dist/workplaneShapes.d.ts.map +1 -1
- package/dist/workplaneShapes.js +25 -70
- package/dist/workplaneShapes.js.map +1 -1
- package/package.json +1 -1
package/dist/serverCadMeasure.js
CHANGED
|
@@ -29,9 +29,10 @@
|
|
|
29
29
|
*/
|
|
30
30
|
import { circularEdgeRadius, faceRadius, planarFaceAngle, } from "./cadMeasurements.js";
|
|
31
31
|
import { withCadKernel } from "./serverCadKernel.js";
|
|
32
|
-
import { edgeSolidForShape, orientedSolidForShape, ServerCadError } from "./serverCadOperations.js";
|
|
32
|
+
import { edgeSolidForShape, orientedSolidForShape, ServerCadError, treatmentBakesRotation } from "./serverCadOperations.js";
|
|
33
33
|
import { faceOutwardNormal } from "./serverCadShell.js";
|
|
34
34
|
import { placedSolidForShape } from "./serverShapeBooleans.js";
|
|
35
|
+
import { shapePlacementMatrix } from "./serverShapeGroups.js";
|
|
35
36
|
function edgeMeasurement(cad, handle, index) {
|
|
36
37
|
let geometryType = "unknown";
|
|
37
38
|
try {
|
|
@@ -124,7 +125,37 @@ function resolveTarget(cad, target, label) {
|
|
|
124
125
|
// listings use, and which is right for them -- hands back the solid in its own
|
|
125
126
|
// frame with the rotation applied and the translation not. Two parts 60mm
|
|
126
127
|
// apart both measured from the origin through that, so this read zero.
|
|
127
|
-
|
|
128
|
+
// Edges have their own canonical solid: for an untreated plain revolve it
|
|
129
|
+
// is rebuilt from the retained profile, exactly like GET /edges and edge
|
|
130
|
+
// treatments. The stored mesh has many more edges and cannot resolve those
|
|
131
|
+
// listed indexes. Faces continue to use their existing placed solid.
|
|
132
|
+
let solid;
|
|
133
|
+
if (target.entity === "edge") {
|
|
134
|
+
solid = edgeSolidForShape(cad, target.shape);
|
|
135
|
+
// The edge listing and treatment solid is in the shape frame: its mirror
|
|
136
|
+
// is already applied, while a treatment may bake a parametric shape's
|
|
137
|
+
// rotation into the geometry. Put that same solid where it sits without
|
|
138
|
+
// applying either transform twice. Untreated revolves are the exception:
|
|
139
|
+
// their exact edge solid is rebuilt from the profile before rotation.
|
|
140
|
+
const rotationAlreadyApplied = treatmentBakesRotation(target.shape)
|
|
141
|
+
&& target.shape.sketchOperation !== "revolve";
|
|
142
|
+
const placementShape = {
|
|
143
|
+
...target.shape,
|
|
144
|
+
mirrorX: undefined,
|
|
145
|
+
mirrorY: undefined,
|
|
146
|
+
mirrorZ: undefined,
|
|
147
|
+
...(rotationAlreadyApplied ? { rotation: 0, rotationX: 0, rotationZ: 0 } : {}),
|
|
148
|
+
};
|
|
149
|
+
const elements = shapePlacementMatrix(placementShape).elements;
|
|
150
|
+
solid = cad.transform(solid, [
|
|
151
|
+
elements[0], elements[4], elements[8], elements[12],
|
|
152
|
+
elements[1], elements[5], elements[9], elements[13],
|
|
153
|
+
elements[2], elements[6], elements[10], elements[14],
|
|
154
|
+
]);
|
|
155
|
+
}
|
|
156
|
+
else {
|
|
157
|
+
solid = placedSolidForShape(cad, target.shape);
|
|
158
|
+
}
|
|
128
159
|
if (target.entity === "shape") {
|
|
129
160
|
return { handle: solid, face: null };
|
|
130
161
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"serverCadMeasure.js","sourceRoot":"","sources":["../src/serverCadMeasure.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAGH,OAAO,EACL,kBAAkB,EAClB,UAAU,EACV,eAAe,GAGhB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,iBAAiB,EAAE,qBAAqB,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;
|
|
1
|
+
{"version":3,"file":"serverCadMeasure.js","sourceRoot":"","sources":["../src/serverCadMeasure.ts"],"names":[],"mappings":"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"}
|
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
*/
|
|
17
17
|
import type { EvolutionData, OcctKernel, ShapeHandle } from "occt-wasm";
|
|
18
18
|
import type { SketchProfile, WorkplaneShape } from "./domain/sketchforge.js";
|
|
19
|
+
import { type SketchFaceDraftRequest } from "./sketchFaceDraftKernel.js";
|
|
19
20
|
export type ServerCadEdge = {
|
|
20
21
|
index: number;
|
|
21
22
|
length: number;
|
|
@@ -46,43 +47,7 @@ export declare class ServerCadError extends Error {
|
|
|
46
47
|
readonly status: number;
|
|
47
48
|
constructor(message: string, status?: number);
|
|
48
49
|
}
|
|
49
|
-
|
|
50
|
-
readonly x: {
|
|
51
|
-
readonly x: 1;
|
|
52
|
-
readonly y: 0;
|
|
53
|
-
readonly z: 0;
|
|
54
|
-
};
|
|
55
|
-
readonly y: {
|
|
56
|
-
readonly x: 0;
|
|
57
|
-
readonly y: 1;
|
|
58
|
-
readonly z: 0;
|
|
59
|
-
};
|
|
60
|
-
readonly z: {
|
|
61
|
-
readonly x: 0;
|
|
62
|
-
readonly y: 0;
|
|
63
|
-
readonly z: 1;
|
|
64
|
-
};
|
|
65
|
-
readonly "-x": {
|
|
66
|
-
readonly x: -1;
|
|
67
|
-
readonly y: 0;
|
|
68
|
-
readonly z: 0;
|
|
69
|
-
};
|
|
70
|
-
readonly "-y": {
|
|
71
|
-
readonly x: 0;
|
|
72
|
-
readonly y: -1;
|
|
73
|
-
readonly z: 0;
|
|
74
|
-
};
|
|
75
|
-
readonly "-z": {
|
|
76
|
-
readonly x: 0;
|
|
77
|
-
readonly y: 0;
|
|
78
|
-
readonly z: -1;
|
|
79
|
-
};
|
|
80
|
-
};
|
|
81
|
-
export type SketchFaceDraftRequest = {
|
|
82
|
-
sourceFaceId: string;
|
|
83
|
-
angle: number;
|
|
84
|
-
pullDirection: keyof typeof DRAFT_PULL_AXES;
|
|
85
|
-
};
|
|
50
|
+
export type { SketchFaceDraftRequest } from "./sketchFaceDraftKernel.js";
|
|
86
51
|
/**
|
|
87
52
|
* Whether the kernel considers a shape sound.
|
|
88
53
|
*
|
|
@@ -131,8 +96,12 @@ export declare function localSolidForShape(cad: OcctKernel, shape: WorkplaneShap
|
|
|
131
96
|
* straightened. `treatmentBakesRotation` is the other half of that bargain and
|
|
132
97
|
* reads the same predicate.
|
|
133
98
|
*
|
|
134
|
-
* For stored geometry this is the local solid
|
|
135
|
-
* the shape, which is where it already was.
|
|
99
|
+
* For stored geometry this is the local solid with only its mirror applied:
|
|
100
|
+
* the rotation stays on the shape, which is where it already was.
|
|
101
|
+
*
|
|
102
|
+
* Mirrored either way, because the result is stored with the shape's mirror
|
|
103
|
+
* flags cleared. Building it unmirrored handed back the unmirrored shape and
|
|
104
|
+
* reported success (#413).
|
|
136
105
|
*/
|
|
137
106
|
export declare function orientedSolidForShape(cad: OcctKernel, shape: WorkplaneShape): ShapeHandle;
|
|
138
107
|
/** The edges of a shape, in the order a treatment request refers to them by index. */
|
|
@@ -175,6 +144,7 @@ export declare function allEdgeTreatmentEdgeCount(shape: WorkplaneShape, _kind:
|
|
|
175
144
|
* the treatment. For an untreated revolve that is the exact solid rebuilt from
|
|
176
145
|
* its profile (#347); a revolve with no exact solid is refused rather than
|
|
177
146
|
* listed or treated by its facets. Everything else is the oriented solid.
|
|
147
|
+
* Both carry the shape's mirror, which the treated result no longer does.
|
|
178
148
|
*/
|
|
179
149
|
export declare function edgeSolidForShape(cad: OcctKernel, shape: WorkplaneShape): ShapeHandle;
|
|
180
150
|
/** Build the analytical full-turn BREP for chamfering a retained plain revolve. */
|
|
@@ -189,9 +159,11 @@ export declare function exactPlainSketchRevolveResult(shape: WorkplaneShape): Pr
|
|
|
189
159
|
/**
|
|
190
160
|
* Apply a prism draft along the shape's vertical extrusion axis.
|
|
191
161
|
*
|
|
192
|
-
*
|
|
193
|
-
*
|
|
194
|
-
*
|
|
162
|
+
* The geometry only: the caller records the retained angle and source frame
|
|
163
|
+
* (`retainedPrismDraftFields`) that a sketch edit replays it from. The B-rep
|
|
164
|
+
* is built about the centre of the profile's bounds
|
|
165
|
+
* (`draftPrismProfileOffset`), and the exact BREP and viewport mesh are
|
|
166
|
+
* persisted together, as with shell and edge treatments.
|
|
195
167
|
*/
|
|
196
168
|
export declare function applyDraftPrism(shape: WorkplaneShape, request: {
|
|
197
169
|
angle: number;
|
|
@@ -213,5 +185,4 @@ export declare function meshedCadResult(cad: OcctKernel, result: ShapeHandle, so
|
|
|
213
185
|
* the viewport expects -- so the shape keeps its place on the workplane.
|
|
214
186
|
*/
|
|
215
187
|
export declare function shapeWithCadResult(shape: WorkplaneShape, result: ServerCadResult): WorkplaneShape;
|
|
216
|
-
export {};
|
|
217
188
|
//# sourceMappingURL=serverCadOperations.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"serverCadOperations.d.ts","sourceRoot":"","sources":["../src/serverCadOperations.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"serverCadOperations.d.ts","sourceRoot":"","sources":["../src/serverCadOperations.ts"],"names":[],"mappings":"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"}
|
|
@@ -16,11 +16,13 @@
|
|
|
16
16
|
*/
|
|
17
17
|
import { faceIdsFromEvolution } from "./faceLineage.js";
|
|
18
18
|
import { withCadKernel } from "./serverCadKernel.js";
|
|
19
|
-
import { exactSolidForShape, shapeIsTurned, unrotatedSolidForShape, UnbuildableShapeError, EXACT_SOLID_KINDS, } from "./cadSolids.js";
|
|
19
|
+
import { exactSolidForShape, mirroredInShapeFrame, shapeIsTurned, unrotatedSolidForShape, UnbuildableShapeError, EXACT_SOLID_KINDS, } from "./cadSolids.js";
|
|
20
20
|
import { canonicalizeShape } from "./workplaneShapes.js";
|
|
21
21
|
import { createLocalId } from "./localIds.js";
|
|
22
22
|
import { cadSketchRegions } from "./sketchCadProfile.js";
|
|
23
23
|
import { normalizeSketchRevolveSettings, sketchProfileToRevolvePolygons } from "./sketchRevolve.js";
|
|
24
|
+
import { triangleFaceGroups } from "./cadFaceMesh.js";
|
|
25
|
+
import { draftSketchFace, draftPrismProfileOffset, faceIdsForCadResult } from "./sketchFaceDraftKernel.js";
|
|
24
26
|
export class ServerCadError extends Error {
|
|
25
27
|
status;
|
|
26
28
|
constructor(message, status = 422) {
|
|
@@ -32,10 +34,6 @@ export class ServerCadError extends Error {
|
|
|
32
34
|
const MESH_DEFLECTION = 0.1;
|
|
33
35
|
const MIN_CAD_DIMENSION = 0.01;
|
|
34
36
|
const FACE_HASH_UPPER_BOUND = 2_147_483_647;
|
|
35
|
-
const DRAFT_PULL_AXES = {
|
|
36
|
-
x: { x: 1, y: 0, z: 0 }, y: { x: 0, y: 1, z: 0 }, z: { x: 0, y: 0, z: 1 },
|
|
37
|
-
"-x": { x: -1, y: 0, z: 0 }, "-y": { x: 0, y: -1, z: 0 }, "-z": { x: 0, y: 0, z: -1 },
|
|
38
|
-
};
|
|
39
37
|
function meshPositionsOf(shape) {
|
|
40
38
|
const positions = shape.importedMesh?.positions;
|
|
41
39
|
return positions && positions.length >= 9 ? positions : null;
|
|
@@ -184,12 +182,16 @@ export function localSolidForShape(cad, shape) {
|
|
|
184
182
|
* straightened. `treatmentBakesRotation` is the other half of that bargain and
|
|
185
183
|
* reads the same predicate.
|
|
186
184
|
*
|
|
187
|
-
* For stored geometry this is the local solid
|
|
188
|
-
* the shape, which is where it already was.
|
|
185
|
+
* For stored geometry this is the local solid with only its mirror applied:
|
|
186
|
+
* the rotation stays on the shape, which is where it already was.
|
|
187
|
+
*
|
|
188
|
+
* Mirrored either way, because the result is stored with the shape's mirror
|
|
189
|
+
* flags cleared. Building it unmirrored handed back the unmirrored shape and
|
|
190
|
+
* reported success (#413).
|
|
189
191
|
*/
|
|
190
192
|
export function orientedSolidForShape(cad, shape) {
|
|
191
193
|
if (!rotationIsRebuilt(shape))
|
|
192
|
-
return localSolidForShape(cad, shape);
|
|
194
|
+
return mirroredStoredSolid(cad, localSolidForShape(cad, shape), shape);
|
|
193
195
|
try {
|
|
194
196
|
return exactSolidForShape(cad, shape);
|
|
195
197
|
}
|
|
@@ -199,6 +201,25 @@ export function orientedSolidForShape(cad, shape) {
|
|
|
199
201
|
throw error;
|
|
200
202
|
}
|
|
201
203
|
}
|
|
204
|
+
/**
|
|
205
|
+
* A solid stored on the shape -- its BREP, its mesh, or a revolve rebuilt from
|
|
206
|
+
* its profile -- with the shape's mirror flags applied about its own centre.
|
|
207
|
+
*
|
|
208
|
+
* The bounds centre rather than the origin, because stored geometry is not
|
|
209
|
+
* always in the builders' frame (an earlier treatment's BREP keeps whatever
|
|
210
|
+
* frame it was made in); the viewport mirrors the normalized mesh about its
|
|
211
|
+
* centre, and a plane through any other point would only move the result.
|
|
212
|
+
*/
|
|
213
|
+
function mirroredStoredSolid(cad, solid, shape) {
|
|
214
|
+
if (!shape.mirrorX && !shape.mirrorY && !shape.mirrorZ)
|
|
215
|
+
return solid;
|
|
216
|
+
const bounds = cad.getBoundingBox(solid, false);
|
|
217
|
+
return mirroredInShapeFrame(cad, solid, shape, {
|
|
218
|
+
x: (bounds.xmin + bounds.xmax) / 2,
|
|
219
|
+
y: (bounds.ymin + bounds.ymax) / 2,
|
|
220
|
+
z: (bounds.zmin + bounds.zmax) / 2,
|
|
221
|
+
});
|
|
222
|
+
}
|
|
202
223
|
/** How many faces of the solid meet along this edge. A seam reports one. */
|
|
203
224
|
function adjacentFaceCount(cad, solid, handle) {
|
|
204
225
|
try {
|
|
@@ -272,12 +293,7 @@ export function applyBakedMirror(shape, axis, pivot) {
|
|
|
272
293
|
throw error;
|
|
273
294
|
}
|
|
274
295
|
const centerY = shape.height / 2;
|
|
275
|
-
|
|
276
|
-
solid = cad.mirror(solid, { x: 0, y: 0, z: 0 }, { x: 1, y: 0, z: 0 });
|
|
277
|
-
if (shape.mirrorY)
|
|
278
|
-
solid = cad.mirror(solid, { x: 0, y: centerY, z: 0 }, { x: 0, y: 1, z: 0 });
|
|
279
|
-
if (shape.mirrorZ)
|
|
280
|
-
solid = cad.mirror(solid, { x: 0, y: 0, z: 0 }, { x: 0, y: 0, z: 1 });
|
|
296
|
+
solid = mirroredInShapeFrame(cad, solid, shape, { x: 0, y: centerY, z: 0 });
|
|
281
297
|
const center = { x: 0, y: centerY, z: 0 };
|
|
282
298
|
const angle = (degrees) => degrees * Math.PI / 180;
|
|
283
299
|
if (shape.rotationZ)
|
|
@@ -482,12 +498,14 @@ function exactRevolveSolidForShape(cad, shape) {
|
|
|
482
498
|
* the treatment. For an untreated revolve that is the exact solid rebuilt from
|
|
483
499
|
* its profile (#347); a revolve with no exact solid is refused rather than
|
|
484
500
|
* listed or treated by its facets. Everything else is the oriented solid.
|
|
501
|
+
* Both carry the shape's mirror, which the treated result no longer does.
|
|
485
502
|
*/
|
|
486
503
|
export function edgeSolidForShape(cad, shape) {
|
|
487
504
|
const refusal = revolveWithoutExactEdges(shape);
|
|
488
505
|
if (refusal)
|
|
489
506
|
throw new ServerCadError(refusal);
|
|
490
|
-
|
|
507
|
+
const revolve = exactRevolveSolidForShape(cad, shape);
|
|
508
|
+
return revolve ? mirroredStoredSolid(cad, revolve, shape) : orientedSolidForShape(cad, shape);
|
|
491
509
|
}
|
|
492
510
|
/** Build the analytical full-turn BREP for chamfering a retained plain revolve. */
|
|
493
511
|
export function isPlainFullTurnSketchRevolve(shape) {
|
|
@@ -589,9 +607,11 @@ export function exactPlainSketchRevolveResult(shape) {
|
|
|
589
607
|
/**
|
|
590
608
|
* Apply a prism draft along the shape's vertical extrusion axis.
|
|
591
609
|
*
|
|
592
|
-
*
|
|
593
|
-
*
|
|
594
|
-
*
|
|
610
|
+
* The geometry only: the caller records the retained angle and source frame
|
|
611
|
+
* (`retainedPrismDraftFields`) that a sketch edit replays it from. The B-rep
|
|
612
|
+
* is built about the centre of the profile's bounds
|
|
613
|
+
* (`draftPrismProfileOffset`), and the exact BREP and viewport mesh are
|
|
614
|
+
* persisted together, as with shell and edge treatments.
|
|
595
615
|
*/
|
|
596
616
|
export function applyDraftPrism(shape, request) {
|
|
597
617
|
if (!Number.isFinite(request.angle) || request.angle === 0 || Math.abs(request.angle) >= 45) {
|
|
@@ -609,12 +629,7 @@ export function applyDraftPrism(shape, request) {
|
|
|
609
629
|
return Promise.reject(new ServerCadError("Draft prism currently requires one closed polygonal sketch profile made from straight segments.", 400));
|
|
610
630
|
}
|
|
611
631
|
return withCadKernel((cad) => {
|
|
612
|
-
const
|
|
613
|
-
const maxX = Math.max(...points.map(({ x }) => x));
|
|
614
|
-
const minZ = Math.min(...points.map(({ z }) => z));
|
|
615
|
-
const maxZ = Math.max(...points.map(({ z }) => z));
|
|
616
|
-
const centerX = (minX + maxX) / 2;
|
|
617
|
-
const centerZ = (minZ + maxZ) / 2;
|
|
632
|
+
const { x: centerX, z: centerZ } = draftPrismProfileOffset(shape.sketchProfile);
|
|
618
633
|
const edges = points.map((point, index) => {
|
|
619
634
|
const next = points[(index + 1) % points.length];
|
|
620
635
|
return cad.makeLineEdge({ x: point.x - centerX, y: 0, z: point.z - centerZ }, { x: next.x - centerX, y: 0, z: next.z - centerZ });
|
|
@@ -663,75 +678,15 @@ export function applySketchFaceDraft(shape, request) {
|
|
|
663
678
|
const face = faces[selected[0]];
|
|
664
679
|
if (!face)
|
|
665
680
|
throw new ServerCadError("The selected source face is no longer available.");
|
|
666
|
-
const
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
try {
|
|
670
|
-
drafted = cad.draft(solid, face, angle, direction);
|
|
671
|
-
}
|
|
672
|
-
catch {
|
|
673
|
-
const rotation = canonicalDraftRotation(request.pullDirection);
|
|
674
|
-
try {
|
|
675
|
-
if (!rotation)
|
|
676
|
-
throw new Error("No canonical rotation for the selected pull axis.");
|
|
677
|
-
const rotatedSolid = cad.rotate(solid, rotation.axis, rotation.angle);
|
|
678
|
-
const oldNormal = faceNormal(cad, face);
|
|
679
|
-
if (!oldNormal)
|
|
680
|
-
throw new Error("The selected face has no usable normal.");
|
|
681
|
-
const targetNormal = rotateVector(oldNormal, rotation.axis.direction, rotation.angle);
|
|
682
|
-
const targetCenter = rotateVector(cad.getSurfaceCenterOfMass(face), rotation.axis.direction, rotation.angle);
|
|
683
|
-
const bounds = cad.getBoundingBox(solid, false);
|
|
684
|
-
const scale = Math.max(1, Math.hypot(bounds.xmax - bounds.xmin, bounds.ymax - bounds.ymin, bounds.zmax - bounds.zmin));
|
|
685
|
-
const matches = cad.getSubShapes(rotatedSolid, "face").filter((candidate) => {
|
|
686
|
-
const normal = faceNormal(cad, candidate);
|
|
687
|
-
const center = cad.getSurfaceCenterOfMass(candidate);
|
|
688
|
-
return normal && Math.hypot(normal.x - targetNormal.x, normal.y - targetNormal.y, normal.z - targetNormal.z) <= 1e-7
|
|
689
|
-
&& Math.hypot(center.x - targetCenter.x, center.y - targetCenter.y, center.z - targetCenter.z) <= scale * 1e-8;
|
|
690
|
-
});
|
|
691
|
-
if (matches.length !== 1)
|
|
692
|
-
throw new Error("Could not uniquely identify the selected face after rotating the solid.");
|
|
693
|
-
const canonicalDraft = cad.draft(rotatedSolid, matches[0], angle, { x: 0, y: 0, z: 1 });
|
|
694
|
-
drafted = cad.rotate(canonicalDraft, rotation.axis, -rotation.angle);
|
|
695
|
-
}
|
|
696
|
-
catch {
|
|
697
|
-
throw new ServerCadError("The selected source face cannot be drafted along that local pull axis and angle.");
|
|
698
|
-
}
|
|
699
|
-
}
|
|
681
|
+
const drafted = draftSketchFace(cad, solid, face, request);
|
|
682
|
+
if (!drafted)
|
|
683
|
+
throw new ServerCadError("The selected source face cannot be drafted along that local pull axis and angle.");
|
|
700
684
|
if (!cadResultIsValid(cad, drafted) || !cad.isSolid(drafted)) {
|
|
701
685
|
throw new ServerCadError("The face draft did not produce a valid solid.");
|
|
702
686
|
}
|
|
703
687
|
return meshedCadResult(cad, exactRevolve ? scaleRevolveResult(cad, drafted, shape) : drafted, shape);
|
|
704
688
|
});
|
|
705
689
|
}
|
|
706
|
-
function canonicalDraftRotation(direction) {
|
|
707
|
-
switch (direction) {
|
|
708
|
-
case "x": return { axis: { point: { x: 0, y: 0, z: 0 }, direction: { x: 0, y: 1, z: 0 } }, angle: -Math.PI / 2 };
|
|
709
|
-
case "-x": return { axis: { point: { x: 0, y: 0, z: 0 }, direction: { x: 0, y: 1, z: 0 } }, angle: Math.PI / 2 };
|
|
710
|
-
case "y": return { axis: { point: { x: 0, y: 0, z: 0 }, direction: { x: 1, y: 0, z: 0 } }, angle: Math.PI / 2 };
|
|
711
|
-
case "-y": return { axis: { point: { x: 0, y: 0, z: 0 }, direction: { x: 1, y: 0, z: 0 } }, angle: -Math.PI / 2 };
|
|
712
|
-
case "z": return null;
|
|
713
|
-
case "-z": return { axis: { point: { x: 0, y: 0, z: 0 }, direction: { x: 0, y: 1, z: 0 } }, angle: Math.PI };
|
|
714
|
-
}
|
|
715
|
-
}
|
|
716
|
-
function rotateVector(vector, axis, angle) {
|
|
717
|
-
const cosine = Math.cos(angle), sine = Math.sin(angle);
|
|
718
|
-
const dot = axis.x * vector.x + axis.y * vector.y + axis.z * vector.z;
|
|
719
|
-
const cross = { x: axis.y * vector.z - axis.z * vector.y, y: axis.z * vector.x - axis.x * vector.z, z: axis.x * vector.y - axis.y * vector.x };
|
|
720
|
-
return {
|
|
721
|
-
x: vector.x * cosine + cross.x * sine + axis.x * dot * (1 - cosine),
|
|
722
|
-
y: vector.y * cosine + cross.y * sine + axis.y * dot * (1 - cosine),
|
|
723
|
-
z: vector.z * cosine + cross.z * sine + axis.z * dot * (1 - cosine),
|
|
724
|
-
};
|
|
725
|
-
}
|
|
726
|
-
function faceNormal(cad, face) {
|
|
727
|
-
try {
|
|
728
|
-
const bounds = cad.uvBounds(face);
|
|
729
|
-
return cad.surfaceNormal(face, (bounds.uMin + bounds.uMax) / 2, (bounds.vMin + bounds.vMax) / 2);
|
|
730
|
-
}
|
|
731
|
-
catch {
|
|
732
|
-
return null;
|
|
733
|
-
}
|
|
734
|
-
}
|
|
735
690
|
/** The exact geometry and a mesh of it, which is what a shape stores after any CAD operation. */
|
|
736
691
|
export function meshedCadResult(cad, result, sourceShape, lineage, sourceSolid) {
|
|
737
692
|
const mesh = cad.meshShape(result, { linearDeflection: MESH_DEFLECTION });
|
|
@@ -746,12 +701,7 @@ export function meshedCadResult(cad, result, sourceShape, lineage, sourceSolid)
|
|
|
746
701
|
}
|
|
747
702
|
const faces = cad.getSubShapes(result, "face");
|
|
748
703
|
const faceIndexByHash = new Map(faces.map((face, index) => [cad.hashCode(face, 2_147_483_647), index]));
|
|
749
|
-
const faceGroups =
|
|
750
|
-
for (let group = 0; group + 2 < (mesh.faceGroups?.length ?? 0); group += 3) {
|
|
751
|
-
const index = faceIndexByHash.get(mesh.faceGroups[group + 2]);
|
|
752
|
-
if (index !== undefined)
|
|
753
|
-
faceGroups.push(mesh.faceGroups[group], mesh.faceGroups[group + 1], index);
|
|
754
|
-
}
|
|
704
|
+
const faceGroups = triangleFaceGroups(mesh.faceGroups, faceIndexByHash);
|
|
755
705
|
const faceIds = sourceShape
|
|
756
706
|
? lineage
|
|
757
707
|
? faceIdsFromEvolution(sourceShape.id, sourceShape.faceIds, lineage.sourceFaceHashes, faces.map((face) => cad.hashCode(face, FACE_HASH_UPPER_BOUND)), lineage.evolution)
|
|
@@ -766,56 +716,8 @@ export function meshedCadResult(cad, result, sourceShape, lineage, sourceSolid)
|
|
|
766
716
|
...(faceGroups.length ? { faceGroups } : {}),
|
|
767
717
|
};
|
|
768
718
|
}
|
|
769
|
-
/**
|
|
770
|
-
* Keep an ID only when an exact face BREP or a unique planar support surface
|
|
771
|
-
* occurs on each side. OCCT face ordering and hash codes are kernel details,
|
|
772
|
-
* so an unmatched or ambiguous face receives a new application ID.
|
|
773
|
-
*/
|
|
774
719
|
function faceIdsForResult(cad, source, resultFaces, sourceSolid = orientedSolidForShape(cad, source)) {
|
|
775
|
-
|
|
776
|
-
const fingerprint = (face) => {
|
|
777
|
-
const brep = cad.toBREP(face);
|
|
778
|
-
try {
|
|
779
|
-
if (cad.surfaceType(face) !== "plane")
|
|
780
|
-
return `brep:${brep}`;
|
|
781
|
-
const bounds = cad.uvBounds(face);
|
|
782
|
-
const normal = cad.surfaceNormal(face, (bounds.uMin + bounds.uMax) / 2, (bounds.vMin + bounds.vMax) / 2);
|
|
783
|
-
const center = cad.getSurfaceCenterOfMass(face);
|
|
784
|
-
const round = (value) => Math.round(value * 1e6) / 1e6;
|
|
785
|
-
const n = [round(normal.x), round(normal.y), round(normal.z)];
|
|
786
|
-
const offset = round(center.x * normal.x + center.y * normal.y + center.z * normal.z);
|
|
787
|
-
return `plane:${n.join(",")}:${offset}`;
|
|
788
|
-
}
|
|
789
|
-
catch {
|
|
790
|
-
return `brep:${brep}`;
|
|
791
|
-
}
|
|
792
|
-
};
|
|
793
|
-
const sourceByBrep = new Map();
|
|
794
|
-
sourceFaces.forEach((face, index) => {
|
|
795
|
-
const key = fingerprint(face);
|
|
796
|
-
sourceByBrep.set(key, [...(sourceByBrep.get(key) ?? []), index]);
|
|
797
|
-
});
|
|
798
|
-
const resultCounts = new Map();
|
|
799
|
-
const resultBreps = resultFaces.map((face) => {
|
|
800
|
-
const key = fingerprint(face);
|
|
801
|
-
resultCounts.set(key, (resultCounts.get(key) ?? 0) + 1);
|
|
802
|
-
return key;
|
|
803
|
-
});
|
|
804
|
-
const used = new Set();
|
|
805
|
-
return resultBreps.map((brep, index) => {
|
|
806
|
-
const matches = sourceByBrep.get(brep) ?? [];
|
|
807
|
-
const sourceIndex = matches.length === 1 && resultCounts.get(brep) === 1 ? matches[0] : undefined;
|
|
808
|
-
const inherited = sourceIndex === undefined
|
|
809
|
-
? undefined
|
|
810
|
-
: source.faceIds?.[sourceIndex] ?? `face_${encodeURIComponent(source.id)}_${sourceIndex}`;
|
|
811
|
-
if (inherited && !used.has(inherited)) {
|
|
812
|
-
used.add(inherited);
|
|
813
|
-
return inherited;
|
|
814
|
-
}
|
|
815
|
-
const fresh = createLocalId(`${source.id}-face-${index}`);
|
|
816
|
-
used.add(fresh);
|
|
817
|
-
return fresh.startsWith("face_") ? fresh : `face_${fresh}`;
|
|
818
|
-
});
|
|
720
|
+
return faceIdsForCadResult(cad, source, resultFaces, sourceSolid);
|
|
819
721
|
}
|
|
820
722
|
function freshFaceIds(cad, solid, shapeId) {
|
|
821
723
|
return cad.getSubShapes(solid, "face").map((_, index) => `face_${createLocalId(`${shapeId}-face-${index}`)}`);
|