@snaptrude/plugin-core 0.0.0-dev-20260911064951 → 0.0.0-surfaces-20260921090636
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/CHANGELOG.md +0 -25
- package/api-manifest.json +151 -12
- package/dist/api/core/geom/create/index.d.ts +918 -93
- package/dist/api/core/geom/create/index.d.ts.map +1 -1
- package/dist/api/core/geom/query/brep.d.ts +50 -0
- package/dist/api/core/geom/query/brep.d.ts.map +1 -1
- package/dist/api/core/geom/query/curve.d.ts +58 -35
- package/dist/api/core/geom/query/curve.d.ts.map +1 -1
- package/dist/api/core/geom/query/edge.d.ts +2 -2
- package/dist/api/core/geom/query/face.d.ts +105 -0
- package/dist/api/core/geom/query/face.d.ts.map +1 -1
- package/dist/api/core/geom/update/curve.d.ts +5 -5
- package/dist/api/core/geom/update/profile.d.ts +1 -1
- package/dist/api/core/io/import/index.d.ts +1 -3
- package/dist/api/core/io/import/index.d.ts.map +1 -1
- package/dist/api/design/create/index.d.ts +22 -310
- package/dist/api/design/create/index.d.ts.map +1 -1
- package/dist/api/design/delete/index.d.ts +0 -4
- package/dist/api/design/delete/index.d.ts.map +1 -1
- package/dist/api/design/doors/index.d.ts +13 -20
- package/dist/api/design/doors/index.d.ts.map +1 -1
- package/dist/api/design/index.d.ts +0 -5
- package/dist/api/design/index.d.ts.map +1 -1
- package/dist/api/design/query/geometry/index.d.ts +27 -1
- package/dist/api/design/query/geometry/index.d.ts.map +1 -1
- package/dist/api/design/query/index.d.ts +47 -0
- package/dist/api/design/query/index.d.ts.map +1 -1
- package/dist/api/design/query/spaces.d.ts +5 -5
- package/dist/api/design/update/index.d.ts +87 -0
- package/dist/api/design/update/index.d.ts.map +1 -1
- package/dist/api/entity/referenceLine.d.ts +2 -2
- package/dist/api/entity/referenceLine.d.ts.map +1 -1
- package/dist/api/entity/space.d.ts +5 -4
- package/dist/api/entity/space.d.ts.map +1 -1
- package/dist/api/entity/story.d.ts +4 -4
- package/dist/api/presentation/annotate.d.ts +2 -2
- package/dist/api/presentation/shapes.d.ts +2 -2
- package/dist/api/program/site.d.ts +4 -4
- package/dist/api/program/spreadsheet.d.ts +4 -4
- package/dist/handles.d.ts +12 -22
- package/dist/handles.d.ts.map +1 -1
- package/dist/index.cjs +2773 -2445
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2726 -2422
- package/dist/index.js.map +1 -1
- package/dist/massParameters.d.ts +280 -0
- package/dist/massParameters.d.ts.map +1 -0
- package/dist/massParameters.ops.d.ts +135 -0
- package/dist/massParameters.ops.d.ts.map +1 -0
- package/package.json +1 -1
- package/src/api/core/geom/create/index.ts +1011 -94
- package/src/api/core/geom/query/brep.ts +51 -0
- package/src/api/core/geom/query/curve.ts +25 -2
- package/src/api/core/geom/query/edge.ts +2 -2
- package/src/api/core/geom/query/face.ts +109 -4
- package/src/api/core/io/import/index.ts +3 -11
- package/src/api/design/create/index.ts +38 -335
- package/src/api/design/delete/index.ts +0 -4
- package/src/api/design/doors/index.ts +13 -20
- package/src/api/design/index.ts +0 -5
- package/src/api/design/query/geometry/index.ts +29 -0
- package/src/api/design/query/index.ts +50 -0
- package/src/api/design/update/index.ts +94 -0
- package/src/handles.ts +15 -27
- package/src/index.ts +2 -0
- package/src/massParameters.ops.ts +243 -0
- package/src/massParameters.ts +418 -0
- package/test/massParameters.test.mjs +936 -0
- package/dist/api/design/create/bulk-items.d.ts +0 -185
- package/dist/api/design/create/bulk-items.d.ts.map +0 -1
- package/dist/api/design/create/opening-fields.d.ts +0 -37
- package/dist/api/design/create/opening-fields.d.ts.map +0 -1
- package/dist/api/design/dimensions.d.ts +0 -427
- package/dist/api/design/dimensions.d.ts.map +0 -1
- package/src/api/design/create/bulk-items.ts +0 -186
- package/src/api/design/create/opening-fields.ts +0 -37
- package/src/api/design/dimensions.ts +0 -453
|
@@ -1,15 +1,46 @@
|
|
|
1
1
|
import * as z from "zod"
|
|
2
2
|
import { PluginApiReturn } from "../../../../types"
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
MAX_SPLINE_THROUGH_POINTS,
|
|
5
|
+
MAX_SPLINE_POLES,
|
|
6
|
+
MAX_PATH_CURVES,
|
|
7
|
+
MAX_TWIST_LEVELS,
|
|
8
|
+
MAX_FILLET_LAW_SAMPLES,
|
|
9
|
+
} from "../../../../massParameters"
|
|
10
|
+
import type { SweepAlongCurveRecordOptions } from "../../../../massParameters"
|
|
11
|
+
import { Vec3Handle, LineHandle, ArcHandle, SplineHandle, CircleHandle, CurveHandle, ProfileHandle, ContourHandle, BrepHandle, FaceHandle, EdgeHandle, Vec3Components } from "../../../../handles"
|
|
12
|
+
|
|
13
|
+
/** Maximum boundary items one patch may span. */
|
|
14
|
+
export const MAX_PATCH_BOUNDARY_CURVES = 16
|
|
15
|
+
/** Maximum interior points one patch may be pulled through. */
|
|
16
|
+
export const MAX_PATCH_INTERIOR_POINTS = 64
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* An edge named together with the solid it belongs to — an edge handle cannot
|
|
20
|
+
* name its own solid, and one patch may meet two solids. `face` is the adjacent
|
|
21
|
+
* face a tangent patch continues: REQUIRED under `continuity: "tangent"`
|
|
22
|
+
* (a solid edge has two faces — the wall or the top of a rim — and only the
|
|
23
|
+
* caller knows which), ignored otherwise. Owner LAST, like every read that
|
|
24
|
+
* takes `(face, brep)`.
|
|
25
|
+
*/
|
|
26
|
+
export type OwnedEdge = { edge: EdgeHandle; brep: BrepHandle; face?: FaceHandle }
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* The trailing bag of {@linkcode PluginGeomCreateApi.brepFromSweepAlongCurve}:
|
|
30
|
+
* the recorded switches plus `rail`, a live curve handle that never enters a
|
|
31
|
+
* record (a record is pure JSON, and a dead handle would not regenerate).
|
|
32
|
+
*/
|
|
33
|
+
export type SweepAlongCurveOptions = SweepAlongCurveRecordOptions & { rail?: CurveHandle }
|
|
4
34
|
|
|
5
35
|
/**
|
|
6
36
|
* Curve creation — construct new geometric curves from point handles (all-handle
|
|
7
37
|
* model, §11).
|
|
8
38
|
*
|
|
9
39
|
* Each method takes point handles ({@linkcode Vec3Handle}) and returns an opaque
|
|
10
|
-
* curve handle ({@linkcode LineHandle}
|
|
11
|
-
* query, update, or entity-creation
|
|
12
|
-
* via the
|
|
40
|
+
* curve handle ({@linkcode LineHandle}, {@linkcode ArcHandle}, or
|
|
41
|
+
* {@linkcode SplineHandle}) that you pass to query, update, or entity-creation
|
|
42
|
+
* methods. Read geometry back as plain values via the
|
|
43
|
+
* `snaptrude.core.geom.query.*` methods.
|
|
13
44
|
*
|
|
14
45
|
* Accessed via `snaptrude.core.geom.create`.
|
|
15
46
|
*/
|
|
@@ -83,6 +114,102 @@ export abstract class PluginGeomCreateApi {
|
|
|
83
114
|
radius: number,
|
|
84
115
|
): PluginApiReturn<CircleHandle>
|
|
85
116
|
|
|
117
|
+
/**
|
|
118
|
+
* Create an open NURBS curve passing exactly THROUGH each point, in order
|
|
119
|
+
* (centripetal Catmull-Rom fit → clamped cubic B-spline; C1-smooth, no cusps
|
|
120
|
+
* on uneven spacing). Host API call — returns a handle. The points are
|
|
121
|
+
* interpolated, NOT control points. For a CLOSED smooth loop use
|
|
122
|
+
* {@linkcode PluginGeomCreateApi.profileFromSplinePoints} — closed splines
|
|
123
|
+
* exist only as profiles, never as a single curve handle.
|
|
124
|
+
*
|
|
125
|
+
* Pure host-side math — the geometry kernel is not loaded. The result is a
|
|
126
|
+
* {@linkcode CurveHandle}: pass it to `profileFromCurves` alongside lines and
|
|
127
|
+
* arcs, or read it back via `core.geom.query.curve.*`.
|
|
128
|
+
*
|
|
129
|
+
* @param points 3..256 ordered through-points; consecutive points must be distinct
|
|
130
|
+
* @returns The new open curve as a {@linkcode SplineHandle}
|
|
131
|
+
* @throws VALIDATION if fewer than 3 points (2 points are a straight line —
|
|
132
|
+
* use {@linkcode PluginGeomCreateApi.line}), more than 256 points, or two
|
|
133
|
+
* consecutive points coincide
|
|
134
|
+
*
|
|
135
|
+
* @examplePrompt Draw a smooth curve through these points
|
|
136
|
+
* @examplePrompt Make a wavy edge that passes through A, B, C and D
|
|
137
|
+
* @examplePrompt Freeform curved wall path through these clicks
|
|
138
|
+
*
|
|
139
|
+
* # Example
|
|
140
|
+
* ```ts
|
|
141
|
+
* const spline = await snaptrude.core.geom.create.splineFromPoints([p0, p1, p2, p3])
|
|
142
|
+
* // Mixed profile: smooth top, straight closing base
|
|
143
|
+
* const base = await snaptrude.core.geom.create.line(p3, p0)
|
|
144
|
+
* const profile = await snaptrude.core.geom.create.profileFromCurves([spline, base])
|
|
145
|
+
* ```
|
|
146
|
+
*/
|
|
147
|
+
public abstract splineFromPoints(points: Vec3Handle[]): PluginApiReturn<SplineHandle>
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Create an open NURBS curve DEFINED BY control points — the curve is pulled
|
|
151
|
+
* TOWARD the interior points, not through them; it starts at the first point
|
|
152
|
+
* and ends at the last. Knots are computed for you (clamped, uniform) —
|
|
153
|
+
* there is no knot-vector argument. For a curve that must pass THROUGH given
|
|
154
|
+
* points use {@linkcode PluginGeomCreateApi.splineFromPoints}.
|
|
155
|
+
*
|
|
156
|
+
* A curve made here records as `splinePoles` in a mass recipe and is
|
|
157
|
+
* re-minted verbatim on edit — so an agent that read a `splinePoles` curve
|
|
158
|
+
* back off a mass can move its poles and rebuild the mass with
|
|
159
|
+
* `design.update.parameters`. Pure host-side math — the geometry kernel is
|
|
160
|
+
* not loaded, and nothing is created in the scene.
|
|
161
|
+
*
|
|
162
|
+
* @param controlPoints 3..512 control points ({@linkcode Vec3Handle}s), in order
|
|
163
|
+
* @param options.degree 2 or 3; default `min(3, controlPoints.length - 1)`
|
|
164
|
+
* @returns The new open curve as a {@linkcode SplineHandle}
|
|
165
|
+
* @throws VALIDATION when fewer than `degree + 1` points are given, two
|
|
166
|
+
* consecutive points coincide, or `degree` is not 2 or 3
|
|
167
|
+
*
|
|
168
|
+
* @examplePrompt Draw a smooth curve controlled by these four points
|
|
169
|
+
* @examplePrompt Rebuild this edge from its control polygon
|
|
170
|
+
*
|
|
171
|
+
* # Example
|
|
172
|
+
* ```ts
|
|
173
|
+
* const curve = await snaptrude.core.geom.create.splineFromControlPoints([p0, p1, p2, p3])
|
|
174
|
+
* // Quadratic instead of the default cubic
|
|
175
|
+
* const tighter = await snaptrude.core.geom.create.splineFromControlPoints(
|
|
176
|
+
* [p0, p1, p2, p3],
|
|
177
|
+
* { degree: 2 },
|
|
178
|
+
* )
|
|
179
|
+
* ```
|
|
180
|
+
*/
|
|
181
|
+
public abstract splineFromControlPoints(
|
|
182
|
+
controlPoints: Vec3Handle[],
|
|
183
|
+
options?: { degree?: number },
|
|
184
|
+
): PluginApiReturn<SplineHandle>
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Drops a curve onto a face along the face's normal and returns the curves it
|
|
188
|
+
* lands on — one per connected run, empty when the curve misses the face
|
|
189
|
+
* entirely. Host API call — returns new curve handles; the inputs are
|
|
190
|
+
* read-only. No lengths are involved: the result is a curve in the same
|
|
191
|
+
* internal length units as its inputs.
|
|
192
|
+
*
|
|
193
|
+
* **Not available on the shipped kernel build.** The member exists so the
|
|
194
|
+
* contract is stable, and every call throws VALIDATION until the projection
|
|
195
|
+
* primitives ship in a newer OpenCascade build.
|
|
196
|
+
*
|
|
197
|
+
* @param curve The curve to project
|
|
198
|
+
* @param face The face to project onto
|
|
199
|
+
* @param faceBrep The solid `face` belongs to — a face handle cannot name its
|
|
200
|
+
* own solid
|
|
201
|
+
* @returns The projected curves as {@linkcode CurveHandle}`[]`
|
|
202
|
+
* @throws VALIDATION always on this build (the message names the kernel
|
|
203
|
+
* version the member needs); once available, if `face` is not a face of
|
|
204
|
+
* `faceBrep`
|
|
205
|
+
* @throws OPERATION_FAILED if the kernel could not project the curve
|
|
206
|
+
*/
|
|
207
|
+
public abstract curvesFromProjection(
|
|
208
|
+
curve: CurveHandle,
|
|
209
|
+
face: FaceHandle,
|
|
210
|
+
faceBrep: BrepHandle,
|
|
211
|
+
): PluginApiReturn<CurveHandle[]>
|
|
212
|
+
|
|
86
213
|
/**
|
|
87
214
|
* Create a closed profile from an ordered list of point handles connected by
|
|
88
215
|
* line segments (last auto-connected to first). Host API call — returns a handle.
|
|
@@ -116,6 +243,39 @@ export abstract class PluginGeomCreateApi {
|
|
|
116
243
|
*/
|
|
117
244
|
public abstract profileFromCurves(curves: CurveHandle[]): PluginApiReturn<ProfileHandle>
|
|
118
245
|
|
|
246
|
+
/**
|
|
247
|
+
* Create a CLOSED smooth profile passing through each point, in order, with
|
|
248
|
+
* the loop closed smoothly back from the last point to the first (do NOT
|
|
249
|
+
* repeat the first point). Host API call — returns a handle. This is the
|
|
250
|
+
* closed counterpart of {@linkcode PluginGeomCreateApi.splineFromPoints} and
|
|
251
|
+
* the one-call route from points to an extrudable outline: wrap in
|
|
252
|
+
* `contourFromProfile` and extrude/loft/sweep as usual.
|
|
253
|
+
*
|
|
254
|
+
* The whole loop is smooth — v1 takes no mixed straight/spline input. For a
|
|
255
|
+
* profile that is part curve and part straight, build the pieces with
|
|
256
|
+
* `splineFromPoints` + `line` and join them with
|
|
257
|
+
* {@linkcode PluginGeomCreateApi.profileFromCurves}.
|
|
258
|
+
*
|
|
259
|
+
* @param points 3..256 ordered through-points of the loop (first point NOT repeated)
|
|
260
|
+
* @returns The new closed profile as a {@linkcode ProfileHandle}
|
|
261
|
+
* @throws VALIDATION if fewer than 3 points, more than 256 points,
|
|
262
|
+
* consecutive points coincide (including last→first), or the loop
|
|
263
|
+
* self-intersects
|
|
264
|
+
*
|
|
265
|
+
* @examplePrompt Make a blob-shaped floor plate through these points
|
|
266
|
+
* @examplePrompt Organic curved outline through these corners
|
|
267
|
+
* @examplePrompt Freeform podium profile
|
|
268
|
+
*
|
|
269
|
+
* # Example
|
|
270
|
+
* ```ts
|
|
271
|
+
* const profile = await snaptrude.core.geom.create.profileFromSplinePoints([p0, p1, p2, p3, p4])
|
|
272
|
+
* const contour = await snaptrude.core.geom.create.contourFromProfile(profile)
|
|
273
|
+
* const brep = await snaptrude.core.geom.create.brepFromExtrusion(contour, { x: 0, y: 1, z: 0 }, 3)
|
|
274
|
+
* const podium = await snaptrude.design.create.massFromBrep(brep, "Podium")
|
|
275
|
+
* ```
|
|
276
|
+
*/
|
|
277
|
+
public abstract profileFromSplinePoints(points: Vec3Handle[]): PluginApiReturn<ProfileHandle>
|
|
278
|
+
|
|
119
279
|
/**
|
|
120
280
|
* Create an axis-aligned **rectangle** profile (XZ plane) of `width` × `depth`,
|
|
121
281
|
* centred at `center` (defaults to the origin). Host API call — returns a handle.
|
|
@@ -237,15 +397,27 @@ export abstract class PluginGeomCreateApi {
|
|
|
237
397
|
*
|
|
238
398
|
* @param contour The cross-section to extrude (outer profile + optional holes)
|
|
239
399
|
* @param direction Extrusion direction as plain `{x, y, z}` components (non-zero, normalised by the host)
|
|
240
|
-
* @param amount Extrusion distance (non-zero; negative extrudes opposite to `direction`)
|
|
400
|
+
* @param amount Extrusion distance in internal length units (non-zero; negative extrudes opposite to `direction`)
|
|
401
|
+
* @param options Optional twist and taper, both about `direction` through the
|
|
402
|
+
* base contour's centroid. `twistInDegrees` — total rotation base → top in
|
|
403
|
+
* DEGREES (an angle: never scaled by the project's length unit);
|
|
404
|
+
* `topScale` — the top outline's scale, a ratio (1 = no taper); `levels` —
|
|
405
|
+
* how many sections to build through, a count (2..64). Leave `levels` out
|
|
406
|
+
* and the host resolves one and writes it into the record, so the mass
|
|
407
|
+
* regenerates identically ever after. Omit the bag and this is the straight
|
|
408
|
+
* extrusion it has always been, byte for byte.
|
|
241
409
|
* @returns The new solid as a {@linkcode BrepHandle}
|
|
242
410
|
* @throws if the extrusion is degenerate (zero amount, zero direction, or a
|
|
243
411
|
* direction lying in the contour plane) or the contour cannot be extruded
|
|
244
412
|
* into a valid solid
|
|
413
|
+
* @throws VALIDATION if `twistInDegrees` is not finite, `topScale` is not a
|
|
414
|
+
* positive finite ratio, or `levels` is outside 2..64
|
|
245
415
|
*
|
|
246
416
|
* @examplePrompt Extrude this profile 3 metres up
|
|
247
417
|
* @examplePrompt Make a solid by extruding this outline
|
|
248
418
|
* @examplePrompt Create a cylinder from a circle profile
|
|
419
|
+
* @examplePrompt Extrude this floor plate 40m up with a 90 degree twist
|
|
420
|
+
* @examplePrompt Taper this tower to 60 percent of its footprint at the top
|
|
249
421
|
*
|
|
250
422
|
* # Example
|
|
251
423
|
* ```ts
|
|
@@ -259,6 +431,81 @@ export abstract class PluginGeomCreateApi {
|
|
|
259
431
|
contour: ContourHandle,
|
|
260
432
|
direction: Vec3Components,
|
|
261
433
|
amount: number,
|
|
434
|
+
options?: { twistInDegrees?: number; topScale?: number; levels?: number },
|
|
435
|
+
): PluginApiReturn<BrepHandle>
|
|
436
|
+
|
|
437
|
+
/**
|
|
438
|
+
* Stretches a surface across a closed loop of boundary curves and thickens it
|
|
439
|
+
* into a SOLID in one call — a roof over four curves, a canopy between two
|
|
440
|
+
* rails, a blend across a gap. `thickness` is in internal length units and is
|
|
441
|
+
* required: only solids reach the canvas, and there is no separate surface
|
|
442
|
+
* object to keep. Pass edges as `{ edge, brep, face }` with
|
|
443
|
+
* `continuity: "tangent"` to leave the named face smoothly. The result carries
|
|
444
|
+
* NO recipe (`design.query.getParameters` returns `null`) — label it when you
|
|
445
|
+
* commit it, because the label is all the provenance there is.
|
|
446
|
+
*
|
|
447
|
+
* Runs on the OpenCascade kernel (the first kernel call loads a wasm of tens
|
|
448
|
+
* of MB — expect a pause of seconds).
|
|
449
|
+
*
|
|
450
|
+
* @param boundary 3..16 items forming ONE closed loop (ends meeting within
|
|
451
|
+
* tolerance): a curve, or an edge named WITH the solid it belongs to
|
|
452
|
+
* ({@linkcode OwnedEdge}) — an edge handle cannot name its own solid, and
|
|
453
|
+
* one patch may meet two solids. Read scene breps with
|
|
454
|
+
* `design.query.geometry.getBrep(x, { frame: "world" })` so every item is in
|
|
455
|
+
* one frame.
|
|
456
|
+
* @param thickness Solid thickness in internal length units (> 0)
|
|
457
|
+
* @param options `interiorPoints` pull the surface through them (≤ 64, plain
|
|
458
|
+
* `{x, y, z}` in the same frame as the boundary). `continuity` —
|
|
459
|
+
* `"position"` (default) or `"tangent"`: every boundary item must then be an
|
|
460
|
+
* edge item that also names the `face` to continue (a solid edge has two
|
|
461
|
+
* faces — the wall or the top of a rim). `side` — `"below"` (default) or
|
|
462
|
+
* `"above"`: which side of the boundary the solid grows to.
|
|
463
|
+
* @returns The thickened patch as a new {@linkcode BrepHandle}
|
|
464
|
+
* @throws VALIDATION if the boundary is not one closed loop (the message names
|
|
465
|
+
* the gap and its size), a count cap is exceeded, `thickness` is not
|
|
466
|
+
* positive, `continuity: "tangent"` is used with a curve item or with an
|
|
467
|
+
* edge item that names no `face` (the message names the edge's two candidate
|
|
468
|
+
* faces), or a `face` is not adjacent to its `edge`
|
|
469
|
+
* @throws OPERATION_FAILED if the kernel could not fill the boundary, the
|
|
470
|
+
* filled surface misses its own boundary by more than 0.254 mm (the message
|
|
471
|
+
* carries the measured gap), or the thicken produced no solid
|
|
472
|
+
*
|
|
473
|
+
* @examplePrompt Patch a roof over these four boundary curves, 250 mm thick
|
|
474
|
+
* @examplePrompt Span a canopy between these two curved rails, 300 mm thick
|
|
475
|
+
*
|
|
476
|
+
* # Example
|
|
477
|
+
* ```ts
|
|
478
|
+
* // A roof over four curves
|
|
479
|
+
* const roof = await snaptrude.core.geom.create.brepFromPatch(
|
|
480
|
+
* [curveA, curveB, curveC, curveD],
|
|
481
|
+
* 0.25,
|
|
482
|
+
* )
|
|
483
|
+
* const mass = await snaptrude.design.create.massFromBrep(roof, "Roof patch")
|
|
484
|
+
* ```
|
|
485
|
+
*
|
|
486
|
+
* ```ts
|
|
487
|
+
* // A canopy between two towers' rims, leaving every wall it meets smoothly:
|
|
488
|
+
* // with `continuity: "tangent"` EVERY item is an edge naming its face.
|
|
489
|
+
* const canopy = await snaptrude.core.geom.create.brepFromPatch(
|
|
490
|
+
* [
|
|
491
|
+
* { edge: rimA, brep: towerA, face: wallA },
|
|
492
|
+
* { edge: sideA, brep: towerA, face: endA },
|
|
493
|
+
* { edge: rimB, brep: towerB, face: wallB },
|
|
494
|
+
* { edge: sideB, brep: towerB, face: endB },
|
|
495
|
+
* ],
|
|
496
|
+
* 0.3,
|
|
497
|
+
* { continuity: "tangent" },
|
|
498
|
+
* )
|
|
499
|
+
* ```
|
|
500
|
+
*/
|
|
501
|
+
public abstract brepFromPatch(
|
|
502
|
+
boundary: (CurveHandle | OwnedEdge)[],
|
|
503
|
+
thickness: number,
|
|
504
|
+
options?: {
|
|
505
|
+
interiorPoints?: Vec3Components[]
|
|
506
|
+
continuity?: "position" | "tangent"
|
|
507
|
+
side?: "below" | "above"
|
|
508
|
+
},
|
|
262
509
|
): PluginApiReturn<BrepHandle>
|
|
263
510
|
|
|
264
511
|
/**
|
|
@@ -289,7 +536,9 @@ export abstract class PluginGeomCreateApi {
|
|
|
289
536
|
* bottom — sections are auto-matched)
|
|
290
537
|
* @param intermediateContours Optional in-between cross-sections, ordered
|
|
291
538
|
* bottom to top (hole-free; edge counts may differ — every section is
|
|
292
|
-
* normalized to the largest)
|
|
539
|
+
* normalized to the largest). Any count is accepted; a loft of more
|
|
540
|
+
* than 32 sections counting the bottom and the top still builds but
|
|
541
|
+
* carries no parameter record (records are capped, calls are not)
|
|
293
542
|
* @param options Optional behavior switches. `compatibility` — `"auto"`
|
|
294
543
|
* (default) inserts vertices to match differing edge counts; `"strict"`
|
|
295
544
|
* skips normalization and throws VALIDATION when outer edge counts (or,
|
|
@@ -299,7 +548,11 @@ export abstract class PluginGeomCreateApi {
|
|
|
299
548
|
* correspondence unchanged (a twisted correspondence then builds through
|
|
300
549
|
* the triangulated lane for hole-free straight-edged pairs).
|
|
301
550
|
* `{ compatibility: "strict", seamAlignment: "authored" }` reproduces
|
|
302
|
-
* pre-0.9.4 lofting exactly.
|
|
551
|
+
* pre-0.9.4 lofting exactly. `smoothing` — `"ruled"` (default) keeps the
|
|
552
|
+
* straight-sided lane above unchanged; `"smooth"` lofts every section in
|
|
553
|
+
* ONE kernel pass, so the sides curve continuously through the
|
|
554
|
+
* intermediates instead of creasing at each one (a vase, a curved tower —
|
|
555
|
+
* the sections must still be planar and hole-free).
|
|
303
556
|
* @returns The new solid as a {@linkcode BrepHandle}
|
|
304
557
|
* @throws VALIDATION if the contours are coincident, their hole counts
|
|
305
558
|
* differ, any section has holes when intermediates are present
|
|
@@ -321,6 +574,7 @@ export abstract class PluginGeomCreateApi {
|
|
|
321
574
|
* @examplePrompt Loft these outlines even though their corners don't line up
|
|
322
575
|
* @examplePrompt Loft these outlines exactly as authored, corner to corner
|
|
323
576
|
* @examplePrompt Fail the loft if my sections don't have matching edge counts
|
|
577
|
+
* @examplePrompt Loft these three outlines with smoothly curving sides
|
|
324
578
|
*
|
|
325
579
|
* # Example
|
|
326
580
|
* ```ts
|
|
@@ -338,7 +592,11 @@ export abstract class PluginGeomCreateApi {
|
|
|
338
592
|
bottomContour: ContourHandle,
|
|
339
593
|
topContour: ContourHandle,
|
|
340
594
|
intermediateContours?: ContourHandle[],
|
|
341
|
-
options?: {
|
|
595
|
+
options?: {
|
|
596
|
+
compatibility?: "strict" | "auto"
|
|
597
|
+
seamAlignment?: "authored" | "auto"
|
|
598
|
+
smoothing?: "ruled" | "smooth"
|
|
599
|
+
},
|
|
342
600
|
): PluginApiReturn<BrepHandle>
|
|
343
601
|
|
|
344
602
|
/**
|
|
@@ -474,44 +732,92 @@ export abstract class PluginGeomCreateApi {
|
|
|
474
732
|
public abstract brepFromIntersection(a: BrepHandle, b: BrepHandle): PluginApiReturn<BrepHandle>
|
|
475
733
|
|
|
476
734
|
/**
|
|
477
|
-
* Rounds the given
|
|
478
|
-
*
|
|
479
|
-
*
|
|
480
|
-
*
|
|
481
|
-
*
|
|
482
|
-
*
|
|
483
|
-
*
|
|
484
|
-
*
|
|
735
|
+
* Rounds the given edges of a solid with a constant radius. Host API call —
|
|
736
|
+
* returns a new {@linkcode BrepHandle}; the input brep is read-only.
|
|
737
|
+
*
|
|
738
|
+
* Works on curved solids: edges may be straight, circular or spline, and
|
|
739
|
+
* adjacent edges (corner blends) are allowed. To pick a **rim** — the circle
|
|
740
|
+
* where a cylinder meets a flat cap — walk the edges and keep the ones whose
|
|
741
|
+
* two faces are a `cylinder` and a `plane`:
|
|
742
|
+
* `core.geom.query.brep.listEdges(brep)` → per edge
|
|
743
|
+
* `core.geom.query.edge.listFaces(edge)` → `core.geom.query.face.getSurfaceKind`
|
|
744
|
+
* on both faces. (`core.geom.query.brep.listEdgesBetween` takes two VERTEX
|
|
745
|
+
* indices — it is NOT a face-pair lookup.) For one cap's rim only,
|
|
746
|
+
* `core.geom.query.face.listEdges(capFace)` after a `getSurfaceKind` census of
|
|
747
|
+
* `brep.listFaces` is the shorter walk.
|
|
748
|
+
*
|
|
749
|
+
* When the input brep carries a creation recipe, the result carries it too,
|
|
750
|
+
* with this operation appended to `operations`; `design.create.massFromBrep`
|
|
751
|
+
* then keeps the mass editable through `design.update.parameters`.
|
|
752
|
+
*
|
|
753
|
+
* Runs on the OpenCascade kernel (the first kernel call loads a wasm of tens
|
|
754
|
+
* of MB — expect a pause of seconds).
|
|
485
755
|
*
|
|
486
756
|
* Inspect the result via `core.geom.query.brep.*`, or commit it to the scene
|
|
487
757
|
* with `design.create.massFromBrep`.
|
|
488
758
|
*
|
|
489
759
|
* @param brep The solid whose edges to round
|
|
490
|
-
* @param edges The
|
|
491
|
-
*
|
|
760
|
+
* @param edges The edges to fillet (one or more, all on `brep`, no
|
|
761
|
+
* duplicates; more than 64 still fillets but the result carries no
|
|
762
|
+
* parameter record)
|
|
763
|
+
* @param radius Fillet radius in internal length units (positive, finite) —
|
|
764
|
+
* the radius at the START of the blend when a variable form is used
|
|
765
|
+
* @param options Optional VARIABLE blend, in one of two forms, each naming
|
|
766
|
+
* exactly ONE edge: the law belongs to the whole tangent chain that edge
|
|
767
|
+
* lies on, and it is measured from that edge's start. `endRadius` —
|
|
768
|
+
* the radius at the far end, in internal length units, interpolated
|
|
769
|
+
* linearly along the chain; needs an OPEN chain with two distinct ends, and
|
|
770
|
+
* is refused on a closed rim (where the kernel silently builds a constant
|
|
771
|
+
* radius) — use `radii` there. `radii` — a sampled law instead:
|
|
772
|
+
* `position` is normalised ARC LENGTH along the chain (a ratio 0..1, never
|
|
773
|
+
* converted), `radius` is internal length units; 2..32 rows with strictly
|
|
774
|
+
* increasing `position`. On a closed rim 0 and 1 are the same point, so give
|
|
775
|
+
* them the same radius and put the variation in the interior rows. The two
|
|
776
|
+
* forms are mutually exclusive; omitted, the fillet is the constant-radius
|
|
777
|
+
* one it has always been.
|
|
492
778
|
* @returns The filleted solid as a new {@linkcode BrepHandle}
|
|
493
|
-
* @throws VALIDATION if `edges` is empty, `radius` is
|
|
494
|
-
* number, an edge is not on `brep`, an edge
|
|
495
|
-
*
|
|
496
|
-
*
|
|
497
|
-
*
|
|
498
|
-
*
|
|
499
|
-
*
|
|
500
|
-
* @
|
|
779
|
+
* @throws VALIDATION if `edges` is empty or holds a duplicate, `radius` is
|
|
780
|
+
* not a positive finite number, an edge is not on `brep`, or an edge has no
|
|
781
|
+
* crease to round — it is a seam of a closed face, or it lies between two
|
|
782
|
+
* patches of one smooth surface; for a variable blend, if `endRadius` and
|
|
783
|
+
* `radii` are both given, more than one edge is passed, a `radii` table is
|
|
784
|
+
* outside 2..32 rows or its positions do not strictly increase within
|
|
785
|
+
* 0..1, or `endRadius` names a closed rim (the message points at `radii`)
|
|
786
|
+
* @throws PRECONDITION_FAILED if an edge could not be located on the kernel
|
|
787
|
+
* solid after healing (select a different edge, or fillet before the
|
|
788
|
+
* operation that curved the solid), or the kernel could not blend the edge
|
|
789
|
+
* named in the message (reduce the radius or drop that edge)
|
|
790
|
+
* @throws OPERATION_FAILED if the kernel or the translation fails, or the
|
|
791
|
+
* result is non-manifold, splits into several solids, or contains a surface
|
|
792
|
+
* Snaptrude cannot represent
|
|
793
|
+
*
|
|
794
|
+
* @examplePrompt Round the rim of the column with 200 mm
|
|
795
|
+
* @examplePrompt Soften where the dome meets the wall
|
|
501
796
|
* @examplePrompt Fillet the corners of the podium with a 0.5m radius
|
|
502
797
|
* @examplePrompt Soften the vertical edges of this tower
|
|
798
|
+
* @examplePrompt Blend this edge from 200mm at one end to 600mm at the other
|
|
799
|
+
* @examplePrompt Round this rim wider at the back than at the front
|
|
503
800
|
*
|
|
504
801
|
* # Example
|
|
505
802
|
* ```ts
|
|
506
|
-
*
|
|
507
|
-
* const edges = await snaptrude.core.geom.query.brep.listEdges(
|
|
508
|
-
* const
|
|
803
|
+
* // Rim = every edge between the cylinder side and a plane cap
|
|
804
|
+
* const edges = await snaptrude.core.geom.query.brep.listEdges(column)
|
|
805
|
+
* const rim = []
|
|
806
|
+
* for (const edge of edges) {
|
|
807
|
+
* const faces = await snaptrude.core.geom.query.edge.listFaces(edge)
|
|
808
|
+
* const kinds = await Promise.all(
|
|
809
|
+
* faces.map((f) => snaptrude.core.geom.query.face.getSurfaceKind(f)),
|
|
810
|
+
* )
|
|
811
|
+
* if (kinds.includes("cylinder") && kinds.includes("plane")) rim.push(edge)
|
|
812
|
+
* }
|
|
813
|
+
* const rounded = await snaptrude.core.geom.create.brepFromFillet(column, rim, 0.787) // 200 mm
|
|
509
814
|
* ```
|
|
510
815
|
*/
|
|
511
816
|
public abstract brepFromFillet(
|
|
512
817
|
brep: BrepHandle,
|
|
513
818
|
edges: EdgeHandle[],
|
|
514
819
|
radius: number,
|
|
820
|
+
options?: { endRadius?: number; radii?: { position: number; radius: number }[] },
|
|
515
821
|
): PluginApiReturn<BrepHandle>
|
|
516
822
|
|
|
517
823
|
/**
|
|
@@ -519,6 +825,14 @@ export abstract class PluginGeomCreateApi {
|
|
|
519
825
|
* moves faces outward, negative moves them inward. Host API call — returns
|
|
520
826
|
* a new {@linkcode BrepHandle}; the input brep is read-only.
|
|
521
827
|
*
|
|
828
|
+
* Works on curved solids: a sphere offsets to a sphere, a torus to a torus,
|
|
829
|
+
* a cylinder to a cylinder. There is nothing to select — the whole solid is
|
|
830
|
+
* offset.
|
|
831
|
+
*
|
|
832
|
+
* When the input brep carries a creation recipe, the result carries it too,
|
|
833
|
+
* with this operation appended to `operations`; `design.create.massFromBrep`
|
|
834
|
+
* then keeps the mass editable through `design.update.parameters`.
|
|
835
|
+
*
|
|
522
836
|
* Runs on the OpenCascade kernel (the first kernel call loads a wasm of
|
|
523
837
|
* tens of MB — expect a pause of seconds).
|
|
524
838
|
*
|
|
@@ -530,9 +844,15 @@ export abstract class PluginGeomCreateApi {
|
|
|
530
844
|
* @returns The offset solid as a new {@linkcode BrepHandle}
|
|
531
845
|
* @throws VALIDATION if `distance` is not finite, is too small to offset
|
|
532
846
|
* anything, or an inward distance consumes the solid entirely
|
|
533
|
-
* @throws OPERATION_FAILED if the kernel
|
|
534
|
-
* result
|
|
535
|
-
*
|
|
847
|
+
* @throws OPERATION_FAILED if the kernel or the translation fails, or the
|
|
848
|
+
* result is non-manifold, splits into several solids, or contains a surface
|
|
849
|
+
* Snaptrude cannot represent (an offset free-form NURBS surface may have no
|
|
850
|
+
* exact representation — the model is left unchanged). A distance the
|
|
851
|
+
* solid cannot carry surfaces here, with a hint asking for a smaller one;
|
|
852
|
+
* there is no per-face refusal — the kernel's per-face history verdict
|
|
853
|
+
* ("this face was not offset") is logged, never raised (P4-D57)
|
|
854
|
+
*
|
|
855
|
+
* @examplePrompt Thicken the torus ring by 100 mm
|
|
536
856
|
* @examplePrompt Grow this solid by 0.5m in every direction
|
|
537
857
|
* @examplePrompt Shrink this mass by 200mm
|
|
538
858
|
* @examplePrompt Offset the building envelope outward by 1m
|
|
@@ -551,6 +871,17 @@ export abstract class PluginGeomCreateApi {
|
|
|
551
871
|
* input brep is read-only. The outer surface is kept and the walls grow
|
|
552
872
|
* inward.
|
|
553
873
|
*
|
|
874
|
+
* Works on curved solids: the open faces may be spherical, cylindrical,
|
|
875
|
+
* conical, toroidal or free-form patches, not only flat ones. To open the
|
|
876
|
+
* flat base of a dome, census the faces first — `core.geom.query.brep.listFaces`
|
|
877
|
+
* then `core.geom.query.face.getSurfaceKind` on each — and keep the `"plane"`
|
|
878
|
+
* one. A closed curved surface is stored as several patches (a sphere as
|
|
879
|
+
* lunes), so opening "the sphere" may mean passing several faces.
|
|
880
|
+
*
|
|
881
|
+
* When the input brep carries a creation recipe, the result carries it too,
|
|
882
|
+
* with this operation appended to `operations`; `design.create.massFromBrep`
|
|
883
|
+
* then keeps the mass editable through `design.update.parameters`.
|
|
884
|
+
*
|
|
554
885
|
* Runs on the OpenCascade kernel (the first kernel call loads a wasm of
|
|
555
886
|
* tens of MB — expect a pause of seconds).
|
|
556
887
|
*
|
|
@@ -558,24 +889,36 @@ export abstract class PluginGeomCreateApi {
|
|
|
558
889
|
* with `design.create.massFromBrep`.
|
|
559
890
|
*
|
|
560
891
|
* @param brep The solid to hollow
|
|
561
|
-
* @param openFaces The faces to remove as openings (
|
|
892
|
+
* @param openFaces The faces to remove as openings (one or more, all on
|
|
893
|
+
* `brep`, no duplicates; more than 32 still shells but the result carries
|
|
894
|
+
* no parameter record)
|
|
562
895
|
* @param thickness Wall thickness (positive, finite, smaller than half the solid's smallest span)
|
|
563
896
|
* @returns The hollowed solid as a new {@linkcode BrepHandle}
|
|
564
|
-
* @throws VALIDATION if `openFaces` is empty, a face is
|
|
565
|
-
* `thickness` is not a positive finite number, or the
|
|
566
|
-
* large (it must be smaller than half the solid's smallest
|
|
567
|
-
*
|
|
568
|
-
*
|
|
569
|
-
*
|
|
897
|
+
* @throws VALIDATION if `openFaces` is empty or holds a duplicate, a face is
|
|
898
|
+
* not on `brep`, `thickness` is not a positive finite number, or the
|
|
899
|
+
* thickness is too large (it must be smaller than half the solid's smallest
|
|
900
|
+
* span)
|
|
901
|
+
* @throws OPERATION_FAILED if the kernel or the translation fails, or the
|
|
902
|
+
* result is non-manifold, splits into several solids, or contains a surface
|
|
903
|
+
* Snaptrude cannot represent. A thickness the solid cannot carry surfaces
|
|
904
|
+
* here, with a hint asking for one below half the smallest span; there is
|
|
905
|
+
* no per-face refusal — the kernel's per-face history verdict ("this kept
|
|
906
|
+
* face was not thickened") is logged, never raised (P4-D57)
|
|
907
|
+
*
|
|
908
|
+
* @examplePrompt Hollow the dome into a 300 mm shell, open at the base
|
|
570
909
|
* @examplePrompt Hollow this mass into 200mm walls
|
|
571
910
|
* @examplePrompt Shell this form with the top face open
|
|
572
911
|
* @examplePrompt Turn this solid tower into a tube open at both ends
|
|
573
912
|
*
|
|
574
913
|
* # Example
|
|
575
914
|
* ```ts
|
|
576
|
-
*
|
|
577
|
-
* const faces = await snaptrude.core.geom.query.brep.listFaces(
|
|
578
|
-
* const
|
|
915
|
+
* // Open the dome at its flat base: the one face whose surface is a plane
|
|
916
|
+
* const faces = await snaptrude.core.geom.query.brep.listFaces(dome)
|
|
917
|
+
* const base = []
|
|
918
|
+
* for (const face of faces) {
|
|
919
|
+
* if ((await snaptrude.core.geom.query.face.getSurfaceKind(face)) === "plane") base.push(face)
|
|
920
|
+
* }
|
|
921
|
+
* const hollow = await snaptrude.core.geom.create.brepFromShell(dome, base, 1.181) // 300 mm
|
|
579
922
|
* ```
|
|
580
923
|
*/
|
|
581
924
|
public abstract brepFromShell(
|
|
@@ -625,28 +968,89 @@ export abstract class PluginGeomCreateApi {
|
|
|
625
968
|
): PluginApiReturn<BrepHandle[]>
|
|
626
969
|
|
|
627
970
|
/**
|
|
628
|
-
*
|
|
629
|
-
*
|
|
630
|
-
*
|
|
971
|
+
* Cuts a solid with a FACE of another solid — the curved twin of
|
|
972
|
+
* {@linkcode PluginGeomCreateApi.brepsFromSplit}, which cuts with a plane.
|
|
973
|
+
* Host API call — returns new {@linkcode BrepHandle}s; both inputs are
|
|
974
|
+
* read-only. BOTH breps must be in the same frame: read scene masses with
|
|
975
|
+
* `design.query.geometry.getBrep(x, { frame: "world" })` (the default is each
|
|
976
|
+
* mass's own local frame, and two masses have two). The pieces come back in
|
|
977
|
+
* DESCENDING volume order; pick the one you want with
|
|
978
|
+
* `core.geom.query.brep.getCentroid` or `getVolume` and commit it. A piece
|
|
979
|
+
* carries no recipe — label it.
|
|
980
|
+
*
|
|
981
|
+
* Runs on the OpenCascade kernel (the first kernel call loads a wasm of tens
|
|
982
|
+
* of MB — expect a pause of seconds).
|
|
983
|
+
*
|
|
984
|
+
* @param brep The solid to cut
|
|
985
|
+
* @param toolFace The cutting face, read-only
|
|
986
|
+
* @param toolBrep The solid `toolFace` belongs to — a face handle cannot name
|
|
987
|
+
* its own solid
|
|
988
|
+
* @returns The resulting pieces as {@linkcode BrepHandle}`[]`, largest first
|
|
989
|
+
* @throws VALIDATION if `toolFace` is not a face of `toolBrep`, `toolBrep` IS
|
|
990
|
+
* `brep`, or the cut produced a single part — the surface does not pass all
|
|
991
|
+
* the way through (extend it past the mass on every side, and check both
|
|
992
|
+
* breps were read in the same frame)
|
|
993
|
+
* @throws OPERATION_FAILED if the kernel could not split the solid
|
|
994
|
+
*
|
|
995
|
+
* @examplePrompt Cut this mass with the curved roof surface and keep the lower part
|
|
631
996
|
*
|
|
632
|
-
*
|
|
633
|
-
*
|
|
634
|
-
*
|
|
997
|
+
* # Example
|
|
998
|
+
* ```ts
|
|
999
|
+
* const target = await snaptrude.design.query.geometry.getBrep(tower, { frame: "world" })
|
|
1000
|
+
* const tool = await snaptrude.design.query.geometry.getBrep(roof, { frame: "world" })
|
|
1001
|
+
* const [toolFace] = await snaptrude.core.geom.query.brep.listFaces(tool)
|
|
1002
|
+
* const pieces = await snaptrude.core.geom.create.brepsFromSplitByFace(target, toolFace, tool)
|
|
1003
|
+
* ```
|
|
1004
|
+
*/
|
|
1005
|
+
public abstract brepsFromSplitByFace(
|
|
1006
|
+
brep: BrepHandle,
|
|
1007
|
+
toolFace: FaceHandle,
|
|
1008
|
+
toolBrep: BrepHandle,
|
|
1009
|
+
): PluginApiReturn<BrepHandle[]>
|
|
1010
|
+
|
|
1011
|
+
/**
|
|
1012
|
+
* Bevels the given edges of a solid with a symmetric planar cut. Host API
|
|
1013
|
+
* call — returns a new {@linkcode BrepHandle}; the input brep is read-only.
|
|
1014
|
+
*
|
|
1015
|
+
* Works on curved solids: edges may be straight, circular or spline, and
|
|
1016
|
+
* adjacent edges are allowed. Pick edges the same way as for
|
|
1017
|
+
* {@linkcode PluginGeomCreateApi.brepFromFillet} — `brep.listEdges`, then
|
|
1018
|
+
* `core.geom.query.edge.listFaces` and `core.geom.query.face.getSurfaceKind`
|
|
1019
|
+
* on both faces of each edge. (`core.geom.query.brep.listEdgesBetween` takes
|
|
1020
|
+
* two VERTEX indices — it is NOT a face-pair lookup.) Chamfering a cylinder's
|
|
1021
|
+
* rim yields a cone patch where a fillet would yield a torus patch.
|
|
1022
|
+
*
|
|
1023
|
+
* When the input brep carries a creation recipe, the result carries it too,
|
|
1024
|
+
* with this operation appended to `operations`; `design.create.massFromBrep`
|
|
1025
|
+
* then keeps the mass editable through `design.update.parameters`.
|
|
1026
|
+
*
|
|
1027
|
+
* Runs on the OpenCascade kernel (the first kernel call loads a wasm of tens
|
|
1028
|
+
* of MB — expect a pause of seconds).
|
|
635
1029
|
*
|
|
636
1030
|
* Inspect the result via `core.geom.query.brep.*`, or commit it to the scene
|
|
637
1031
|
* with `design.create.massFromBrep`.
|
|
638
1032
|
*
|
|
639
1033
|
* @param brep The solid whose edges to bevel
|
|
640
|
-
* @param edges The
|
|
1034
|
+
* @param edges The edges to chamfer (one or more, all on `brep`, no
|
|
1035
|
+
* duplicates; more than 64 still chamfers but the result carries no
|
|
1036
|
+
* parameter record)
|
|
641
1037
|
* @param distance Chamfer distance from the edge on each adjacent face (positive, finite)
|
|
642
1038
|
* @returns The chamfered solid as a new {@linkcode BrepHandle}
|
|
643
|
-
* @throws VALIDATION if `edges` is empty, `distance` is
|
|
644
|
-
* finite number, an edge is not on `brep`, an edge
|
|
645
|
-
*
|
|
646
|
-
*
|
|
647
|
-
* @throws
|
|
648
|
-
*
|
|
649
|
-
*
|
|
1039
|
+
* @throws VALIDATION if `edges` is empty or holds a duplicate, `distance` is
|
|
1040
|
+
* not a positive finite number, an edge is not on `brep`, or an edge has no
|
|
1041
|
+
* crease to cut — it is a seam of a closed face, or it lies between two
|
|
1042
|
+
* patches of one smooth surface
|
|
1043
|
+
* @throws PRECONDITION_FAILED if an edge could not be located on the kernel
|
|
1044
|
+
* solid after healing (select a different edge, or chamfer before the
|
|
1045
|
+
* operation that curved the solid)
|
|
1046
|
+
* @throws OPERATION_FAILED if the kernel or the translation fails, or the
|
|
1047
|
+
* result is non-manifold, splits into several solids, or contains a surface
|
|
1048
|
+
* Snaptrude cannot represent. A distance larger than an adjacent face
|
|
1049
|
+
* surfaces here, with a hint asking for a smaller one: unlike
|
|
1050
|
+
* {@linkcode PluginGeomCreateApi.brepFromFillet}, a chamfer has no
|
|
1051
|
+
* per-edge kernel verdict, so the failure names no edge (P4-D59)
|
|
1052
|
+
*
|
|
1053
|
+
* @examplePrompt Chamfer the top edge of the cylinder
|
|
650
1054
|
* @examplePrompt Bevel these edges by 100mm
|
|
651
1055
|
* @examplePrompt Chamfer the top edges of the plinth
|
|
652
1056
|
* @examplePrompt Cut a 45-degree flat along the corners of this mass
|
|
@@ -682,11 +1086,15 @@ export abstract class PluginGeomCreateApi {
|
|
|
682
1086
|
* tapering across a bend or along an arc edge would create faces Snaptrude
|
|
683
1087
|
* cannot represent and throws (sweep each straight run separately and union
|
|
684
1088
|
* the results instead). An optional `transition` picks the corner
|
|
685
|
-
* treatment: `"miter"` (default) is today's sharp mitred bend;
|
|
1089
|
+
* treatment: `"miter"` (default) is today's sharp mitred bend; `"round"`
|
|
1090
|
+
* carries the section around each turning corner on a tangent circular arc,
|
|
1091
|
+
* so the corner patch is a real curved (cylindrical) surface rather than a
|
|
1092
|
+
* flat cut (open paths only — `"round"` on a closed ring path is refused);
|
|
686
1093
|
* `{ bevel: b }` chamfers each turning corner by cutting `b` back along
|
|
687
1094
|
* both adjacent legs (works on open and closed paths — each leg must be
|
|
688
|
-
* long enough for its cuts). On a corner-less path `transition` has no
|
|
689
|
-
* varying-scale lane takes straight paths, so it never sees
|
|
1095
|
+
* long enough for its cuts). On a corner-less path `transition` has no
|
|
1096
|
+
* effect, and the varying-scale lane takes straight paths, so it never sees
|
|
1097
|
+
* a corner.
|
|
690
1098
|
*
|
|
691
1099
|
* Open paths run on the OpenCascade kernel (the first kernel call loads a
|
|
692
1100
|
* wasm of tens of MB — expect a pause of seconds); closed paths are
|
|
@@ -696,19 +1104,22 @@ export abstract class PluginGeomCreateApi {
|
|
|
696
1104
|
* with `design.create.massFromBrep`.
|
|
697
1105
|
*
|
|
698
1106
|
* @param profile The cross-section to sweep (hole-free contour)
|
|
699
|
-
* @param path The polyline path as plain `{x, y, z}` points (
|
|
700
|
-
* first point as the last to close the path into a ring
|
|
1107
|
+
* @param path The polyline path as plain `{x, y, z}` points (2 or more;
|
|
1108
|
+
* repeat the first point as the last to close the path into a ring; more
|
|
1109
|
+
* than 512 points still sweeps but the result carries no parameter record)
|
|
701
1110
|
* @param options Optional scale law and corner transition. Scale law:
|
|
702
1111
|
* `startScale`/`endScale` (linear taper by arc length) or `scales` (one
|
|
703
1112
|
* factor per path point; mutually exclusive with
|
|
704
1113
|
* `startScale`/`endScale`); every factor must be finite and within
|
|
705
|
-
* 1e-3..1e3. `transition`: `"miter"` (default, sharp corners)
|
|
706
|
-
* `
|
|
707
|
-
*
|
|
1114
|
+
* 1e-3..1e3. `transition`: `"miter"` (default, sharp corners),
|
|
1115
|
+
* `"round"` (arc-carried corners — curved corner patches; open paths
|
|
1116
|
+
* only) or `{ bevel: b }` (chamfered corners, `b` finite within
|
|
1117
|
+
* 1e-3..1e3; open and closed paths)
|
|
708
1118
|
* @returns The swept solid as a new {@linkcode BrepHandle}
|
|
709
1119
|
* @throws VALIDATION if the profile has holes, the path has fewer than 2
|
|
710
|
-
* points, consecutive path points coincide, a
|
|
711
|
-
* or the profile plane contains the first
|
|
1120
|
+
* points, consecutive path points coincide, a
|
|
1121
|
+
* coordinate is not finite, or the profile plane contains the first
|
|
1122
|
+
* path segment's direction
|
|
712
1123
|
* (degenerate sweep); for closed paths, if the ring has fewer than 3
|
|
713
1124
|
* distinct corners, the path is non-planar, a corner doubles back, the
|
|
714
1125
|
* profile has an arc edge, or the profile is too large for a mitred
|
|
@@ -716,11 +1127,14 @@ export abstract class PluginGeomCreateApi {
|
|
|
716
1127
|
* is combined with `startScale`/`endScale`, `scales` does not match the
|
|
717
1128
|
* path length, or a varying scale is used on a bent or closed path or
|
|
718
1129
|
* with an arc-edged profile; for `{ bevel }`, if a leg is too short for
|
|
719
|
-
* the cuts its
|
|
720
|
-
* back so its
|
|
1130
|
+
* the cuts its bevelled corners take from it or a corner nearly doubles
|
|
1131
|
+
* back so its bevel collapses (the errors name the corner)
|
|
1132
|
+
* @throws PRECONDITION_FAILED if `transition` is `"round"` and the path is
|
|
1133
|
+
* closed — round corners are an open-path lane; use `"miter"` or
|
|
1134
|
+
* `{ bevel }` on a ring
|
|
721
1135
|
* @throws OPERATION_FAILED if the kernel cannot sweep the profile into a
|
|
722
|
-
* valid solid
|
|
723
|
-
*
|
|
1136
|
+
* valid solid — including a `"round"` corner whose arc does not fit its
|
|
1137
|
+
* legs, which is not pre-checked and so is not named per corner
|
|
724
1138
|
*
|
|
725
1139
|
* @examplePrompt Sweep this profile along the corridor path
|
|
726
1140
|
* @examplePrompt Extrude the railing section along this route
|
|
@@ -729,6 +1143,7 @@ export abstract class PluginGeomCreateApi {
|
|
|
729
1143
|
* @examplePrompt Taper this duct from 1x1 to 2x2 along its run
|
|
730
1144
|
* @examplePrompt Sweep a column section that narrows toward the top
|
|
731
1145
|
* @examplePrompt Chamfer the corners of this swept frame by 200mm
|
|
1146
|
+
* @examplePrompt Sweep this handrail with rounded corners at the bends
|
|
732
1147
|
*
|
|
733
1148
|
* # Example
|
|
734
1149
|
* ```ts
|
|
@@ -767,17 +1182,75 @@ export abstract class PluginGeomCreateApi {
|
|
|
767
1182
|
startScale?: number
|
|
768
1183
|
endScale?: number
|
|
769
1184
|
scales?: number[]
|
|
770
|
-
transition?: "miter" | { bevel: number }
|
|
1185
|
+
transition?: "miter" | "round" | { bevel: number }
|
|
771
1186
|
},
|
|
772
1187
|
): PluginApiReturn<BrepHandle>
|
|
773
1188
|
|
|
1189
|
+
/**
|
|
1190
|
+
* Sweeps a cross-section along a SMOOTH path — splines, arcs and lines chained
|
|
1191
|
+
* end to end — with control of how the profile turns.
|
|
1192
|
+
* {@linkcode PluginGeomCreateApi.brepFromSweep} takes a polyline path; this
|
|
1193
|
+
* takes curves. Host API call — returns a new {@linkcode BrepHandle}; the
|
|
1194
|
+
* inputs are read-only. Records as `sweepAlongCurve`, so the orientation stays
|
|
1195
|
+
* editable through `design.update.parameters` (agent-editable; the panel shows
|
|
1196
|
+
* it read-only — a string is not a scalar row).
|
|
1197
|
+
*
|
|
1198
|
+
* Runs on the OpenCascade kernel (the first kernel call loads a wasm of tens
|
|
1199
|
+
* of MB — expect a pause of seconds).
|
|
1200
|
+
*
|
|
1201
|
+
* @param profile Hole-free cross-section contour; placed at the first curve's start
|
|
1202
|
+
* @param path 1..64 curves, ordered, meeting end to end within tolerance
|
|
1203
|
+
* @param options `orientation` — `"upright"` (default) keeps the profile's up
|
|
1204
|
+
* aligned with world up (ducts, handrails, ribbons that must not roll);
|
|
1205
|
+
* `"frenet"` lets it roll with the path's curvature; `"fixed"` carries the
|
|
1206
|
+
* authored frame along unchanged, which is a pure translation — use it to
|
|
1207
|
+
* bend a footprint along an arc. `rail` is a second guide curve and needs a
|
|
1208
|
+
* newer kernel build than the one shipped here.
|
|
1209
|
+
* @returns The swept solid as a new {@linkcode BrepHandle}
|
|
1210
|
+
* @throws VALIDATION if the path curves are not connected, the path is closed,
|
|
1211
|
+
* the profile has holes, the first tangent lies in the profile plane, the
|
|
1212
|
+
* path runs vertically under `"upright"` (that frame is undefined there —
|
|
1213
|
+
* the message names the run and points at `"frenet"`), the path turns
|
|
1214
|
+
* parallel to the profile under `"fixed"`, or `rail` is passed on a kernel
|
|
1215
|
+
* build that cannot carry it
|
|
1216
|
+
* @throws OPERATION_FAILED if the kernel could not sweep the profile — a
|
|
1217
|
+
* self-intersection on a tight bend
|
|
1218
|
+
*
|
|
1219
|
+
* @examplePrompt Sweep a 600x400 duct along this curved route and keep it upright
|
|
1220
|
+
* @examplePrompt Run this handrail along the curved stair edge
|
|
1221
|
+
* @examplePrompt Bend this footprint along the arc
|
|
1222
|
+
*
|
|
1223
|
+
* # Example
|
|
1224
|
+
* ```ts
|
|
1225
|
+
* const route = await snaptrude.core.geom.create.splineFromPoints(points)
|
|
1226
|
+
* const duct = await snaptrude.core.geom.create.brepFromSweepAlongCurve(profile, [route], {
|
|
1227
|
+
* orientation: "upright",
|
|
1228
|
+
* })
|
|
1229
|
+
* ```
|
|
1230
|
+
*/
|
|
1231
|
+
public abstract brepFromSweepAlongCurve(
|
|
1232
|
+
profile: ContourHandle,
|
|
1233
|
+
path: CurveHandle[],
|
|
1234
|
+
options?: SweepAlongCurveOptions,
|
|
1235
|
+
): PluginApiReturn<BrepHandle>
|
|
1236
|
+
|
|
774
1237
|
/**
|
|
775
1238
|
* Revolves a planar profile about an axis to make a solid of revolution — a
|
|
776
1239
|
* full turn by default. Host API call — returns a new
|
|
777
1240
|
* {@linkcode BrepHandle}; the input contour is read-only. Holes in the
|
|
778
|
-
* profile are allowed
|
|
779
|
-
*
|
|
780
|
-
*
|
|
1241
|
+
* profile are allowed, and segments may run at any angle to the axis: an
|
|
1242
|
+
* inclined segment revolves into a cone, an arc into a sphere or torus
|
|
1243
|
+
* section. This is the general route to domes, vases, columns and rotundas.
|
|
1244
|
+
*
|
|
1245
|
+
* Two rules bind the axis to the profile. First, the axis line must lie IN
|
|
1246
|
+
* the profile's plane — a revolution turns a planar section about a line
|
|
1247
|
+
* drawn in that same plane. An axis that misses the plane (skew to it, or
|
|
1248
|
+
* parallel but offset out of it) is refused: move the axis into the
|
|
1249
|
+
* profile's plane, or move the profile onto the axis's plane. Second,
|
|
1250
|
+
* within that plane the whole profile stays on ONE side of the axis.
|
|
1251
|
+
* Vertices and whole segments may lie ON the axis — that is how a dome's
|
|
1252
|
+
* pole and a cylinder's inner edge are authored — but no part of the profile
|
|
1253
|
+
* may cross to the other side, which would sweep a self-intersecting solid.
|
|
781
1254
|
*
|
|
782
1255
|
* Runs on the OpenCascade kernel (the first kernel call loads a wasm of
|
|
783
1256
|
* tens of MB — expect a pause of seconds).
|
|
@@ -791,19 +1264,25 @@ export abstract class PluginGeomCreateApi {
|
|
|
791
1264
|
* @param angleInDegrees Optional revolution angle in degrees (0 < angle ≤ 360; default 360)
|
|
792
1265
|
* @returns The revolved solid as a new {@linkcode BrepHandle}
|
|
793
1266
|
* @throws VALIDATION if `axisDirection` is zero-length, `angleInDegrees` is
|
|
794
|
-
* not in (0, 360],
|
|
795
|
-
*
|
|
796
|
-
*
|
|
797
|
-
*
|
|
798
|
-
*
|
|
1267
|
+
* not in (0, 360], a coordinate is not finite, or the profile crosses the
|
|
1268
|
+
* axis (the message names the offending segment — keep the whole profile
|
|
1269
|
+
* on one side; points may touch the axis but not cross it)
|
|
1270
|
+
* @throws PRECONDITION_FAILED if the axis does not lie in the profile's
|
|
1271
|
+
* plane — skew to it, or parallel but offset out of it (the message asks
|
|
1272
|
+
* you to move the axis into that plane)
|
|
1273
|
+
* @throws OPERATION_FAILED if the kernel cannot revolve the profile into a
|
|
1274
|
+
* valid solid
|
|
799
1275
|
*
|
|
800
1276
|
* @examplePrompt Create a dome from this section
|
|
801
1277
|
* @examplePrompt Revolve this profile 360 degrees around the vertical axis
|
|
802
1278
|
* @examplePrompt Build a rotunda by revolving this wall section
|
|
1279
|
+
* @examplePrompt Make a dome by revolving a quarter-circle about the vertical axis
|
|
1280
|
+
* @examplePrompt Turn this curved outline into a vase
|
|
803
1281
|
*
|
|
804
1282
|
* # Example
|
|
805
1283
|
* ```ts
|
|
806
|
-
* // A cylinder: revolve a 2m-wide, 3m-tall rectangle about the Y axis at
|
|
1284
|
+
* // A cylinder: revolve a 2m-wide, 3m-tall rectangle about the Y axis at
|
|
1285
|
+
* // its edge — the left edge sits ON the axis, which is legal.
|
|
807
1286
|
* const rect = await snaptrude.core.geom.create.profileFromLinePoints([
|
|
808
1287
|
* await snaptrude.core.math.vec3.new(0, 0, 0),
|
|
809
1288
|
* await snaptrude.core.math.vec3.new(2, 0, 0),
|
|
@@ -824,6 +1303,158 @@ export abstract class PluginGeomCreateApi {
|
|
|
824
1303
|
axisDirection: Vec3Components,
|
|
825
1304
|
angleInDegrees?: number,
|
|
826
1305
|
): PluginApiReturn<BrepHandle>
|
|
1306
|
+
|
|
1307
|
+
/**
|
|
1308
|
+
* Create a solid **sphere** B-rep from a centre and radius. Host API call —
|
|
1309
|
+
* returns a {@linkcode BrepHandle}; commit it to the scene with
|
|
1310
|
+
* `design.create.massFromBrep`. The result carries an exact spherical
|
|
1311
|
+
* surface (not a faceted approximation) and a creation recipe — read the
|
|
1312
|
+
* committed mass's parameters back with `design.query.getParameters` and edit
|
|
1313
|
+
* them with `design.update.parameters`.
|
|
1314
|
+
*
|
|
1315
|
+
* Runs on the OpenCascade kernel (the first kernel call loads a wasm of tens
|
|
1316
|
+
* of MB — expect a pause of seconds).
|
|
1317
|
+
*
|
|
1318
|
+
* @param centre Sphere centre as plain `{x, y, z}` components (raw Babylon units)
|
|
1319
|
+
* @param radius Sphere radius (> 0, raw Babylon units)
|
|
1320
|
+
* @returns The new solid as a {@linkcode BrepHandle}
|
|
1321
|
+
* @throws VALIDATION if `radius` is not a positive finite number or a
|
|
1322
|
+
* coordinate is not finite
|
|
1323
|
+
*
|
|
1324
|
+
* @examplePrompt Create a sphere of radius 5 at the origin
|
|
1325
|
+
* @examplePrompt Add a 3m ball on top of the tower
|
|
1326
|
+
*
|
|
1327
|
+
* # Example
|
|
1328
|
+
* ```ts
|
|
1329
|
+
* const brep = await snaptrude.core.geom.create.brepFromSphere({ x: 0, y: 5, z: 0 }, 5)
|
|
1330
|
+
* const mass = await snaptrude.design.create.massFromBrep(brep, "Sphere")
|
|
1331
|
+
* ```
|
|
1332
|
+
*/
|
|
1333
|
+
public abstract brepFromSphere(
|
|
1334
|
+
centre: Vec3Components,
|
|
1335
|
+
radius: number,
|
|
1336
|
+
): PluginApiReturn<BrepHandle>
|
|
1337
|
+
|
|
1338
|
+
/**
|
|
1339
|
+
* Create a solid **cylinder** B-rep from its bottom-cap centre, axis
|
|
1340
|
+
* direction, radius and height. Host API call — returns a
|
|
1341
|
+
* {@linkcode BrepHandle}; commit with `design.create.massFromBrep`. The
|
|
1342
|
+
* bottom cap sits AT `base` and the solid extends `height` along `axis` —
|
|
1343
|
+
* place `base` on the floor and use axis `{x: 0, y: 1, z: 0}` for an upright
|
|
1344
|
+
* column. Carries a creation recipe (radius, height), editable through
|
|
1345
|
+
* `design.update.parameters`.
|
|
1346
|
+
*
|
|
1347
|
+
* Runs on the OpenCascade kernel (the first kernel call loads a wasm of tens
|
|
1348
|
+
* of MB — expect a pause of seconds).
|
|
1349
|
+
*
|
|
1350
|
+
* @param base Centre of the bottom cap as plain `{x, y, z}` components
|
|
1351
|
+
* @param axis Axis direction as plain `{x, y, z}` components (non-zero, normalised by the host)
|
|
1352
|
+
* @param radius Cylinder radius (> 0)
|
|
1353
|
+
* @param height Cylinder height along `axis` (> 0)
|
|
1354
|
+
* @returns The new solid as a {@linkcode BrepHandle}
|
|
1355
|
+
* @throws VALIDATION if `radius`/`height` are not positive finite numbers or
|
|
1356
|
+
* `axis` is zero-length
|
|
1357
|
+
*
|
|
1358
|
+
* @examplePrompt Create a cylinder 2m across and 4m tall
|
|
1359
|
+
* @examplePrompt Add a circular column here
|
|
1360
|
+
*
|
|
1361
|
+
* # Example
|
|
1362
|
+
* ```ts
|
|
1363
|
+
* const brep = await snaptrude.core.geom.create.brepFromCylinder(
|
|
1364
|
+
* { x: 0, y: 0, z: 0 },
|
|
1365
|
+
* { x: 0, y: 1, z: 0 },
|
|
1366
|
+
* 1,
|
|
1367
|
+
* 4,
|
|
1368
|
+
* )
|
|
1369
|
+
* const column = await snaptrude.design.create.massFromBrep(brep, "Column")
|
|
1370
|
+
* ```
|
|
1371
|
+
*/
|
|
1372
|
+
public abstract brepFromCylinder(
|
|
1373
|
+
base: Vec3Components,
|
|
1374
|
+
axis: Vec3Components,
|
|
1375
|
+
radius: number,
|
|
1376
|
+
height: number,
|
|
1377
|
+
): PluginApiReturn<BrepHandle>
|
|
1378
|
+
|
|
1379
|
+
/**
|
|
1380
|
+
* Create a solid **cone or frustum** B-rep: bottom-cap centre, axis, base
|
|
1381
|
+
* radius, height, and an optional top radius (default 0 — a full cone to a
|
|
1382
|
+
* point; > 0 — a frustum / tapered column). Host API call — returns a
|
|
1383
|
+
* {@linkcode BrepHandle}; commit with `design.create.massFromBrep`. Carries
|
|
1384
|
+
* a creation recipe (radii + height), editable through `design.update.parameters`.
|
|
1385
|
+
*
|
|
1386
|
+
* Runs on the OpenCascade kernel (the first kernel call loads a wasm of tens
|
|
1387
|
+
* of MB — expect a pause of seconds).
|
|
1388
|
+
*
|
|
1389
|
+
* @param base Centre of the bottom cap as plain `{x, y, z}` components
|
|
1390
|
+
* @param axis Axis direction as plain `{x, y, z}` components (non-zero, normalised by the host)
|
|
1391
|
+
* @param baseRadius Radius at the base (> 0)
|
|
1392
|
+
* @param height Height along `axis` (> 0)
|
|
1393
|
+
* @param topRadius Optional radius at the top (≥ 0, ≠ `baseRadius`; default 0 = apex)
|
|
1394
|
+
* @returns The new solid as a {@linkcode BrepHandle}
|
|
1395
|
+
* @throws VALIDATION if radii/height are invalid, `topRadius === baseRadius`
|
|
1396
|
+
* (that is a cylinder — use {@linkcode PluginGeomCreateApi.brepFromCylinder}),
|
|
1397
|
+
* or `axis` is zero-length
|
|
1398
|
+
*
|
|
1399
|
+
* @examplePrompt Create a cone roof 4m wide and 3m tall
|
|
1400
|
+
* @examplePrompt Make a tapered column narrowing from 1m to 0.6m
|
|
1401
|
+
*
|
|
1402
|
+
* # Example
|
|
1403
|
+
* ```ts
|
|
1404
|
+
* const roof = await snaptrude.core.geom.create.brepFromCone(
|
|
1405
|
+
* { x: 0, y: 9, z: 0 },
|
|
1406
|
+
* { x: 0, y: 1, z: 0 },
|
|
1407
|
+
* 2,
|
|
1408
|
+
* 3,
|
|
1409
|
+
* )
|
|
1410
|
+
* ```
|
|
1411
|
+
*/
|
|
1412
|
+
public abstract brepFromCone(
|
|
1413
|
+
base: Vec3Components,
|
|
1414
|
+
axis: Vec3Components,
|
|
1415
|
+
baseRadius: number,
|
|
1416
|
+
height: number,
|
|
1417
|
+
topRadius?: number,
|
|
1418
|
+
): PluginApiReturn<BrepHandle>
|
|
1419
|
+
|
|
1420
|
+
/**
|
|
1421
|
+
* Create a solid **torus** (ring / donut) B-rep from its centre, plane
|
|
1422
|
+
* normal, ring radius and tube radius. Host API call — returns a
|
|
1423
|
+
* {@linkcode BrepHandle}; commit with `design.create.massFromBrep`.
|
|
1424
|
+
* `majorRadius` is centre-to-tube-centre; `minorRadius` is the tube's own
|
|
1425
|
+
* radius and must be strictly smaller. Carries a creation recipe, editable
|
|
1426
|
+
* through `design.update.parameters`.
|
|
1427
|
+
*
|
|
1428
|
+
* Runs on the OpenCascade kernel (the first kernel call loads a wasm of tens
|
|
1429
|
+
* of MB — expect a pause of seconds).
|
|
1430
|
+
*
|
|
1431
|
+
* @param centre Torus centre as plain `{x, y, z}` components
|
|
1432
|
+
* @param axis Plane normal of the ring as plain `{x, y, z}` components (non-zero)
|
|
1433
|
+
* @param majorRadius Ring radius, centre to tube centre (> 0)
|
|
1434
|
+
* @param minorRadius Tube radius (> 0 and < `majorRadius` — a self-intersecting torus is rejected)
|
|
1435
|
+
* @returns The new solid as a {@linkcode BrepHandle}
|
|
1436
|
+
* @throws VALIDATION if a radius is invalid, `minorRadius >= majorRadius`,
|
|
1437
|
+
* or `axis` is zero-length
|
|
1438
|
+
*
|
|
1439
|
+
* @examplePrompt Create a donut-shaped ring 10m across with a 1m tube
|
|
1440
|
+
* @examplePrompt Add a torus canopy around the tower
|
|
1441
|
+
*
|
|
1442
|
+
* # Example
|
|
1443
|
+
* ```ts
|
|
1444
|
+
* const ring = await snaptrude.core.geom.create.brepFromTorus(
|
|
1445
|
+
* { x: 0, y: 6, z: 0 },
|
|
1446
|
+
* { x: 0, y: 1, z: 0 },
|
|
1447
|
+
* 5,
|
|
1448
|
+
* 1,
|
|
1449
|
+
* )
|
|
1450
|
+
* ```
|
|
1451
|
+
*/
|
|
1452
|
+
public abstract brepFromTorus(
|
|
1453
|
+
centre: Vec3Components,
|
|
1454
|
+
axis: Vec3Components,
|
|
1455
|
+
majorRadius: number,
|
|
1456
|
+
minorRadius: number,
|
|
1457
|
+
): PluginApiReturn<BrepHandle>
|
|
827
1458
|
}
|
|
828
1459
|
|
|
829
1460
|
/**
|
|
@@ -877,6 +1508,38 @@ export const PluginGeomCreateCircleArgs = z.object({
|
|
|
877
1508
|
|
|
878
1509
|
export type PluginGeomCreateCircleArgs = z.infer<typeof PluginGeomCreateCircleArgs>
|
|
879
1510
|
|
|
1511
|
+
/**
|
|
1512
|
+
* Arguments for {@linkcode PluginGeomCreateApi.splineFromPoints}.
|
|
1513
|
+
*
|
|
1514
|
+
* | Property | Type | Description |
|
|
1515
|
+
* |---|---|---|
|
|
1516
|
+
* | `points` | {@linkcode Vec3Handle}`[]` | 3..256 ordered through-points of the curve |
|
|
1517
|
+
*/
|
|
1518
|
+
export const PluginGeomCreateSplineFromPointsArgs = z.object({
|
|
1519
|
+
points: z.array(Vec3Handle).min(3).max(MAX_SPLINE_THROUGH_POINTS),
|
|
1520
|
+
})
|
|
1521
|
+
|
|
1522
|
+
export type PluginGeomCreateSplineFromPointsArgs = z.infer<
|
|
1523
|
+
typeof PluginGeomCreateSplineFromPointsArgs
|
|
1524
|
+
>
|
|
1525
|
+
|
|
1526
|
+
/**
|
|
1527
|
+
* Arguments for {@linkcode PluginGeomCreateApi.splineFromControlPoints}.
|
|
1528
|
+
*
|
|
1529
|
+
* | Property | Type | Description |
|
|
1530
|
+
* |---|---|---|
|
|
1531
|
+
* | `controlPoints` | {@linkcode Vec3Handle}`[]` | 3..512 control points of the curve, in order |
|
|
1532
|
+
* | `options` | `object`? | `degree`: 2 or 3 (default `min(3, controlPoints.length - 1)`) |
|
|
1533
|
+
*/
|
|
1534
|
+
export const PluginGeomCreateSplineFromControlPointsArgs = z.object({
|
|
1535
|
+
controlPoints: z.array(Vec3Handle).min(3).max(MAX_SPLINE_POLES),
|
|
1536
|
+
options: z.object({ degree: z.number().int().min(2).max(3).optional() }).optional(),
|
|
1537
|
+
})
|
|
1538
|
+
|
|
1539
|
+
export type PluginGeomCreateSplineFromControlPointsArgs = z.infer<
|
|
1540
|
+
typeof PluginGeomCreateSplineFromControlPointsArgs
|
|
1541
|
+
>
|
|
1542
|
+
|
|
880
1543
|
/**
|
|
881
1544
|
* Arguments for {@linkcode PluginGeomCreateApi.profileFromLinePoints}.
|
|
882
1545
|
*
|
|
@@ -907,6 +1570,21 @@ export type PluginGeomCreateProfileFromCurvesArgs = z.infer<
|
|
|
907
1570
|
typeof PluginGeomCreateProfileFromCurvesArgs
|
|
908
1571
|
>
|
|
909
1572
|
|
|
1573
|
+
/**
|
|
1574
|
+
* Arguments for {@linkcode PluginGeomCreateApi.profileFromSplinePoints}.
|
|
1575
|
+
*
|
|
1576
|
+
* | Property | Type | Description |
|
|
1577
|
+
* |---|---|---|
|
|
1578
|
+
* | `points` | {@linkcode Vec3Handle}`[]` | 3..256 ordered through-points of the closed loop (first point NOT repeated) |
|
|
1579
|
+
*/
|
|
1580
|
+
export const PluginGeomCreateProfileFromSplinePointsArgs = z.object({
|
|
1581
|
+
points: z.array(Vec3Handle).min(3).max(MAX_SPLINE_THROUGH_POINTS),
|
|
1582
|
+
})
|
|
1583
|
+
|
|
1584
|
+
export type PluginGeomCreateProfileFromSplinePointsArgs = z.infer<
|
|
1585
|
+
typeof PluginGeomCreateProfileFromSplinePointsArgs
|
|
1586
|
+
>
|
|
1587
|
+
|
|
910
1588
|
/**
|
|
911
1589
|
* Arguments for {@linkcode PluginGeomCreateApi.contourFromProfile}.
|
|
912
1590
|
*
|
|
@@ -962,6 +1640,7 @@ export type PluginGeomCreateBrepFromFacesArgs = z.infer<
|
|
|
962
1640
|
* | `contour` | {@linkcode ContourHandle} | The cross-section to extrude |
|
|
963
1641
|
* | `direction` | {@linkcode Vec3Components} | Extrusion direction (non-zero, finite components) |
|
|
964
1642
|
* | `amount` | `number` | Extrusion distance (finite, non-zero) |
|
|
1643
|
+
* | `options` | `object`? | Optional twist and taper: `twistInDegrees` (an angle, finite), `topScale` (a ratio, finite and positive) and `levels` (a count, 2..64) |
|
|
965
1644
|
*/
|
|
966
1645
|
export const PluginGeomCreateBrepFromExtrusionArgs = z.object({
|
|
967
1646
|
contour: ContourHandle,
|
|
@@ -974,6 +1653,13 @@ export const PluginGeomCreateBrepFromExtrusionArgs = z.object({
|
|
|
974
1653
|
.number()
|
|
975
1654
|
.finite()
|
|
976
1655
|
.refine((value) => value !== 0, { message: "amount must be non-zero" }),
|
|
1656
|
+
options: z
|
|
1657
|
+
.object({
|
|
1658
|
+
twistInDegrees: z.number().finite().optional(),
|
|
1659
|
+
topScale: z.number().finite().positive().optional(),
|
|
1660
|
+
levels: z.number().int().min(2).max(MAX_TWIST_LEVELS).optional(),
|
|
1661
|
+
})
|
|
1662
|
+
.optional(),
|
|
977
1663
|
})
|
|
978
1664
|
|
|
979
1665
|
export type PluginGeomCreateBrepFromExtrusionArgs = z.infer<
|
|
@@ -987,8 +1673,8 @@ export type PluginGeomCreateBrepFromExtrusionArgs = z.infer<
|
|
|
987
1673
|
* |---|---|---|
|
|
988
1674
|
* | `bottomContour` | {@linkcode ContourHandle} | The bottom cross-section |
|
|
989
1675
|
* | `topContour` | {@linkcode ContourHandle} | The top cross-section |
|
|
990
|
-
* | `intermediateContours` | {@linkcode ContourHandle}`[]`? | Optional in-between cross-sections, ordered bottom to top |
|
|
991
|
-
* | `options` | `object`? | Optional behavior switches: `compatibility` (`"strict"` throws on mismatched edge counts instead of auto-matching; default `"auto"`)
|
|
1676
|
+
* | `intermediateContours` | {@linkcode ContourHandle}`[]`? | Optional in-between cross-sections, ordered bottom to top (any count; more than 32 sections in all builds but carries no parameter record) |
|
|
1677
|
+
* | `options` | `object`? | Optional behavior switches: `compatibility` (`"strict"` throws on mismatched edge counts instead of auto-matching; default `"auto"`), `seamAlignment` (`"authored"` keeps the authored correspondence instead of searching seam rotations; default `"auto"`) and `smoothing` (`"smooth"` lofts every section in one pass, so the sides curve through the intermediates; default `"ruled"`) |
|
|
992
1678
|
*/
|
|
993
1679
|
export const PluginGeomCreateBrepFromLoftArgs = z.object({
|
|
994
1680
|
bottomContour: ContourHandle,
|
|
@@ -998,6 +1684,7 @@ export const PluginGeomCreateBrepFromLoftArgs = z.object({
|
|
|
998
1684
|
.object({
|
|
999
1685
|
compatibility: z.enum(["strict", "auto"]).optional(),
|
|
1000
1686
|
seamAlignment: z.enum(["authored", "auto"]).optional(),
|
|
1687
|
+
smoothing: z.enum(["ruled", "smooth"]).optional(),
|
|
1001
1688
|
})
|
|
1002
1689
|
.optional(),
|
|
1003
1690
|
})
|
|
@@ -1050,16 +1737,97 @@ const FiniteVec3Components = z.object({
|
|
|
1050
1737
|
* | Property | Type | Description |
|
|
1051
1738
|
* |---|---|---|
|
|
1052
1739
|
* | `brep` | {@linkcode BrepHandle} | The solid whose edges to round |
|
|
1053
|
-
* | `edges` | {@linkcode EdgeHandle}`[]` | The
|
|
1054
|
-
* | `radius` | `number` | Fillet radius (positive, finite) |
|
|
1740
|
+
* | `edges` | {@linkcode EdgeHandle}`[]` | The edges to fillet (one or more; more than 64 builds but carries no parameter record) |
|
|
1741
|
+
* | `radius` | `number` | Fillet radius (positive, finite); the start radius of a variable blend |
|
|
1742
|
+
* | `options` | `object`? | Optional variable blend: `endRadius` (positive, finite) or `radii` (2..32 rows of `{ position, radius }`, `position` a ratio 0..1 strictly increasing). Mutually exclusive, and either one takes exactly ONE edge |
|
|
1055
1743
|
*/
|
|
1056
|
-
export const PluginGeomCreateBrepFromFilletArgs = z
|
|
1744
|
+
export const PluginGeomCreateBrepFromFilletArgs = z
|
|
1745
|
+
.object({
|
|
1746
|
+
brep: BrepHandle,
|
|
1747
|
+
edges: z.array(EdgeHandle).min(1),
|
|
1748
|
+
radius: z.number().finite().positive(),
|
|
1749
|
+
options: z
|
|
1750
|
+
.object({
|
|
1751
|
+
endRadius: z.number().finite().positive().optional(),
|
|
1752
|
+
radii: z
|
|
1753
|
+
.array(
|
|
1754
|
+
z.object({
|
|
1755
|
+
position: z.number().finite().min(0).max(1),
|
|
1756
|
+
radius: z.number().finite().positive(),
|
|
1757
|
+
}),
|
|
1758
|
+
)
|
|
1759
|
+
.min(2)
|
|
1760
|
+
.max(MAX_FILLET_LAW_SAMPLES)
|
|
1761
|
+
.optional(),
|
|
1762
|
+
})
|
|
1763
|
+
.optional(),
|
|
1764
|
+
})
|
|
1765
|
+
.superRefine((a, ctx) => {
|
|
1766
|
+
const { endRadius, radii } = a.options ?? {}
|
|
1767
|
+
if (endRadius === undefined && radii === undefined) return
|
|
1768
|
+
if (endRadius !== undefined && radii !== undefined) {
|
|
1769
|
+
ctx.addIssue({ code: "custom", message: "endRadius is mutually exclusive with radii" })
|
|
1770
|
+
}
|
|
1771
|
+
// The law belongs to the blend contour the one edge lies on, and `position`
|
|
1772
|
+
// is measured from that edge's start: a second edge would have no origin.
|
|
1773
|
+
if (a.edges.length !== 1) {
|
|
1774
|
+
ctx.addIssue({
|
|
1775
|
+
code: "custom",
|
|
1776
|
+
message: "a variable fillet takes exactly one edge — the blend contour it runs along",
|
|
1777
|
+
})
|
|
1778
|
+
}
|
|
1779
|
+
if (radii?.some((row, i) => i > 0 && row.position <= radii[i - 1].position)) {
|
|
1780
|
+
ctx.addIssue({ code: "custom", message: "radii positions must strictly increase" })
|
|
1781
|
+
}
|
|
1782
|
+
})
|
|
1783
|
+
|
|
1784
|
+
export type PluginGeomCreateBrepFromFilletArgs = z.infer<typeof PluginGeomCreateBrepFromFilletArgs>
|
|
1785
|
+
|
|
1786
|
+
/** An edge with the solid it belongs to. See {@linkcode OwnedEdge}. */
|
|
1787
|
+
export const OwnedEdge = z.object({
|
|
1788
|
+
edge: EdgeHandle,
|
|
1057
1789
|
brep: BrepHandle,
|
|
1058
|
-
|
|
1059
|
-
radius: z.number().finite().positive(),
|
|
1790
|
+
face: FaceHandle.optional(),
|
|
1060
1791
|
})
|
|
1061
1792
|
|
|
1062
|
-
|
|
1793
|
+
/**
|
|
1794
|
+
* Arguments for {@linkcode PluginGeomCreateApi.brepFromPatch}.
|
|
1795
|
+
*
|
|
1796
|
+
* | Property | Type | Description |
|
|
1797
|
+
* |---|---|---|
|
|
1798
|
+
* | `boundary` | ({@linkcode CurveHandle} \| {@linkcode OwnedEdge})`[]` | 3..16 items forming one closed loop |
|
|
1799
|
+
* | `thickness` | `number` | Solid thickness in internal length units (positive, finite) |
|
|
1800
|
+
* | `options` | `object`? | `interiorPoints` (≤ 64 plain `{x, y, z}` the surface is pulled through), `continuity` (`"position"` default, or `"tangent"` — every item must then be an edge item naming its `face`), `side` (`"below"` default, or `"above"`) |
|
|
1801
|
+
*/
|
|
1802
|
+
export const PluginGeomCreateBrepFromPatchArgs = z
|
|
1803
|
+
.object({
|
|
1804
|
+
boundary: z
|
|
1805
|
+
.array(z.union([CurveHandle, OwnedEdge]))
|
|
1806
|
+
.min(3)
|
|
1807
|
+
.max(MAX_PATCH_BOUNDARY_CURVES),
|
|
1808
|
+
thickness: z.number().finite().positive(),
|
|
1809
|
+
options: z
|
|
1810
|
+
.object({
|
|
1811
|
+
interiorPoints: z.array(FiniteVec3Components).max(MAX_PATCH_INTERIOR_POINTS).optional(),
|
|
1812
|
+
continuity: z.enum(["position", "tangent"]).optional(),
|
|
1813
|
+
side: z.enum(["below", "above"]).optional(),
|
|
1814
|
+
})
|
|
1815
|
+
.optional(),
|
|
1816
|
+
})
|
|
1817
|
+
.superRefine((a, ctx) => {
|
|
1818
|
+
if (a.options?.continuity !== "tangent") return
|
|
1819
|
+
// `Add_2` continues exactly ONE support face, and a solid edge has two: a
|
|
1820
|
+
// tangent patch must be told which, per item, at the wire.
|
|
1821
|
+
if (a.boundary.some((item) => !("edge" in item) || item.face === undefined)) {
|
|
1822
|
+
ctx.addIssue({
|
|
1823
|
+
code: "custom",
|
|
1824
|
+
message:
|
|
1825
|
+
'continuity: "tangent" needs every boundary item to be an edge with its brep and the face to continue',
|
|
1826
|
+
})
|
|
1827
|
+
}
|
|
1828
|
+
})
|
|
1829
|
+
|
|
1830
|
+
export type PluginGeomCreateBrepFromPatchArgs = z.infer<typeof PluginGeomCreateBrepFromPatchArgs>
|
|
1063
1831
|
|
|
1064
1832
|
/**
|
|
1065
1833
|
* Arguments for {@linkcode PluginGeomCreateApi.brepFromOffset}.
|
|
@@ -1085,7 +1853,7 @@ export type PluginGeomCreateBrepFromOffsetArgs = z.infer<typeof PluginGeomCreate
|
|
|
1085
1853
|
* | Property | Type | Description |
|
|
1086
1854
|
* |---|---|---|
|
|
1087
1855
|
* | `brep` | {@linkcode BrepHandle} | The solid to hollow |
|
|
1088
|
-
* | `openFaces` | {@linkcode FaceHandle}`[]` | The faces to remove as openings (
|
|
1856
|
+
* | `openFaces` | {@linkcode FaceHandle}`[]` | The faces to remove as openings (one or more; more than 32 builds but carries no parameter record) |
|
|
1089
1857
|
* | `thickness` | `number` | Wall thickness (positive, finite) |
|
|
1090
1858
|
*/
|
|
1091
1859
|
export const PluginGeomCreateBrepFromShellArgs = z.object({
|
|
@@ -1113,13 +1881,51 @@ export const PluginGeomCreateBrepsFromSplitArgs = z.object({
|
|
|
1113
1881
|
|
|
1114
1882
|
export type PluginGeomCreateBrepsFromSplitArgs = z.infer<typeof PluginGeomCreateBrepsFromSplitArgs>
|
|
1115
1883
|
|
|
1884
|
+
/**
|
|
1885
|
+
* Arguments for {@linkcode PluginGeomCreateApi.brepsFromSplitByFace}.
|
|
1886
|
+
*
|
|
1887
|
+
* | Property | Type | Description |
|
|
1888
|
+
* |---|---|---|
|
|
1889
|
+
* | `brep` | {@linkcode BrepHandle} | The solid to cut |
|
|
1890
|
+
* | `toolFace` | {@linkcode FaceHandle} | The cutting face (read-only) |
|
|
1891
|
+
* | `toolBrep` | {@linkcode BrepHandle} | The solid `toolFace` belongs to (owner last) |
|
|
1892
|
+
*/
|
|
1893
|
+
export const PluginGeomCreateBrepsFromSplitByFaceArgs = z.object({
|
|
1894
|
+
brep: BrepHandle,
|
|
1895
|
+
toolFace: FaceHandle,
|
|
1896
|
+
toolBrep: BrepHandle,
|
|
1897
|
+
})
|
|
1898
|
+
|
|
1899
|
+
export type PluginGeomCreateBrepsFromSplitByFaceArgs = z.infer<
|
|
1900
|
+
typeof PluginGeomCreateBrepsFromSplitByFaceArgs
|
|
1901
|
+
>
|
|
1902
|
+
|
|
1903
|
+
/**
|
|
1904
|
+
* Arguments for {@linkcode PluginGeomCreateApi.curvesFromProjection}.
|
|
1905
|
+
*
|
|
1906
|
+
* | Property | Type | Description |
|
|
1907
|
+
* |---|---|---|
|
|
1908
|
+
* | `curve` | {@linkcode CurveHandle} | The curve to project |
|
|
1909
|
+
* | `face` | {@linkcode FaceHandle} | The face to project onto |
|
|
1910
|
+
* | `faceBrep` | {@linkcode BrepHandle} | The solid `face` belongs to (owner last) |
|
|
1911
|
+
*/
|
|
1912
|
+
export const PluginGeomCreateCurvesFromProjectionArgs = z.object({
|
|
1913
|
+
curve: CurveHandle,
|
|
1914
|
+
face: FaceHandle,
|
|
1915
|
+
faceBrep: BrepHandle,
|
|
1916
|
+
})
|
|
1917
|
+
|
|
1918
|
+
export type PluginGeomCreateCurvesFromProjectionArgs = z.infer<
|
|
1919
|
+
typeof PluginGeomCreateCurvesFromProjectionArgs
|
|
1920
|
+
>
|
|
1921
|
+
|
|
1116
1922
|
/**
|
|
1117
1923
|
* Arguments for {@linkcode PluginGeomCreateApi.brepFromChamfer}.
|
|
1118
1924
|
*
|
|
1119
1925
|
* | Property | Type | Description |
|
|
1120
1926
|
* |---|---|---|
|
|
1121
1927
|
* | `brep` | {@linkcode BrepHandle} | The solid whose edges to bevel |
|
|
1122
|
-
* | `edges` | {@linkcode EdgeHandle}`[]` | The
|
|
1928
|
+
* | `edges` | {@linkcode EdgeHandle}`[]` | The edges to chamfer (one or more; more than 64 builds but carries no parameter record) |
|
|
1123
1929
|
* | `distance` | `number` | Chamfer distance from the edge on each adjacent face (positive, finite) |
|
|
1124
1930
|
*/
|
|
1125
1931
|
export const PluginGeomCreateBrepFromChamferArgs = z.object({
|
|
@@ -1142,8 +1948,8 @@ const SweepScaleFactor = z.number().finite().min(1e-3).max(1e3)
|
|
|
1142
1948
|
* | Property | Type | Description |
|
|
1143
1949
|
* |---|---|---|
|
|
1144
1950
|
* | `profile` | {@linkcode ContourHandle} | The cross-section to sweep (hole-free) |
|
|
1145
|
-
* | `path` | {@linkcode Vec3Components}`[]` | The polyline path (
|
|
1146
|
-
* | `options` | `object`? | Optional scale law: `startScale`/`endScale` (linear taper by arc length) or per-point `scales` (mutually exclusive; factors finite, 1e-3..1e3; `scales.length` must equal `path.length`). Optional corner `transition`: `"miter"` (default) or `{ bevel }` (chamfered corners; finite, 1e-3..1e3) |
|
|
1951
|
+
* | `path` | {@linkcode Vec3Components}`[]` | The polyline path (2 or more points, finite components — more than 512 builds but carries no parameter record; repeating the first point as the last closes it into a ring — closed paths must be flat and straight-segmented and take a straight-edged profile) |
|
|
1952
|
+
* | `options` | `object`? | Optional scale law: `startScale`/`endScale` (linear taper by arc length) or per-point `scales` (mutually exclusive; factors finite, 1e-3..1e3; `scales.length` must equal `path.length`). Optional corner `transition`: `"miter"` (default), `"round"` (arc-carried corners) or `{ bevel }` (chamfered corners; finite, 1e-3..1e3) |
|
|
1147
1953
|
*/
|
|
1148
1954
|
export const PluginGeomCreateBrepFromSweepArgs = z
|
|
1149
1955
|
.object({
|
|
@@ -1157,6 +1963,7 @@ export const PluginGeomCreateBrepFromSweepArgs = z
|
|
|
1157
1963
|
transition: z
|
|
1158
1964
|
.union([
|
|
1159
1965
|
z.literal("miter"),
|
|
1966
|
+
z.literal("round"),
|
|
1160
1967
|
z.object({ bevel: z.number().finite().min(1e-3).max(1e3) }),
|
|
1161
1968
|
])
|
|
1162
1969
|
.optional(),
|
|
@@ -1182,14 +1989,38 @@ export const PluginGeomCreateBrepFromSweepArgs = z
|
|
|
1182
1989
|
|
|
1183
1990
|
export type PluginGeomCreateBrepFromSweepArgs = z.infer<typeof PluginGeomCreateBrepFromSweepArgs>
|
|
1184
1991
|
|
|
1992
|
+
/**
|
|
1993
|
+
* Arguments for {@linkcode PluginGeomCreateApi.brepFromSweepAlongCurve}.
|
|
1994
|
+
*
|
|
1995
|
+
* | Property | Type | Description |
|
|
1996
|
+
* |---|---|---|
|
|
1997
|
+
* | `profile` | {@linkcode ContourHandle} | The cross-section to sweep (hole-free) |
|
|
1998
|
+
* | `path` | {@linkcode CurveHandle}`[]` | 1..64 curves, ordered, meeting end to end |
|
|
1999
|
+
* | `options` | `object`? | `orientation` — `"upright"` (default), `"frenet"` or `"fixed"`; `rail` — a second guide {@linkcode CurveHandle} (needs a newer kernel build) |
|
|
2000
|
+
*/
|
|
2001
|
+
export const PluginGeomCreateBrepFromSweepAlongCurveArgs = z.object({
|
|
2002
|
+
profile: ContourHandle,
|
|
2003
|
+
path: z.array(CurveHandle).min(1).max(MAX_PATH_CURVES),
|
|
2004
|
+
options: z
|
|
2005
|
+
.object({
|
|
2006
|
+
orientation: z.enum(["frenet", "fixed", "upright"]).optional(),
|
|
2007
|
+
rail: CurveHandle.optional(),
|
|
2008
|
+
})
|
|
2009
|
+
.optional(),
|
|
2010
|
+
})
|
|
2011
|
+
|
|
2012
|
+
export type PluginGeomCreateBrepFromSweepAlongCurveArgs = z.infer<
|
|
2013
|
+
typeof PluginGeomCreateBrepFromSweepAlongCurveArgs
|
|
2014
|
+
>
|
|
2015
|
+
|
|
1185
2016
|
/**
|
|
1186
2017
|
* Arguments for {@linkcode PluginGeomCreateApi.brepFromRevolution}.
|
|
1187
2018
|
*
|
|
1188
2019
|
* | Property | Type | Description |
|
|
1189
2020
|
* |---|---|---|
|
|
1190
2021
|
* | `profile` | {@linkcode ContourHandle} | The cross-section to revolve (holes allowed) |
|
|
1191
|
-
* | `axisOrigin` | {@linkcode Vec3Components} | A point on the revolution axis (finite components) |
|
|
1192
|
-
* | `axisDirection` | {@linkcode Vec3Components} | The axis direction (non-zero, finite components) |
|
|
2022
|
+
* | `axisOrigin` | {@linkcode Vec3Components} | A point on the revolution axis (finite components; the axis must lie in the profile's plane) |
|
|
2023
|
+
* | `axisDirection` | {@linkcode Vec3Components} | The axis direction (non-zero, finite components; the axis must lie in the profile's plane) |
|
|
1193
2024
|
* | `angleInDegrees` | `number`? | Revolution angle in degrees (0 < angle ≤ 360; default 360) |
|
|
1194
2025
|
*/
|
|
1195
2026
|
export const PluginGeomCreateBrepFromRevolutionArgs = z.object({
|
|
@@ -1202,3 +2033,89 @@ export const PluginGeomCreateBrepFromRevolutionArgs = z.object({
|
|
|
1202
2033
|
export type PluginGeomCreateBrepFromRevolutionArgs = z.infer<
|
|
1203
2034
|
typeof PluginGeomCreateBrepFromRevolutionArgs
|
|
1204
2035
|
>
|
|
2036
|
+
|
|
2037
|
+
/**
|
|
2038
|
+
* Arguments for {@linkcode PluginGeomCreateApi.brepFromSphere}.
|
|
2039
|
+
*
|
|
2040
|
+
* | Property | Type | Description |
|
|
2041
|
+
* |---|---|---|
|
|
2042
|
+
* | `centre` | {@linkcode Vec3Components} | Sphere centre (finite components) |
|
|
2043
|
+
* | `radius` | `number` | Sphere radius (finite; positivity is checked host-side so the error names the parameter) |
|
|
2044
|
+
*/
|
|
2045
|
+
export const PluginGeomCreateBrepFromSphereArgs = z.object({
|
|
2046
|
+
centre: FiniteVec3Components,
|
|
2047
|
+
radius: z.number().finite(),
|
|
2048
|
+
})
|
|
2049
|
+
|
|
2050
|
+
export type PluginGeomCreateBrepFromSphereArgs = z.infer<
|
|
2051
|
+
typeof PluginGeomCreateBrepFromSphereArgs
|
|
2052
|
+
>
|
|
2053
|
+
|
|
2054
|
+
/**
|
|
2055
|
+
* Arguments for {@linkcode PluginGeomCreateApi.brepFromCylinder}.
|
|
2056
|
+
*
|
|
2057
|
+
* | Property | Type | Description |
|
|
2058
|
+
* |---|---|---|
|
|
2059
|
+
* | `base` | {@linkcode Vec3Components} | Centre of the bottom cap (finite components) |
|
|
2060
|
+
* | `axis` | {@linkcode Vec3Components} | Axis direction (non-zero, finite components) |
|
|
2061
|
+
* | `radius` | `number` | Cylinder radius (finite, positive) |
|
|
2062
|
+
* | `height` | `number` | Height along `axis` (finite, positive) |
|
|
2063
|
+
*/
|
|
2064
|
+
export const PluginGeomCreateBrepFromCylinderArgs = z.object({
|
|
2065
|
+
base: FiniteVec3Components,
|
|
2066
|
+
axis: FiniteVec3Components,
|
|
2067
|
+
radius: z.number().finite(),
|
|
2068
|
+
height: z.number().finite(),
|
|
2069
|
+
})
|
|
2070
|
+
|
|
2071
|
+
export type PluginGeomCreateBrepFromCylinderArgs = z.infer<
|
|
2072
|
+
typeof PluginGeomCreateBrepFromCylinderArgs
|
|
2073
|
+
>
|
|
2074
|
+
|
|
2075
|
+
/**
|
|
2076
|
+
* Arguments for {@linkcode PluginGeomCreateApi.brepFromCone}.
|
|
2077
|
+
*
|
|
2078
|
+
* | Property | Type | Description |
|
|
2079
|
+
* |---|---|---|
|
|
2080
|
+
* | `base` | {@linkcode Vec3Components} | Centre of the bottom cap (finite components) |
|
|
2081
|
+
* | `axis` | {@linkcode Vec3Components} | Axis direction (non-zero, finite components) |
|
|
2082
|
+
* | `baseRadius` | `number` | Radius at the base (finite, positive) |
|
|
2083
|
+
* | `height` | `number` | Height along `axis` (finite, positive) |
|
|
2084
|
+
* | `topRadius` | `number`? | Radius at the top (finite, ≥ 0, ≠ `baseRadius`; default 0 = apex) |
|
|
2085
|
+
*/
|
|
2086
|
+
export const PluginGeomCreateBrepFromConeArgs = z
|
|
2087
|
+
.object({
|
|
2088
|
+
base: FiniteVec3Components,
|
|
2089
|
+
axis: FiniteVec3Components,
|
|
2090
|
+
baseRadius: z.number().finite(),
|
|
2091
|
+
height: z.number().finite(),
|
|
2092
|
+
topRadius: z.number().finite().optional(),
|
|
2093
|
+
})
|
|
2094
|
+
.refine((a) => (a.topRadius ?? 0) !== a.baseRadius, {
|
|
2095
|
+
message: "topRadius must differ from baseRadius — equal radii are a cylinder",
|
|
2096
|
+
})
|
|
2097
|
+
|
|
2098
|
+
export type PluginGeomCreateBrepFromConeArgs = z.infer<typeof PluginGeomCreateBrepFromConeArgs>
|
|
2099
|
+
|
|
2100
|
+
/**
|
|
2101
|
+
* Arguments for {@linkcode PluginGeomCreateApi.brepFromTorus}.
|
|
2102
|
+
*
|
|
2103
|
+
* | Property | Type | Description |
|
|
2104
|
+
* |---|---|---|
|
|
2105
|
+
* | `centre` | {@linkcode Vec3Components} | Torus centre (finite components) |
|
|
2106
|
+
* | `axis` | {@linkcode Vec3Components} | Plane normal of the ring (non-zero, finite components) |
|
|
2107
|
+
* | `majorRadius` | `number` | Ring radius, centre to tube centre (finite, positive) |
|
|
2108
|
+
* | `minorRadius` | `number` | Tube radius (finite, positive, strictly less than `majorRadius`) |
|
|
2109
|
+
*/
|
|
2110
|
+
export const PluginGeomCreateBrepFromTorusArgs = z
|
|
2111
|
+
.object({
|
|
2112
|
+
centre: FiniteVec3Components,
|
|
2113
|
+
axis: FiniteVec3Components,
|
|
2114
|
+
majorRadius: z.number().finite(),
|
|
2115
|
+
minorRadius: z.number().finite(),
|
|
2116
|
+
})
|
|
2117
|
+
.refine((a) => a.minorRadius < a.majorRadius, {
|
|
2118
|
+
message: "minorRadius must be smaller than majorRadius — the torus would self-intersect",
|
|
2119
|
+
})
|
|
2120
|
+
|
|
2121
|
+
export type PluginGeomCreateBrepFromTorusArgs = z.infer<typeof PluginGeomCreateBrepFromTorusArgs>
|