onshape 0.1.3 → 0.2.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.
@@ -0,0 +1,372 @@
1
+ "use strict";
2
+ // Advanced feature builders for Onshape — fillet, chamfer, shell, draft, revolve,
3
+ // boolean, mirror, patterns, offset-plane, and assembly mate/connector/group.
4
+ // 1:1 port of onshape_cli/builders/advanced.py.
5
+ //
6
+ // Every builder emits the standard BTFeatureDefinitionCall-1406 envelope the
7
+ // POST .../features endpoint expects. Selection is query-string based so it
8
+ // survives topology changes; explicit deterministic IDs are also supported.
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ exports.qBodyOfFeature = exports.qAllBodies = exports.qCircularEdges = exports.qEdgesOfFeature = exports.qAllEdges = void 0;
11
+ exports.featureCall = featureCall;
12
+ exports.pQuery = pQuery;
13
+ exports.pSketchRegion = pSketchRegion;
14
+ exports.pQuantity = pQuantity;
15
+ exports.pEnum = pEnum;
16
+ exports.pBool = pBool;
17
+ exports.buildFillet = buildFillet;
18
+ exports.buildChamfer = buildChamfer;
19
+ exports.buildShell = buildShell;
20
+ exports.buildDraft = buildDraft;
21
+ exports.buildRevolveAxis = buildRevolveAxis;
22
+ exports.buildBoolean = buildBoolean;
23
+ exports.buildMirror = buildMirror;
24
+ exports.buildLinearPattern = buildLinearPattern;
25
+ exports.buildCircularPattern = buildCircularPattern;
26
+ exports.buildOffsetPlaneSelect = buildOffsetPlaneSelect;
27
+ exports.buildAssemblyMate = buildAssemblyMate;
28
+ exports.buildAssemblyMateConnector = buildAssemblyMateConnector;
29
+ exports.buildAssemblyGroup = buildAssemblyGroup;
30
+ // --- Low-level parameter helpers -------------------------------------------
31
+ function featureCall(featureType, name, parameters, namespace = "") {
32
+ return {
33
+ btType: "BTFeatureDefinitionCall-1406",
34
+ feature: {
35
+ btType: "BTMFeature-134",
36
+ featureType,
37
+ name,
38
+ suppressed: false,
39
+ namespace,
40
+ parameters,
41
+ },
42
+ };
43
+ }
44
+ function pQuery(parameterId, opts = {}) {
45
+ const query = {
46
+ btType: "BTMIndividualQuery-138",
47
+ deterministicIds: opts.deterministicIds ?? [],
48
+ };
49
+ if (opts.queryString) {
50
+ query.queryStatement = null;
51
+ query.queryString = opts.queryString;
52
+ }
53
+ if (opts.featureId)
54
+ query.featureId = opts.featureId;
55
+ return {
56
+ btType: "BTMParameterQueryList-148",
57
+ queries: [query],
58
+ parameterId,
59
+ parameterName: "",
60
+ libraryRelationType: "NONE",
61
+ };
62
+ }
63
+ function pSketchRegion(parameterId, sketchFeatureId) {
64
+ return {
65
+ btType: "BTMParameterQueryList-148",
66
+ queries: [
67
+ {
68
+ btType: "BTMIndividualSketchRegionQuery-140",
69
+ queryStatement: null,
70
+ filterInnerLoops: true,
71
+ queryString: `query = qSketchRegion(id + "${sketchFeatureId}", true);`,
72
+ featureId: sketchFeatureId,
73
+ deterministicIds: [],
74
+ },
75
+ ],
76
+ parameterId,
77
+ parameterName: "",
78
+ libraryRelationType: "NONE",
79
+ };
80
+ }
81
+ function pQuantity(parameterId, value, units = "in", opts = {}) {
82
+ let expression;
83
+ if (opts.variable)
84
+ expression = `#${opts.variable}`;
85
+ else if (opts.isInteger)
86
+ expression = `${Math.trunc(value)}`;
87
+ else if (units)
88
+ expression = `${value} ${units}`;
89
+ else
90
+ expression = `${value}`;
91
+ return {
92
+ btType: "BTMParameterQuantity-147",
93
+ isInteger: opts.isInteger ?? false,
94
+ value,
95
+ units: "",
96
+ expression,
97
+ parameterId,
98
+ parameterName: "",
99
+ libraryRelationType: "NONE",
100
+ };
101
+ }
102
+ function pEnum(parameterId, enumName, value) {
103
+ return {
104
+ btType: "BTMParameterEnum-145",
105
+ namespace: "",
106
+ enumName,
107
+ value,
108
+ parameterId,
109
+ parameterName: "",
110
+ libraryRelationType: "NONE",
111
+ };
112
+ }
113
+ function pBool(parameterId, value) {
114
+ return {
115
+ btType: "BTMParameterBoolean-144",
116
+ value,
117
+ parameterId,
118
+ parameterName: "",
119
+ libraryRelationType: "NONE",
120
+ };
121
+ }
122
+ // --- Reusable selection query strings --------------------------------------
123
+ const qAllEdges = () => "query = qOwnedByBody(qAllModifiableSolidBodies(), EntityType.EDGE);";
124
+ exports.qAllEdges = qAllEdges;
125
+ const qEdgesOfFeature = (featureId) => `query = qCreatedBy(makeId("${featureId}"), EntityType.EDGE);`;
126
+ exports.qEdgesOfFeature = qEdgesOfFeature;
127
+ const qCircularEdges = () => "query = qGeometry(qOwnedByBody(qAllModifiableSolidBodies(), EntityType.EDGE), GeometryType.CIRCLE);";
128
+ exports.qCircularEdges = qCircularEdges;
129
+ const qAllBodies = () => "query = qAllModifiableSolidBodies();";
130
+ exports.qAllBodies = qAllBodies;
131
+ const qBodyOfFeature = (featureId) => `query = qCreatedBy(makeId("${featureId}"), EntityType.BODY);`;
132
+ exports.qBodyOfFeature = qBodyOfFeature;
133
+ function resolveEntityQuery(parameterId, sel, entity = "EDGE") {
134
+ if (sel.edgeIds && sel.edgeIds.length)
135
+ return pQuery(parameterId, { deterministicIds: sel.edgeIds });
136
+ if (sel.queryString)
137
+ return pQuery(parameterId, { queryString: sel.queryString });
138
+ if (sel.featureId) {
139
+ const qs = entity === "EDGE" ? (0, exports.qEdgesOfFeature)(sel.featureId) : (0, exports.qBodyOfFeature)(sel.featureId);
140
+ return pQuery(parameterId, { queryString: qs });
141
+ }
142
+ if (sel.circular)
143
+ return pQuery(parameterId, { queryString: (0, exports.qCircularEdges)() });
144
+ if (sel.selectAll)
145
+ return pQuery(parameterId, { queryString: (0, exports.qAllEdges)() });
146
+ throw new Error("No selection: pass edges, query, feature, --all, or --circular");
147
+ }
148
+ // --- Feature builders ------------------------------------------------------
149
+ function buildFillet(opts) {
150
+ const entities = resolveEntityQuery("entities", opts);
151
+ return featureCall("fillet", opts.name ?? "Fillet", [
152
+ entities,
153
+ pQuantity("radius", opts.radius ?? 0.1, "in", { variable: opts.radiusVariable }),
154
+ pEnum("filletType", "FilletType", opts.filletType ?? "EDGE"),
155
+ ]);
156
+ }
157
+ function buildChamfer(opts) {
158
+ const entities = resolveEntityQuery("entities", opts);
159
+ const chamferType = opts.chamferType ?? "EQUAL_OFFSETS";
160
+ const params = [
161
+ entities,
162
+ pEnum("chamferType", "ChamferType", chamferType),
163
+ pQuantity("width", opts.width ?? 0.1, "in", { variable: opts.widthVariable }),
164
+ ];
165
+ if (chamferType === "OFFSET_ANGLE" && opts.angle !== undefined) {
166
+ params.push(pQuantity("angle", opts.angle, "deg"));
167
+ }
168
+ return featureCall("chamfer", opts.name ?? "Chamfer", params);
169
+ }
170
+ function buildShell(opts) {
171
+ let entities;
172
+ if (opts.faceIds && opts.faceIds.length)
173
+ entities = pQuery("entities", { deterministicIds: opts.faceIds });
174
+ else if (opts.queryString)
175
+ entities = pQuery("entities", { queryString: opts.queryString });
176
+ else
177
+ entities = pQuery("entities", { deterministicIds: [] });
178
+ const inward = opts.inward ?? true;
179
+ return featureCall("shell", opts.name ?? "Shell", [
180
+ entities,
181
+ pQuantity("thickness", opts.thickness ?? 0.125, "in", { variable: opts.thicknessVariable }),
182
+ pBool("oppositeDirection", !inward),
183
+ ]);
184
+ }
185
+ function buildDraft(opts) {
186
+ return featureCall("draft", opts.name ?? "Draft", [
187
+ pQuery("neutralPlane", { queryString: opts.neutralPlaneQuery }),
188
+ pQuery("draftFaces", { queryString: opts.faceQuery }),
189
+ pQuantity("angle", opts.angle ?? 3.0, "deg"),
190
+ pBool("oppositeDirection", false),
191
+ ]);
192
+ }
193
+ function buildRevolveAxis(opts) {
194
+ const axis = opts.axisIds && opts.axisIds.length
195
+ ? pQuery("axis", { deterministicIds: opts.axisIds })
196
+ : pQuery("axis", { queryString: opts.axisQuery });
197
+ const full = (opts.revolveType ?? "FULL") === "FULL";
198
+ const params = [
199
+ pEnum("bodyType", "ExtendedToolBodyType", "SOLID"),
200
+ pEnum("operationType", "NewBodyOperationType", opts.operationType ?? "NEW"),
201
+ pSketchRegion("entities", opts.sketchFeatureId),
202
+ axis,
203
+ pBool("fullRevolve", full),
204
+ ];
205
+ if (!full) {
206
+ params.push(pEnum("endBound", "RevolveBoundingType", "BLIND"));
207
+ params.push(pQuantity("angle", opts.angle ?? 360.0, "deg"));
208
+ }
209
+ params.push(pBool("defaultScope", true));
210
+ return featureCall("revolve", opts.name ?? "Revolve", params);
211
+ }
212
+ function buildBoolean(opts) {
213
+ const operationType = opts.operationType ?? "UNION";
214
+ let tools;
215
+ if (opts.toolIds && opts.toolIds.length)
216
+ tools = pQuery("tools", { deterministicIds: opts.toolIds });
217
+ else if (opts.toolsQuery)
218
+ tools = pQuery("tools", { queryString: opts.toolsQuery });
219
+ else
220
+ tools = pQuery("tools", { queryString: (0, exports.qAllBodies)() });
221
+ const params = [
222
+ pEnum("operationType", "BooleanOperationType", operationType),
223
+ pBool("defaultScope", false),
224
+ tools,
225
+ pBool("toolsExplicit", true),
226
+ ];
227
+ if (operationType === "SUBTRACTION") {
228
+ params.push(pBool("targetsAndToolsNeedGrouping", false));
229
+ if (opts.targetsQuery)
230
+ params.push(pQuery("targets", { queryString: opts.targetsQuery }));
231
+ }
232
+ return featureCall("booleanBodies", opts.name ?? "Boolean", params);
233
+ }
234
+ function buildMirror(opts) {
235
+ let plane;
236
+ if (opts.mirrorPlaneIds && opts.mirrorPlaneIds.length)
237
+ plane = pQuery("mirrorPlane", { deterministicIds: opts.mirrorPlaneIds });
238
+ else if (opts.mirrorPlaneQuery)
239
+ plane = pQuery("mirrorPlane", { queryString: opts.mirrorPlaneQuery });
240
+ else
241
+ throw new Error("Provide --plane-ids or --plane-query");
242
+ return featureCall("mirror", opts.name ?? "Mirror", [
243
+ pEnum("patternType", "MirrorType", opts.patternType ?? "PART"),
244
+ pEnum("operationType", "NewBodyOperationType", "NEW"),
245
+ pQuery("entities", { queryString: opts.entitiesQuery }),
246
+ plane,
247
+ ]);
248
+ }
249
+ function buildLinearPattern(opts) {
250
+ const direction = opts.directionIds && opts.directionIds.length
251
+ ? pQuery("directionOne", { deterministicIds: opts.directionIds })
252
+ : pQuery("directionOne", { queryString: opts.directionQuery });
253
+ return featureCall("linearPattern", opts.name ?? "Linear Pattern", [
254
+ pEnum("patternType", "PatternType", opts.patternType ?? "PART"),
255
+ pEnum("operationType", "NewBodyOperationType", "NEW"),
256
+ pQuery("entities", { queryString: opts.entitiesQuery }),
257
+ direction,
258
+ pBool("oppositeDirection", opts.opposite ?? false),
259
+ pQuantity("distance", opts.distance),
260
+ pQuantity("instanceCount", opts.instanceCount, "", { isInteger: true }),
261
+ pBool("hasSecondDir", false),
262
+ ]);
263
+ }
264
+ function buildCircularPattern(opts) {
265
+ const axis = opts.axisIds && opts.axisIds.length
266
+ ? pQuery("axis", { deterministicIds: opts.axisIds })
267
+ : pQuery("axis", { queryString: opts.axisQuery });
268
+ return featureCall("circularPattern", opts.name ?? "Circular Pattern", [
269
+ pEnum("patternType", "PatternType", opts.patternType ?? "PART"),
270
+ pEnum("operationType", "NewBodyOperationType", "NEW"),
271
+ pQuery("entities", { queryString: opts.entitiesQuery }),
272
+ axis,
273
+ pQuantity("angle", opts.angle ?? 360.0, "deg"),
274
+ pQuantity("instanceCount", opts.instanceCount, "", { isInteger: true }),
275
+ pBool("equalSpace", opts.equalSpacing ?? true),
276
+ ]);
277
+ }
278
+ function buildOffsetPlaneSelect(opts) {
279
+ let base;
280
+ if (opts.basePlaneIds && opts.basePlaneIds.length)
281
+ base = pQuery("entities", { deterministicIds: opts.basePlaneIds });
282
+ else if (opts.basePlaneQuery)
283
+ base = pQuery("entities", { queryString: opts.basePlaneQuery });
284
+ else
285
+ base = pQuery("entities", { deterministicIds: ["JCC"] }); // Front
286
+ return featureCall("cPlane", opts.name ?? "Plane", [
287
+ pEnum("cplaneType", "CPlaneType", "OFFSET"),
288
+ base,
289
+ pQuantity("offset", opts.offset ?? 1.0),
290
+ pBool("oppositeDirection", false),
291
+ ]);
292
+ }
293
+ // --- Assembly feature builders (posted to the assembly /features endpoint) --
294
+ function buildAssemblyMate(opts) {
295
+ const queries = opts.mateConnectorIds.map((fid) => ({
296
+ btType: "BTMFeatureQueryWithOccurrence-157",
297
+ path: [],
298
+ featureId: fid,
299
+ queryData: "",
300
+ }));
301
+ return {
302
+ btType: "BTFeatureDefinitionCall-1406",
303
+ feature: {
304
+ btType: "BTMMate-64",
305
+ featureType: "mate",
306
+ name: opts.name ?? "Mate",
307
+ suppressed: false,
308
+ parameters: [
309
+ pEnum("mateType", "Mate type", opts.mateType ?? "FASTENED"),
310
+ {
311
+ btType: "BTMParameterQueryWithOccurrenceList-67",
312
+ queries,
313
+ parameterId: "mateConnectorsQuery",
314
+ },
315
+ ],
316
+ },
317
+ };
318
+ }
319
+ function buildAssemblyMateConnector(opts) {
320
+ return {
321
+ btType: "BTFeatureDefinitionCall-1406",
322
+ feature: {
323
+ btType: "BTMMateConnector-66",
324
+ featureType: "mateConnector",
325
+ name: opts.name ?? "Mate connector",
326
+ suppressed: false,
327
+ parameters: [
328
+ {
329
+ btType: "BTMParameterEnum-145",
330
+ enumName: "Origin type",
331
+ value: "ON_ENTITY",
332
+ parameterId: "originType",
333
+ namespace: "",
334
+ },
335
+ {
336
+ btType: "BTMParameterQueryWithOccurrenceList-67",
337
+ parameterId: "originQuery",
338
+ queries: [
339
+ {
340
+ btType: "BTMInferenceQueryWithOccurrence-1083",
341
+ inferenceType: opts.inferenceType ?? "CENTROID",
342
+ path: [opts.occurrenceId],
343
+ deterministicIds: [],
344
+ },
345
+ ],
346
+ },
347
+ ],
348
+ },
349
+ };
350
+ }
351
+ function buildAssemblyGroup(opts) {
352
+ const queries = opts.occurrenceIds.map((oid) => ({
353
+ btType: "BTMIndividualOccurrenceQuery-626",
354
+ path: [oid],
355
+ }));
356
+ return {
357
+ btType: "BTFeatureDefinitionCall-1406",
358
+ feature: {
359
+ btType: "BTMMateGroup-65",
360
+ featureType: "mateGroup",
361
+ name: opts.name ?? "Group",
362
+ suppressed: false,
363
+ parameters: [
364
+ {
365
+ btType: "BTMParameterQueryWithOccurrenceList-67",
366
+ queries,
367
+ parameterId: "occurrencesQuery",
368
+ },
369
+ ],
370
+ },
371
+ };
372
+ }
@@ -6,6 +6,10 @@ exports.buildCircleSketch = buildCircleSketch;
6
6
  exports.buildCircleAxisSketch = buildCircleAxisSketch;
7
7
  exports.buildCandyCanePathSketch = buildCandyCanePathSketch;
8
8
  exports.buildExtrude = buildExtrude;
9
+ exports.buildThicken = buildThicken;
10
+ exports.buildSketchFromEntities = buildSketchFromEntities;
11
+ exports.buildRectangleSketch = buildRectangleSketch;
12
+ exports.buildLineSketch = buildLineSketch;
9
13
  exports.buildRevolve = buildRevolve;
10
14
  exports.buildOffsetPlane = buildOffsetPlane;
11
15
  exports.buildSweep = buildSweep;
@@ -32,7 +36,7 @@ function parsePoint2(value) {
32
36
  function toMeters(value) {
33
37
  return value * INCH_TO_METER;
34
38
  }
35
- function circleEntity(id, center, radius) {
39
+ function circleEntity(id, center, radius, isConstruction = false) {
36
40
  return {
37
41
  btType: "BTMSketchCurve-4",
38
42
  entityId: id,
@@ -46,9 +50,24 @@ function circleEntity(id, center, radius) {
46
50
  yDir: 0,
47
51
  clockwise: false,
48
52
  },
49
- isConstruction: false,
53
+ isConstruction,
50
54
  };
51
55
  }
56
+ function rectangleEntities(prefix, corner1, corner2) {
57
+ const [x1, y1] = corner1;
58
+ const [x2, y2] = corner2;
59
+ const corners = [
60
+ [x1, y1],
61
+ [x2, y1],
62
+ [x2, y2],
63
+ [x1, y2],
64
+ ];
65
+ const segments = [];
66
+ for (let i = 0; i < 4; i += 1) {
67
+ segments.push(lineEntity(`${prefix}.${i}`, corners[i], corners[(i + 1) % 4]));
68
+ }
69
+ return segments;
70
+ }
52
71
  function lineEntity(id, start, end, isConstruction = false) {
53
72
  const x1 = toMeters(start[0]);
54
73
  const y1 = toMeters(start[1]);
@@ -236,6 +255,20 @@ function buildCandyCanePathSketch(input) {
236
255
  }
237
256
  return sketch(input.name, planeId(input.plane), entities);
238
257
  }
258
+ function depthQuantity(parameterId, value, variable) {
259
+ if (!variable)
260
+ return pQuantity(parameterId, value, "in");
261
+ return {
262
+ btType: "BTMParameterQuantity-147",
263
+ isInteger: false,
264
+ value,
265
+ units: "",
266
+ expression: `#${variable}`,
267
+ parameterId,
268
+ parameterName: "",
269
+ libraryRelationType: "NONE",
270
+ };
271
+ }
239
272
  function buildExtrude(input) {
240
273
  return {
241
274
  btType: "BTFeatureDefinitionCall-1406",
@@ -248,13 +281,69 @@ function buildExtrude(input) {
248
281
  parameters: [
249
282
  sketchRegion("entities", input.sketchFeatureId),
250
283
  pEnum("operationType", "NewBodyOperationType", input.operationType),
251
- pQuantity("depth", input.depth, "in"),
284
+ depthQuantity("depth", input.depth, input.depthVariable),
252
285
  pBool("oppositeDirection", false),
253
286
  pBool("defaultScope", true),
254
287
  ],
255
288
  },
256
289
  };
257
290
  }
291
+ /** thicken — mirrors onshape_cli/builders/thicken.py (bare BTMFeature-134). */
292
+ function buildThicken(input) {
293
+ const expression = input.thicknessVariable ? `#${input.thicknessVariable}` : `${input.thickness} in`;
294
+ return {
295
+ btType: "BTMFeature-134",
296
+ name: input.name,
297
+ suppressed: false,
298
+ namespace: "",
299
+ featureType: "thicken",
300
+ parameters: [
301
+ { btType: "BTMParameterEnum-145", enumName: "NewBodyOperationType", value: input.operationType, parameterId: "operationType" },
302
+ sketchRegion("entities", input.sketchFeatureId),
303
+ { btType: "BTMParameterBoolean-144", value: input.midplane ?? false, parameterId: "midplane" },
304
+ { btType: "BTMParameterQuantity-147", expression, parameterId: "thickness1" },
305
+ { btType: "BTMParameterBoolean-144", value: input.opposite ?? false, parameterId: "oppositeDirection" },
306
+ { btType: "BTMParameterQuantity-147", expression: "0 in", parameterId: "thickness2" },
307
+ ],
308
+ };
309
+ }
310
+ /** Generic sketch from a parsed entity list (create-sketch). Matches the
311
+ * Python contract: types line/circle/rectangle (arc is not supported). */
312
+ function buildSketchFromEntities(input) {
313
+ const out = [];
314
+ input.entities.forEach((entity, index) => {
315
+ const type = String(entity.type ?? "");
316
+ const construction = Boolean(entity.construction);
317
+ if (type === "line") {
318
+ out.push(lineEntity(`e${index}`, point(entity.start), point(entity.end), construction));
319
+ }
320
+ else if (type === "circle") {
321
+ out.push(circleEntity(`e${index}`, point(entity.center), Number(entity.radius), construction));
322
+ }
323
+ else if (type === "rectangle") {
324
+ out.push(...rectangleEntities(`e${index}`, point(entity.corner1), point(entity.corner2)));
325
+ }
326
+ else if (type === "arc") {
327
+ throw new Error("arc entities not supported by this sketch builder yet; use line/circle/rectangle");
328
+ }
329
+ else {
330
+ throw new Error(`Unknown sketch entity type '${type}'. Use line, circle, or rectangle.`);
331
+ }
332
+ });
333
+ return sketch(input.name, planeId(input.plane), out);
334
+ }
335
+ function buildRectangleSketch(input) {
336
+ return sketch(input.name, planeId(input.plane), rectangleEntities("rect", input.corner1, input.corner2));
337
+ }
338
+ function buildLineSketch(input) {
339
+ return sketch(input.name, planeId(input.plane), [lineEntity("line.1", input.start, input.end)]);
340
+ }
341
+ function point(value) {
342
+ if (Array.isArray(value) && value.length === 2 && value.every((v) => Number.isFinite(Number(v)))) {
343
+ return [Number(value[0]), Number(value[1])];
344
+ }
345
+ throw new Error(`Expected a [x, y] point; got ${JSON.stringify(value)}`);
346
+ }
258
347
  function buildRevolve(input) {
259
348
  return {
260
349
  btType: "BTFeatureDefinitionCall-1406",