@constructorfleet/sketchforge-engine 1.20.0 → 1.21.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/README.md +2 -2
- package/dist/domain/sketchforge.d.ts +4 -0
- package/dist/domain/sketchforge.d.ts.map +1 -1
- package/dist/engine.d.ts.map +1 -1
- package/dist/engine.js +160 -23
- package/dist/engine.js.map +1 -1
- package/dist/faceDraftSegmentLineage.d.ts +45 -0
- package/dist/faceDraftSegmentLineage.d.ts.map +1 -0
- package/dist/faceDraftSegmentLineage.js +200 -0
- package/dist/faceDraftSegmentLineage.js.map +1 -0
- package/dist/parametricRecompute.d.ts.map +1 -1
- package/dist/parametricRecompute.js +87 -4
- package/dist/parametricRecompute.js.map +1 -1
- package/dist/revolveRequests.d.ts +2 -0
- package/dist/revolveRequests.d.ts.map +1 -1
- package/dist/serverCadOperations.js +1 -1
- package/dist/serverCadOperations.js.map +1 -1
- package/dist/skfProject.d.ts.map +1 -1
- package/dist/skfProject.js +141 -16
- package/dist/skfProject.js.map +1 -1
- package/package.json +1 -1
package/dist/skfProject.js
CHANGED
|
@@ -8,7 +8,7 @@ import { canonicalizeShape } from "./workplaneShapes.js";
|
|
|
8
8
|
import { importedShapeFromStl } from "./stlImport.js";
|
|
9
9
|
import { importedShapeFromSvg } from "./svgImport.js";
|
|
10
10
|
import { normalizeSnapGrid, normalizeWorkspaceSettings } from "./workplaneSettings.js";
|
|
11
|
-
import { cadSketchRegions } from "./sketchCadProfile.js";
|
|
11
|
+
import { cadSketchRegions, cadSketchSweepPaths } from "./sketchCadProfile.js";
|
|
12
12
|
export const SKF_SCHEMA_ID = "com.sketchforge.project";
|
|
13
13
|
export const SKF_FORMAT_VERSION = 2;
|
|
14
14
|
export const SKF_MINIMUM_READER_VERSION = 2;
|
|
@@ -441,6 +441,7 @@ async function serializeShapeNode(shape, nodeId, nodes, builder, sourceAssetsByA
|
|
|
441
441
|
sketchSourceNodeId: undefined,
|
|
442
442
|
faceDraft: undefined,
|
|
443
443
|
faceDraftSourceFrame: undefined,
|
|
444
|
+
faceDraftSourceSegmentId: undefined,
|
|
444
445
|
sketchSourceOfObjectId: shape.id,
|
|
445
446
|
},
|
|
446
447
|
});
|
|
@@ -579,33 +580,33 @@ function activeProjectIndexes(state) {
|
|
|
579
580
|
});
|
|
580
581
|
previous = featureId;
|
|
581
582
|
}
|
|
582
|
-
const
|
|
583
|
-
|
|
584
|
-
const
|
|
585
|
-
const featureId = `feature/${safeNodeToken(node.nodeId)}/${type}/${index}`;
|
|
583
|
+
const faceDraft = node.definition.faceDraft;
|
|
584
|
+
if (faceDraft) {
|
|
585
|
+
const featureId = `feature/${safeNodeToken(node.nodeId)}/face-draft`;
|
|
586
586
|
features.push({
|
|
587
587
|
id: featureId,
|
|
588
|
-
type,
|
|
588
|
+
type: "face-draft",
|
|
589
589
|
outputObjectId: node.objectId,
|
|
590
590
|
inputObjectIds: [node.objectId],
|
|
591
591
|
dependsOnFeatureIds: previous ? [previous] : [],
|
|
592
|
-
parameters: { ...
|
|
592
|
+
parameters: { ...faceDraft },
|
|
593
593
|
});
|
|
594
594
|
previous = featureId;
|
|
595
|
-
}
|
|
596
|
-
const
|
|
597
|
-
|
|
598
|
-
const
|
|
595
|
+
}
|
|
596
|
+
const treatments = Array.isArray(node.definition.edgeTreatments) ? node.definition.edgeTreatments : [];
|
|
597
|
+
treatments.forEach((treatment, index) => {
|
|
598
|
+
const type = treatment.kind === "fillet" ? "fillet" : "chamfer";
|
|
599
|
+
const featureId = `feature/${safeNodeToken(node.nodeId)}/${type}/${index}`;
|
|
599
600
|
features.push({
|
|
600
601
|
id: featureId,
|
|
601
|
-
type
|
|
602
|
+
type,
|
|
602
603
|
outputObjectId: node.objectId,
|
|
603
604
|
inputObjectIds: [node.objectId],
|
|
604
605
|
dependsOnFeatureIds: previous ? [previous] : [],
|
|
605
|
-
parameters: { ...
|
|
606
|
+
parameters: { ...treatment },
|
|
606
607
|
});
|
|
607
608
|
previous = featureId;
|
|
608
|
-
}
|
|
609
|
+
});
|
|
609
610
|
if (node.definition.mirrorX || node.definition.mirrorY || node.definition.mirrorZ) {
|
|
610
611
|
const featureId = `feature/${safeNodeToken(node.nodeId)}/mirror`;
|
|
611
612
|
features.push({
|
|
@@ -993,14 +994,95 @@ function validateShapeDefinition(definition, label, options = {}) {
|
|
|
993
994
|
&& Math.abs(Math.abs(revolveSettings.sweepAngle) - 360) <= 1e-6
|
|
994
995
|
&& (revolveSettings.pitch === undefined || revolveSettings.pitch === 0)
|
|
995
996
|
&& (revolveSettings.coreRadius === undefined || revolveSettings.coreRadius === 0);
|
|
997
|
+
const treatments = Array.isArray(definition.edgeTreatments) ? definition.edgeTreatments : [];
|
|
998
|
+
const treatment = treatments[0] && typeof treatments[0] === "object" && !Array.isArray(treatments[0])
|
|
999
|
+
? treatments[0]
|
|
1000
|
+
: undefined;
|
|
1001
|
+
const history = options.edgeTreatmentHistory ?? [];
|
|
1002
|
+
const historyFeature = history[0]?.feature;
|
|
1003
|
+
const isPersistedRevolveDraftTreatment = Boolean(plainFullTurnRevolve
|
|
1004
|
+
&& definition.sketchProfile !== undefined
|
|
1005
|
+
&& cadSketchRegions(definition.sketchProfile).length === 1
|
|
1006
|
+
&& definition.draftPrismAngle === undefined
|
|
1007
|
+
&& treatments.length === 1
|
|
1008
|
+
&& (treatment?.kind === "chamfer" || treatment?.kind === "fillet")
|
|
1009
|
+
&& treatment.allEdges === true
|
|
1010
|
+
&& treatment.edges === undefined
|
|
1011
|
+
&& (treatment.kind === "fillet"
|
|
1012
|
+
|| typeof treatment.chamferAngle === "number" && Math.abs(treatment.chamferAngle - 45) < 0.001)
|
|
1013
|
+
&& typeof treatment.amount === "number"
|
|
1014
|
+
&& Number.isFinite(treatment.amount)
|
|
1015
|
+
&& treatment.amount > 0
|
|
1016
|
+
&& Number.isInteger(treatment.edgeCount)
|
|
1017
|
+
&& treatment.edgeCount > 0
|
|
1018
|
+
&& history.length === 1
|
|
1019
|
+
&& historyFeature?.kind === treatment.kind
|
|
1020
|
+
&& historyFeature.allEdges === treatment.allEdges
|
|
1021
|
+
&& (treatment.kind === "fillet" || historyFeature.chamferAngle === treatment.chamferAngle)
|
|
1022
|
+
&& historyFeature.amount === treatment.amount
|
|
1023
|
+
&& historyFeature.edgeCount === treatment.edgeCount);
|
|
1024
|
+
const extrusionRegions = definition.sketchOperation === "extrude" && definition.sketchProfile !== undefined
|
|
1025
|
+
? cadSketchRegions(definition.sketchProfile)
|
|
1026
|
+
: [];
|
|
1027
|
+
const isPersistedExtrusionDraftTreatment = Boolean(definition.sketchOperation === "extrude"
|
|
1028
|
+
&& extrusionRegions.length === 1
|
|
1029
|
+
&& extrusionRegions[0]?.holes.length === 0
|
|
1030
|
+
&& definition.draftPrismAngle === undefined
|
|
1031
|
+
&& treatments.length === 1
|
|
1032
|
+
&& (treatment?.kind === "fillet" || treatment?.kind === "chamfer")
|
|
1033
|
+
&& treatment.allEdges === true
|
|
1034
|
+
&& treatment.edges === undefined
|
|
1035
|
+
&& (treatment.kind === "fillet"
|
|
1036
|
+
|| typeof treatment.chamferAngle === "number" && Math.abs(treatment.chamferAngle - 45) < 0.001)
|
|
1037
|
+
&& typeof treatment.amount === "number"
|
|
1038
|
+
&& Number.isFinite(treatment.amount)
|
|
1039
|
+
&& treatment.amount > 0
|
|
1040
|
+
&& Number.isInteger(treatment.edgeCount)
|
|
1041
|
+
&& treatment.edgeCount > 0
|
|
1042
|
+
&& history.length === 1
|
|
1043
|
+
&& historyFeature?.kind === treatment.kind
|
|
1044
|
+
&& historyFeature.allEdges === true
|
|
1045
|
+
&& (treatment.kind === "fillet" || historyFeature.chamferAngle === treatment.chamferAngle)
|
|
1046
|
+
&& historyFeature.amount === treatment.amount
|
|
1047
|
+
&& historyFeature.edgeCount === treatment.edgeCount);
|
|
1048
|
+
let isPersistedSweepDraftTreatment = false;
|
|
1049
|
+
if (definition.sketchOperation === "sweep" && definition.sketchProfile !== undefined) {
|
|
1050
|
+
try {
|
|
1051
|
+
const { sections, spine } = cadSketchSweepPaths(definition.sketchProfile);
|
|
1052
|
+
isPersistedSweepDraftTreatment = Boolean(sections.length === 1
|
|
1053
|
+
&& sections[0]?.holes.length === 0
|
|
1054
|
+
&& spine.steps.length > 0
|
|
1055
|
+
&& definition.draftPrismAngle === undefined
|
|
1056
|
+
&& treatments.length === 1
|
|
1057
|
+
&& (treatment?.kind === "fillet" || treatment?.kind === "chamfer")
|
|
1058
|
+
&& treatment.allEdges === true
|
|
1059
|
+
&& treatment.edges === undefined
|
|
1060
|
+
&& (treatment.kind === "fillet"
|
|
1061
|
+
|| typeof treatment.chamferAngle === "number" && Math.abs(treatment.chamferAngle - 45) < 0.001)
|
|
1062
|
+
&& typeof treatment.amount === "number"
|
|
1063
|
+
&& Number.isFinite(treatment.amount)
|
|
1064
|
+
&& treatment.amount > 0
|
|
1065
|
+
&& Number.isInteger(treatment.edgeCount)
|
|
1066
|
+
&& treatment.edgeCount > 0
|
|
1067
|
+
&& history.length === 1
|
|
1068
|
+
&& historyFeature?.kind === treatment.kind
|
|
1069
|
+
&& historyFeature.allEdges === true
|
|
1070
|
+
&& (treatment.kind === "fillet" || historyFeature.chamferAngle === treatment.chamferAngle)
|
|
1071
|
+
&& historyFeature.amount === treatment.amount
|
|
1072
|
+
&& historyFeature.edgeCount === treatment.edgeCount);
|
|
1073
|
+
}
|
|
1074
|
+
catch {
|
|
1075
|
+
isPersistedSweepDraftTreatment = false;
|
|
1076
|
+
}
|
|
1077
|
+
}
|
|
996
1078
|
if (kind !== "mesh"
|
|
997
1079
|
|| (definition.sketchOperation !== "extrude" && definition.sketchOperation !== "sweep" && !plainFullTurnRevolve)
|
|
998
1080
|
|| definition.sketchProfile === undefined
|
|
999
1081
|
|| plainFullTurnRevolve && cadSketchRegions(definition.sketchProfile).length !== 1
|
|
1000
1082
|
|| definition.sketchSourceId === undefined
|
|
1001
1083
|
|| definition.draftPrismAngle !== undefined
|
|
1002
|
-
|| (
|
|
1003
|
-
|
|
1084
|
+
|| (treatments.length > 0 || options.hasEdgeTreatmentHistory)
|
|
1085
|
+
&& !isPersistedRevolveDraftTreatment && !isPersistedExtrusionDraftTreatment && !isPersistedSweepDraftTreatment) {
|
|
1004
1086
|
throw new LocalizedError("errors.skf.fieldInvalid", { label: `${label}.faceDraft` });
|
|
1005
1087
|
}
|
|
1006
1088
|
const sourceFaceId = stringValue(draft.sourceFaceId, `${label}.faceDraft.sourceFaceId`);
|
|
@@ -1033,6 +1115,47 @@ function validateShapeDefinition(definition, label, options = {}) {
|
|
|
1033
1115
|
}
|
|
1034
1116
|
});
|
|
1035
1117
|
}
|
|
1118
|
+
if (definition.faceDraftSourceFaceIds !== undefined) {
|
|
1119
|
+
if (!Array.isArray(definition.faceDraftSourceFaceIds) || definition.faceDraftSourceFaceIds.length === 0) {
|
|
1120
|
+
throw new LocalizedError("errors.skf.fieldInvalid", { label: `${label}.faceDraftSourceFaceIds` });
|
|
1121
|
+
}
|
|
1122
|
+
const sourceFaceIds = definition.faceDraftSourceFaceIds.map((id, index) => stringValue(id, `${label}.faceDraftSourceFaceIds[${index}]`));
|
|
1123
|
+
if (sourceFaceIds.some((id) => !id.trim()) || new Set(sourceFaceIds).size !== sourceFaceIds.length
|
|
1124
|
+
|| typeof definition.faceDraft === "object" && definition.faceDraft !== null
|
|
1125
|
+
&& !sourceFaceIds.includes(definition.faceDraft.sourceFaceId)) {
|
|
1126
|
+
throw new LocalizedError("errors.skf.fieldInvalid", { label: `${label}.faceDraftSourceFaceIds` });
|
|
1127
|
+
}
|
|
1128
|
+
}
|
|
1129
|
+
if (definition.faceDraftSourceSegmentId !== undefined) {
|
|
1130
|
+
const sourceSegmentId = stringValue(definition.faceDraftSourceSegmentId, `${label}.faceDraftSourceSegmentId`);
|
|
1131
|
+
const profile = definition.sketchProfile;
|
|
1132
|
+
let regions = [];
|
|
1133
|
+
try {
|
|
1134
|
+
if (profile)
|
|
1135
|
+
regions = cadSketchRegions(profile);
|
|
1136
|
+
}
|
|
1137
|
+
catch {
|
|
1138
|
+
regions = [];
|
|
1139
|
+
}
|
|
1140
|
+
const segments = profile?.segments ?? [];
|
|
1141
|
+
const pointsById = new Map(profile?.points.map((point) => [point.id, point]) ?? []);
|
|
1142
|
+
const sourceSegmentMatches = segments.filter((segment) => segment.id === sourceSegmentId);
|
|
1143
|
+
const containsBezier = segments.some((segment) => {
|
|
1144
|
+
if (segment.kind !== undefined && segment.kind !== "line")
|
|
1145
|
+
return true;
|
|
1146
|
+
if (segment.kind !== undefined)
|
|
1147
|
+
return false;
|
|
1148
|
+
const start = pointsById.get(segment.startId);
|
|
1149
|
+
const end = pointsById.get(segment.endId);
|
|
1150
|
+
return Boolean(start && end && ((start.handleOut && end.handleIn) || (start.handleIn && end.handleOut)));
|
|
1151
|
+
});
|
|
1152
|
+
if (!sourceSegmentId.trim() || kind !== "mesh" || definition.sketchOperation !== "extrude"
|
|
1153
|
+
|| definition.faceDraft === undefined || !profile || regions.length !== 1 || regions[0]?.holes.length !== 0
|
|
1154
|
+
|| regions[0]?.outer.steps.length !== segments.length || containsBezier
|
|
1155
|
+
|| sourceSegmentMatches.length !== 1) {
|
|
1156
|
+
throw new LocalizedError("errors.skf.fieldInvalid", { label: `${label}.faceDraftSourceSegmentId` });
|
|
1157
|
+
}
|
|
1158
|
+
}
|
|
1036
1159
|
if (kind === "gear") {
|
|
1037
1160
|
const teeth = finiteNumber(definition.teeth, `${label}.teeth`);
|
|
1038
1161
|
if (!Number.isInteger(teeth) || teeth < 6 || teeth > 64)
|
|
@@ -1203,6 +1326,7 @@ async function validateDocumentAndAssets(raw, files) {
|
|
|
1203
1326
|
const definition = objectRecord(node.definition, `node '${nodeId}'.definition`);
|
|
1204
1327
|
const objectId = validateShapeDefinition(definition, `node '${nodeId}'`, {
|
|
1205
1328
|
hasEdgeTreatmentHistory: Boolean(node.edgeTreatmentHistory?.length),
|
|
1329
|
+
edgeTreatmentHistory: node.edgeTreatmentHistory,
|
|
1206
1330
|
});
|
|
1207
1331
|
if (node.objectId !== objectId)
|
|
1208
1332
|
throw new LocalizedError("errors.skf.nodeObjectIdMismatch", { id: nodeId });
|
|
@@ -1538,6 +1662,7 @@ function validateLegacyRuntimeShape(shape, label) {
|
|
|
1538
1662
|
delete definition.cadBrep;
|
|
1539
1663
|
validateShapeDefinition(definition, label, {
|
|
1540
1664
|
hasEdgeTreatmentHistory: Array.isArray(edgeHistory) && edgeHistory.length > 0,
|
|
1665
|
+
edgeTreatmentHistory: Array.isArray(edgeHistory) ? edgeHistory : undefined,
|
|
1541
1666
|
});
|
|
1542
1667
|
if (importedMesh) {
|
|
1543
1668
|
const mesh = objectRecord(importedMesh, `${label}.importedMesh`);
|