@constructorfleet/sketchforge-engine 1.25.0 → 1.27.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/cadAnalysis.d.ts +94 -0
- package/dist/cadAnalysis.d.ts.map +1 -0
- package/dist/cadAnalysis.js +143 -0
- package/dist/cadAnalysis.js.map +1 -0
- package/dist/cadShell.d.ts +143 -0
- package/dist/cadShell.d.ts.map +1 -0
- package/dist/cadShell.js +306 -0
- package/dist/cadShell.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/domain/sketchforge.d.ts +1 -1
- package/dist/domain/sketchforge.d.ts.map +1 -1
- package/dist/engine.d.ts.map +1 -1
- package/dist/engine.js +70 -79
- 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/parametricRecompute.d.ts.map +1 -1
- package/dist/parametricRecompute.js +7 -4
- package/dist/parametricRecompute.js.map +1 -1
- package/dist/revolveRequests.d.ts.map +1 -1
- package/dist/serverCadInterference.d.ts +8 -45
- package/dist/serverCadInterference.d.ts.map +1 -1
- package/dist/serverCadInterference.js +13 -42
- package/dist/serverCadInterference.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 +117 -160
- package/dist/serverCadOperations.js.map +1 -1
- package/dist/serverCadShell.d.ts +7 -94
- package/dist/serverCadShell.d.ts.map +1 -1
- package/dist/serverCadShell.js +25 -269
- package/dist/serverCadShell.js.map +1 -1
- package/dist/serverCadThickness.d.ts +8 -8
- package/dist/serverCadThickness.d.ts.map +1 -1
- package/dist/serverCadThickness.js +15 -42
- package/dist/serverCadThickness.js.map +1 -1
- package/dist/serverShapeBooleans.js +1 -1
- package/dist/serverShapeBooleans.js.map +1 -1
- package/dist/serverStepExplode.d.ts +1 -2
- package/dist/serverStepExplode.d.ts.map +1 -1
- package/dist/serverStepExplode.js +15 -148
- package/dist/serverStepExplode.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 +575 -0
- package/dist/sketchFaceDraftKernel.js.map +1 -0
- package/dist/stepAssemblyExplode.d.ts +45 -0
- package/dist/stepAssemblyExplode.d.ts.map +1 -0
- package/dist/stepAssemblyExplode.js +195 -0
- package/dist/stepAssemblyExplode.js.map +1 -0
- package/dist/support/cadModifierTypes.d.ts +82 -0
- package/dist/support/cadModifierTypes.d.ts.map +1 -1
- package/dist/support/i18n/locales/en/messages.json +15 -1
- package/dist/support/lib/operator-configuration.json +11 -0
- package/dist/workplaneShapes.d.ts.map +1 -1
- package/dist/workplaneShapes.js +5 -0
- package/dist/workplaneShapes.js.map +1 -1
- package/package.json +1 -1
|
@@ -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,12 +16,14 @@
|
|
|
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
|
+
import { sketchExtrusionSolid } from "./sketchExtrusionSolid.js";
|
|
23
24
|
import { normalizeSketchRevolveSettings, sketchProfileToRevolvePolygons } from "./sketchRevolve.js";
|
|
24
25
|
import { triangleFaceGroups } from "./cadFaceMesh.js";
|
|
26
|
+
import { draftSketchFace, draftPrismProfileOffset, faceIdsForCadResult } from "./sketchFaceDraftKernel.js";
|
|
25
27
|
export class ServerCadError extends Error {
|
|
26
28
|
status;
|
|
27
29
|
constructor(message, status = 422) {
|
|
@@ -33,10 +35,31 @@ export class ServerCadError extends Error {
|
|
|
33
35
|
const MESH_DEFLECTION = 0.1;
|
|
34
36
|
const MIN_CAD_DIMENSION = 0.01;
|
|
35
37
|
const FACE_HASH_UPPER_BOUND = 2_147_483_647;
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
38
|
+
function sketchResizeFactors(shape) {
|
|
39
|
+
const mesh = shape.importedMesh;
|
|
40
|
+
if (shape.faceDraftSourceScale)
|
|
41
|
+
return shape.faceDraftSourceScale;
|
|
42
|
+
const factor = (drawn, base) => base && base > 0 ? drawn / base : 1;
|
|
43
|
+
return {
|
|
44
|
+
width: factor(shape.width, mesh?.baseWidth),
|
|
45
|
+
depth: factor(shape.depth, mesh?.baseDepth),
|
|
46
|
+
height: factor(shape.height, mesh?.baseHeight),
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
function scaledSketchProfile(profile, width, depth) {
|
|
50
|
+
const xs = profile.points.map((point) => point.x);
|
|
51
|
+
const zs = profile.points.map((point) => point.z);
|
|
52
|
+
const centerX = (Math.min(...xs) + Math.max(...xs)) / 2;
|
|
53
|
+
const centerZ = (Math.min(...zs) + Math.max(...zs)) / 2;
|
|
54
|
+
const scalePoint = (point) => ({
|
|
55
|
+
...point,
|
|
56
|
+
x: centerX + (point.x - centerX) * width,
|
|
57
|
+
z: centerZ + (point.z - centerZ) * depth,
|
|
58
|
+
...(point.handleIn ? { handleIn: { ...point.handleIn, x: centerX + (point.handleIn.x - centerX) * width, z: centerZ + (point.handleIn.z - centerZ) * depth } } : {}),
|
|
59
|
+
...(point.handleOut ? { handleOut: { ...point.handleOut, x: centerX + (point.handleOut.x - centerX) * width, z: centerZ + (point.handleOut.z - centerZ) * depth } } : {}),
|
|
60
|
+
});
|
|
61
|
+
return { ...profile, points: profile.points.map(scalePoint) };
|
|
62
|
+
}
|
|
40
63
|
function meshPositionsOf(shape) {
|
|
41
64
|
const positions = shape.importedMesh?.positions;
|
|
42
65
|
return positions && positions.length >= 9 ? positions : null;
|
|
@@ -185,12 +208,16 @@ export function localSolidForShape(cad, shape) {
|
|
|
185
208
|
* straightened. `treatmentBakesRotation` is the other half of that bargain and
|
|
186
209
|
* reads the same predicate.
|
|
187
210
|
*
|
|
188
|
-
* For stored geometry this is the local solid
|
|
189
|
-
* the shape, which is where it already was.
|
|
211
|
+
* For stored geometry this is the local solid with only its mirror applied:
|
|
212
|
+
* the rotation stays on the shape, which is where it already was.
|
|
213
|
+
*
|
|
214
|
+
* Mirrored either way, because the result is stored with the shape's mirror
|
|
215
|
+
* flags cleared. Building it unmirrored handed back the unmirrored shape and
|
|
216
|
+
* reported success (#413).
|
|
190
217
|
*/
|
|
191
218
|
export function orientedSolidForShape(cad, shape) {
|
|
192
219
|
if (!rotationIsRebuilt(shape))
|
|
193
|
-
return localSolidForShape(cad, shape);
|
|
220
|
+
return mirroredStoredSolid(cad, localSolidForShape(cad, shape), shape);
|
|
194
221
|
try {
|
|
195
222
|
return exactSolidForShape(cad, shape);
|
|
196
223
|
}
|
|
@@ -200,6 +227,25 @@ export function orientedSolidForShape(cad, shape) {
|
|
|
200
227
|
throw error;
|
|
201
228
|
}
|
|
202
229
|
}
|
|
230
|
+
/**
|
|
231
|
+
* A solid stored on the shape -- its BREP, its mesh, or a revolve rebuilt from
|
|
232
|
+
* its profile -- with the shape's mirror flags applied about its own centre.
|
|
233
|
+
*
|
|
234
|
+
* The bounds centre rather than the origin, because stored geometry is not
|
|
235
|
+
* always in the builders' frame (an earlier treatment's BREP keeps whatever
|
|
236
|
+
* frame it was made in); the viewport mirrors the normalized mesh about its
|
|
237
|
+
* centre, and a plane through any other point would only move the result.
|
|
238
|
+
*/
|
|
239
|
+
function mirroredStoredSolid(cad, solid, shape) {
|
|
240
|
+
if (!shape.mirrorX && !shape.mirrorY && !shape.mirrorZ)
|
|
241
|
+
return solid;
|
|
242
|
+
const bounds = cad.getBoundingBox(solid, false);
|
|
243
|
+
return mirroredInShapeFrame(cad, solid, shape, {
|
|
244
|
+
x: (bounds.xmin + bounds.xmax) / 2,
|
|
245
|
+
y: (bounds.ymin + bounds.ymax) / 2,
|
|
246
|
+
z: (bounds.zmin + bounds.zmax) / 2,
|
|
247
|
+
});
|
|
248
|
+
}
|
|
203
249
|
/** How many faces of the solid meet along this edge. A seam reports one. */
|
|
204
250
|
function adjacentFaceCount(cad, solid, handle) {
|
|
205
251
|
try {
|
|
@@ -273,12 +319,7 @@ export function applyBakedMirror(shape, axis, pivot) {
|
|
|
273
319
|
throw error;
|
|
274
320
|
}
|
|
275
321
|
const centerY = shape.height / 2;
|
|
276
|
-
|
|
277
|
-
solid = cad.mirror(solid, { x: 0, y: 0, z: 0 }, { x: 1, y: 0, z: 0 });
|
|
278
|
-
if (shape.mirrorY)
|
|
279
|
-
solid = cad.mirror(solid, { x: 0, y: centerY, z: 0 }, { x: 0, y: 1, z: 0 });
|
|
280
|
-
if (shape.mirrorZ)
|
|
281
|
-
solid = cad.mirror(solid, { x: 0, y: 0, z: 0 }, { x: 0, y: 0, z: 1 });
|
|
322
|
+
solid = mirroredInShapeFrame(cad, solid, shape, { x: 0, y: centerY, z: 0 });
|
|
282
323
|
const center = { x: 0, y: centerY, z: 0 };
|
|
283
324
|
const angle = (degrees) => degrees * Math.PI / 180;
|
|
284
325
|
if (shape.rotationZ)
|
|
@@ -447,6 +488,13 @@ function revolveWithoutExactEdges(shape) {
|
|
|
447
488
|
* viewport stretches the mesh by.
|
|
448
489
|
*/
|
|
449
490
|
function revolveResizeFactors(shape) {
|
|
491
|
+
if (shape.faceDraftSourceScale) {
|
|
492
|
+
return {
|
|
493
|
+
radialX: shape.faceDraftSourceScale.width,
|
|
494
|
+
radialZ: shape.faceDraftSourceScale.depth,
|
|
495
|
+
axial: shape.faceDraftSourceScale.height,
|
|
496
|
+
};
|
|
497
|
+
}
|
|
450
498
|
const mesh = shape.importedMesh;
|
|
451
499
|
const ratio = (drawn, base) => (base && base > 0 && drawn > 0 ? drawn / base : 1);
|
|
452
500
|
return {
|
|
@@ -483,12 +531,14 @@ function exactRevolveSolidForShape(cad, shape) {
|
|
|
483
531
|
* the treatment. For an untreated revolve that is the exact solid rebuilt from
|
|
484
532
|
* its profile (#347); a revolve with no exact solid is refused rather than
|
|
485
533
|
* listed or treated by its facets. Everything else is the oriented solid.
|
|
534
|
+
* Both carry the shape's mirror, which the treated result no longer does.
|
|
486
535
|
*/
|
|
487
536
|
export function edgeSolidForShape(cad, shape) {
|
|
488
537
|
const refusal = revolveWithoutExactEdges(shape);
|
|
489
538
|
if (refusal)
|
|
490
539
|
throw new ServerCadError(refusal);
|
|
491
|
-
|
|
540
|
+
const revolve = exactRevolveSolidForShape(cad, shape);
|
|
541
|
+
return revolve ? mirroredStoredSolid(cad, revolve, shape) : orientedSolidForShape(cad, shape);
|
|
492
542
|
}
|
|
493
543
|
/** Build the analytical full-turn BREP for chamfering a retained plain revolve. */
|
|
494
544
|
export function isPlainFullTurnSketchRevolve(shape) {
|
|
@@ -538,6 +588,9 @@ export function exactPlainSketchRevolveSolid(cad, sketchProfile, sketchRevolve,
|
|
|
538
588
|
}, (sketchRevolve.startAngle * Math.PI) / 180);
|
|
539
589
|
});
|
|
540
590
|
let solid = solids[0];
|
|
591
|
+
// Callers that cannot express a resized revolve analytically (for example,
|
|
592
|
+
// exact face listing of a radially elliptical legacy shape) use this bounds
|
|
593
|
+
// fit. Face drafting of a supported resize passes profile scales instead.
|
|
541
594
|
if (targetShape?.importedMesh && targetShape.width > 0 && targetShape.depth > 0 && targetShape.height > 0) {
|
|
542
595
|
const bounds = cad.getBoundingBox(solid, false);
|
|
543
596
|
const sx = targetShape.width / Math.max(bounds.xmax - bounds.xmin, 1e-9);
|
|
@@ -553,25 +606,6 @@ export function exactPlainSketchRevolveSolid(cad, sketchProfile, sketchRevolve,
|
|
|
553
606
|
throw new ServerCadError("The retained sketch revolve could not be rebuilt as exact CAD geometry.");
|
|
554
607
|
return solid;
|
|
555
608
|
}
|
|
556
|
-
function scaleRevolveResult(cad, solid, shape) {
|
|
557
|
-
const mesh = shape.importedMesh;
|
|
558
|
-
if (!mesh)
|
|
559
|
-
return solid;
|
|
560
|
-
const factors = [
|
|
561
|
-
shape.width / Math.max(mesh.baseWidth ?? shape.width, 1e-9),
|
|
562
|
-
shape.height / Math.max(mesh.baseHeight ?? shape.height, 1e-9),
|
|
563
|
-
shape.depth / Math.max(mesh.baseDepth ?? shape.depth, 1e-9),
|
|
564
|
-
];
|
|
565
|
-
if (factors.every((factor) => Math.abs(factor - 1) < 1e-8))
|
|
566
|
-
return solid;
|
|
567
|
-
const bounds = cad.getBoundingBox(solid, false);
|
|
568
|
-
const [sx, sy, sz] = factors;
|
|
569
|
-
return cad.transform(solid, [
|
|
570
|
-
sx, 0, 0, -(bounds.xmin + bounds.xmax) * sx / 2,
|
|
571
|
-
0, sy, 0, -bounds.ymin * sy,
|
|
572
|
-
0, 0, sz, -(bounds.zmin + bounds.zmax) * sz / 2,
|
|
573
|
-
]);
|
|
574
|
-
}
|
|
575
609
|
/** Rebuild the exact CAD representation of an eligible retained revolve. */
|
|
576
610
|
export function exactPlainSketchRevolveResult(shape) {
|
|
577
611
|
if (!shape.sketchProfile || !isPlainFullTurnSketchRevolve(shape)) {
|
|
@@ -590,9 +624,11 @@ export function exactPlainSketchRevolveResult(shape) {
|
|
|
590
624
|
/**
|
|
591
625
|
* Apply a prism draft along the shape's vertical extrusion axis.
|
|
592
626
|
*
|
|
593
|
-
*
|
|
594
|
-
*
|
|
595
|
-
*
|
|
627
|
+
* The geometry only: the caller records the retained angle and source frame
|
|
628
|
+
* (`retainedPrismDraftFields`) that a sketch edit replays it from. The B-rep
|
|
629
|
+
* is built about the centre of the profile's bounds
|
|
630
|
+
* (`draftPrismProfileOffset`), and the exact BREP and viewport mesh are
|
|
631
|
+
* persisted together, as with shell and edge treatments.
|
|
596
632
|
*/
|
|
597
633
|
export function applyDraftPrism(shape, request) {
|
|
598
634
|
if (!Number.isFinite(request.angle) || request.angle === 0 || Math.abs(request.angle) >= 45) {
|
|
@@ -601,7 +637,9 @@ export function applyDraftPrism(shape, request) {
|
|
|
601
637
|
if (shape.sketchOperation !== "extrude" || !shape.sketchProfile) {
|
|
602
638
|
return Promise.reject(new ServerCadError("Draft prism requires a sketch extrusion with its source profile retained.", 400));
|
|
603
639
|
}
|
|
604
|
-
const
|
|
640
|
+
const scale = sketchResizeFactors(shape);
|
|
641
|
+
const profile = scaledSketchProfile(shape.sketchProfile, scale.width, scale.depth);
|
|
642
|
+
const { points, segments } = profile;
|
|
605
643
|
if (points.length < 3 || segments.length !== points.length
|
|
606
644
|
|| segments.some((segment, index) => segment.kind && segment.kind !== "line"
|
|
607
645
|
|| segment.startId !== points[index].id
|
|
@@ -610,12 +648,7 @@ export function applyDraftPrism(shape, request) {
|
|
|
610
648
|
return Promise.reject(new ServerCadError("Draft prism currently requires one closed polygonal sketch profile made from straight segments.", 400));
|
|
611
649
|
}
|
|
612
650
|
return withCadKernel((cad) => {
|
|
613
|
-
const
|
|
614
|
-
const maxX = Math.max(...points.map(({ x }) => x));
|
|
615
|
-
const minZ = Math.min(...points.map(({ z }) => z));
|
|
616
|
-
const maxZ = Math.max(...points.map(({ z }) => z));
|
|
617
|
-
const centerX = (minX + maxX) / 2;
|
|
618
|
-
const centerZ = (minZ + maxZ) / 2;
|
|
651
|
+
const { x: centerX, z: centerZ } = draftPrismProfileOffset(profile);
|
|
619
652
|
const edges = points.map((point, index) => {
|
|
620
653
|
const next = points[(index + 1) % points.length];
|
|
621
654
|
return cad.makeLineEdge({ x: point.x - centerX, y: 0, z: point.z - centerZ }, { x: next.x - centerX, y: 0, z: next.z - centerZ });
|
|
@@ -643,14 +676,40 @@ export function applySketchFaceDraft(shape, request) {
|
|
|
643
676
|
return Promise.reject(new ServerCadError("The face draft angle must be non-zero and between -45 and 45 degrees.", 400));
|
|
644
677
|
}
|
|
645
678
|
const exactRevolve = isPlainFullTurnSketchRevolve(shape);
|
|
679
|
+
if (exactRevolve) {
|
|
680
|
+
const resize = revolveResizeFactors(shape);
|
|
681
|
+
if (Math.abs(resize.radialX - resize.radialZ) > 1e-6 * Math.max(resize.radialX, resize.radialZ)) {
|
|
682
|
+
return Promise.reject(new ServerCadError("Face drafting requires an equal resize across the revolve's radial axes; unequal radial resizing makes an elliptical shape that cannot be drafted exactly.", 400));
|
|
683
|
+
}
|
|
684
|
+
}
|
|
646
685
|
if ((!exactRevolve && shape.sketchOperation !== "extrude" && shape.sketchOperation !== "sweep")
|
|
647
686
|
|| !shape.sketchProfile || (!shape.cadBrep && !exactRevolve)) {
|
|
648
687
|
return Promise.reject(new ServerCadError("Face drafts require an exact retained sketch extrusion, sweep, or plain full-turn revolve.", 400));
|
|
649
688
|
}
|
|
650
689
|
return withCadKernel((cad) => {
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
690
|
+
let solid;
|
|
691
|
+
if (exactRevolve) {
|
|
692
|
+
const resize = revolveResizeFactors(shape);
|
|
693
|
+
const hasResize = [resize.radialX, resize.radialZ, resize.axial]
|
|
694
|
+
.some((factor) => Math.abs(factor - 1) > 1e-8);
|
|
695
|
+
solid = hasResize
|
|
696
|
+
? exactPlainSketchRevolveSolid(cad, shape.sketchProfile, shape.sketchRevolve, undefined, {
|
|
697
|
+
radial: resize.radialX,
|
|
698
|
+
axial: resize.axial,
|
|
699
|
+
})
|
|
700
|
+
: exactPlainSketchRevolveSolid(cad, shape.sketchProfile, shape.sketchRevolve, shape);
|
|
701
|
+
}
|
|
702
|
+
else {
|
|
703
|
+
solid = solidFromBrep(cad, shape.cadBrep);
|
|
704
|
+
}
|
|
705
|
+
const resize = sketchResizeFactors(shape);
|
|
706
|
+
if (!exactRevolve && shape.sketchOperation === "extrude"
|
|
707
|
+
&& [resize.width, resize.depth, resize.height].some((factor) => Math.abs(factor - 1) > 1e-8)) {
|
|
708
|
+
solid = sketchExtrusionSolid(cad, scaledSketchProfile(shape.sketchProfile, resize.width, resize.depth), shape.height);
|
|
709
|
+
if (!cadResultIsValid(cad, solid) || !cad.isSolid(solid)) {
|
|
710
|
+
throw new ServerCadError("The resized sketch extrusion could not be rebuilt as exact CAD geometry.");
|
|
711
|
+
}
|
|
712
|
+
}
|
|
654
713
|
const faces = cad.getSubShapes(solid, "face");
|
|
655
714
|
const ids = shape.faceIds?.length === faces.length ? shape.faceIds
|
|
656
715
|
: exactRevolve && !shape.faceColors ? faces.map((_, index) => `face_${encodeURIComponent(shape.id)}_${index}`)
|
|
@@ -664,75 +723,15 @@ export function applySketchFaceDraft(shape, request) {
|
|
|
664
723
|
const face = faces[selected[0]];
|
|
665
724
|
if (!face)
|
|
666
725
|
throw new ServerCadError("The selected source face is no longer available.");
|
|
667
|
-
const
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
try {
|
|
671
|
-
drafted = cad.draft(solid, face, angle, direction);
|
|
672
|
-
}
|
|
673
|
-
catch {
|
|
674
|
-
const rotation = canonicalDraftRotation(request.pullDirection);
|
|
675
|
-
try {
|
|
676
|
-
if (!rotation)
|
|
677
|
-
throw new Error("No canonical rotation for the selected pull axis.");
|
|
678
|
-
const rotatedSolid = cad.rotate(solid, rotation.axis, rotation.angle);
|
|
679
|
-
const oldNormal = faceNormal(cad, face);
|
|
680
|
-
if (!oldNormal)
|
|
681
|
-
throw new Error("The selected face has no usable normal.");
|
|
682
|
-
const targetNormal = rotateVector(oldNormal, rotation.axis.direction, rotation.angle);
|
|
683
|
-
const targetCenter = rotateVector(cad.getSurfaceCenterOfMass(face), rotation.axis.direction, rotation.angle);
|
|
684
|
-
const bounds = cad.getBoundingBox(solid, false);
|
|
685
|
-
const scale = Math.max(1, Math.hypot(bounds.xmax - bounds.xmin, bounds.ymax - bounds.ymin, bounds.zmax - bounds.zmin));
|
|
686
|
-
const matches = cad.getSubShapes(rotatedSolid, "face").filter((candidate) => {
|
|
687
|
-
const normal = faceNormal(cad, candidate);
|
|
688
|
-
const center = cad.getSurfaceCenterOfMass(candidate);
|
|
689
|
-
return normal && Math.hypot(normal.x - targetNormal.x, normal.y - targetNormal.y, normal.z - targetNormal.z) <= 1e-7
|
|
690
|
-
&& Math.hypot(center.x - targetCenter.x, center.y - targetCenter.y, center.z - targetCenter.z) <= scale * 1e-8;
|
|
691
|
-
});
|
|
692
|
-
if (matches.length !== 1)
|
|
693
|
-
throw new Error("Could not uniquely identify the selected face after rotating the solid.");
|
|
694
|
-
const canonicalDraft = cad.draft(rotatedSolid, matches[0], angle, { x: 0, y: 0, z: 1 });
|
|
695
|
-
drafted = cad.rotate(canonicalDraft, rotation.axis, -rotation.angle);
|
|
696
|
-
}
|
|
697
|
-
catch {
|
|
698
|
-
throw new ServerCadError("The selected source face cannot be drafted along that local pull axis and angle.");
|
|
699
|
-
}
|
|
700
|
-
}
|
|
726
|
+
const drafted = draftSketchFace(cad, solid, face, request);
|
|
727
|
+
if (!drafted)
|
|
728
|
+
throw new ServerCadError("The selected source face cannot be drafted along that local pull axis and angle.");
|
|
701
729
|
if (!cadResultIsValid(cad, drafted) || !cad.isSolid(drafted)) {
|
|
702
730
|
throw new ServerCadError("The face draft did not produce a valid solid.");
|
|
703
731
|
}
|
|
704
|
-
return meshedCadResult(cad,
|
|
732
|
+
return meshedCadResult(cad, drafted, shape, undefined, solid);
|
|
705
733
|
});
|
|
706
734
|
}
|
|
707
|
-
function canonicalDraftRotation(direction) {
|
|
708
|
-
switch (direction) {
|
|
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 "-x": return { axis: { point: { x: 0, y: 0, z: 0 }, direction: { x: 0, y: 1, 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 "-y": return { axis: { point: { x: 0, y: 0, z: 0 }, direction: { x: 1, y: 0, z: 0 } }, angle: -Math.PI / 2 };
|
|
713
|
-
case "z": return null;
|
|
714
|
-
case "-z": return { axis: { point: { x: 0, y: 0, z: 0 }, direction: { x: 0, y: 1, z: 0 } }, angle: Math.PI };
|
|
715
|
-
}
|
|
716
|
-
}
|
|
717
|
-
function rotateVector(vector, axis, angle) {
|
|
718
|
-
const cosine = Math.cos(angle), sine = Math.sin(angle);
|
|
719
|
-
const dot = axis.x * vector.x + axis.y * vector.y + axis.z * vector.z;
|
|
720
|
-
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 };
|
|
721
|
-
return {
|
|
722
|
-
x: vector.x * cosine + cross.x * sine + axis.x * dot * (1 - cosine),
|
|
723
|
-
y: vector.y * cosine + cross.y * sine + axis.y * dot * (1 - cosine),
|
|
724
|
-
z: vector.z * cosine + cross.z * sine + axis.z * dot * (1 - cosine),
|
|
725
|
-
};
|
|
726
|
-
}
|
|
727
|
-
function faceNormal(cad, face) {
|
|
728
|
-
try {
|
|
729
|
-
const bounds = cad.uvBounds(face);
|
|
730
|
-
return cad.surfaceNormal(face, (bounds.uMin + bounds.uMax) / 2, (bounds.vMin + bounds.vMax) / 2);
|
|
731
|
-
}
|
|
732
|
-
catch {
|
|
733
|
-
return null;
|
|
734
|
-
}
|
|
735
|
-
}
|
|
736
735
|
/** The exact geometry and a mesh of it, which is what a shape stores after any CAD operation. */
|
|
737
736
|
export function meshedCadResult(cad, result, sourceShape, lineage, sourceSolid) {
|
|
738
737
|
const mesh = cad.meshShape(result, { linearDeflection: MESH_DEFLECTION });
|
|
@@ -762,56 +761,8 @@ export function meshedCadResult(cad, result, sourceShape, lineage, sourceSolid)
|
|
|
762
761
|
...(faceGroups.length ? { faceGroups } : {}),
|
|
763
762
|
};
|
|
764
763
|
}
|
|
765
|
-
/**
|
|
766
|
-
* Keep an ID only when an exact face BREP or a unique planar support surface
|
|
767
|
-
* occurs on each side. OCCT face ordering and hash codes are kernel details,
|
|
768
|
-
* so an unmatched or ambiguous face receives a new application ID.
|
|
769
|
-
*/
|
|
770
764
|
function faceIdsForResult(cad, source, resultFaces, sourceSolid = orientedSolidForShape(cad, source)) {
|
|
771
|
-
|
|
772
|
-
const fingerprint = (face) => {
|
|
773
|
-
const brep = cad.toBREP(face);
|
|
774
|
-
try {
|
|
775
|
-
if (cad.surfaceType(face) !== "plane")
|
|
776
|
-
return `brep:${brep}`;
|
|
777
|
-
const bounds = cad.uvBounds(face);
|
|
778
|
-
const normal = cad.surfaceNormal(face, (bounds.uMin + bounds.uMax) / 2, (bounds.vMin + bounds.vMax) / 2);
|
|
779
|
-
const center = cad.getSurfaceCenterOfMass(face);
|
|
780
|
-
const round = (value) => Math.round(value * 1e6) / 1e6;
|
|
781
|
-
const n = [round(normal.x), round(normal.y), round(normal.z)];
|
|
782
|
-
const offset = round(center.x * normal.x + center.y * normal.y + center.z * normal.z);
|
|
783
|
-
return `plane:${n.join(",")}:${offset}`;
|
|
784
|
-
}
|
|
785
|
-
catch {
|
|
786
|
-
return `brep:${brep}`;
|
|
787
|
-
}
|
|
788
|
-
};
|
|
789
|
-
const sourceByBrep = new Map();
|
|
790
|
-
sourceFaces.forEach((face, index) => {
|
|
791
|
-
const key = fingerprint(face);
|
|
792
|
-
sourceByBrep.set(key, [...(sourceByBrep.get(key) ?? []), index]);
|
|
793
|
-
});
|
|
794
|
-
const resultCounts = new Map();
|
|
795
|
-
const resultBreps = resultFaces.map((face) => {
|
|
796
|
-
const key = fingerprint(face);
|
|
797
|
-
resultCounts.set(key, (resultCounts.get(key) ?? 0) + 1);
|
|
798
|
-
return key;
|
|
799
|
-
});
|
|
800
|
-
const used = new Set();
|
|
801
|
-
return resultBreps.map((brep, index) => {
|
|
802
|
-
const matches = sourceByBrep.get(brep) ?? [];
|
|
803
|
-
const sourceIndex = matches.length === 1 && resultCounts.get(brep) === 1 ? matches[0] : undefined;
|
|
804
|
-
const inherited = sourceIndex === undefined
|
|
805
|
-
? undefined
|
|
806
|
-
: source.faceIds?.[sourceIndex] ?? `face_${encodeURIComponent(source.id)}_${sourceIndex}`;
|
|
807
|
-
if (inherited && !used.has(inherited)) {
|
|
808
|
-
used.add(inherited);
|
|
809
|
-
return inherited;
|
|
810
|
-
}
|
|
811
|
-
const fresh = createLocalId(`${source.id}-face-${index}`);
|
|
812
|
-
used.add(fresh);
|
|
813
|
-
return fresh.startsWith("face_") ? fresh : `face_${fresh}`;
|
|
814
|
-
});
|
|
765
|
+
return faceIdsForCadResult(cad, source, resultFaces, sourceSolid);
|
|
815
766
|
}
|
|
816
767
|
function freshFaceIds(cad, solid, shapeId) {
|
|
817
768
|
return cad.getSubShapes(solid, "face").map((_, index) => `face_${createLocalId(`${shapeId}-face-${index}`)}`);
|
|
@@ -864,6 +815,12 @@ export function shapeWithCadResult(shape, result) {
|
|
|
864
815
|
}));
|
|
865
816
|
return canonicalizeShape({
|
|
866
817
|
...shape,
|
|
818
|
+
// A baked rotation can move the bounds away from the source's pivot. The
|
|
819
|
+
// mesh is rebased to those bounds, so move its project origin by the same
|
|
820
|
+
// offset. Other results keep the source frame they were built in.
|
|
821
|
+
x: shape.x + (bakedRotation ? centerX : 0),
|
|
822
|
+
z: shape.z + (bakedRotation ? centerZ : 0),
|
|
823
|
+
elevation: (shape.elevation ?? 0) + (bakedRotation ? minY : 0),
|
|
867
824
|
faceIds: result.faceIds,
|
|
868
825
|
faceColors: Object.keys(survivingColors).length ? survivingColors : undefined,
|
|
869
826
|
kind: "mesh",
|