@snaptrude/plugin-core 0.9.17 → 0.9.18-edgesetbacks-20261021.1
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/AGENTS.md +231 -231
- package/CHANGELOG.md +408 -408
- package/CLAUDE.md +11 -11
- package/api-manifest.json +1428 -712
- package/dist/api/analysis/daylight.d.ts +5 -5
- package/dist/api/analysis/solar.d.ts +2 -2
- package/dist/api/core/camera/index.d.ts +29 -0
- package/dist/api/core/camera/index.d.ts.map +1 -1
- package/dist/api/core/geom/create/index.d.ts +7 -1
- package/dist/api/core/geom/create/index.d.ts.map +1 -1
- package/dist/api/core/geom/update/contour.d.ts +8 -2
- package/dist/api/core/geom/update/contour.d.ts.map +1 -1
- package/dist/api/core/storeys/index.d.ts +5 -2
- package/dist/api/core/storeys/index.d.ts.map +1 -1
- package/dist/api/core/zoom/index.d.ts +13 -0
- package/dist/api/core/zoom/index.d.ts.map +1 -1
- package/dist/api/design/bim.d.ts +299 -0
- package/dist/api/design/bim.d.ts.map +1 -0
- package/dist/api/design/boolean/index.d.ts +2 -0
- package/dist/api/design/boolean/index.d.ts.map +1 -1
- package/dist/api/design/catalog.d.ts +320 -0
- package/dist/api/design/catalog.d.ts.map +1 -0
- package/dist/api/design/create/bulk-items.d.ts +65 -25
- package/dist/api/design/create/bulk-items.d.ts.map +1 -1
- package/dist/api/design/create/index.d.ts +299 -100
- package/dist/api/design/create/index.d.ts.map +1 -1
- package/dist/api/design/create/opening-fields.d.ts +13 -12
- package/dist/api/design/create/opening-fields.d.ts.map +1 -1
- package/dist/api/design/delete/index.d.ts +1 -0
- package/dist/api/design/delete/index.d.ts.map +1 -1
- package/dist/api/design/doors/index.d.ts +18 -24
- package/dist/api/design/doors/index.d.ts.map +1 -1
- package/dist/api/design/family.d.ts +813 -35
- package/dist/api/design/family.d.ts.map +1 -1
- package/dist/api/design/index.d.ts +16 -0
- package/dist/api/design/index.d.ts.map +1 -1
- package/dist/api/design/networks.d.ts +1703 -0
- package/dist/api/design/networks.d.ts.map +1 -0
- package/dist/api/design/query/grids.d.ts +2 -2
- package/dist/api/design/query/index.d.ts +42 -32
- package/dist/api/design/query/index.d.ts.map +1 -1
- package/dist/api/design/selection/index.d.ts +10 -10
- package/dist/api/design/types/index.d.ts +40 -24
- package/dist/api/design/types/index.d.ts.map +1 -1
- package/dist/api/design/update/index.d.ts +111 -6
- package/dist/api/design/update/index.d.ts.map +1 -1
- package/dist/api/design/windows/index.d.ts +8 -8
- package/dist/api/design/windows/index.d.ts.map +1 -1
- package/dist/api/entity/buildableEnvelope.d.ts +84 -2
- package/dist/api/entity/buildableEnvelope.d.ts.map +1 -1
- package/dist/api/presentation/aiInspiration.d.ts +10 -10
- package/dist/api/presentation/annotate.d.ts +38 -22
- package/dist/api/presentation/annotate.d.ts.map +1 -1
- package/dist/api/presentation/drawingContract.d.ts +32 -0
- package/dist/api/presentation/drawingContract.d.ts.map +1 -0
- package/dist/api/presentation/drawings.d.ts +3523 -0
- package/dist/api/presentation/drawings.d.ts.map +1 -0
- package/dist/api/presentation/export.d.ts +23 -5
- package/dist/api/presentation/export.d.ts.map +1 -1
- package/dist/api/presentation/index.d.ts +32 -12
- package/dist/api/presentation/index.d.ts.map +1 -1
- package/dist/api/presentation/placedViews.d.ts +106 -6
- package/dist/api/presentation/placedViews.d.ts.map +1 -1
- package/dist/api/presentation/shapes.d.ts +2 -2
- package/dist/api/presentation/sheets.d.ts +175 -19
- package/dist/api/presentation/sheets.d.ts.map +1 -1
- package/dist/api/presentation/viewPresets.d.ts +222 -0
- package/dist/api/presentation/viewPresets.d.ts.map +1 -0
- package/dist/api/presentation/views.d.ts +141 -8
- package/dist/api/presentation/views.d.ts.map +1 -1
- package/dist/api/presentation/walkthroughs.d.ts +6 -6
- package/dist/errors/codes.d.ts +3 -1
- package/dist/errors/codes.d.ts.map +1 -1
- package/dist/index.cjs +3831 -2444
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +3705 -2444
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/scripts/check-dist-fresh.mjs +22 -22
- package/scripts/generate-manifest.mjs +243 -238
- package/scripts/generate-manifest.test.mjs +303 -303
- package/src/api/analysis/daylight.ts +470 -470
- package/src/api/analysis/heatmaps.ts +683 -683
- package/src/api/analysis/illuminance.ts +155 -155
- package/src/api/analysis/index.ts +61 -61
- package/src/api/analysis/shadows.ts +183 -183
- package/src/api/analysis/solar.ts +237 -237
- package/src/api/analysis/sunlightHours.ts +211 -211
- package/src/api/analysis/sunpath.ts +83 -83
- package/src/api/analysis/weather.ts +179 -179
- package/src/api/core/buildings.ts +485 -485
- package/src/api/core/camera/index.ts +696 -667
- package/src/api/core/comment/index.ts +376 -376
- package/src/api/core/geom/create/index.ts +2139 -2133
- package/src/api/core/geom/delete/index.ts +84 -84
- package/src/api/core/geom/index.ts +35 -35
- package/src/api/core/geom/query/arc.ts +169 -169
- package/src/api/core/geom/query/brep.ts +621 -621
- package/src/api/core/geom/query/circle.ts +404 -404
- package/src/api/core/geom/query/contour.ts +540 -540
- package/src/api/core/geom/query/curve.ts +1102 -1102
- package/src/api/core/geom/query/edge.ts +130 -130
- package/src/api/core/geom/query/face.ts +508 -508
- package/src/api/core/geom/query/halfedge.ts +210 -210
- package/src/api/core/geom/query/index.ts +63 -63
- package/src/api/core/geom/query/profile.ts +473 -473
- package/src/api/core/geom/query/vertex.ts +205 -205
- package/src/api/core/geom/update/contour.ts +323 -317
- package/src/api/core/geom/update/curve.ts +209 -209
- package/src/api/core/geom/update/index.ts +29 -29
- package/src/api/core/geom/update/profile.ts +379 -379
- package/src/api/core/groups.ts +521 -521
- package/src/api/core/handles/index.ts +234 -234
- package/src/api/core/history/index.ts +84 -84
- package/src/api/core/index.ts +99 -99
- package/src/api/core/io/export/index.ts +126 -126
- package/src/api/core/io/import/index.ts +504 -504
- package/src/api/core/io/index.ts +42 -42
- package/src/api/core/io/job/index.ts +140 -140
- package/src/api/core/io/query/index.ts +71 -71
- package/src/api/core/io/terrain/index.ts +360 -360
- package/src/api/core/io/underlay/index.ts +705 -705
- package/src/api/core/layers.ts +540 -540
- package/src/api/core/math/index.ts +20 -20
- package/src/api/core/math/quat.ts +172 -172
- package/src/api/core/math/vec3.ts +179 -179
- package/src/api/core/mode/index.ts +108 -108
- package/src/api/core/project/index.ts +479 -479
- package/src/api/core/proposals/index.ts +570 -570
- package/src/api/core/storeys/index.ts +311 -308
- package/src/api/core/storeys/layers.ts +339 -339
- package/src/api/core/tags.ts +911 -911
- package/src/api/core/units/index.ts +164 -164
- package/src/api/core/user.ts +46 -46
- package/src/api/core/zoom/index.ts +64 -51
- package/src/api/design/bim.ts +210 -0
- package/src/api/design/boolean/index.ts +181 -179
- package/src/api/design/catalog.ts +203 -0
- package/src/api/design/create/bulk-items.ts +294 -254
- package/src/api/design/create/grids.ts +137 -137
- package/src/api/design/create/index.ts +2178 -1980
- package/src/api/design/create/opening-fields.ts +40 -37
- package/src/api/design/delete/index.ts +75 -74
- package/src/api/design/dimensions.ts +453 -453
- package/src/api/design/doors/index.ts +516 -500
- package/src/api/design/edit/index.ts +54 -54
- package/src/api/design/erase/index.ts +151 -151
- package/src/api/design/family.ts +1342 -704
- package/src/api/design/furniture/index.ts +319 -319
- package/src/api/design/grids.ts +237 -237
- package/src/api/design/index.ts +304 -274
- package/src/api/design/lock.ts +69 -69
- package/src/api/design/materials/index.ts +608 -608
- package/src/api/design/networks.ts +607 -0
- package/src/api/design/query/geometry/index.ts +319 -319
- package/src/api/design/query/grids.ts +197 -197
- package/src/api/design/query/index.ts +1236 -1226
- package/src/api/design/query/referenceLines.ts +52 -52
- package/src/api/design/query/spaces.ts +275 -275
- package/src/api/design/selection/index.ts +273 -273
- package/src/api/design/shared.ts +40 -40
- package/src/api/design/transform/index.ts +254 -254
- package/src/api/design/types/index.ts +163 -156
- package/src/api/design/update/index.ts +1096 -983
- package/src/api/design/visibility.ts +143 -143
- package/src/api/design/windows/index.ts +351 -333
- package/src/api/entity/buildableEnvelope.ts +397 -322
- package/src/api/entity/index.ts +30 -30
- package/src/api/entity/referenceLine.ts +235 -235
- package/src/api/entity/space.ts +612 -612
- package/src/api/entity/story.ts +517 -517
- package/src/api/index.ts +47 -47
- package/src/api/presentation/aiInspiration.ts +1116 -1116
- package/src/api/presentation/annotate.ts +417 -385
- package/src/api/presentation/camera.ts +289 -289
- package/src/api/presentation/diagrams.ts +194 -194
- package/src/api/presentation/drawingContract.ts +70 -0
- package/src/api/presentation/drawings.ts +1179 -0
- package/src/api/presentation/export.ts +134 -108
- package/src/api/presentation/import.ts +159 -159
- package/src/api/presentation/index.ts +160 -135
- package/src/api/presentation/placedViews.ts +1211 -1120
- package/src/api/presentation/sections.ts +420 -420
- package/src/api/presentation/shapes.ts +274 -274
- package/src/api/presentation/sheets.ts +746 -585
- package/src/api/presentation/slideshow.ts +134 -134
- package/src/api/presentation/tables.ts +84 -84
- package/src/api/presentation/viewPresets.ts +241 -0
- package/src/api/presentation/views.ts +742 -673
- package/src/api/presentation/walkthroughs.ts +1201 -1201
- package/src/api/program/adjacency.ts +164 -164
- package/src/api/program/areas.ts +408 -408
- package/src/api/program/classification.ts +138 -138
- package/src/api/program/cores.ts +83 -83
- package/src/api/program/departments.ts +517 -517
- package/src/api/program/index.ts +73 -73
- package/src/api/program/labels.ts +332 -332
- package/src/api/program/layout.ts +422 -422
- package/src/api/program/metadata.ts +364 -364
- package/src/api/program/metrics.ts +120 -120
- package/src/api/program/site.ts +748 -748
- package/src/api/program/spreadsheet.ts +2698 -2698
- package/src/api/workspace/index.ts +612 -612
- package/src/errors/codes.ts +143 -136
- package/src/errors/envelope.ts +75 -75
- package/src/errors/index.ts +21 -21
- package/src/errors/plugin-error.ts +134 -134
- package/src/handles.ts +297 -297
- package/src/host-utils.ts +67 -67
- package/src/index.ts +7 -7
- package/src/massParameters.ops.ts +246 -246
- package/src/massParameters.ts +427 -427
- package/src/types.ts +16 -16
- package/test/drawingContract.test.mjs +288 -0
- package/test/errors.test.mjs +185 -184
- package/test/massParameters.test.mjs +952 -952
- package/test/presentationViewSettings.test.mjs +85 -0
- package/tsconfig.json +22 -22
- package/tsup.config.ts +12 -12
|
@@ -1,2133 +1,2139 @@
|
|
|
1
|
-
import * as z from "zod"
|
|
2
|
-
import { PluginApiReturn } from "../../../../types"
|
|
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 }
|
|
34
|
-
|
|
35
|
-
/**
|
|
36
|
-
* Curve creation — construct new geometric curves from point handles (all-handle
|
|
37
|
-
* model, §11).
|
|
38
|
-
*
|
|
39
|
-
* Each method takes point handles ({@linkcode Vec3Handle}) and returns an opaque
|
|
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.
|
|
44
|
-
*
|
|
45
|
-
* Accessed via `snaptrude.core.geom.create`.
|
|
46
|
-
*/
|
|
47
|
-
export abstract class PluginGeomCreateApi {
|
|
48
|
-
constructor() {}
|
|
49
|
-
|
|
50
|
-
/**
|
|
51
|
-
* Create a straight line segment between two point handles. Host API call —
|
|
52
|
-
* returns a handle.
|
|
53
|
-
*
|
|
54
|
-
* @param startPoint Start point of the line segment
|
|
55
|
-
* @param endPoint End point of the line segment
|
|
56
|
-
* @returns The new line as a {@linkcode LineHandle}
|
|
57
|
-
*
|
|
58
|
-
* @examplePrompt Draw a line from point A to point B
|
|
59
|
-
* @examplePrompt Draw a straight edge between these two points
|
|
60
|
-
*
|
|
61
|
-
* @example
|
|
62
|
-
* ```ts
|
|
63
|
-
* const line = snaptrude.core.geom.create.line(startPoint, endPoint)
|
|
64
|
-
* ```
|
|
65
|
-
*/
|
|
66
|
-
public abstract line(startPoint: Vec3Handle, endPoint: Vec3Handle): PluginApiReturn<LineHandle>
|
|
67
|
-
|
|
68
|
-
/**
|
|
69
|
-
* Create a circular arc from its start, end, centre, and axis point handles.
|
|
70
|
-
* Host API call — returns a handle.
|
|
71
|
-
*
|
|
72
|
-
* @param startPoint Start point of the arc
|
|
73
|
-
* @param endPoint End point of the arc
|
|
74
|
-
* @param centrePoint Centre point of the arc
|
|
75
|
-
* @param axis Axis direction of the arc
|
|
76
|
-
* @returns The new arc as an {@linkcode ArcHandle}
|
|
77
|
-
*
|
|
78
|
-
* @examplePrompt Draw an arc between these two points around a centre
|
|
79
|
-
* @examplePrompt Add a curved segment from A to B
|
|
80
|
-
*
|
|
81
|
-
* @example
|
|
82
|
-
* ```ts
|
|
83
|
-
* const arc = snaptrude.core.geom.create.arc(startPoint, endPoint, centrePoint, axis)
|
|
84
|
-
* ```
|
|
85
|
-
*/
|
|
86
|
-
public abstract arc(
|
|
87
|
-
startPoint: Vec3Handle,
|
|
88
|
-
endPoint: Vec3Handle,
|
|
89
|
-
centrePoint: Vec3Handle,
|
|
90
|
-
axis: Vec3Handle,
|
|
91
|
-
): PluginApiReturn<ArcHandle>
|
|
92
|
-
|
|
93
|
-
/**
|
|
94
|
-
* Create a circle from a centre point, an axis (plane normal), and a radius.
|
|
95
|
-
* Host API call — returns a handle. A circle is a closed curve; read it back via
|
|
96
|
-
* `snaptrude.core.geom.query.circle.*`.
|
|
97
|
-
*
|
|
98
|
-
* @param centrePoint Centre point of the circle
|
|
99
|
-
* @param axis Axis direction (plane normal) of the circle
|
|
100
|
-
* @param radius Radius of the circle
|
|
101
|
-
* @returns The new circle as a {@linkcode CircleHandle}
|
|
102
|
-
*
|
|
103
|
-
* @examplePrompt Make a circle of radius 2 at this point
|
|
104
|
-
* @examplePrompt Draw a circular outline 5m across
|
|
105
|
-
*
|
|
106
|
-
* @example
|
|
107
|
-
* ```ts
|
|
108
|
-
* const circle = snaptrude.core.geom.create.circle(centrePoint, axis, 2)
|
|
109
|
-
* ```
|
|
110
|
-
*/
|
|
111
|
-
public abstract circle(
|
|
112
|
-
centrePoint: Vec3Handle,
|
|
113
|
-
axis: Vec3Handle,
|
|
114
|
-
radius: number,
|
|
115
|
-
): PluginApiReturn<CircleHandle>
|
|
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. An edge's control points
|
|
161
|
-
* rebuild the same curve here only when its knots are clamped uniform.
|
|
162
|
-
*
|
|
163
|
-
* @param controlPoints 3..512 control points ({@linkcode Vec3Handle}s), in order
|
|
164
|
-
* @param options.degree 2 or 3; default `min(3, controlPoints.length - 1)`
|
|
165
|
-
* @returns The new open curve as a {@linkcode SplineHandle}
|
|
166
|
-
* @throws VALIDATION when fewer than `degree + 1` points are given, two
|
|
167
|
-
* consecutive points coincide, or `degree` is not 2 or 3
|
|
168
|
-
*
|
|
169
|
-
* @examplePrompt Draw a smooth curve controlled by these four points
|
|
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
|
-
* @param curve The curve to project
|
|
194
|
-
* @param face The face to project onto
|
|
195
|
-
* @param faceBrep The solid `face` belongs to — a face handle cannot name its
|
|
196
|
-
* own solid
|
|
197
|
-
* @returns The projected curves as {@linkcode CurveHandle}`[]`
|
|
198
|
-
* @throws VALIDATION if `face` is not a face of `faceBrep`, or the curve's
|
|
199
|
-
* midpoint lies on the face's surface (there is no drop direction there)
|
|
200
|
-
* @throws OPERATION_FAILED if the kernel could not project the curve
|
|
201
|
-
*/
|
|
202
|
-
public abstract curvesFromProjection(
|
|
203
|
-
curve: CurveHandle,
|
|
204
|
-
face: FaceHandle,
|
|
205
|
-
faceBrep: BrepHandle,
|
|
206
|
-
): PluginApiReturn<CurveHandle[]>
|
|
207
|
-
|
|
208
|
-
/**
|
|
209
|
-
* Create a closed profile from an ordered list of point handles connected by
|
|
210
|
-
* line segments (last auto-connected to first). Host API call — returns a handle.
|
|
211
|
-
*
|
|
212
|
-
* @param points Ordered vertex handles of the profile
|
|
213
|
-
* @returns The new profile as a {@linkcode ProfileHandle}
|
|
214
|
-
*
|
|
215
|
-
* @examplePrompt Draw a closed polygon through these corner points
|
|
216
|
-
* @examplePrompt Create an L-shaped outline from a list of points
|
|
217
|
-
*
|
|
218
|
-
* @example
|
|
219
|
-
* ```ts
|
|
220
|
-
* const profile = snaptrude.core.geom.create.profileFromLinePoints(points)
|
|
221
|
-
* ```
|
|
222
|
-
*/
|
|
223
|
-
public abstract profileFromLinePoints(points: Vec3Handle[]): PluginApiReturn<ProfileHandle>
|
|
224
|
-
|
|
225
|
-
/**
|
|
226
|
-
* Create a profile from an ordered list of curve handles forming a closed loop.
|
|
227
|
-
* Host API call — returns a handle.
|
|
228
|
-
*
|
|
229
|
-
* @param curves Ordered curve handles forming a closed loop
|
|
230
|
-
* @returns The new profile as a {@linkcode ProfileHandle}
|
|
231
|
-
*
|
|
232
|
-
* @examplePrompt Join these lines and arcs into one closed shape
|
|
233
|
-
*
|
|
234
|
-
* @example
|
|
235
|
-
* ```ts
|
|
236
|
-
* const profile = snaptrude.core.geom.create.profileFromCurves([line, arc])
|
|
237
|
-
* ```
|
|
238
|
-
*/
|
|
239
|
-
public abstract profileFromCurves(curves: CurveHandle[]): PluginApiReturn<ProfileHandle>
|
|
240
|
-
|
|
241
|
-
/**
|
|
242
|
-
* Create a CLOSED smooth profile passing through each point, in order, with
|
|
243
|
-
* the loop closed smoothly back from the last point to the first (do NOT
|
|
244
|
-
* repeat the first point). Host API call — returns a handle. This is the
|
|
245
|
-
* closed counterpart of {@linkcode PluginGeomCreateApi.splineFromPoints} and
|
|
246
|
-
* the one-call route from points to an extrudable outline: wrap in
|
|
247
|
-
* `contourFromProfile` and extrude/loft/sweep as usual.
|
|
248
|
-
*
|
|
249
|
-
* The whole loop is smooth — this call takes no mixed straight/spline input.
|
|
250
|
-
* For a profile that is part curve and part straight, build the pieces with
|
|
251
|
-
* `splineFromPoints` + `line` and join them with
|
|
252
|
-
* {@linkcode PluginGeomCreateApi.profileFromCurves}.
|
|
253
|
-
*
|
|
254
|
-
* @param points 3..256 ordered through-points of the loop (first point NOT repeated)
|
|
255
|
-
* @returns The new closed profile as a {@linkcode ProfileHandle}
|
|
256
|
-
* @throws VALIDATION if fewer than 3 points, more than 256 points,
|
|
257
|
-
* consecutive points coincide (including last→first), or the loop
|
|
258
|
-
* self-intersects
|
|
259
|
-
*
|
|
260
|
-
* @examplePrompt Make a blob-shaped floor plate through these points
|
|
261
|
-
* @examplePrompt Organic curved outline through these corners
|
|
262
|
-
* @examplePrompt Freeform podium profile
|
|
263
|
-
*
|
|
264
|
-
* # Example
|
|
265
|
-
* ```ts
|
|
266
|
-
* const profile = await snaptrude.core.geom.create.profileFromSplinePoints([p0, p1, p2, p3, p4])
|
|
267
|
-
* const contour = await snaptrude.core.geom.create.contourFromProfile(profile)
|
|
268
|
-
* const brep = await snaptrude.core.geom.create.brepFromExtrusion(contour, { x: 0, y: 1, z: 0 }, 3)
|
|
269
|
-
* const podium = await snaptrude.design.create.massFromBrep(brep, "Podium")
|
|
270
|
-
* ```
|
|
271
|
-
*/
|
|
272
|
-
public abstract profileFromSplinePoints(points: Vec3Handle[]): PluginApiReturn<ProfileHandle>
|
|
273
|
-
|
|
274
|
-
/**
|
|
275
|
-
* Create an axis-aligned **rectangle** profile in the XZ plane,
|
|
276
|
-
* `width` × `depth`, centred at `center` (defaults to the origin). Host API
|
|
277
|
-
* call — returns a handle.
|
|
278
|
-
*
|
|
279
|
-
* Pair with `design.create.space` / `design.create.spaces` to author a rectangular
|
|
280
|
-
* (box) space — there is no dedicated rectangular-space creator; build the profile
|
|
281
|
-
* here, then extrude it.
|
|
282
|
-
*
|
|
283
|
-
* @param width Extent along X
|
|
284
|
-
* @param depth Extent along Z
|
|
285
|
-
* @param center Optional centre point (default origin)
|
|
286
|
-
* @returns The new rectangle profile as a {@linkcode ProfileHandle}
|
|
287
|
-
*
|
|
288
|
-
* @examplePrompt Draw a 4m by 3m rectangle
|
|
289
|
-
* @examplePrompt Make a rectangular outline for a room footprint
|
|
290
|
-
*
|
|
291
|
-
* @example
|
|
292
|
-
* ```ts
|
|
293
|
-
* const rect = snaptrude.core.geom.create.profileRect(4, 3)
|
|
294
|
-
* const contour = snaptrude.core.geom.create.contourFromProfile(rect)
|
|
295
|
-
* const space = snaptrude.design.create.space(contour, 3)
|
|
296
|
-
* ```
|
|
297
|
-
*/
|
|
298
|
-
public abstract profileRect(
|
|
299
|
-
width: number,
|
|
300
|
-
depth: number,
|
|
301
|
-
center?: Vec3Handle,
|
|
302
|
-
): PluginApiReturn<ProfileHandle>
|
|
303
|
-
|
|
304
|
-
/**
|
|
305
|
-
* Create a contour (an outer profile loop, no holes). Host API call — returns a handle.
|
|
306
|
-
*
|
|
307
|
-
* @param outer The outer boundary loop
|
|
308
|
-
* @returns The new contour as a {@linkcode ContourHandle}
|
|
309
|
-
* @example
|
|
310
|
-
* ```ts
|
|
311
|
-
* const contour = snaptrude.core.geom.create.contourFromProfile(outer)
|
|
312
|
-
* ```
|
|
313
|
-
*/
|
|
314
|
-
public abstract contourFromProfile(outer: ProfileHandle): PluginApiReturn<ContourHandle>
|
|
315
|
-
|
|
316
|
-
/**
|
|
317
|
-
* Create a contour from an outer profile plus zero or more inner profiles (holes).
|
|
318
|
-
* Host API call — returns a handle.
|
|
319
|
-
*
|
|
320
|
-
*
|
|
321
|
-
*
|
|
322
|
-
*
|
|
323
|
-
*
|
|
324
|
-
* @
|
|
325
|
-
* @
|
|
326
|
-
*
|
|
327
|
-
* @
|
|
328
|
-
*
|
|
329
|
-
*
|
|
330
|
-
*
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
*
|
|
342
|
-
*
|
|
343
|
-
*
|
|
344
|
-
*
|
|
345
|
-
*
|
|
346
|
-
*
|
|
347
|
-
*
|
|
348
|
-
*
|
|
349
|
-
*
|
|
350
|
-
*
|
|
351
|
-
*
|
|
352
|
-
*
|
|
353
|
-
*
|
|
354
|
-
*
|
|
355
|
-
*
|
|
356
|
-
*
|
|
357
|
-
*
|
|
358
|
-
*
|
|
359
|
-
*
|
|
360
|
-
*
|
|
361
|
-
*
|
|
362
|
-
*
|
|
363
|
-
*
|
|
364
|
-
*
|
|
365
|
-
*
|
|
366
|
-
*
|
|
367
|
-
*
|
|
368
|
-
*
|
|
369
|
-
* const
|
|
370
|
-
* const
|
|
371
|
-
* const
|
|
372
|
-
*
|
|
373
|
-
*
|
|
374
|
-
*
|
|
375
|
-
* [
|
|
376
|
-
* [
|
|
377
|
-
* ]
|
|
378
|
-
*
|
|
379
|
-
*
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
*
|
|
388
|
-
*
|
|
389
|
-
*
|
|
390
|
-
*
|
|
391
|
-
*
|
|
392
|
-
*
|
|
393
|
-
*
|
|
394
|
-
*
|
|
395
|
-
*
|
|
396
|
-
*
|
|
397
|
-
* @param
|
|
398
|
-
*
|
|
399
|
-
*
|
|
400
|
-
*
|
|
401
|
-
*
|
|
402
|
-
*
|
|
403
|
-
*
|
|
404
|
-
* at
|
|
405
|
-
*
|
|
406
|
-
*
|
|
407
|
-
*
|
|
408
|
-
*
|
|
409
|
-
*
|
|
410
|
-
*
|
|
411
|
-
*
|
|
412
|
-
*
|
|
413
|
-
* @throws
|
|
414
|
-
*
|
|
415
|
-
*
|
|
416
|
-
*
|
|
417
|
-
*
|
|
418
|
-
*
|
|
419
|
-
*
|
|
420
|
-
*
|
|
421
|
-
*
|
|
422
|
-
* @examplePrompt Extrude this
|
|
423
|
-
* @examplePrompt
|
|
424
|
-
*
|
|
425
|
-
*
|
|
426
|
-
*
|
|
427
|
-
*
|
|
428
|
-
*
|
|
429
|
-
*
|
|
430
|
-
* const
|
|
431
|
-
*
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
*
|
|
445
|
-
*
|
|
446
|
-
*
|
|
447
|
-
*
|
|
448
|
-
*
|
|
449
|
-
*
|
|
450
|
-
*
|
|
451
|
-
*
|
|
452
|
-
*
|
|
453
|
-
*
|
|
454
|
-
*
|
|
455
|
-
*
|
|
456
|
-
*
|
|
457
|
-
*
|
|
458
|
-
*
|
|
459
|
-
*
|
|
460
|
-
*
|
|
461
|
-
*
|
|
462
|
-
*
|
|
463
|
-
*
|
|
464
|
-
*
|
|
465
|
-
* `"
|
|
466
|
-
*
|
|
467
|
-
*
|
|
468
|
-
*
|
|
469
|
-
*
|
|
470
|
-
*
|
|
471
|
-
*
|
|
472
|
-
*
|
|
473
|
-
*
|
|
474
|
-
*
|
|
475
|
-
*
|
|
476
|
-
*
|
|
477
|
-
*
|
|
478
|
-
*
|
|
479
|
-
*
|
|
480
|
-
*
|
|
481
|
-
*
|
|
482
|
-
*
|
|
483
|
-
*
|
|
484
|
-
*
|
|
485
|
-
*
|
|
486
|
-
*
|
|
487
|
-
*
|
|
488
|
-
*
|
|
489
|
-
*
|
|
490
|
-
*
|
|
491
|
-
*
|
|
492
|
-
*
|
|
493
|
-
*
|
|
494
|
-
*
|
|
495
|
-
*
|
|
496
|
-
*
|
|
497
|
-
* { edge:
|
|
498
|
-
*
|
|
499
|
-
*
|
|
500
|
-
*
|
|
501
|
-
*
|
|
502
|
-
*
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
*
|
|
519
|
-
*
|
|
520
|
-
*
|
|
521
|
-
*
|
|
522
|
-
*
|
|
523
|
-
*
|
|
524
|
-
*
|
|
525
|
-
*
|
|
526
|
-
*
|
|
527
|
-
*
|
|
528
|
-
*
|
|
529
|
-
*
|
|
530
|
-
*
|
|
531
|
-
*
|
|
532
|
-
* are
|
|
533
|
-
*
|
|
534
|
-
*
|
|
535
|
-
*
|
|
536
|
-
*
|
|
537
|
-
*
|
|
538
|
-
*
|
|
539
|
-
*
|
|
540
|
-
* @param
|
|
541
|
-
*
|
|
542
|
-
*
|
|
543
|
-
*
|
|
544
|
-
*
|
|
545
|
-
*
|
|
546
|
-
*
|
|
547
|
-
*
|
|
548
|
-
*
|
|
549
|
-
*
|
|
550
|
-
*
|
|
551
|
-
*
|
|
552
|
-
*
|
|
553
|
-
*
|
|
554
|
-
*
|
|
555
|
-
*
|
|
556
|
-
*
|
|
557
|
-
*
|
|
558
|
-
*
|
|
559
|
-
*
|
|
560
|
-
*
|
|
561
|
-
*
|
|
562
|
-
*
|
|
563
|
-
*
|
|
564
|
-
*
|
|
565
|
-
*
|
|
566
|
-
*
|
|
567
|
-
*
|
|
568
|
-
*
|
|
569
|
-
*
|
|
570
|
-
*
|
|
571
|
-
*
|
|
572
|
-
* @
|
|
573
|
-
*
|
|
574
|
-
*
|
|
575
|
-
* @examplePrompt
|
|
576
|
-
* @examplePrompt Loft a
|
|
577
|
-
* @examplePrompt
|
|
578
|
-
* @examplePrompt Loft
|
|
579
|
-
* @examplePrompt
|
|
580
|
-
* @examplePrompt Loft these
|
|
581
|
-
*
|
|
582
|
-
*
|
|
583
|
-
*
|
|
584
|
-
*
|
|
585
|
-
*
|
|
586
|
-
*
|
|
587
|
-
*
|
|
588
|
-
*
|
|
589
|
-
*
|
|
590
|
-
*
|
|
591
|
-
*
|
|
592
|
-
*
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
*
|
|
610
|
-
*
|
|
611
|
-
*
|
|
612
|
-
*
|
|
613
|
-
*
|
|
614
|
-
*
|
|
615
|
-
*
|
|
616
|
-
*
|
|
617
|
-
*
|
|
618
|
-
*
|
|
619
|
-
* @
|
|
620
|
-
*
|
|
621
|
-
*
|
|
622
|
-
* @
|
|
623
|
-
*
|
|
624
|
-
*
|
|
625
|
-
*
|
|
626
|
-
*
|
|
627
|
-
*
|
|
628
|
-
*
|
|
629
|
-
*
|
|
630
|
-
*
|
|
631
|
-
*
|
|
632
|
-
*
|
|
633
|
-
* { x:
|
|
634
|
-
*
|
|
635
|
-
*
|
|
636
|
-
*
|
|
637
|
-
*
|
|
638
|
-
*
|
|
639
|
-
* [
|
|
640
|
-
* ]
|
|
641
|
-
*
|
|
642
|
-
*
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
*
|
|
654
|
-
*
|
|
655
|
-
*
|
|
656
|
-
*
|
|
657
|
-
*
|
|
658
|
-
*
|
|
659
|
-
*
|
|
660
|
-
*
|
|
661
|
-
*
|
|
662
|
-
*
|
|
663
|
-
* @
|
|
664
|
-
*
|
|
665
|
-
*
|
|
666
|
-
* @
|
|
667
|
-
*
|
|
668
|
-
*
|
|
669
|
-
*
|
|
670
|
-
*
|
|
671
|
-
*
|
|
672
|
-
*
|
|
673
|
-
*
|
|
674
|
-
*
|
|
675
|
-
*
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
*
|
|
684
|
-
*
|
|
685
|
-
* {@linkcode
|
|
686
|
-
*
|
|
687
|
-
*
|
|
688
|
-
*
|
|
689
|
-
*
|
|
690
|
-
*
|
|
691
|
-
*
|
|
692
|
-
*
|
|
693
|
-
*
|
|
694
|
-
*
|
|
695
|
-
*
|
|
696
|
-
*
|
|
697
|
-
* @
|
|
698
|
-
* @
|
|
699
|
-
* @
|
|
700
|
-
*
|
|
701
|
-
*
|
|
702
|
-
*
|
|
703
|
-
*
|
|
704
|
-
*
|
|
705
|
-
*
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
*
|
|
711
|
-
*
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
*
|
|
717
|
-
*
|
|
718
|
-
*
|
|
719
|
-
*
|
|
720
|
-
*
|
|
721
|
-
*
|
|
722
|
-
*
|
|
723
|
-
*
|
|
724
|
-
*
|
|
725
|
-
*
|
|
726
|
-
* @
|
|
727
|
-
* @
|
|
728
|
-
* @
|
|
729
|
-
*
|
|
730
|
-
*
|
|
731
|
-
*
|
|
732
|
-
*
|
|
733
|
-
*
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
*
|
|
739
|
-
*
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
*
|
|
745
|
-
*
|
|
746
|
-
*
|
|
747
|
-
* on
|
|
748
|
-
*
|
|
749
|
-
*
|
|
750
|
-
* `
|
|
751
|
-
*
|
|
752
|
-
*
|
|
753
|
-
*
|
|
754
|
-
*
|
|
755
|
-
*
|
|
756
|
-
*
|
|
757
|
-
*
|
|
758
|
-
*
|
|
759
|
-
*
|
|
760
|
-
*
|
|
761
|
-
*
|
|
762
|
-
*
|
|
763
|
-
*
|
|
764
|
-
*
|
|
765
|
-
*
|
|
766
|
-
*
|
|
767
|
-
*
|
|
768
|
-
*
|
|
769
|
-
* @param
|
|
770
|
-
*
|
|
771
|
-
*
|
|
772
|
-
*
|
|
773
|
-
*
|
|
774
|
-
*
|
|
775
|
-
*
|
|
776
|
-
*
|
|
777
|
-
*
|
|
778
|
-
* radius
|
|
779
|
-
*
|
|
780
|
-
*
|
|
781
|
-
*
|
|
782
|
-
*
|
|
783
|
-
*
|
|
784
|
-
*
|
|
785
|
-
*
|
|
786
|
-
*
|
|
787
|
-
*
|
|
788
|
-
*
|
|
789
|
-
*
|
|
790
|
-
*
|
|
791
|
-
*
|
|
792
|
-
*
|
|
793
|
-
*
|
|
794
|
-
*
|
|
795
|
-
*
|
|
796
|
-
*
|
|
797
|
-
*
|
|
798
|
-
*
|
|
799
|
-
*
|
|
800
|
-
*
|
|
801
|
-
*
|
|
802
|
-
* @
|
|
803
|
-
*
|
|
804
|
-
*
|
|
805
|
-
*
|
|
806
|
-
*
|
|
807
|
-
*
|
|
808
|
-
*
|
|
809
|
-
*
|
|
810
|
-
*
|
|
811
|
-
*
|
|
812
|
-
*
|
|
813
|
-
*
|
|
814
|
-
*
|
|
815
|
-
*
|
|
816
|
-
*
|
|
817
|
-
*
|
|
818
|
-
*
|
|
819
|
-
*
|
|
820
|
-
*
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
*
|
|
837
|
-
*
|
|
838
|
-
*
|
|
839
|
-
*
|
|
840
|
-
*
|
|
841
|
-
*
|
|
842
|
-
*
|
|
843
|
-
*
|
|
844
|
-
*
|
|
845
|
-
*
|
|
846
|
-
*
|
|
847
|
-
*
|
|
848
|
-
*
|
|
849
|
-
*
|
|
850
|
-
*
|
|
851
|
-
*
|
|
852
|
-
*
|
|
853
|
-
*
|
|
854
|
-
*
|
|
855
|
-
*
|
|
856
|
-
*
|
|
857
|
-
*
|
|
858
|
-
*
|
|
859
|
-
*
|
|
860
|
-
*
|
|
861
|
-
*
|
|
862
|
-
*
|
|
863
|
-
*
|
|
864
|
-
*
|
|
865
|
-
*
|
|
866
|
-
*
|
|
867
|
-
*
|
|
868
|
-
*
|
|
869
|
-
*
|
|
870
|
-
*
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
*
|
|
876
|
-
*
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
*
|
|
882
|
-
*
|
|
883
|
-
*
|
|
884
|
-
*
|
|
885
|
-
*
|
|
886
|
-
*
|
|
887
|
-
*
|
|
888
|
-
*
|
|
889
|
-
*
|
|
890
|
-
*
|
|
891
|
-
*
|
|
892
|
-
*
|
|
893
|
-
*
|
|
894
|
-
*
|
|
895
|
-
*
|
|
896
|
-
*
|
|
897
|
-
*
|
|
898
|
-
*
|
|
899
|
-
*
|
|
900
|
-
*
|
|
901
|
-
*
|
|
902
|
-
*
|
|
903
|
-
*
|
|
904
|
-
* @
|
|
905
|
-
*
|
|
906
|
-
*
|
|
907
|
-
*
|
|
908
|
-
* @
|
|
909
|
-
*
|
|
910
|
-
*
|
|
911
|
-
*
|
|
912
|
-
*
|
|
913
|
-
*
|
|
914
|
-
*
|
|
915
|
-
*
|
|
916
|
-
*
|
|
917
|
-
*
|
|
918
|
-
*
|
|
919
|
-
*
|
|
920
|
-
*
|
|
921
|
-
*
|
|
922
|
-
*
|
|
923
|
-
*
|
|
924
|
-
*
|
|
925
|
-
*
|
|
926
|
-
*
|
|
927
|
-
*
|
|
928
|
-
*
|
|
929
|
-
*
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
*
|
|
945
|
-
*
|
|
946
|
-
*
|
|
947
|
-
*
|
|
948
|
-
*
|
|
949
|
-
*
|
|
950
|
-
*
|
|
951
|
-
*
|
|
952
|
-
*
|
|
953
|
-
*
|
|
954
|
-
*
|
|
955
|
-
* @
|
|
956
|
-
*
|
|
957
|
-
* @
|
|
958
|
-
* @
|
|
959
|
-
* @
|
|
960
|
-
*
|
|
961
|
-
*
|
|
962
|
-
*
|
|
963
|
-
*
|
|
964
|
-
*
|
|
965
|
-
*
|
|
966
|
-
*
|
|
967
|
-
*
|
|
968
|
-
*
|
|
969
|
-
*
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
*
|
|
985
|
-
*
|
|
986
|
-
*
|
|
987
|
-
*
|
|
988
|
-
*
|
|
989
|
-
*
|
|
990
|
-
*
|
|
991
|
-
*
|
|
992
|
-
*
|
|
993
|
-
*
|
|
994
|
-
*
|
|
995
|
-
*
|
|
996
|
-
*
|
|
997
|
-
*
|
|
998
|
-
*
|
|
999
|
-
*
|
|
1000
|
-
*
|
|
1001
|
-
*
|
|
1002
|
-
* @
|
|
1003
|
-
*
|
|
1004
|
-
*
|
|
1005
|
-
*
|
|
1006
|
-
*
|
|
1007
|
-
*
|
|
1008
|
-
*
|
|
1009
|
-
*
|
|
1010
|
-
*
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
*
|
|
1026
|
-
*
|
|
1027
|
-
*
|
|
1028
|
-
*
|
|
1029
|
-
*
|
|
1030
|
-
*
|
|
1031
|
-
*
|
|
1032
|
-
*
|
|
1033
|
-
*
|
|
1034
|
-
*
|
|
1035
|
-
*
|
|
1036
|
-
*
|
|
1037
|
-
*
|
|
1038
|
-
*
|
|
1039
|
-
*
|
|
1040
|
-
*
|
|
1041
|
-
*
|
|
1042
|
-
*
|
|
1043
|
-
*
|
|
1044
|
-
*
|
|
1045
|
-
*
|
|
1046
|
-
* @
|
|
1047
|
-
*
|
|
1048
|
-
*
|
|
1049
|
-
*
|
|
1050
|
-
* @
|
|
1051
|
-
*
|
|
1052
|
-
*
|
|
1053
|
-
*
|
|
1054
|
-
*
|
|
1055
|
-
*
|
|
1056
|
-
*
|
|
1057
|
-
*
|
|
1058
|
-
*
|
|
1059
|
-
*
|
|
1060
|
-
*
|
|
1061
|
-
*
|
|
1062
|
-
*
|
|
1063
|
-
*
|
|
1064
|
-
*
|
|
1065
|
-
*
|
|
1066
|
-
*
|
|
1067
|
-
*
|
|
1068
|
-
*
|
|
1069
|
-
*
|
|
1070
|
-
*
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
*
|
|
1086
|
-
*
|
|
1087
|
-
*
|
|
1088
|
-
*
|
|
1089
|
-
*
|
|
1090
|
-
*
|
|
1091
|
-
*
|
|
1092
|
-
*
|
|
1093
|
-
*
|
|
1094
|
-
*
|
|
1095
|
-
*
|
|
1096
|
-
*
|
|
1097
|
-
*
|
|
1098
|
-
*
|
|
1099
|
-
*
|
|
1100
|
-
*
|
|
1101
|
-
*
|
|
1102
|
-
*
|
|
1103
|
-
*
|
|
1104
|
-
*
|
|
1105
|
-
* a
|
|
1106
|
-
*
|
|
1107
|
-
*
|
|
1108
|
-
*
|
|
1109
|
-
*
|
|
1110
|
-
*
|
|
1111
|
-
*
|
|
1112
|
-
*
|
|
1113
|
-
*
|
|
1114
|
-
*
|
|
1115
|
-
*
|
|
1116
|
-
*
|
|
1117
|
-
*
|
|
1118
|
-
*
|
|
1119
|
-
*
|
|
1120
|
-
*
|
|
1121
|
-
*
|
|
1122
|
-
*
|
|
1123
|
-
*
|
|
1124
|
-
*
|
|
1125
|
-
*
|
|
1126
|
-
*
|
|
1127
|
-
*
|
|
1128
|
-
*
|
|
1129
|
-
*
|
|
1130
|
-
*
|
|
1131
|
-
*
|
|
1132
|
-
*
|
|
1133
|
-
*
|
|
1134
|
-
*
|
|
1135
|
-
* is
|
|
1136
|
-
* path
|
|
1137
|
-
*
|
|
1138
|
-
*
|
|
1139
|
-
*
|
|
1140
|
-
*
|
|
1141
|
-
*
|
|
1142
|
-
*
|
|
1143
|
-
*
|
|
1144
|
-
*
|
|
1145
|
-
*
|
|
1146
|
-
*
|
|
1147
|
-
*
|
|
1148
|
-
*
|
|
1149
|
-
* @
|
|
1150
|
-
*
|
|
1151
|
-
*
|
|
1152
|
-
*
|
|
1153
|
-
* @examplePrompt
|
|
1154
|
-
* @examplePrompt
|
|
1155
|
-
*
|
|
1156
|
-
*
|
|
1157
|
-
*
|
|
1158
|
-
*
|
|
1159
|
-
*
|
|
1160
|
-
*
|
|
1161
|
-
*
|
|
1162
|
-
*
|
|
1163
|
-
*
|
|
1164
|
-
*
|
|
1165
|
-
*
|
|
1166
|
-
*
|
|
1167
|
-
* //
|
|
1168
|
-
* const
|
|
1169
|
-
* { x: 0, y: 0, z: 0 },
|
|
1170
|
-
* { x: 0, y:
|
|
1171
|
-
* { x:
|
|
1172
|
-
*
|
|
1173
|
-
*
|
|
1174
|
-
*
|
|
1175
|
-
*
|
|
1176
|
-
*
|
|
1177
|
-
*
|
|
1178
|
-
*
|
|
1179
|
-
*
|
|
1180
|
-
*
|
|
1181
|
-
*
|
|
1182
|
-
*
|
|
1183
|
-
*
|
|
1184
|
-
*
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
*
|
|
1205
|
-
*
|
|
1206
|
-
*
|
|
1207
|
-
*
|
|
1208
|
-
*
|
|
1209
|
-
*
|
|
1210
|
-
*
|
|
1211
|
-
*
|
|
1212
|
-
*
|
|
1213
|
-
*
|
|
1214
|
-
*
|
|
1215
|
-
*
|
|
1216
|
-
*
|
|
1217
|
-
* @
|
|
1218
|
-
* @
|
|
1219
|
-
*
|
|
1220
|
-
*
|
|
1221
|
-
*
|
|
1222
|
-
*
|
|
1223
|
-
*
|
|
1224
|
-
* @throws
|
|
1225
|
-
*
|
|
1226
|
-
*
|
|
1227
|
-
*
|
|
1228
|
-
*
|
|
1229
|
-
*
|
|
1230
|
-
*
|
|
1231
|
-
*
|
|
1232
|
-
*
|
|
1233
|
-
*
|
|
1234
|
-
*
|
|
1235
|
-
*
|
|
1236
|
-
*
|
|
1237
|
-
*
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
*
|
|
1253
|
-
*
|
|
1254
|
-
*
|
|
1255
|
-
*
|
|
1256
|
-
*
|
|
1257
|
-
*
|
|
1258
|
-
*
|
|
1259
|
-
* the axis.
|
|
1260
|
-
*
|
|
1261
|
-
*
|
|
1262
|
-
*
|
|
1263
|
-
*
|
|
1264
|
-
*
|
|
1265
|
-
*
|
|
1266
|
-
*
|
|
1267
|
-
*
|
|
1268
|
-
*
|
|
1269
|
-
*
|
|
1270
|
-
*
|
|
1271
|
-
*
|
|
1272
|
-
*
|
|
1273
|
-
*
|
|
1274
|
-
*
|
|
1275
|
-
*
|
|
1276
|
-
*
|
|
1277
|
-
*
|
|
1278
|
-
*
|
|
1279
|
-
* @
|
|
1280
|
-
*
|
|
1281
|
-
*
|
|
1282
|
-
*
|
|
1283
|
-
*
|
|
1284
|
-
*
|
|
1285
|
-
* @
|
|
1286
|
-
*
|
|
1287
|
-
*
|
|
1288
|
-
* @
|
|
1289
|
-
*
|
|
1290
|
-
*
|
|
1291
|
-
*
|
|
1292
|
-
*
|
|
1293
|
-
*
|
|
1294
|
-
*
|
|
1295
|
-
*
|
|
1296
|
-
*
|
|
1297
|
-
*
|
|
1298
|
-
*
|
|
1299
|
-
*
|
|
1300
|
-
*
|
|
1301
|
-
* const
|
|
1302
|
-
*
|
|
1303
|
-
*
|
|
1304
|
-
*
|
|
1305
|
-
*
|
|
1306
|
-
* )
|
|
1307
|
-
*
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
*
|
|
1324
|
-
*
|
|
1325
|
-
*
|
|
1326
|
-
*
|
|
1327
|
-
*
|
|
1328
|
-
*
|
|
1329
|
-
*
|
|
1330
|
-
*
|
|
1331
|
-
*
|
|
1332
|
-
*
|
|
1333
|
-
*
|
|
1334
|
-
* @
|
|
1335
|
-
* @
|
|
1336
|
-
*
|
|
1337
|
-
*
|
|
1338
|
-
*
|
|
1339
|
-
*
|
|
1340
|
-
*
|
|
1341
|
-
*
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
*
|
|
1356
|
-
*
|
|
1357
|
-
*
|
|
1358
|
-
*
|
|
1359
|
-
*
|
|
1360
|
-
*
|
|
1361
|
-
*
|
|
1362
|
-
*
|
|
1363
|
-
*
|
|
1364
|
-
*
|
|
1365
|
-
*
|
|
1366
|
-
*
|
|
1367
|
-
*
|
|
1368
|
-
* @
|
|
1369
|
-
* @
|
|
1370
|
-
*
|
|
1371
|
-
*
|
|
1372
|
-
*
|
|
1373
|
-
*
|
|
1374
|
-
*
|
|
1375
|
-
*
|
|
1376
|
-
*
|
|
1377
|
-
*
|
|
1378
|
-
*
|
|
1379
|
-
* const
|
|
1380
|
-
*
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
*
|
|
1397
|
-
*
|
|
1398
|
-
*
|
|
1399
|
-
* @
|
|
1400
|
-
*
|
|
1401
|
-
*
|
|
1402
|
-
*
|
|
1403
|
-
*
|
|
1404
|
-
*
|
|
1405
|
-
* @
|
|
1406
|
-
*
|
|
1407
|
-
*
|
|
1408
|
-
*
|
|
1409
|
-
* @
|
|
1410
|
-
* @
|
|
1411
|
-
*
|
|
1412
|
-
*
|
|
1413
|
-
*
|
|
1414
|
-
*
|
|
1415
|
-
*
|
|
1416
|
-
*
|
|
1417
|
-
*
|
|
1418
|
-
*
|
|
1419
|
-
*
|
|
1420
|
-
*
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
*
|
|
1438
|
-
*
|
|
1439
|
-
*
|
|
1440
|
-
*
|
|
1441
|
-
*
|
|
1442
|
-
*
|
|
1443
|
-
*
|
|
1444
|
-
*
|
|
1445
|
-
*
|
|
1446
|
-
*
|
|
1447
|
-
*
|
|
1448
|
-
*
|
|
1449
|
-
* @
|
|
1450
|
-
* @
|
|
1451
|
-
*
|
|
1452
|
-
*
|
|
1453
|
-
*
|
|
1454
|
-
*
|
|
1455
|
-
*
|
|
1456
|
-
*
|
|
1457
|
-
*
|
|
1458
|
-
*
|
|
1459
|
-
*
|
|
1460
|
-
*
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
}
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
*
|
|
1493
|
-
*
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
*
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
export
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
}
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
}
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
*
|
|
1653
|
-
*
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
.finite()
|
|
1665
|
-
.
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
})
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
*
|
|
1687
|
-
*
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
})
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
*
|
|
1727
|
-
*
|
|
1728
|
-
*
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
})
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
*
|
|
1752
|
-
*
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
.
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
if (
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
if (
|
|
1790
|
-
ctx.addIssue({
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
*
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
|
|
1825
|
-
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
*
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
export
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
*
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
})
|
|
1893
|
-
|
|
1894
|
-
export
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
*
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
})
|
|
1910
|
-
|
|
1911
|
-
export
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
*
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
})
|
|
1929
|
-
|
|
1930
|
-
export
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
*
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
export
|
|
1950
|
-
|
|
1951
|
-
|
|
1952
|
-
|
|
1953
|
-
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
*
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
|
|
1968
|
-
|
|
1969
|
-
|
|
1970
|
-
|
|
1971
|
-
|
|
1972
|
-
|
|
1973
|
-
|
|
1974
|
-
|
|
1975
|
-
|
|
1976
|
-
|
|
1977
|
-
|
|
1978
|
-
|
|
1979
|
-
|
|
1980
|
-
|
|
1981
|
-
|
|
1982
|
-
|
|
1983
|
-
|
|
1984
|
-
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
if (options.
|
|
1995
|
-
ctx.addIssue({
|
|
1996
|
-
code: z.ZodIssueCode.custom,
|
|
1997
|
-
message: "scales
|
|
1998
|
-
})
|
|
1999
|
-
}
|
|
2000
|
-
|
|
2001
|
-
|
|
2002
|
-
|
|
2003
|
-
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
|
|
2010
|
-
|
|
2011
|
-
*
|
|
2012
|
-
|
|
2013
|
-
|
|
2014
|
-
|
|
2015
|
-
|
|
2016
|
-
|
|
2017
|
-
|
|
2018
|
-
|
|
2019
|
-
|
|
2020
|
-
|
|
2021
|
-
|
|
2022
|
-
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
|
|
2026
|
-
|
|
2027
|
-
|
|
2028
|
-
|
|
2029
|
-
|
|
2030
|
-
|
|
2031
|
-
|
|
2032
|
-
|
|
2033
|
-
|
|
2034
|
-
|
|
2035
|
-
*
|
|
2036
|
-
*
|
|
2037
|
-
|
|
2038
|
-
|
|
2039
|
-
|
|
2040
|
-
|
|
2041
|
-
|
|
2042
|
-
|
|
2043
|
-
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
|
|
2050
|
-
|
|
2051
|
-
|
|
2052
|
-
|
|
2053
|
-
|
|
2054
|
-
|
|
2055
|
-
|
|
2056
|
-
|
|
2057
|
-
|
|
2058
|
-
|
|
2059
|
-
|
|
2060
|
-
})
|
|
2061
|
-
|
|
2062
|
-
|
|
2063
|
-
|
|
2064
|
-
|
|
2065
|
-
|
|
2066
|
-
|
|
2067
|
-
|
|
2068
|
-
|
|
2069
|
-
|
|
2070
|
-
|
|
2071
|
-
|
|
2072
|
-
|
|
2073
|
-
*
|
|
2074
|
-
*
|
|
2075
|
-
|
|
2076
|
-
|
|
2077
|
-
|
|
2078
|
-
|
|
2079
|
-
|
|
2080
|
-
|
|
2081
|
-
|
|
2082
|
-
|
|
2083
|
-
|
|
2084
|
-
|
|
2085
|
-
|
|
2086
|
-
|
|
2087
|
-
|
|
2088
|
-
|
|
2089
|
-
|
|
2090
|
-
|
|
2091
|
-
|
|
2092
|
-
|
|
2093
|
-
|
|
2094
|
-
*
|
|
2095
|
-
*
|
|
2096
|
-
* |
|
|
2097
|
-
|
|
2098
|
-
|
|
2099
|
-
|
|
2100
|
-
|
|
2101
|
-
|
|
2102
|
-
|
|
2103
|
-
|
|
2104
|
-
|
|
2105
|
-
|
|
2106
|
-
|
|
2107
|
-
|
|
2108
|
-
|
|
2109
|
-
|
|
2110
|
-
|
|
2111
|
-
|
|
2112
|
-
|
|
2113
|
-
|
|
2114
|
-
|
|
2115
|
-
|
|
2116
|
-
|
|
2117
|
-
|
|
2118
|
-
|
|
2119
|
-
*
|
|
2120
|
-
*
|
|
2121
|
-
|
|
2122
|
-
|
|
2123
|
-
|
|
2124
|
-
|
|
2125
|
-
|
|
2126
|
-
|
|
2127
|
-
|
|
2128
|
-
|
|
2129
|
-
.
|
|
2130
|
-
|
|
2131
|
-
|
|
2132
|
-
|
|
2133
|
-
|
|
1
|
+
import * as z from "zod"
|
|
2
|
+
import { PluginApiReturn } from "../../../../types"
|
|
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 }
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Curve creation — construct new geometric curves from point handles (all-handle
|
|
37
|
+
* model, §11).
|
|
38
|
+
*
|
|
39
|
+
* Each method takes point handles ({@linkcode Vec3Handle}) and returns an opaque
|
|
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.
|
|
44
|
+
*
|
|
45
|
+
* Accessed via `snaptrude.core.geom.create`.
|
|
46
|
+
*/
|
|
47
|
+
export abstract class PluginGeomCreateApi {
|
|
48
|
+
constructor() {}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Create a straight line segment between two point handles. Host API call —
|
|
52
|
+
* returns a handle.
|
|
53
|
+
*
|
|
54
|
+
* @param startPoint Start point of the line segment
|
|
55
|
+
* @param endPoint End point of the line segment
|
|
56
|
+
* @returns The new line as a {@linkcode LineHandle}
|
|
57
|
+
*
|
|
58
|
+
* @examplePrompt Draw a line from point A to point B
|
|
59
|
+
* @examplePrompt Draw a straight edge between these two points
|
|
60
|
+
*
|
|
61
|
+
* @example
|
|
62
|
+
* ```ts
|
|
63
|
+
* const line = snaptrude.core.geom.create.line(startPoint, endPoint)
|
|
64
|
+
* ```
|
|
65
|
+
*/
|
|
66
|
+
public abstract line(startPoint: Vec3Handle, endPoint: Vec3Handle): PluginApiReturn<LineHandle>
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Create a circular arc from its start, end, centre, and axis point handles.
|
|
70
|
+
* Host API call — returns a handle.
|
|
71
|
+
*
|
|
72
|
+
* @param startPoint Start point of the arc
|
|
73
|
+
* @param endPoint End point of the arc
|
|
74
|
+
* @param centrePoint Centre point of the arc
|
|
75
|
+
* @param axis Axis direction of the arc
|
|
76
|
+
* @returns The new arc as an {@linkcode ArcHandle}
|
|
77
|
+
*
|
|
78
|
+
* @examplePrompt Draw an arc between these two points around a centre
|
|
79
|
+
* @examplePrompt Add a curved segment from A to B
|
|
80
|
+
*
|
|
81
|
+
* @example
|
|
82
|
+
* ```ts
|
|
83
|
+
* const arc = snaptrude.core.geom.create.arc(startPoint, endPoint, centrePoint, axis)
|
|
84
|
+
* ```
|
|
85
|
+
*/
|
|
86
|
+
public abstract arc(
|
|
87
|
+
startPoint: Vec3Handle,
|
|
88
|
+
endPoint: Vec3Handle,
|
|
89
|
+
centrePoint: Vec3Handle,
|
|
90
|
+
axis: Vec3Handle,
|
|
91
|
+
): PluginApiReturn<ArcHandle>
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Create a circle from a centre point, an axis (plane normal), and a radius.
|
|
95
|
+
* Host API call — returns a handle. A circle is a closed curve; read it back via
|
|
96
|
+
* `snaptrude.core.geom.query.circle.*`.
|
|
97
|
+
*
|
|
98
|
+
* @param centrePoint Centre point of the circle
|
|
99
|
+
* @param axis Axis direction (plane normal) of the circle
|
|
100
|
+
* @param radius Radius of the circle
|
|
101
|
+
* @returns The new circle as a {@linkcode CircleHandle}
|
|
102
|
+
*
|
|
103
|
+
* @examplePrompt Make a circle of radius 2 at this point
|
|
104
|
+
* @examplePrompt Draw a circular outline 5m across
|
|
105
|
+
*
|
|
106
|
+
* @example
|
|
107
|
+
* ```ts
|
|
108
|
+
* const circle = snaptrude.core.geom.create.circle(centrePoint, axis, 2)
|
|
109
|
+
* ```
|
|
110
|
+
*/
|
|
111
|
+
public abstract circle(
|
|
112
|
+
centrePoint: Vec3Handle,
|
|
113
|
+
axis: Vec3Handle,
|
|
114
|
+
radius: number,
|
|
115
|
+
): PluginApiReturn<CircleHandle>
|
|
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. An edge's control points
|
|
161
|
+
* rebuild the same curve here only when its knots are clamped uniform.
|
|
162
|
+
*
|
|
163
|
+
* @param controlPoints 3..512 control points ({@linkcode Vec3Handle}s), in order
|
|
164
|
+
* @param options.degree 2 or 3; default `min(3, controlPoints.length - 1)`
|
|
165
|
+
* @returns The new open curve as a {@linkcode SplineHandle}
|
|
166
|
+
* @throws VALIDATION when fewer than `degree + 1` points are given, two
|
|
167
|
+
* consecutive points coincide, or `degree` is not 2 or 3
|
|
168
|
+
*
|
|
169
|
+
* @examplePrompt Draw a smooth curve controlled by these four points
|
|
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
|
+
* @param curve The curve to project
|
|
194
|
+
* @param face The face to project onto
|
|
195
|
+
* @param faceBrep The solid `face` belongs to — a face handle cannot name its
|
|
196
|
+
* own solid
|
|
197
|
+
* @returns The projected curves as {@linkcode CurveHandle}`[]`
|
|
198
|
+
* @throws VALIDATION if `face` is not a face of `faceBrep`, or the curve's
|
|
199
|
+
* midpoint lies on the face's surface (there is no drop direction there)
|
|
200
|
+
* @throws OPERATION_FAILED if the kernel could not project the curve
|
|
201
|
+
*/
|
|
202
|
+
public abstract curvesFromProjection(
|
|
203
|
+
curve: CurveHandle,
|
|
204
|
+
face: FaceHandle,
|
|
205
|
+
faceBrep: BrepHandle,
|
|
206
|
+
): PluginApiReturn<CurveHandle[]>
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* Create a closed profile from an ordered list of point handles connected by
|
|
210
|
+
* line segments (last auto-connected to first). Host API call — returns a handle.
|
|
211
|
+
*
|
|
212
|
+
* @param points Ordered vertex handles of the profile
|
|
213
|
+
* @returns The new profile as a {@linkcode ProfileHandle}
|
|
214
|
+
*
|
|
215
|
+
* @examplePrompt Draw a closed polygon through these corner points
|
|
216
|
+
* @examplePrompt Create an L-shaped outline from a list of points
|
|
217
|
+
*
|
|
218
|
+
* @example
|
|
219
|
+
* ```ts
|
|
220
|
+
* const profile = snaptrude.core.geom.create.profileFromLinePoints(points)
|
|
221
|
+
* ```
|
|
222
|
+
*/
|
|
223
|
+
public abstract profileFromLinePoints(points: Vec3Handle[]): PluginApiReturn<ProfileHandle>
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* Create a profile from an ordered list of curve handles forming a closed loop.
|
|
227
|
+
* Host API call — returns a handle.
|
|
228
|
+
*
|
|
229
|
+
* @param curves Ordered curve handles forming a closed loop
|
|
230
|
+
* @returns The new profile as a {@linkcode ProfileHandle}
|
|
231
|
+
*
|
|
232
|
+
* @examplePrompt Join these lines and arcs into one closed shape
|
|
233
|
+
*
|
|
234
|
+
* @example
|
|
235
|
+
* ```ts
|
|
236
|
+
* const profile = snaptrude.core.geom.create.profileFromCurves([line, arc])
|
|
237
|
+
* ```
|
|
238
|
+
*/
|
|
239
|
+
public abstract profileFromCurves(curves: CurveHandle[]): PluginApiReturn<ProfileHandle>
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* Create a CLOSED smooth profile passing through each point, in order, with
|
|
243
|
+
* the loop closed smoothly back from the last point to the first (do NOT
|
|
244
|
+
* repeat the first point). Host API call — returns a handle. This is the
|
|
245
|
+
* closed counterpart of {@linkcode PluginGeomCreateApi.splineFromPoints} and
|
|
246
|
+
* the one-call route from points to an extrudable outline: wrap in
|
|
247
|
+
* `contourFromProfile` and extrude/loft/sweep as usual.
|
|
248
|
+
*
|
|
249
|
+
* The whole loop is smooth — this call takes no mixed straight/spline input.
|
|
250
|
+
* For a profile that is part curve and part straight, build the pieces with
|
|
251
|
+
* `splineFromPoints` + `line` and join them with
|
|
252
|
+
* {@linkcode PluginGeomCreateApi.profileFromCurves}.
|
|
253
|
+
*
|
|
254
|
+
* @param points 3..256 ordered through-points of the loop (first point NOT repeated)
|
|
255
|
+
* @returns The new closed profile as a {@linkcode ProfileHandle}
|
|
256
|
+
* @throws VALIDATION if fewer than 3 points, more than 256 points,
|
|
257
|
+
* consecutive points coincide (including last→first), or the loop
|
|
258
|
+
* self-intersects
|
|
259
|
+
*
|
|
260
|
+
* @examplePrompt Make a blob-shaped floor plate through these points
|
|
261
|
+
* @examplePrompt Organic curved outline through these corners
|
|
262
|
+
* @examplePrompt Freeform podium profile
|
|
263
|
+
*
|
|
264
|
+
* # Example
|
|
265
|
+
* ```ts
|
|
266
|
+
* const profile = await snaptrude.core.geom.create.profileFromSplinePoints([p0, p1, p2, p3, p4])
|
|
267
|
+
* const contour = await snaptrude.core.geom.create.contourFromProfile(profile)
|
|
268
|
+
* const brep = await snaptrude.core.geom.create.brepFromExtrusion(contour, { x: 0, y: 1, z: 0 }, 3)
|
|
269
|
+
* const podium = await snaptrude.design.create.massFromBrep(brep, "Podium")
|
|
270
|
+
* ```
|
|
271
|
+
*/
|
|
272
|
+
public abstract profileFromSplinePoints(points: Vec3Handle[]): PluginApiReturn<ProfileHandle>
|
|
273
|
+
|
|
274
|
+
/**
|
|
275
|
+
* Create an axis-aligned **rectangle** profile in the XZ plane,
|
|
276
|
+
* `width` × `depth`, centred at `center` (defaults to the origin). Host API
|
|
277
|
+
* call — returns a handle.
|
|
278
|
+
*
|
|
279
|
+
* Pair with `design.create.space` / `design.create.spaces` to author a rectangular
|
|
280
|
+
* (box) space — there is no dedicated rectangular-space creator; build the profile
|
|
281
|
+
* here, then extrude it.
|
|
282
|
+
*
|
|
283
|
+
* @param width Extent along X
|
|
284
|
+
* @param depth Extent along Z
|
|
285
|
+
* @param center Optional centre point (default origin)
|
|
286
|
+
* @returns The new rectangle profile as a {@linkcode ProfileHandle}
|
|
287
|
+
*
|
|
288
|
+
* @examplePrompt Draw a 4m by 3m rectangle
|
|
289
|
+
* @examplePrompt Make a rectangular outline for a room footprint
|
|
290
|
+
*
|
|
291
|
+
* @example
|
|
292
|
+
* ```ts
|
|
293
|
+
* const rect = snaptrude.core.geom.create.profileRect(4, 3)
|
|
294
|
+
* const contour = snaptrude.core.geom.create.contourFromProfile(rect)
|
|
295
|
+
* const space = snaptrude.design.create.space(contour, 3)
|
|
296
|
+
* ```
|
|
297
|
+
*/
|
|
298
|
+
public abstract profileRect(
|
|
299
|
+
width: number,
|
|
300
|
+
depth: number,
|
|
301
|
+
center?: Vec3Handle,
|
|
302
|
+
): PluginApiReturn<ProfileHandle>
|
|
303
|
+
|
|
304
|
+
/**
|
|
305
|
+
* Create a contour (an outer profile loop, no holes). Host API call — returns a handle.
|
|
306
|
+
*
|
|
307
|
+
* @param outer The outer boundary loop
|
|
308
|
+
* @returns The new contour as a {@linkcode ContourHandle}
|
|
309
|
+
* @example
|
|
310
|
+
* ```ts
|
|
311
|
+
* const contour = snaptrude.core.geom.create.contourFromProfile(outer)
|
|
312
|
+
* ```
|
|
313
|
+
*/
|
|
314
|
+
public abstract contourFromProfile(outer: ProfileHandle): PluginApiReturn<ContourHandle>
|
|
315
|
+
|
|
316
|
+
/**
|
|
317
|
+
* Create a contour from an outer profile plus zero or more inner profiles (holes).
|
|
318
|
+
* Host API call — returns a handle.
|
|
319
|
+
*
|
|
320
|
+
* A hole here is part of the footprint and cannot be moved or deleted later;
|
|
321
|
+
* for an editable hole in a slab use `design.create.void`.
|
|
322
|
+
*
|
|
323
|
+
* @param outer The outer boundary loop
|
|
324
|
+
* @param holes Optional inner hole loops
|
|
325
|
+
* @returns The new contour as a {@linkcode ContourHandle}
|
|
326
|
+
*
|
|
327
|
+
* @examplePrompt Make a shape with a hole in the middle
|
|
328
|
+
* @examplePrompt Cut a courtyard opening out of this floor outline
|
|
329
|
+
*
|
|
330
|
+
* @example
|
|
331
|
+
* ```ts
|
|
332
|
+
* const contour = snaptrude.core.geom.create.contourFromProfiles(outer, [hole])
|
|
333
|
+
* ```
|
|
334
|
+
*/
|
|
335
|
+
public abstract contourFromProfiles(
|
|
336
|
+
outer: ProfileHandle,
|
|
337
|
+
holes?: ProfileHandle[],
|
|
338
|
+
): PluginApiReturn<ContourHandle>
|
|
339
|
+
|
|
340
|
+
/**
|
|
341
|
+
* Create a closed solid **B-rep** from explicit face loops. Host API call —
|
|
342
|
+
* returns a {@linkcode BrepHandle}. Faces are plain arrays of `{x, y, z}`
|
|
343
|
+
* point components, NOT point handles (bulk-data precedent:
|
|
344
|
+
* `design.query.geometry.getTriangulatedMeshes`), in raw Babylon units.
|
|
345
|
+
*
|
|
346
|
+
* Each face is one planar loop of at least 3 points; at least 4 faces are
|
|
347
|
+
* required. Loops may be authored in any consistent winding — the host
|
|
348
|
+
* validates edge coherence (every edge shared by exactly two faces, in
|
|
349
|
+
* opposite directions) and fixes the global orientation so faces point
|
|
350
|
+
* outward. Faces must be planar and the solid must be closed; holes in faces
|
|
351
|
+
* are not supported (v1).
|
|
352
|
+
*
|
|
353
|
+
* Inspect the result via `core.geom.query.brep.*`, or commit it to the scene
|
|
354
|
+
* with `design.create.massFromBrep`.
|
|
355
|
+
*
|
|
356
|
+
* @param faces Face loops — each an ordered array of `{x, y, z}` points (≥3 points per face, ≥4 faces)
|
|
357
|
+
* @returns The new solid as a {@linkcode BrepHandle}
|
|
358
|
+
* @throws if a face is degenerate or non-planar, an edge is not shared by
|
|
359
|
+
* exactly two faces (open shell, non-manifold, or inconsistent winding), or
|
|
360
|
+
* the faces do not form a valid closed solid
|
|
361
|
+
*
|
|
362
|
+
* @examplePrompt Create a brep from faces
|
|
363
|
+
* @examplePrompt Build a custom solid from a set of faces
|
|
364
|
+
* @examplePrompt Make a pyramid from triangular faces
|
|
365
|
+
*
|
|
366
|
+
* # Example
|
|
367
|
+
* ```ts
|
|
368
|
+
* // A pyramid: square base + 4 triangular sides
|
|
369
|
+
* const apex = { x: 0, y: 4, z: 0 }
|
|
370
|
+
* const a = { x: -2, y: 0, z: -2 }
|
|
371
|
+
* const b = { x: 2, y: 0, z: -2 }
|
|
372
|
+
* const c = { x: 2, y: 0, z: 2 }
|
|
373
|
+
* const d = { x: -2, y: 0, z: 2 }
|
|
374
|
+
* const brep = await snaptrude.core.geom.create.brepFromFaces([
|
|
375
|
+
* [a, d, c, b], // base
|
|
376
|
+
* [a, b, apex],
|
|
377
|
+
* [b, c, apex],
|
|
378
|
+
* [c, d, apex],
|
|
379
|
+
* [d, a, apex],
|
|
380
|
+
* ])
|
|
381
|
+
* const faceCount = await snaptrude.core.geom.query.brep.getFaceCount(brep) // 5
|
|
382
|
+
* ```
|
|
383
|
+
*/
|
|
384
|
+
public abstract brepFromFaces(faces: Vec3Components[][]): PluginApiReturn<BrepHandle>
|
|
385
|
+
|
|
386
|
+
/**
|
|
387
|
+
* Create a closed solid **B-rep** by extruding a contour along a direction.
|
|
388
|
+
* Host API call — returns a {@linkcode BrepHandle}. The direction is
|
|
389
|
+
* normalised by the host, so `amount` is the extrusion distance in raw
|
|
390
|
+
* Babylon units (negative extrudes the opposite way). The contour is copied —
|
|
391
|
+
* the input handle is never mutated. Holes and arc/circle profiles extrude
|
|
392
|
+
* natively (a circle profile yields a cylinder).
|
|
393
|
+
*
|
|
394
|
+
* Inspect the result via `core.geom.query.brep.*`, or commit it to the scene
|
|
395
|
+
* with `design.create.massFromBrep`.
|
|
396
|
+
*
|
|
397
|
+
* @param contour The cross-section to extrude (outer profile + optional holes)
|
|
398
|
+
* @param direction Extrusion direction as plain `{x, y, z}` components (non-zero, normalised by the host)
|
|
399
|
+
* @param amount Extrusion distance in internal length units (non-zero; negative extrudes opposite to `direction`)
|
|
400
|
+
* @param options Optional twist and taper, both about `direction` through the
|
|
401
|
+
* base contour's centroid. `twistInDegrees` — total rotation base → top in
|
|
402
|
+
* DEGREES (an angle: never scaled by the project's length unit), positive
|
|
403
|
+
* turning the top CLOCKWISE seen from the far end of `direction` looking
|
|
404
|
+
* back at the base — for the usual upward extrusion, the plan view;
|
|
405
|
+
* `topScale` — the top outline's scale, a ratio (1 = no taper); `levels` —
|
|
406
|
+
* how many sections to build through, a count (2..64; each step may turn
|
|
407
|
+
* at most 22.5°). Leave `levels` out
|
|
408
|
+
* and the host resolves one and writes it into the record, so the mass
|
|
409
|
+
* regenerates identically ever after. An extrusion without twist or
|
|
410
|
+
* taper (no `options`, or zero twist and a `topScale` of 1) is
|
|
411
|
+
* built exactly as before these options existed.
|
|
412
|
+
* @returns The new solid as a {@linkcode BrepHandle}
|
|
413
|
+
* @throws if the extrusion is degenerate (zero amount, zero direction, or a
|
|
414
|
+
* direction lying in the plane of the contour) or the contour cannot be
|
|
415
|
+
* extruded into a valid solid
|
|
416
|
+
* @throws VALIDATION if `twistInDegrees` is not finite or turns more than
|
|
417
|
+
* 1440°, `topScale` is not a positive finite ratio, `levels` is outside
|
|
418
|
+
* 2..64 or too few for the twist (more than 22.5° per step), a twist is
|
|
419
|
+
* asked of a `direction` that is not the contour's normal, the contour has
|
|
420
|
+
* holes under a twist or taper, or a scaled section self-intersects
|
|
421
|
+
*
|
|
422
|
+
* @examplePrompt Extrude this profile 3 metres up
|
|
423
|
+
* @examplePrompt Make a solid by extruding this outline
|
|
424
|
+
* @examplePrompt Create a cylinder from a circle profile
|
|
425
|
+
* @examplePrompt Extrude this floor plate 40m up with a 90 degree twist
|
|
426
|
+
* @examplePrompt Taper this tower to 60 percent of its footprint at the top
|
|
427
|
+
*
|
|
428
|
+
* # Example
|
|
429
|
+
* ```ts
|
|
430
|
+
* const rect = await snaptrude.core.geom.create.profileRect(4, 3)
|
|
431
|
+
* const contour = await snaptrude.core.geom.create.contourFromProfile(rect)
|
|
432
|
+
* const brep = await snaptrude.core.geom.create.brepFromExtrusion(contour, { x: 0, y: 1, z: 0 }, 3)
|
|
433
|
+
* const faceCount = await snaptrude.core.geom.query.brep.getFaceCount(brep) // 6
|
|
434
|
+
* ```
|
|
435
|
+
*/
|
|
436
|
+
public abstract brepFromExtrusion(
|
|
437
|
+
contour: ContourHandle,
|
|
438
|
+
direction: Vec3Components,
|
|
439
|
+
amount: number,
|
|
440
|
+
options?: { twistInDegrees?: number; topScale?: number; levels?: number },
|
|
441
|
+
): PluginApiReturn<BrepHandle>
|
|
442
|
+
|
|
443
|
+
/**
|
|
444
|
+
* Stretches a surface across a closed loop of boundary curves and thickens it
|
|
445
|
+
* into a SOLID in one call — a roof over four curves, a canopy between two
|
|
446
|
+
* rails, a blend across a gap. `thickness` is in internal length units and is
|
|
447
|
+
* required: only solids reach the canvas, and there is no separate surface
|
|
448
|
+
* object to keep. Pass edges as `{ edge, brep, face }` with
|
|
449
|
+
* `continuity: "tangent"` to leave the named face smoothly. The result carries
|
|
450
|
+
* NO recipe (`design.query.getParameters` returns `null`) — label it when you
|
|
451
|
+
* commit it, because the label is all the provenance there is.
|
|
452
|
+
*
|
|
453
|
+
* Runs on the OpenCascade kernel (the first kernel call loads a wasm of tens
|
|
454
|
+
* of MB — expect a pause of seconds).
|
|
455
|
+
*
|
|
456
|
+
* @param boundary 3..16 items forming ONE closed loop (ends meeting within
|
|
457
|
+
* tolerance): a curve, or an edge named WITH the solid it belongs to
|
|
458
|
+
* ({@linkcode OwnedEdge}) — an edge handle cannot name its own solid, and
|
|
459
|
+
* one patch may meet two solids. Read scene breps with
|
|
460
|
+
* `design.query.geometry.getBrep(x, { frame: "world" })` so every item is in
|
|
461
|
+
* one frame.
|
|
462
|
+
* @param thickness Solid thickness in internal length units (> 0)
|
|
463
|
+
* @param options `interiorPoints` pull the surface through them (≤ 64, plain
|
|
464
|
+
* `{x, y, z}` in the same frame as the boundary). `continuity` —
|
|
465
|
+
* `"position"` (default) or `"tangent"`: every boundary item must then be an
|
|
466
|
+
* edge item that also names the `face` to continue (a solid edge has two
|
|
467
|
+
* faces — the wall or the top of a rim). `side` — `"below"` (default) or
|
|
468
|
+
* `"above"`: which side of the boundary the solid grows to.
|
|
469
|
+
* @returns The thickened patch as a new {@linkcode BrepHandle}
|
|
470
|
+
* @throws VALIDATION if the boundary is not one closed loop (the message names
|
|
471
|
+
* the gap and its size), a count cap is exceeded, `thickness` is not
|
|
472
|
+
* positive, `continuity: "tangent"` is used with a curve item or with an
|
|
473
|
+
* edge item that names no `face` (the message names the edge's two candidate
|
|
474
|
+
* faces), or a `face` is not adjacent to its `edge`
|
|
475
|
+
* @throws OPERATION_FAILED if the kernel could not fill the boundary, the
|
|
476
|
+
* filled surface misses its own boundary by more than 0.254 mm (the message
|
|
477
|
+
* carries the measured gap), or the thicken produced no solid
|
|
478
|
+
*
|
|
479
|
+
* @examplePrompt Patch a roof over these four boundary curves, 250 mm thick
|
|
480
|
+
* @examplePrompt Span a canopy between these two curved rails, 300 mm thick
|
|
481
|
+
*
|
|
482
|
+
* # Example
|
|
483
|
+
* ```ts
|
|
484
|
+
* // A roof over four curves
|
|
485
|
+
* const roof = await snaptrude.core.geom.create.brepFromPatch(
|
|
486
|
+
* [curveA, curveB, curveC, curveD],
|
|
487
|
+
* 0.984, // 250 mm
|
|
488
|
+
* )
|
|
489
|
+
* const mass = await snaptrude.design.create.massFromBrep(roof, "Roof patch")
|
|
490
|
+
* ```
|
|
491
|
+
*
|
|
492
|
+
* ```ts
|
|
493
|
+
* // A canopy between two towers' rims, leaving every wall it meets smoothly:
|
|
494
|
+
* // with `continuity: "tangent"` EVERY item is an edge naming its face.
|
|
495
|
+
* const canopy = await snaptrude.core.geom.create.brepFromPatch(
|
|
496
|
+
* [
|
|
497
|
+
* { edge: rimA, brep: towerA, face: wallA },
|
|
498
|
+
* { edge: sideA, brep: towerA, face: endA },
|
|
499
|
+
* { edge: rimB, brep: towerB, face: wallB },
|
|
500
|
+
* { edge: sideB, brep: towerB, face: endB },
|
|
501
|
+
* ],
|
|
502
|
+
* 1.181, // 300 mm
|
|
503
|
+
* { continuity: "tangent" },
|
|
504
|
+
* )
|
|
505
|
+
* ```
|
|
506
|
+
*/
|
|
507
|
+
public abstract brepFromPatch(
|
|
508
|
+
boundary: (CurveHandle | OwnedEdge)[],
|
|
509
|
+
thickness: number,
|
|
510
|
+
options?: {
|
|
511
|
+
interiorPoints?: Vec3Components[]
|
|
512
|
+
continuity?: "position" | "tangent"
|
|
513
|
+
side?: "below" | "above"
|
|
514
|
+
},
|
|
515
|
+
): PluginApiReturn<BrepHandle>
|
|
516
|
+
|
|
517
|
+
/**
|
|
518
|
+
* Create a closed solid **B-rep** by lofting between a bottom and a top
|
|
519
|
+
* contour, optionally through intermediate cross-sections. Host API call —
|
|
520
|
+
* returns a {@linkcode BrepHandle}. Sections with different edge counts are
|
|
521
|
+
* auto-matched: vertices are deterministically inserted on the smaller
|
|
522
|
+
* sections at the larger section's perimeter positions, so the same input
|
|
523
|
+
* always yields the same solid. For straight-edge (all-line) sections the
|
|
524
|
+
* seam is auto-aligned too — winding and start-vertex correspondence are
|
|
525
|
+
* chosen to avoid a twist, so outlines authored from any starting corner
|
|
526
|
+
* loft cleanly; arc-bearing sections keep the authored correspondence
|
|
527
|
+
* unchanged. A pair whose side faces would be non-planar under every
|
|
528
|
+
* correspondence still builds for hole-free straight-edged pairs — planar
|
|
529
|
+
* side quads stay quads and warped ones split into planar triangles (the
|
|
530
|
+
* triangulated fallback); arc-bearing or holed twisted pairs are rejected, as
|
|
531
|
+
* is auto-matching that would pair an arc with a straight edge. Matching hole
|
|
532
|
+
* counts are allowed in the two-section form. With intermediates the loft
|
|
533
|
+
* is a chain of ruled segments folded into one solid: sections must be
|
|
534
|
+
* planar and hole-free, ordered bottom → intermediates → top. The contours
|
|
535
|
+
* are copied — the input handles are never mutated.
|
|
536
|
+
*
|
|
537
|
+
* Inspect the result via `core.geom.query.brep.*`, or commit it to the scene
|
|
538
|
+
* with `design.create.massFromBrep`.
|
|
539
|
+
*
|
|
540
|
+
* @param bottomContour The bottom cross-section
|
|
541
|
+
* @param topContour The top cross-section (edge count may differ from the
|
|
542
|
+
* bottom — sections are auto-matched)
|
|
543
|
+
* @param intermediateContours Optional in-between cross-sections, ordered
|
|
544
|
+
* bottom to top (hole-free; edge counts may differ — every section is
|
|
545
|
+
* normalized to the largest). Any count is accepted; a loft of more
|
|
546
|
+
* than 32 sections counting the bottom and the top still builds but
|
|
547
|
+
* carries no parameter record (records are capped, calls are not)
|
|
548
|
+
* @param options Optional behavior switches. `compatibility` — `"auto"`
|
|
549
|
+
* (default) inserts vertices to match differing edge counts; `"strict"`
|
|
550
|
+
* skips normalization and throws VALIDATION when outer edge counts (or,
|
|
551
|
+
* in the two-section form, hole-pair counts) differ. `seamAlignment` —
|
|
552
|
+
* `"auto"` (default) searches seam rotations on straight-edge sections to
|
|
553
|
+
* avoid a twist; `"authored"` keeps the authored start-vertex
|
|
554
|
+
* correspondence unchanged (a twisted correspondence then builds through
|
|
555
|
+
* the triangulated fallback for hole-free straight-edged pairs).
|
|
556
|
+
* `{ compatibility: "strict", seamAlignment: "authored" }` reproduces
|
|
557
|
+
* pre-0.9.4 lofting exactly. `smoothing` — `"ruled"` (default) keeps the
|
|
558
|
+
* straight-sided behaviour described above; `"smooth"` lofts every
|
|
559
|
+
* section in ONE kernel pass, so the sides curve continuously through the
|
|
560
|
+
* intermediates instead of creasing at each one (a vase, a curved tower —
|
|
561
|
+
* the sections must still be planar and hole-free).
|
|
562
|
+
* @returns The new solid as a {@linkcode BrepHandle}
|
|
563
|
+
* @throws VALIDATION if the contours are coincident, their hole counts
|
|
564
|
+
* differ, any section has holes when intermediates are present
|
|
565
|
+
* (multi-section lofts take hole-free sections), a section is non-planar,
|
|
566
|
+
* sections are too dissimilar to auto-match, auto-matching would pair an
|
|
567
|
+
* arc with a straight edge, or — for arc-bearing or holed pairs only — no vertex correspondence avoids a twist (a
|
|
568
|
+
* side face between corresponding edges would be non-planar — the error
|
|
569
|
+
* names the offending sections); with `compatibility: "strict"`, if
|
|
570
|
+
* section edge counts (or hole-pair counts) differ — the error names the
|
|
571
|
+
* sections and counts and points at `compatibility: "auto"`
|
|
572
|
+
* @throws OPERATION_FAILED if the lofted segments cannot be joined into a
|
|
573
|
+
* valid solid
|
|
574
|
+
*
|
|
575
|
+
* @examplePrompt Make a tapered tower from these two outlines
|
|
576
|
+
* @examplePrompt Loft between a large base and a smaller top
|
|
577
|
+
* @examplePrompt Create a frustum from two squares
|
|
578
|
+
* @examplePrompt Loft the tower through these three floor outlines
|
|
579
|
+
* @examplePrompt Loft a four-sided base to a five-sided top
|
|
580
|
+
* @examplePrompt Loft these outlines even though their corners don't line up
|
|
581
|
+
* @examplePrompt Loft these outlines exactly as authored, corner to corner
|
|
582
|
+
* @examplePrompt Fail the loft if my sections don't have matching edge counts
|
|
583
|
+
* @examplePrompt Loft these three outlines with smoothly curving sides
|
|
584
|
+
*
|
|
585
|
+
* # Example
|
|
586
|
+
* ```ts
|
|
587
|
+
* // A square frustum: 4m base lofted to a 2m top, 3m up
|
|
588
|
+
* const base = await snaptrude.core.geom.create.profileRect(4, 4)
|
|
589
|
+
* const top = await snaptrude.core.geom.create.profileRect(2, 2, await snaptrude.core.math.vec3.new(0, 3, 0))
|
|
590
|
+
* const brep = await snaptrude.core.geom.create.brepFromLoft(
|
|
591
|
+
* await snaptrude.core.geom.create.contourFromProfile(base),
|
|
592
|
+
* await snaptrude.core.geom.create.contourFromProfile(top),
|
|
593
|
+
* )
|
|
594
|
+
* const faceCount = await snaptrude.core.geom.query.brep.getFaceCount(brep) // 6
|
|
595
|
+
* ```
|
|
596
|
+
*/
|
|
597
|
+
public abstract brepFromLoft(
|
|
598
|
+
bottomContour: ContourHandle,
|
|
599
|
+
topContour: ContourHandle,
|
|
600
|
+
intermediateContours?: ContourHandle[],
|
|
601
|
+
options?: {
|
|
602
|
+
compatibility?: "strict" | "auto"
|
|
603
|
+
seamAlignment?: "authored" | "auto"
|
|
604
|
+
smoothing?: "ruled" | "smooth"
|
|
605
|
+
},
|
|
606
|
+
): PluginApiReturn<BrepHandle>
|
|
607
|
+
|
|
608
|
+
/**
|
|
609
|
+
* Create a closed solid **B-rep** from indexed mesh data: a vertex position
|
|
610
|
+
* array plus face loops of indices into it. Host API call — returns a
|
|
611
|
+
* {@linkcode BrepHandle}. The indexed form of
|
|
612
|
+
* {@linkcode PluginGeomCreateApi.brepFromFaces} — same validation (planar
|
|
613
|
+
* faces, closed manifold solid, every edge shared by exactly two faces) after
|
|
614
|
+
* the indices are expanded to point loops.
|
|
615
|
+
*
|
|
616
|
+
* Inspect the result via `core.geom.query.brep.*`, or commit it to the scene
|
|
617
|
+
* with `design.create.massFromBrep`.
|
|
618
|
+
*
|
|
619
|
+
* @param positions Vertex positions as plain `{x, y, z}` components (≥4)
|
|
620
|
+
* @param faces Face loops — each an ordered array of indices into `positions` (≥3 indices per face, ≥4 faces)
|
|
621
|
+
* @returns The new solid as a {@linkcode BrepHandle}
|
|
622
|
+
* @throws if an index is not an integer within `positions` bounds, a face is
|
|
623
|
+
* degenerate or non-planar, or the faces do not form a valid closed solid
|
|
624
|
+
*
|
|
625
|
+
* @examplePrompt Create a brep from mesh vertices and indices
|
|
626
|
+
* @examplePrompt Turn this indexed mesh into a solid
|
|
627
|
+
* @examplePrompt Build a solid from vertex positions and face indices
|
|
628
|
+
*
|
|
629
|
+
* # Example
|
|
630
|
+
* ```ts
|
|
631
|
+
* // A tetrahedron from 4 vertices and 4 triangular faces
|
|
632
|
+
* const positions = [
|
|
633
|
+
* { x: 0, y: 0, z: 0 },
|
|
634
|
+
* { x: 4, y: 0, z: 0 },
|
|
635
|
+
* { x: 2, y: 0, z: 4 },
|
|
636
|
+
* { x: 2, y: 3, z: 1.5 },
|
|
637
|
+
* ]
|
|
638
|
+
* const brep = await snaptrude.core.geom.create.brepFromMesh(positions, [
|
|
639
|
+
* [0, 2, 1], // base
|
|
640
|
+
* [0, 1, 3],
|
|
641
|
+
* [1, 2, 3],
|
|
642
|
+
* [2, 0, 3],
|
|
643
|
+
* ])
|
|
644
|
+
* const vertexCount = await snaptrude.core.geom.query.brep.getVertexCount(brep) // 4
|
|
645
|
+
* ```
|
|
646
|
+
*/
|
|
647
|
+
public abstract brepFromMesh(
|
|
648
|
+
positions: Vec3Components[],
|
|
649
|
+
faces: number[][],
|
|
650
|
+
): PluginApiReturn<BrepHandle>
|
|
651
|
+
|
|
652
|
+
/**
|
|
653
|
+
* Create a closed solid **B-rep** as the boolean **union** of two breps
|
|
654
|
+
* (`a ∪ b`). Host API call — returns a new {@linkcode BrepHandle}. Inputs are
|
|
655
|
+
* read-only and may be authored breps (any `core.geom.create` brep
|
|
656
|
+
* constructor) or scene-derived breps from `design.query.geometry.getBrep`;
|
|
657
|
+
* coordinates are combined as-is, so both inputs must share a frame. The
|
|
658
|
+
* result must be a single solid — disjoint inputs are rejected.
|
|
659
|
+
*
|
|
660
|
+
* The first boolean call loads the OpenCascade geometry kernel (a wasm of
|
|
661
|
+
* tens of MB — expect a pause of seconds); subsequent calls are fast.
|
|
662
|
+
*
|
|
663
|
+
* @param a First solid
|
|
664
|
+
* @param b Second solid
|
|
665
|
+
* @returns The union as a new {@linkcode BrepHandle}
|
|
666
|
+
* @throws if the inputs do not overlap or touch (the union would be disjoint
|
|
667
|
+
* solids) or the result cannot be built as a valid single solid
|
|
668
|
+
*
|
|
669
|
+
* @examplePrompt Union these two solids
|
|
670
|
+
* @examplePrompt Merge these breps into one mass
|
|
671
|
+
* @examplePrompt Combine the tower and the podium into a single solid
|
|
672
|
+
*
|
|
673
|
+
* # Example
|
|
674
|
+
* ```ts
|
|
675
|
+
* const a = await snaptrude.core.geom.create.brepFromExtrusion(baseContour, { x: 0, y: 1, z: 0 }, 3)
|
|
676
|
+
* const b = await snaptrude.core.geom.create.brepFromExtrusion(overlappingContour, { x: 0, y: 1, z: 0 }, 5)
|
|
677
|
+
* const merged = await snaptrude.core.geom.create.brepFromUnion(a, b)
|
|
678
|
+
* ```
|
|
679
|
+
*/
|
|
680
|
+
public abstract brepFromUnion(a: BrepHandle, b: BrepHandle): PluginApiReturn<BrepHandle>
|
|
681
|
+
|
|
682
|
+
/**
|
|
683
|
+
* Create a closed solid **B-rep** as the boolean **subtraction** of two
|
|
684
|
+
* breps: **`a` minus `b`** — `b` is cut away from `a`. Host API call —
|
|
685
|
+
* returns a new {@linkcode BrepHandle}. Argument order matters:
|
|
686
|
+
* `brepFromSubtraction(a, b)` removes `b`'s volume from `a`. Inputs are
|
|
687
|
+
* read-only and may be authored or scene-derived breps (see
|
|
688
|
+
* {@linkcode PluginGeomCreateApi.brepFromUnion}); coordinates are combined
|
|
689
|
+
* as-is.
|
|
690
|
+
*
|
|
691
|
+
* The first boolean call loads the OpenCascade geometry kernel (a wasm of
|
|
692
|
+
* tens of MB — expect a pause of seconds); subsequent calls are fast.
|
|
693
|
+
*
|
|
694
|
+
* Returns a detached solid; to cut an editable hole in a slab, floor or roof
|
|
695
|
+
* in the model use `design.create.void`.
|
|
696
|
+
*
|
|
697
|
+
* @param a The solid to subtract from
|
|
698
|
+
* @param b The solid to remove from `a`
|
|
699
|
+
* @returns `a` minus `b` as a new {@linkcode BrepHandle}
|
|
700
|
+
* @throws if `b` consumes `a` entirely (empty result), the result splits into
|
|
701
|
+
* disjoint solids, or it cannot be built as a valid single solid
|
|
702
|
+
*
|
|
703
|
+
* @examplePrompt Subtract the courtyard from the building mass
|
|
704
|
+
* @examplePrompt Cut this solid out of that one
|
|
705
|
+
* @examplePrompt Subtract this box solid from that solid
|
|
706
|
+
*
|
|
707
|
+
* # Example
|
|
708
|
+
* ```ts
|
|
709
|
+
* // buildingBrep minus courtyardBrep — order matters
|
|
710
|
+
* const carved = await snaptrude.core.geom.create.brepFromSubtraction(buildingBrep, courtyardBrep)
|
|
711
|
+
* ```
|
|
712
|
+
*/
|
|
713
|
+
public abstract brepFromSubtraction(a: BrepHandle, b: BrepHandle): PluginApiReturn<BrepHandle>
|
|
714
|
+
|
|
715
|
+
/**
|
|
716
|
+
* Create a closed solid **B-rep** as the boolean **intersection** of two
|
|
717
|
+
* breps (`a ∩ b` — the shared volume only). Host API call — returns a new
|
|
718
|
+
* {@linkcode BrepHandle}. Inputs are read-only and may be authored or
|
|
719
|
+
* scene-derived breps (see {@linkcode PluginGeomCreateApi.brepFromUnion});
|
|
720
|
+
* coordinates are combined as-is.
|
|
721
|
+
*
|
|
722
|
+
* The first boolean call loads the OpenCascade geometry kernel (a wasm of
|
|
723
|
+
* tens of MB — expect a pause of seconds); subsequent calls are fast.
|
|
724
|
+
*
|
|
725
|
+
* @param a First solid
|
|
726
|
+
* @param b Second solid
|
|
727
|
+
* @returns The shared volume as a new {@linkcode BrepHandle}
|
|
728
|
+
* @throws if the inputs do not overlap (empty intersection), the result
|
|
729
|
+
* splits into disjoint solids, or it cannot be built as a valid single
|
|
730
|
+
* solid
|
|
731
|
+
*
|
|
732
|
+
* @examplePrompt Keep only the overlap of these two solids
|
|
733
|
+
* @examplePrompt Intersect these two masses
|
|
734
|
+
* @examplePrompt Clip the tower to the zoning envelope
|
|
735
|
+
*
|
|
736
|
+
* # Example
|
|
737
|
+
* ```ts
|
|
738
|
+
* const overlap = await snaptrude.core.geom.create.brepFromIntersection(towerBrep, envelopeBrep)
|
|
739
|
+
* ```
|
|
740
|
+
*/
|
|
741
|
+
public abstract brepFromIntersection(a: BrepHandle, b: BrepHandle): PluginApiReturn<BrepHandle>
|
|
742
|
+
|
|
743
|
+
/**
|
|
744
|
+
* Rounds the given edges of a solid with a constant radius. Host API call —
|
|
745
|
+
* returns a new {@linkcode BrepHandle}; the input brep is read-only.
|
|
746
|
+
*
|
|
747
|
+
* Works on curved solids: edges may be straight, circular or spline, and
|
|
748
|
+
* adjacent edges (corner blends) are allowed. To pick a **rim** — the circle
|
|
749
|
+
* where a cylinder meets a flat cap — walk the edges and keep the ones whose
|
|
750
|
+
* two faces are a `cylinder` and a `plane`:
|
|
751
|
+
* `core.geom.query.brep.listEdges(brep)` → per edge
|
|
752
|
+
* `core.geom.query.edge.listFaces(edge)` → `core.geom.query.face.getSurfaceKind`
|
|
753
|
+
* on both faces. (`core.geom.query.brep.listEdgesBetween` takes two VERTEX
|
|
754
|
+
* indices — it is NOT a face-pair lookup.) For one cap's rim only, the
|
|
755
|
+
* shorter walk is: find the cap (call `getSurfaceKind` on each face from
|
|
756
|
+
* `brep.listFaces`), then `core.geom.query.face.listEdges(capFace)`.
|
|
757
|
+
*
|
|
758
|
+
* When the input brep carries a creation recipe, the result carries it too,
|
|
759
|
+
* with this operation appended to `operations`; `design.create.massFromBrep`
|
|
760
|
+
* then keeps the mass editable through `design.update.parameters`.
|
|
761
|
+
*
|
|
762
|
+
* Runs on the OpenCascade kernel (the first kernel call loads a wasm of tens
|
|
763
|
+
* of MB — expect a pause of seconds).
|
|
764
|
+
*
|
|
765
|
+
* Inspect the result via `core.geom.query.brep.*`, or commit it to the scene
|
|
766
|
+
* with `design.create.massFromBrep`.
|
|
767
|
+
*
|
|
768
|
+
* @param brep The solid whose edges to round
|
|
769
|
+
* @param edges The edges to fillet (one or more, all on `brep`, no
|
|
770
|
+
* duplicates; more than 64 still fillets but the result carries no
|
|
771
|
+
* parameter record)
|
|
772
|
+
* @param radius Fillet radius in internal length units (positive, finite) —
|
|
773
|
+
* the radius at the START of the blend with `endRadius`; unused with
|
|
774
|
+
* `radii` (the table is the whole law — pass its first row's radius)
|
|
775
|
+
* @param options Optional VARIABLE blend, in one of two forms, each naming
|
|
776
|
+
* exactly ONE edge: the law belongs to the whole tangent chain that edge
|
|
777
|
+
* lies on, and it is measured from that edge's start. `endRadius` —
|
|
778
|
+
* the radius at the far end, in internal length units, interpolated
|
|
779
|
+
* linearly along the chain; on a closed rim it must equal `radius` (0 and
|
|
780
|
+
* 1 are the same point) — use `radii` there. `radii` — a sampled law instead:
|
|
781
|
+
* `position` is normalised ARC LENGTH along the chain (a ratio 0..1, never
|
|
782
|
+
* converted), `radius` is internal length units; 2..32 rows with strictly
|
|
783
|
+
* increasing `position`; before the first row and after the last the
|
|
784
|
+
* radius is held constant. On a closed rim 0 and 1 are the same point, so
|
|
785
|
+
* give them the same radius and put the variation in the interior rows. The two
|
|
786
|
+
* forms are mutually exclusive; without either, the fillet has one constant
|
|
787
|
+
* radius.
|
|
788
|
+
* @returns The filleted solid as a new {@linkcode BrepHandle}
|
|
789
|
+
* @throws VALIDATION if `edges` is empty or holds a duplicate, `radius` is
|
|
790
|
+
* not a positive finite number, an edge is not on `brep`, or an edge has no
|
|
791
|
+
* crease to round — it is a seam of a closed face, or it lies between two
|
|
792
|
+
* patches of one smooth surface; for a variable blend, if `endRadius` and
|
|
793
|
+
* `radii` are both given, more than one edge is passed, a `radii` table is
|
|
794
|
+
* outside 2..32 rows or its positions do not strictly increase within
|
|
795
|
+
* 0..1, or the law's two ends differ on a closed rim (an `endRadius`
|
|
796
|
+
* other than `radius`, or a `radii` table whose first and last radii
|
|
797
|
+
* differ)
|
|
798
|
+
* @throws PRECONDITION_FAILED if an edge could not be located on the kernel
|
|
799
|
+
* solid after healing (select a different edge, or fillet before the
|
|
800
|
+
* operation that curved the solid), or the kernel could not blend the edge
|
|
801
|
+
* named in the message (reduce the radius or drop that edge)
|
|
802
|
+
* @throws OPERATION_FAILED if the kernel or the translation fails, or the
|
|
803
|
+
* result is non-manifold, splits into several solids, or contains a surface
|
|
804
|
+
* Snaptrude cannot represent
|
|
805
|
+
*
|
|
806
|
+
* @examplePrompt Round the rim of the column with 200 mm
|
|
807
|
+
* @examplePrompt Soften where the dome meets the wall
|
|
808
|
+
* @examplePrompt Fillet the corners of the podium with a 0.5m radius
|
|
809
|
+
* @examplePrompt Soften the vertical edges of this tower
|
|
810
|
+
* @examplePrompt Blend this edge from 200mm at one end to 600mm at the other
|
|
811
|
+
* @examplePrompt Round this rim wider at the back than at the front
|
|
812
|
+
*
|
|
813
|
+
* # Example
|
|
814
|
+
* ```ts
|
|
815
|
+
* // Rim = every edge between the cylinder side and a plane cap
|
|
816
|
+
* const edges = await snaptrude.core.geom.query.brep.listEdges(column)
|
|
817
|
+
* const rim = []
|
|
818
|
+
* for (const edge of edges) {
|
|
819
|
+
* const faces = await snaptrude.core.geom.query.edge.listFaces(edge)
|
|
820
|
+
* const kinds = await Promise.all(
|
|
821
|
+
* faces.map((f) => snaptrude.core.geom.query.face.getSurfaceKind(f)),
|
|
822
|
+
* )
|
|
823
|
+
* if (kinds.includes("cylinder") && kinds.includes("plane")) rim.push(edge)
|
|
824
|
+
* }
|
|
825
|
+
* const rounded = await snaptrude.core.geom.create.brepFromFillet(column, rim, 0.787) // 200 mm
|
|
826
|
+
* ```
|
|
827
|
+
*/
|
|
828
|
+
public abstract brepFromFillet(
|
|
829
|
+
brep: BrepHandle,
|
|
830
|
+
edges: EdgeHandle[],
|
|
831
|
+
radius: number,
|
|
832
|
+
options?: { endRadius?: number; radii?: { position: number; radius: number }[] },
|
|
833
|
+
): PluginApiReturn<BrepHandle>
|
|
834
|
+
|
|
835
|
+
/**
|
|
836
|
+
* Grows or shrinks a solid by offsetting every face — positive distance
|
|
837
|
+
* moves faces outward, negative moves them inward. Host API call — returns
|
|
838
|
+
* a new {@linkcode BrepHandle}; the input brep is read-only.
|
|
839
|
+
*
|
|
840
|
+
* Works on curved solids: a sphere offsets to a sphere, a torus to a torus,
|
|
841
|
+
* a cylinder to a cylinder. There is nothing to select — the whole solid is
|
|
842
|
+
* offset.
|
|
843
|
+
*
|
|
844
|
+
* When the input brep carries a creation recipe, the result carries it too,
|
|
845
|
+
* with this operation appended to `operations`; `design.create.massFromBrep`
|
|
846
|
+
* then keeps the mass editable through `design.update.parameters`.
|
|
847
|
+
*
|
|
848
|
+
* Runs on the OpenCascade kernel (the first kernel call loads a wasm of
|
|
849
|
+
* tens of MB — expect a pause of seconds).
|
|
850
|
+
*
|
|
851
|
+
* Inspect the result via `core.geom.query.brep.*`, or commit it to the scene
|
|
852
|
+
* with `design.create.massFromBrep`.
|
|
853
|
+
*
|
|
854
|
+
* @param brep The solid to offset
|
|
855
|
+
* @param distance Offset distance (finite, non-zero; positive grows, negative shrinks)
|
|
856
|
+
* @returns The offset solid as a new {@linkcode BrepHandle}
|
|
857
|
+
* @throws VALIDATION if `distance` is not finite, is too small to offset
|
|
858
|
+
* anything, or an inward distance consumes the solid entirely
|
|
859
|
+
* @throws OPERATION_FAILED if the kernel or the translation fails, or the
|
|
860
|
+
* result is non-manifold, splits into several solids, or contains a surface
|
|
861
|
+
* Snaptrude cannot represent (an offset free-form NURBS surface may have no
|
|
862
|
+
* exact representation — the model is left unchanged). A distance too
|
|
863
|
+
* large for the solid is reported here, with a hint asking for a smaller
|
|
864
|
+
* one. There is no per-face refusal: the whole call fails, and the error
|
|
865
|
+
* names no face
|
|
866
|
+
*
|
|
867
|
+
* @examplePrompt Thicken the torus ring by 100 mm
|
|
868
|
+
* @examplePrompt Grow this solid by 0.5m in every direction
|
|
869
|
+
* @examplePrompt Shrink this mass by 200mm
|
|
870
|
+
* @examplePrompt Offset the building envelope outward by 1m
|
|
871
|
+
*
|
|
872
|
+
* # Example
|
|
873
|
+
* ```ts
|
|
874
|
+
* const brep = await snaptrude.core.geom.create.brepFromExtrusion(contour, { x: 0, y: 1, z: 0 }, 3)
|
|
875
|
+
* const grown = await snaptrude.core.geom.create.brepFromOffset(brep, 0.5)
|
|
876
|
+
* ```
|
|
877
|
+
*/
|
|
878
|
+
public abstract brepFromOffset(brep: BrepHandle, distance: number): PluginApiReturn<BrepHandle>
|
|
879
|
+
|
|
880
|
+
/**
|
|
881
|
+
* Hollows a solid into constant-thickness walls, removing the given faces
|
|
882
|
+
* as openings. Host API call — returns a new {@linkcode BrepHandle}; the
|
|
883
|
+
* input brep is read-only. The outer surface is kept and the walls grow
|
|
884
|
+
* inward.
|
|
885
|
+
*
|
|
886
|
+
* Works on curved solids: the open faces may be spherical, cylindrical,
|
|
887
|
+
* conical, toroidal or free-form patches, not only flat ones. To open the
|
|
888
|
+
* flat base of a dome, check every face first —
|
|
889
|
+
* `core.geom.query.brep.listFaces` then
|
|
890
|
+
* `core.geom.query.face.getSurfaceKind` on each — and keep the `"plane"`
|
|
891
|
+
* one. A closed curved surface is stored as several patches (a sphere as
|
|
892
|
+
* lunes), so opening "the sphere" may mean passing several faces.
|
|
893
|
+
*
|
|
894
|
+
* When the input brep carries a creation recipe, the result carries it too,
|
|
895
|
+
* with this operation appended to `operations`; `design.create.massFromBrep`
|
|
896
|
+
* then keeps the mass editable through `design.update.parameters`.
|
|
897
|
+
*
|
|
898
|
+
* Runs on the OpenCascade kernel (the first kernel call loads a wasm of
|
|
899
|
+
* tens of MB — expect a pause of seconds).
|
|
900
|
+
*
|
|
901
|
+
* Inspect the result via `core.geom.query.brep.*`, or commit it to the scene
|
|
902
|
+
* with `design.create.massFromBrep`.
|
|
903
|
+
*
|
|
904
|
+
* @param brep The solid to hollow
|
|
905
|
+
* @param openFaces The faces to remove as openings (one or more, all on
|
|
906
|
+
* `brep`, no duplicates; more than 32 still shells but the result carries
|
|
907
|
+
* no parameter record)
|
|
908
|
+
* @param thickness Wall thickness (positive, finite, smaller than half the solid's smallest span)
|
|
909
|
+
* @returns The hollowed solid as a new {@linkcode BrepHandle}
|
|
910
|
+
* @throws VALIDATION if `openFaces` is empty or holds a duplicate, a face is
|
|
911
|
+
* not on `brep`, `thickness` is not a positive finite number, or the
|
|
912
|
+
* thickness is too large (it must be smaller than half the solid's smallest
|
|
913
|
+
* span)
|
|
914
|
+
* @throws OPERATION_FAILED if the kernel or the translation fails, or the
|
|
915
|
+
* result is non-manifold, splits into several solids, or contains a surface
|
|
916
|
+
* Snaptrude cannot represent. A thickness too large for the solid is
|
|
917
|
+
* reported here, with a hint asking for one below half the smallest span.
|
|
918
|
+
* There is no per-face refusal: the whole call fails, and the error
|
|
919
|
+
* names no face
|
|
920
|
+
*
|
|
921
|
+
* @examplePrompt Hollow the dome into a 300 mm shell, open at the base
|
|
922
|
+
* @examplePrompt Hollow this mass into 200mm walls
|
|
923
|
+
* @examplePrompt Shell this form with the top face open
|
|
924
|
+
* @examplePrompt Turn this solid tower into a tube open at both ends
|
|
925
|
+
*
|
|
926
|
+
* # Example
|
|
927
|
+
* ```ts
|
|
928
|
+
* // Open the dome at its flat base: the one face whose surface is a plane
|
|
929
|
+
* const faces = await snaptrude.core.geom.query.brep.listFaces(dome)
|
|
930
|
+
* const base = []
|
|
931
|
+
* for (const face of faces) {
|
|
932
|
+
* if ((await snaptrude.core.geom.query.face.getSurfaceKind(face)) === "plane") base.push(face)
|
|
933
|
+
* }
|
|
934
|
+
* const hollow = await snaptrude.core.geom.create.brepFromShell(dome, base, 1.181) // 300 mm
|
|
935
|
+
* ```
|
|
936
|
+
*/
|
|
937
|
+
public abstract brepFromShell(
|
|
938
|
+
brep: BrepHandle,
|
|
939
|
+
openFaces: FaceHandle[],
|
|
940
|
+
thickness: number,
|
|
941
|
+
): PluginApiReturn<BrepHandle>
|
|
942
|
+
|
|
943
|
+
/**
|
|
944
|
+
* Cuts a solid by an infinite plane and returns one brep per resulting
|
|
945
|
+
* piece — a single piece if the plane misses the solid. Host API call —
|
|
946
|
+
* returns new {@linkcode BrepHandle}s; the input brep is read-only. The
|
|
947
|
+
* plane is defined by a point on it and its normal direction.
|
|
948
|
+
*
|
|
949
|
+
* Runs on the OpenCascade kernel (the first kernel call loads a wasm of
|
|
950
|
+
* tens of MB — expect a pause of seconds).
|
|
951
|
+
*
|
|
952
|
+
* Inspect each result via `core.geom.query.brep.*`, or commit them to the
|
|
953
|
+
* scene with `design.create.massFromBrep`.
|
|
954
|
+
*
|
|
955
|
+
* @param brep The solid to split
|
|
956
|
+
* @param planeOrigin A point on the cutting plane as plain `{x, y, z}` components
|
|
957
|
+
* @param planeNormal The plane normal as plain `{x, y, z}` components (non-zero)
|
|
958
|
+
* @returns The resulting pieces as {@linkcode BrepHandle}`[]` (one per solid)
|
|
959
|
+
* @throws VALIDATION if `planeNormal` is zero-length or the origin/normal
|
|
960
|
+
* components are not finite
|
|
961
|
+
* @throws OPERATION_FAILED if the kernel cannot split the solid
|
|
962
|
+
*
|
|
963
|
+
* @examplePrompt Cut this building at 12m height
|
|
964
|
+
* @examplePrompt Split the tower from the podium with a horizontal plane
|
|
965
|
+
* @examplePrompt Slice this mass along a vertical plane
|
|
966
|
+
*
|
|
967
|
+
* # Example
|
|
968
|
+
* ```ts
|
|
969
|
+
* const pieces = await snaptrude.core.geom.create.brepsFromSplit(
|
|
970
|
+
* towerBrep,
|
|
971
|
+
* { x: 0, y: 12, z: 0 },
|
|
972
|
+
* { x: 0, y: 1, z: 0 },
|
|
973
|
+
* )
|
|
974
|
+
* console.log("pieces:", pieces.length)
|
|
975
|
+
* ```
|
|
976
|
+
*/
|
|
977
|
+
public abstract brepsFromSplit(
|
|
978
|
+
brep: BrepHandle,
|
|
979
|
+
planeOrigin: Vec3Components,
|
|
980
|
+
planeNormal: Vec3Components,
|
|
981
|
+
): PluginApiReturn<BrepHandle[]>
|
|
982
|
+
|
|
983
|
+
/**
|
|
984
|
+
* Cuts a solid with a FACE of another solid — the curved twin of
|
|
985
|
+
* {@linkcode PluginGeomCreateApi.brepsFromSplit}, which cuts with a plane.
|
|
986
|
+
* Host API call — returns new {@linkcode BrepHandle}s; both inputs are
|
|
987
|
+
* read-only. BOTH breps must be in the same frame: read scene masses with
|
|
988
|
+
* `design.query.geometry.getBrep(x, { frame: "world" })` (the default is each
|
|
989
|
+
* mass's own local frame, and two masses have two). The pieces come back in
|
|
990
|
+
* DESCENDING volume order; pick the one you want with
|
|
991
|
+
* `core.geom.query.brep.getCentroid` or `getVolume` and commit it. A piece
|
|
992
|
+
* carries no recipe — label it.
|
|
993
|
+
*
|
|
994
|
+
* Runs on the OpenCascade kernel (the first kernel call loads a wasm of tens
|
|
995
|
+
* of MB — expect a pause of seconds).
|
|
996
|
+
*
|
|
997
|
+
* @param brep The solid to cut
|
|
998
|
+
* @param toolFace The cutting face, read-only
|
|
999
|
+
* @param toolBrep The solid `toolFace` belongs to — a face handle cannot name
|
|
1000
|
+
* its own solid
|
|
1001
|
+
* @returns The resulting pieces as {@linkcode BrepHandle}`[]`, largest first
|
|
1002
|
+
* @throws VALIDATION if `toolFace` is not a face of `toolBrep`, `toolBrep` IS
|
|
1003
|
+
* `brep`, or the cut produced a single part — the surface does not pass all
|
|
1004
|
+
* the way through (extend it past the mass on every side, and check both
|
|
1005
|
+
* breps were read in the same frame)
|
|
1006
|
+
* @throws OPERATION_FAILED if the kernel could not split the solid
|
|
1007
|
+
*
|
|
1008
|
+
* @examplePrompt Cut this mass with the curved roof surface and keep the lower part
|
|
1009
|
+
*
|
|
1010
|
+
* # Example
|
|
1011
|
+
* ```ts
|
|
1012
|
+
* const target = await snaptrude.design.query.geometry.getBrep(tower, { frame: "world" })
|
|
1013
|
+
* const tool = await snaptrude.design.query.geometry.getBrep(roof, { frame: "world" })
|
|
1014
|
+
* const [toolFace] = await snaptrude.core.geom.query.brep.listFaces(tool)
|
|
1015
|
+
* const pieces = await snaptrude.core.geom.create.brepsFromSplitByFace(target, toolFace, tool)
|
|
1016
|
+
* ```
|
|
1017
|
+
*/
|
|
1018
|
+
public abstract brepsFromSplitByFace(
|
|
1019
|
+
brep: BrepHandle,
|
|
1020
|
+
toolFace: FaceHandle,
|
|
1021
|
+
toolBrep: BrepHandle,
|
|
1022
|
+
): PluginApiReturn<BrepHandle[]>
|
|
1023
|
+
|
|
1024
|
+
/**
|
|
1025
|
+
* Bevels the given edges of a solid with a symmetric planar cut. Host API
|
|
1026
|
+
* call — returns a new {@linkcode BrepHandle}; the input brep is read-only.
|
|
1027
|
+
*
|
|
1028
|
+
* Works on curved solids: edges may be straight, circular or spline, and
|
|
1029
|
+
* adjacent edges are allowed. Pick edges the same way as for
|
|
1030
|
+
* {@linkcode PluginGeomCreateApi.brepFromFillet} — `brep.listEdges`, then
|
|
1031
|
+
* `core.geom.query.edge.listFaces` and `core.geom.query.face.getSurfaceKind`
|
|
1032
|
+
* on both faces of each edge. (`core.geom.query.brep.listEdgesBetween` takes
|
|
1033
|
+
* two VERTEX indices — it is NOT a face-pair lookup.) Chamfering a cylinder's
|
|
1034
|
+
* rim yields a cone patch where a fillet would yield a torus patch.
|
|
1035
|
+
*
|
|
1036
|
+
* When the input brep carries a creation recipe, the result carries it too,
|
|
1037
|
+
* with this operation appended to `operations`; `design.create.massFromBrep`
|
|
1038
|
+
* then keeps the mass editable through `design.update.parameters`.
|
|
1039
|
+
*
|
|
1040
|
+
* Runs on the OpenCascade kernel (the first kernel call loads a wasm of tens
|
|
1041
|
+
* of MB — expect a pause of seconds).
|
|
1042
|
+
*
|
|
1043
|
+
* Inspect the result via `core.geom.query.brep.*`, or commit it to the scene
|
|
1044
|
+
* with `design.create.massFromBrep`.
|
|
1045
|
+
*
|
|
1046
|
+
* @param brep The solid whose edges to bevel
|
|
1047
|
+
* @param edges The edges to chamfer (one or more, all on `brep`, no
|
|
1048
|
+
* duplicates; more than 64 still chamfers but the result carries no
|
|
1049
|
+
* parameter record)
|
|
1050
|
+
* @param distance Chamfer distance from the edge on each adjacent face (positive, finite)
|
|
1051
|
+
* @returns The chamfered solid as a new {@linkcode BrepHandle}
|
|
1052
|
+
* @throws VALIDATION if `edges` is empty or holds a duplicate, `distance` is
|
|
1053
|
+
* not a positive finite number, an edge is not on `brep`, or an edge has no
|
|
1054
|
+
* crease to cut — it is a seam of a closed face, or it lies between two
|
|
1055
|
+
* patches of one smooth surface
|
|
1056
|
+
* @throws PRECONDITION_FAILED if an edge could not be located on the kernel
|
|
1057
|
+
* solid after healing (select a different edge, or chamfer before the
|
|
1058
|
+
* operation that curved the solid)
|
|
1059
|
+
* @throws OPERATION_FAILED if the kernel or the translation fails, or the
|
|
1060
|
+
* result is non-manifold, splits into several solids, or contains a surface
|
|
1061
|
+
* Snaptrude cannot represent. A distance larger than an adjacent face
|
|
1062
|
+
* is reported here, with a hint asking for a smaller one. Unlike
|
|
1063
|
+
* {@linkcode PluginGeomCreateApi.brepFromFillet}, the kernel does not say
|
|
1064
|
+
* which edge failed a chamfer, so the error names no edge
|
|
1065
|
+
*
|
|
1066
|
+
* @examplePrompt Chamfer the top edge of the cylinder
|
|
1067
|
+
* @examplePrompt Bevel these edges by 100mm
|
|
1068
|
+
* @examplePrompt Chamfer the top edges of the plinth
|
|
1069
|
+
* @examplePrompt Cut a 45-degree flat along the corners of this mass
|
|
1070
|
+
*
|
|
1071
|
+
* # Example
|
|
1072
|
+
* ```ts
|
|
1073
|
+
* const brep = await snaptrude.core.geom.create.brepFromExtrusion(contour, { x: 0, y: 1, z: 0 }, 3)
|
|
1074
|
+
* const edges = await snaptrude.core.geom.query.brep.listEdges(brep)
|
|
1075
|
+
* const beveled = await snaptrude.core.geom.create.brepFromChamfer(brep, [edges[0]], 0.1)
|
|
1076
|
+
* ```
|
|
1077
|
+
*/
|
|
1078
|
+
public abstract brepFromChamfer(
|
|
1079
|
+
brep: BrepHandle,
|
|
1080
|
+
edges: EdgeHandle[],
|
|
1081
|
+
distance: number,
|
|
1082
|
+
): PluginApiReturn<BrepHandle>
|
|
1083
|
+
|
|
1084
|
+
/**
|
|
1085
|
+
* Sweeps a planar profile along a polyline path, with mitred corners at
|
|
1086
|
+
* each bend. Host API call — returns a new {@linkcode BrepHandle}; the
|
|
1087
|
+
* input contour is read-only. The profile must be hole-free and must not
|
|
1088
|
+
* lie in a plane containing the first path segment's direction. Repeating
|
|
1089
|
+
* the first point as the last closes the path into a ring solid (a picture
|
|
1090
|
+
* frame): closed paths must be flat and straight-segmented and take a
|
|
1091
|
+
* straight-edged (arc-free) profile — the ring's cross-section is the
|
|
1092
|
+
* authored profile projected along the first leg onto the first mitre
|
|
1093
|
+
* plane, so a profile not perpendicular to the first leg appears sheared.
|
|
1094
|
+
* An optional scale law tapers the sweep: `startScale`/`endScale`
|
|
1095
|
+
* interpolate linearly by arc length, or `scales` gives one factor per path
|
|
1096
|
+
* point (scaling is about the profile centroid). A uniform scale (all
|
|
1097
|
+
* factors equal) works on any path today's sweep accepts; a varying scale
|
|
1098
|
+
* takes straight (collinear) open paths with straight-edged profiles —
|
|
1099
|
+
* tapering across a bend or along an arc edge would create faces Snaptrude
|
|
1100
|
+
* cannot represent and throws (sweep each straight run separately and union
|
|
1101
|
+
* the results instead). An optional `transition` picks the corner
|
|
1102
|
+
* treatment: `"miter"` (default) is a sharp mitred bend; `"round"`
|
|
1103
|
+
* carries the section around each turning corner on a tangent circular arc,
|
|
1104
|
+
* so the corner patch is a real curved surface (geometrically cylindrical;
|
|
1105
|
+
* `getSurfaceKind` reports it as `"spline"`) rather than a
|
|
1106
|
+
* flat cut (open paths only — `"round"` on a closed ring path is refused);
|
|
1107
|
+
* `{ bevel: b }` chamfers each turning corner by cutting `b` back along
|
|
1108
|
+
* both adjacent legs (works on open and closed paths — each leg must be
|
|
1109
|
+
* long enough for its cuts). On a corner-less path `transition` has no
|
|
1110
|
+
* effect, and a varying scale only accepts straight paths, so it never meets
|
|
1111
|
+
* a corner.
|
|
1112
|
+
*
|
|
1113
|
+
* Open paths run on the OpenCascade kernel (the first kernel call loads a
|
|
1114
|
+
* wasm of tens of MB — expect a pause of seconds); closed paths are
|
|
1115
|
+
* computed host-side and never load the kernel.
|
|
1116
|
+
*
|
|
1117
|
+
* Inspect the result via `core.geom.query.brep.*`, or commit it to the scene
|
|
1118
|
+
* with `design.create.massFromBrep`.
|
|
1119
|
+
*
|
|
1120
|
+
* @param profile The cross-section to sweep (hole-free contour)
|
|
1121
|
+
* @param path The polyline path as plain `{x, y, z}` points (2 or more;
|
|
1122
|
+
* repeat the first point as the last to close the path into a ring; more
|
|
1123
|
+
* than 512 points still sweeps but the result carries no parameter record)
|
|
1124
|
+
* @param options Optional scale law and corner transition. Scale law:
|
|
1125
|
+
* `startScale`/`endScale` (linear taper by arc length) or `scales` (one
|
|
1126
|
+
* factor per path point; mutually exclusive with
|
|
1127
|
+
* `startScale`/`endScale`); every factor must be finite and within
|
|
1128
|
+
* 1e-3..1e3. `transition`: `"miter"` (default, sharp corners),
|
|
1129
|
+
* `"round"` (arc-carried corners — curved corner patches; open paths
|
|
1130
|
+
* only) or `{ bevel: b }` (chamfered corners, `b` finite within
|
|
1131
|
+
* 1e-3..1e3; open and closed paths)
|
|
1132
|
+
* @returns The swept solid as a new {@linkcode BrepHandle}
|
|
1133
|
+
* @throws VALIDATION if the profile has holes, the path has fewer than 2
|
|
1134
|
+
* points, consecutive path points coincide, a
|
|
1135
|
+
* coordinate is not finite, or the profile plane contains the first
|
|
1136
|
+
* path segment's direction
|
|
1137
|
+
* (degenerate sweep); for closed paths, if the ring has fewer than 3
|
|
1138
|
+
* distinct corners, the path is non-planar, a corner doubles back, the
|
|
1139
|
+
* profile has an arc edge, or the profile is too large for a mitred
|
|
1140
|
+
* corner; for scale options, if a factor is outside 1e-3..1e3, `scales`
|
|
1141
|
+
* is combined with `startScale`/`endScale`, `scales` does not match the
|
|
1142
|
+
* path length, or a varying scale is used on a bent or closed path or
|
|
1143
|
+
* with an arc-edged profile; for `{ bevel }`, if a leg is too short for
|
|
1144
|
+
* the cuts its bevelled corners take from it or a corner nearly doubles
|
|
1145
|
+
* back so its bevel collapses (the errors name the corner)
|
|
1146
|
+
* @throws PRECONDITION_FAILED if `transition` is `"round"` and the path is
|
|
1147
|
+
* closed — round corners work on open paths only; use `"miter"` or
|
|
1148
|
+
* `{ bevel }` on a ring
|
|
1149
|
+
* @throws OPERATION_FAILED if the kernel cannot sweep the profile into a
|
|
1150
|
+
* valid solid — including a `"round"` corner whose arc does not fit its
|
|
1151
|
+
* legs, which is not pre-checked and so is not named per corner
|
|
1152
|
+
*
|
|
1153
|
+
* @examplePrompt Sweep this profile along the corridor path
|
|
1154
|
+
* @examplePrompt Extrude the railing section along this route
|
|
1155
|
+
* @examplePrompt Run a duct profile through these points
|
|
1156
|
+
* @examplePrompt Sweep a frame profile around a closed rectangular loop
|
|
1157
|
+
* @examplePrompt Taper this duct from 1x1 to 2x2 along its run
|
|
1158
|
+
* @examplePrompt Sweep a column section that narrows toward the top
|
|
1159
|
+
* @examplePrompt Chamfer the corners of this swept frame by 200mm
|
|
1160
|
+
* @examplePrompt Sweep this handrail with rounded corners at the bends
|
|
1161
|
+
*
|
|
1162
|
+
* # Example
|
|
1163
|
+
* ```ts
|
|
1164
|
+
* const rect = await snaptrude.core.geom.create.profileRect(0.4, 0.4)
|
|
1165
|
+
* const profile = await snaptrude.core.geom.create.contourFromProfile(rect)
|
|
1166
|
+
* // profileRect lies in the XZ plane, so the path must START out of that
|
|
1167
|
+
* // plane (here: straight up), then it can run horizontally.
|
|
1168
|
+
* const duct = await snaptrude.core.geom.create.brepFromSweep(profile, [
|
|
1169
|
+
* { x: 0, y: 0, z: 0 },
|
|
1170
|
+
* { x: 0, y: 2.8, z: 0 },
|
|
1171
|
+
* { x: 10, y: 2.8, z: 0 },
|
|
1172
|
+
* ])
|
|
1173
|
+
* // A closed ring (picture frame): repeat the first point as the last
|
|
1174
|
+
* const frame = await snaptrude.core.geom.create.brepFromSweep(profile, [
|
|
1175
|
+
* { x: 0, y: 0, z: 0 },
|
|
1176
|
+
* { x: 0, y: 3, z: 0 },
|
|
1177
|
+
* { x: 4, y: 3, z: 0 },
|
|
1178
|
+
* { x: 4, y: 0, z: 0 },
|
|
1179
|
+
* { x: 0, y: 0, z: 0 },
|
|
1180
|
+
* ])
|
|
1181
|
+
* // A tapered straight run: 0.4x0.4 at the start, 0.8x0.8 at the end
|
|
1182
|
+
* const flue = await snaptrude.core.geom.create.brepFromSweep(
|
|
1183
|
+
* profile,
|
|
1184
|
+
* [
|
|
1185
|
+
* { x: 0, y: 0, z: 0 },
|
|
1186
|
+
* { x: 0, y: 10, z: 0 },
|
|
1187
|
+
* ],
|
|
1188
|
+
* { startScale: 1, endScale: 2 },
|
|
1189
|
+
* )
|
|
1190
|
+
* ```
|
|
1191
|
+
*/
|
|
1192
|
+
public abstract brepFromSweep(
|
|
1193
|
+
profile: ContourHandle,
|
|
1194
|
+
path: Vec3Components[],
|
|
1195
|
+
options?: {
|
|
1196
|
+
startScale?: number
|
|
1197
|
+
endScale?: number
|
|
1198
|
+
scales?: number[]
|
|
1199
|
+
transition?: "miter" | "round" | { bevel: number }
|
|
1200
|
+
},
|
|
1201
|
+
): PluginApiReturn<BrepHandle>
|
|
1202
|
+
|
|
1203
|
+
/**
|
|
1204
|
+
* Sweeps a cross-section along a SMOOTH path — splines, arcs and lines chained
|
|
1205
|
+
* end to end — with control of how the profile turns.
|
|
1206
|
+
* {@linkcode PluginGeomCreateApi.brepFromSweep} takes a polyline path; this
|
|
1207
|
+
* takes curves. Host API call — returns a new {@linkcode BrepHandle}; the
|
|
1208
|
+
* inputs are read-only. Records as `sweepAlongCurve`, so the orientation stays
|
|
1209
|
+
* editable through `design.update.parameters`. The properties panel shows it
|
|
1210
|
+
* read-only, because it is a text value, not a number. A railed sweep records
|
|
1211
|
+
* nothing (`getParameters` answers `null`).
|
|
1212
|
+
*
|
|
1213
|
+
* Runs on the OpenCascade kernel (the first kernel call loads a wasm of tens
|
|
1214
|
+
* of MB — expect a pause of seconds).
|
|
1215
|
+
*
|
|
1216
|
+
* @param profile Hole-free cross-section contour; placed at the first curve's start
|
|
1217
|
+
* @param path 1..64 curves, ordered, meeting end to end within tolerance
|
|
1218
|
+
* @param options `orientation` — `"upright"` (default) keeps the profile's up
|
|
1219
|
+
* aligned with world up (ducts, handrails, ribbons that must not roll);
|
|
1220
|
+
* `"frenet"` lets it roll with the path's curvature; `"fixed"` carries the
|
|
1221
|
+
* authored frame along unchanged, which is a pure translation — use it to
|
|
1222
|
+
* bend a footprint along an arc. `rail` is a second guide curve.
|
|
1223
|
+
* @returns The swept solid as a new {@linkcode BrepHandle}
|
|
1224
|
+
* @throws VALIDATION if the path curves are not connected, the path is closed,
|
|
1225
|
+
* the profile has holes, the first tangent lies in the profile plane, the
|
|
1226
|
+
* path runs vertically under `"upright"` (that frame is undefined there —
|
|
1227
|
+
* the message names the run and points at `"frenet"`), the path turns
|
|
1228
|
+
* parallel to the profile under `"fixed"`, `rail` is closed, or `rail` and
|
|
1229
|
+
* `orientation` are both given
|
|
1230
|
+
* @throws OPERATION_FAILED if the kernel could not sweep the profile — a
|
|
1231
|
+
* self-intersection on a tight bend
|
|
1232
|
+
*
|
|
1233
|
+
* @examplePrompt Sweep a 600x400 duct along this curved route and keep it upright
|
|
1234
|
+
* @examplePrompt Run this handrail along the curved stair edge
|
|
1235
|
+
* @examplePrompt Bend this footprint along the arc
|
|
1236
|
+
*
|
|
1237
|
+
* # Example
|
|
1238
|
+
* ```ts
|
|
1239
|
+
* const route = await snaptrude.core.geom.create.splineFromPoints(points)
|
|
1240
|
+
* const duct = await snaptrude.core.geom.create.brepFromSweepAlongCurve(profile, [route], {
|
|
1241
|
+
* orientation: "upright",
|
|
1242
|
+
* })
|
|
1243
|
+
* ```
|
|
1244
|
+
*/
|
|
1245
|
+
public abstract brepFromSweepAlongCurve(
|
|
1246
|
+
profile: ContourHandle,
|
|
1247
|
+
path: CurveHandle[],
|
|
1248
|
+
options?: SweepAlongCurveOptions,
|
|
1249
|
+
): PluginApiReturn<BrepHandle>
|
|
1250
|
+
|
|
1251
|
+
/**
|
|
1252
|
+
* Revolves a planar profile about an axis to make a solid of revolution — a
|
|
1253
|
+
* full turn by default. Host API call — returns a new
|
|
1254
|
+
* {@linkcode BrepHandle}; the input contour is read-only. Holes in the
|
|
1255
|
+
* profile are allowed, and segments may run at any angle to the axis: an
|
|
1256
|
+
* inclined segment revolves into a cone, an arc into a sphere or torus
|
|
1257
|
+
* section. This is the general route to domes, vases, columns and rotundas.
|
|
1258
|
+
*
|
|
1259
|
+
* Two rules bind the axis to the profile. First, the axis line must lie IN
|
|
1260
|
+
* the profile's plane or run parallel to it — a revolution turns a planar
|
|
1261
|
+
* section about a line drawn in that same plane; a parallel axis offset out
|
|
1262
|
+
* of the plane is judged by its projection into the plane (the result is a
|
|
1263
|
+
* hollow ring). A skew axis is refused: move the axis into the profile's
|
|
1264
|
+
* plane. Second, within that plane the whole profile stays on ONE side of
|
|
1265
|
+
* the axis.
|
|
1266
|
+
* Vertices and whole segments may lie ON the axis — that is how a dome's
|
|
1267
|
+
* pole and a cylinder's inner edge are authored — but no part of the profile
|
|
1268
|
+
* may cross to the other side, which would sweep a self-intersecting solid.
|
|
1269
|
+
*
|
|
1270
|
+
* Runs on the OpenCascade kernel (the first kernel call loads a wasm of
|
|
1271
|
+
* tens of MB — expect a pause of seconds).
|
|
1272
|
+
*
|
|
1273
|
+
* Inspect the result via `core.geom.query.brep.*`, or commit it to the scene
|
|
1274
|
+
* with `design.create.massFromBrep`.
|
|
1275
|
+
*
|
|
1276
|
+
* @param profile The cross-section to revolve (planar contour, holes allowed)
|
|
1277
|
+
* @param axisOrigin A point on the revolution axis as plain `{x, y, z}` components
|
|
1278
|
+
* @param axisDirection The axis direction as plain `{x, y, z}` components (non-zero)
|
|
1279
|
+
* @param angleInDegrees Optional revolution angle in degrees (0 < angle ≤ 360; default 360)
|
|
1280
|
+
* @returns The revolved solid as a new {@linkcode BrepHandle}
|
|
1281
|
+
* @throws VALIDATION if `axisDirection` is zero-length, `angleInDegrees` is
|
|
1282
|
+
* not in (0, 360], a coordinate is not finite, or the profile crosses the
|
|
1283
|
+
* axis (the message names the offending segment — keep the whole profile
|
|
1284
|
+
* on one side; points may touch the axis but not cross it)
|
|
1285
|
+
* @throws PRECONDITION_FAILED if the axis is skew to the profile's plane
|
|
1286
|
+
* (neither in it nor parallel to it; the message asks you to move the axis
|
|
1287
|
+
* into the plane of the profile)
|
|
1288
|
+
* @throws OPERATION_FAILED if the kernel cannot revolve the profile into a
|
|
1289
|
+
* valid solid
|
|
1290
|
+
*
|
|
1291
|
+
* @examplePrompt Create a dome from this section
|
|
1292
|
+
* @examplePrompt Revolve this profile 360 degrees around the vertical axis
|
|
1293
|
+
* @examplePrompt Build a rotunda by revolving this wall section
|
|
1294
|
+
* @examplePrompt Make a dome by revolving a quarter-circle about the vertical axis
|
|
1295
|
+
* @examplePrompt Turn this curved outline into a vase
|
|
1296
|
+
*
|
|
1297
|
+
* # Example
|
|
1298
|
+
* ```ts
|
|
1299
|
+
* // A cylinder: revolve a 2m-wide, 3m-tall rectangle about the Y axis at
|
|
1300
|
+
* // its edge — the left edge sits ON the axis, which is legal.
|
|
1301
|
+
* const rect = await snaptrude.core.geom.create.profileFromLinePoints([
|
|
1302
|
+
* await snaptrude.core.math.vec3.new(0, 0, 0),
|
|
1303
|
+
* await snaptrude.core.math.vec3.new(2, 0, 0),
|
|
1304
|
+
* await snaptrude.core.math.vec3.new(2, 3, 0),
|
|
1305
|
+
* await snaptrude.core.math.vec3.new(0, 3, 0),
|
|
1306
|
+
* ])
|
|
1307
|
+
* const profile = await snaptrude.core.geom.create.contourFromProfile(rect)
|
|
1308
|
+
* const cylinder = await snaptrude.core.geom.create.brepFromRevolution(
|
|
1309
|
+
* profile,
|
|
1310
|
+
* { x: 0, y: 0, z: 0 },
|
|
1311
|
+
* { x: 0, y: 1, z: 0 },
|
|
1312
|
+
* )
|
|
1313
|
+
* ```
|
|
1314
|
+
*/
|
|
1315
|
+
public abstract brepFromRevolution(
|
|
1316
|
+
profile: ContourHandle,
|
|
1317
|
+
axisOrigin: Vec3Components,
|
|
1318
|
+
axisDirection: Vec3Components,
|
|
1319
|
+
angleInDegrees?: number,
|
|
1320
|
+
): PluginApiReturn<BrepHandle>
|
|
1321
|
+
|
|
1322
|
+
/**
|
|
1323
|
+
* Create a solid **sphere** B-rep (boundary representation: the solid's
|
|
1324
|
+
* exact faces, edges and vertices) from a centre and radius. Host API call
|
|
1325
|
+
* — returns a {@linkcode BrepHandle}; commit it to the scene with
|
|
1326
|
+
* `design.create.massFromBrep`. The result carries an exact spherical
|
|
1327
|
+
* surface (not a faceted approximation) and a creation recipe — read the
|
|
1328
|
+
* committed mass's parameters back with `design.query.getParameters` and edit
|
|
1329
|
+
* them with `design.update.parameters`.
|
|
1330
|
+
*
|
|
1331
|
+
* Runs on the OpenCascade kernel (the first kernel call loads a wasm of tens
|
|
1332
|
+
* of MB — expect a pause of seconds).
|
|
1333
|
+
*
|
|
1334
|
+
* @param centre Sphere centre as plain `{x, y, z}` components (internal length units)
|
|
1335
|
+
* @param radius Sphere radius (> 0, internal length units)
|
|
1336
|
+
* @returns The new solid as a {@linkcode BrepHandle}
|
|
1337
|
+
* @throws VALIDATION if `radius` is not a positive finite number or a
|
|
1338
|
+
* coordinate is not finite
|
|
1339
|
+
*
|
|
1340
|
+
* @examplePrompt Create a sphere of radius 5 at the origin
|
|
1341
|
+
* @examplePrompt Add a 3m ball on top of the tower
|
|
1342
|
+
*
|
|
1343
|
+
* # Example
|
|
1344
|
+
* ```ts
|
|
1345
|
+
* const brep = await snaptrude.core.geom.create.brepFromSphere({ x: 0, y: 5, z: 0 }, 5)
|
|
1346
|
+
* const mass = await snaptrude.design.create.massFromBrep(brep, "Sphere")
|
|
1347
|
+
* ```
|
|
1348
|
+
*/
|
|
1349
|
+
public abstract brepFromSphere(
|
|
1350
|
+
centre: Vec3Components,
|
|
1351
|
+
radius: number,
|
|
1352
|
+
): PluginApiReturn<BrepHandle>
|
|
1353
|
+
|
|
1354
|
+
/**
|
|
1355
|
+
* Create a solid **cylinder** B-rep from its bottom-cap centre, axis
|
|
1356
|
+
* direction, radius and height. Host API call — returns a
|
|
1357
|
+
* {@linkcode BrepHandle}; commit with `design.create.massFromBrep`. The
|
|
1358
|
+
* bottom cap sits AT `base` and the solid extends `height` along `axis` —
|
|
1359
|
+
* place `base` on the floor and use axis `{x: 0, y: 1, z: 0}` for an upright
|
|
1360
|
+
* column. Carries a creation recipe (radius, height), editable through
|
|
1361
|
+
* `design.update.parameters`.
|
|
1362
|
+
*
|
|
1363
|
+
* Runs on the OpenCascade kernel (the first kernel call loads a wasm of tens
|
|
1364
|
+
* of MB — expect a pause of seconds).
|
|
1365
|
+
*
|
|
1366
|
+
* @param base Centre of the bottom cap as plain `{x, y, z}` components
|
|
1367
|
+
* @param axis Axis direction as plain `{x, y, z}` components (non-zero, normalised by the host)
|
|
1368
|
+
* @param radius Cylinder radius (> 0)
|
|
1369
|
+
* @param height Cylinder height along `axis` (> 0)
|
|
1370
|
+
* @returns The new solid as a {@linkcode BrepHandle}
|
|
1371
|
+
* @throws VALIDATION if `radius`/`height` are not positive finite numbers or
|
|
1372
|
+
* `axis` is zero-length
|
|
1373
|
+
*
|
|
1374
|
+
* @examplePrompt Create a cylinder 2m across and 4m tall
|
|
1375
|
+
* @examplePrompt Add a circular column here
|
|
1376
|
+
*
|
|
1377
|
+
* # Example
|
|
1378
|
+
* ```ts
|
|
1379
|
+
* const brep = await snaptrude.core.geom.create.brepFromCylinder(
|
|
1380
|
+
* { x: 0, y: 0, z: 0 },
|
|
1381
|
+
* { x: 0, y: 1, z: 0 },
|
|
1382
|
+
* 1,
|
|
1383
|
+
* 4,
|
|
1384
|
+
* )
|
|
1385
|
+
* const column = await snaptrude.design.create.massFromBrep(brep, "Column")
|
|
1386
|
+
* ```
|
|
1387
|
+
*/
|
|
1388
|
+
public abstract brepFromCylinder(
|
|
1389
|
+
base: Vec3Components,
|
|
1390
|
+
axis: Vec3Components,
|
|
1391
|
+
radius: number,
|
|
1392
|
+
height: number,
|
|
1393
|
+
): PluginApiReturn<BrepHandle>
|
|
1394
|
+
|
|
1395
|
+
/**
|
|
1396
|
+
* Create a solid **cone or frustum** B-rep: bottom-cap centre, axis, base
|
|
1397
|
+
* radius, height, and an optional top radius (default 0 — a full cone to a
|
|
1398
|
+
* point; > 0 — a frustum / tapered column). Host API call — returns a
|
|
1399
|
+
* {@linkcode BrepHandle}; commit with `design.create.massFromBrep`. Carries
|
|
1400
|
+
* a creation recipe (radii + height), editable through `design.update.parameters`.
|
|
1401
|
+
*
|
|
1402
|
+
* Runs on the OpenCascade kernel (the first kernel call loads a wasm of tens
|
|
1403
|
+
* of MB — expect a pause of seconds).
|
|
1404
|
+
*
|
|
1405
|
+
* @param base Centre of the bottom cap as plain `{x, y, z}` components
|
|
1406
|
+
* @param axis Axis direction as plain `{x, y, z}` components (non-zero, normalised by the host)
|
|
1407
|
+
* @param baseRadius Radius at the base (> 0)
|
|
1408
|
+
* @param height Height along `axis` (> 0)
|
|
1409
|
+
* @param topRadius Optional radius at the top (≥ 0, ≠ `baseRadius`; default 0 = apex)
|
|
1410
|
+
* @returns The new solid as a {@linkcode BrepHandle}
|
|
1411
|
+
* @throws VALIDATION if radii/height are invalid, `topRadius === baseRadius`
|
|
1412
|
+
* (that is a cylinder — use {@linkcode PluginGeomCreateApi.brepFromCylinder}),
|
|
1413
|
+
* or `axis` is zero-length
|
|
1414
|
+
*
|
|
1415
|
+
* @examplePrompt Create a cone roof 4m wide and 3m tall
|
|
1416
|
+
* @examplePrompt Make a tapered column narrowing from 1m to 0.6m
|
|
1417
|
+
*
|
|
1418
|
+
* # Example
|
|
1419
|
+
* ```ts
|
|
1420
|
+
* const roof = await snaptrude.core.geom.create.brepFromCone(
|
|
1421
|
+
* { x: 0, y: 9, z: 0 },
|
|
1422
|
+
* { x: 0, y: 1, z: 0 },
|
|
1423
|
+
* 2,
|
|
1424
|
+
* 3,
|
|
1425
|
+
* )
|
|
1426
|
+
* ```
|
|
1427
|
+
*/
|
|
1428
|
+
public abstract brepFromCone(
|
|
1429
|
+
base: Vec3Components,
|
|
1430
|
+
axis: Vec3Components,
|
|
1431
|
+
baseRadius: number,
|
|
1432
|
+
height: number,
|
|
1433
|
+
topRadius?: number,
|
|
1434
|
+
): PluginApiReturn<BrepHandle>
|
|
1435
|
+
|
|
1436
|
+
/**
|
|
1437
|
+
* Create a solid **torus** (ring / donut) B-rep from its centre, plane
|
|
1438
|
+
* normal, ring radius and tube radius. Host API call — returns a
|
|
1439
|
+
* {@linkcode BrepHandle}; commit with `design.create.massFromBrep`.
|
|
1440
|
+
* `majorRadius` is centre-to-tube-centre; `minorRadius` is the tube's own
|
|
1441
|
+
* radius and must be strictly smaller. Carries a creation recipe, editable
|
|
1442
|
+
* through `design.update.parameters`.
|
|
1443
|
+
*
|
|
1444
|
+
* Runs on the OpenCascade kernel (the first kernel call loads a wasm of tens
|
|
1445
|
+
* of MB — expect a pause of seconds).
|
|
1446
|
+
*
|
|
1447
|
+
* @param centre Torus centre as plain `{x, y, z}` components
|
|
1448
|
+
* @param axis Plane normal of the ring as plain `{x, y, z}` components (non-zero)
|
|
1449
|
+
* @param majorRadius Ring radius, centre to tube centre (> 0)
|
|
1450
|
+
* @param minorRadius Tube radius (> 0 and < `majorRadius` — a self-intersecting torus is rejected)
|
|
1451
|
+
* @returns The new solid as a {@linkcode BrepHandle}
|
|
1452
|
+
* @throws VALIDATION if a radius is invalid, `minorRadius >= majorRadius`,
|
|
1453
|
+
* or `axis` is zero-length
|
|
1454
|
+
*
|
|
1455
|
+
* @examplePrompt Create a donut-shaped ring 10m across with a 1m tube
|
|
1456
|
+
* @examplePrompt Add a torus canopy around the tower
|
|
1457
|
+
*
|
|
1458
|
+
* # Example
|
|
1459
|
+
* ```ts
|
|
1460
|
+
* const ring = await snaptrude.core.geom.create.brepFromTorus(
|
|
1461
|
+
* { x: 0, y: 6, z: 0 },
|
|
1462
|
+
* { x: 0, y: 1, z: 0 },
|
|
1463
|
+
* 5,
|
|
1464
|
+
* 1,
|
|
1465
|
+
* )
|
|
1466
|
+
* ```
|
|
1467
|
+
*/
|
|
1468
|
+
public abstract brepFromTorus(
|
|
1469
|
+
centre: Vec3Components,
|
|
1470
|
+
axis: Vec3Components,
|
|
1471
|
+
majorRadius: number,
|
|
1472
|
+
minorRadius: number,
|
|
1473
|
+
): PluginApiReturn<BrepHandle>
|
|
1474
|
+
}
|
|
1475
|
+
|
|
1476
|
+
/**
|
|
1477
|
+
* Arguments for {@linkcode PluginGeomCreateApi.line}.
|
|
1478
|
+
*
|
|
1479
|
+
* | Property | Type | Description |
|
|
1480
|
+
* |---|---|---|
|
|
1481
|
+
* | `startPoint` | {@linkcode Vec3Handle} | Start point of the line segment |
|
|
1482
|
+
* | `endPoint` | {@linkcode Vec3Handle} | End point of the line segment |
|
|
1483
|
+
*/
|
|
1484
|
+
export const PluginGeomCreateLineArgs = z.object({
|
|
1485
|
+
startPoint: Vec3Handle,
|
|
1486
|
+
endPoint: Vec3Handle,
|
|
1487
|
+
})
|
|
1488
|
+
|
|
1489
|
+
export type PluginGeomCreateLineArgs = z.infer<typeof PluginGeomCreateLineArgs>
|
|
1490
|
+
|
|
1491
|
+
/**
|
|
1492
|
+
* Arguments for {@linkcode PluginGeomCreateApi.arc}.
|
|
1493
|
+
*
|
|
1494
|
+
* | Property | Type | Description |
|
|
1495
|
+
* |---|---|---|
|
|
1496
|
+
* | `startPoint` | {@linkcode Vec3Handle} | Start point of the arc |
|
|
1497
|
+
* | `endPoint` | {@linkcode Vec3Handle} | End point of the arc |
|
|
1498
|
+
* | `centrePoint` | {@linkcode Vec3Handle} | Centre point of the arc |
|
|
1499
|
+
* | `axis` | {@linkcode Vec3Handle} | Axis direction of the arc |
|
|
1500
|
+
*/
|
|
1501
|
+
export const PluginGeomCreateArcArgs = z.object({
|
|
1502
|
+
startPoint: Vec3Handle,
|
|
1503
|
+
endPoint: Vec3Handle,
|
|
1504
|
+
centrePoint: Vec3Handle,
|
|
1505
|
+
axis: Vec3Handle,
|
|
1506
|
+
})
|
|
1507
|
+
|
|
1508
|
+
export type PluginGeomCreateArcArgs = z.infer<typeof PluginGeomCreateArcArgs>
|
|
1509
|
+
|
|
1510
|
+
/**
|
|
1511
|
+
* Arguments for {@linkcode PluginGeomCreateApi.circle}.
|
|
1512
|
+
*
|
|
1513
|
+
* | Property | Type | Description |
|
|
1514
|
+
* |---|---|---|
|
|
1515
|
+
* | `centrePoint` | {@linkcode Vec3Handle} | Centre point of the circle |
|
|
1516
|
+
* | `axis` | {@linkcode Vec3Handle} | Axis direction (plane normal) of the circle |
|
|
1517
|
+
* | `radius` | `number` | Radius of the circle |
|
|
1518
|
+
*/
|
|
1519
|
+
export const PluginGeomCreateCircleArgs = z.object({
|
|
1520
|
+
centrePoint: Vec3Handle,
|
|
1521
|
+
axis: Vec3Handle,
|
|
1522
|
+
radius: z.number(),
|
|
1523
|
+
})
|
|
1524
|
+
|
|
1525
|
+
export type PluginGeomCreateCircleArgs = z.infer<typeof PluginGeomCreateCircleArgs>
|
|
1526
|
+
|
|
1527
|
+
/**
|
|
1528
|
+
* Arguments for {@linkcode PluginGeomCreateApi.splineFromPoints}.
|
|
1529
|
+
*
|
|
1530
|
+
* | Property | Type | Description |
|
|
1531
|
+
* |---|---|---|
|
|
1532
|
+
* | `points` | {@linkcode Vec3Handle}`[]` | 3..256 ordered through-points of the curve |
|
|
1533
|
+
*/
|
|
1534
|
+
export const PluginGeomCreateSplineFromPointsArgs = z.object({
|
|
1535
|
+
points: z.array(Vec3Handle).min(3).max(MAX_SPLINE_THROUGH_POINTS),
|
|
1536
|
+
})
|
|
1537
|
+
|
|
1538
|
+
export type PluginGeomCreateSplineFromPointsArgs = z.infer<
|
|
1539
|
+
typeof PluginGeomCreateSplineFromPointsArgs
|
|
1540
|
+
>
|
|
1541
|
+
|
|
1542
|
+
/**
|
|
1543
|
+
* Arguments for {@linkcode PluginGeomCreateApi.splineFromControlPoints}.
|
|
1544
|
+
*
|
|
1545
|
+
* | Property | Type | Description |
|
|
1546
|
+
* |---|---|---|
|
|
1547
|
+
* | `controlPoints` | {@linkcode Vec3Handle}`[]` | 3..512 control points of the curve, in order |
|
|
1548
|
+
* | `options` | `object`? | `degree`: 2 or 3 (default `min(3, controlPoints.length - 1)`) |
|
|
1549
|
+
*/
|
|
1550
|
+
export const PluginGeomCreateSplineFromControlPointsArgs = z.object({
|
|
1551
|
+
controlPoints: z.array(Vec3Handle).min(3).max(MAX_SPLINE_POLES),
|
|
1552
|
+
options: z.object({ degree: z.number().int().min(2).max(3).optional() }).optional(),
|
|
1553
|
+
})
|
|
1554
|
+
|
|
1555
|
+
export type PluginGeomCreateSplineFromControlPointsArgs = z.infer<
|
|
1556
|
+
typeof PluginGeomCreateSplineFromControlPointsArgs
|
|
1557
|
+
>
|
|
1558
|
+
|
|
1559
|
+
/**
|
|
1560
|
+
* Arguments for {@linkcode PluginGeomCreateApi.profileFromLinePoints}.
|
|
1561
|
+
*
|
|
1562
|
+
* | Property | Type | Description |
|
|
1563
|
+
* |---|---|---|
|
|
1564
|
+
* | `points` | {@linkcode Vec3Handle}`[]` | Ordered vertex handles of the profile |
|
|
1565
|
+
*/
|
|
1566
|
+
export const PluginGeomCreateProfileFromLinePointsArgs = z.object({
|
|
1567
|
+
points: z.array(Vec3Handle),
|
|
1568
|
+
})
|
|
1569
|
+
|
|
1570
|
+
export type PluginGeomCreateProfileFromLinePointsArgs = z.infer<
|
|
1571
|
+
typeof PluginGeomCreateProfileFromLinePointsArgs
|
|
1572
|
+
>
|
|
1573
|
+
|
|
1574
|
+
/**
|
|
1575
|
+
* Arguments for {@linkcode PluginGeomCreateApi.profileFromCurves}.
|
|
1576
|
+
*
|
|
1577
|
+
* | Property | Type | Description |
|
|
1578
|
+
* |---|---|---|
|
|
1579
|
+
* | `curves` | {@linkcode CurveHandle}`[]` | Ordered curve handles forming a closed loop |
|
|
1580
|
+
*/
|
|
1581
|
+
export const PluginGeomCreateProfileFromCurvesArgs = z.object({
|
|
1582
|
+
curves: z.array(CurveHandle),
|
|
1583
|
+
})
|
|
1584
|
+
|
|
1585
|
+
export type PluginGeomCreateProfileFromCurvesArgs = z.infer<
|
|
1586
|
+
typeof PluginGeomCreateProfileFromCurvesArgs
|
|
1587
|
+
>
|
|
1588
|
+
|
|
1589
|
+
/**
|
|
1590
|
+
* Arguments for {@linkcode PluginGeomCreateApi.profileFromSplinePoints}.
|
|
1591
|
+
*
|
|
1592
|
+
* | Property | Type | Description |
|
|
1593
|
+
* |---|---|---|
|
|
1594
|
+
* | `points` | {@linkcode Vec3Handle}`[]` | 3..256 ordered through-points of the closed loop (first point NOT repeated) |
|
|
1595
|
+
*/
|
|
1596
|
+
export const PluginGeomCreateProfileFromSplinePointsArgs = z.object({
|
|
1597
|
+
points: z.array(Vec3Handle).min(3).max(MAX_SPLINE_THROUGH_POINTS),
|
|
1598
|
+
})
|
|
1599
|
+
|
|
1600
|
+
export type PluginGeomCreateProfileFromSplinePointsArgs = z.infer<
|
|
1601
|
+
typeof PluginGeomCreateProfileFromSplinePointsArgs
|
|
1602
|
+
>
|
|
1603
|
+
|
|
1604
|
+
/**
|
|
1605
|
+
* Arguments for {@linkcode PluginGeomCreateApi.contourFromProfile}.
|
|
1606
|
+
*
|
|
1607
|
+
* | Property | Type | Description |
|
|
1608
|
+
* |---|---|---|
|
|
1609
|
+
* | `outer` | {@linkcode ProfileHandle} | The outer boundary loop |
|
|
1610
|
+
*/
|
|
1611
|
+
export const PluginGeomCreateContourFromProfileArgs = z.object({
|
|
1612
|
+
outer: ProfileHandle,
|
|
1613
|
+
})
|
|
1614
|
+
|
|
1615
|
+
export type PluginGeomCreateContourFromProfileArgs = z.infer<
|
|
1616
|
+
typeof PluginGeomCreateContourFromProfileArgs
|
|
1617
|
+
>
|
|
1618
|
+
|
|
1619
|
+
/**
|
|
1620
|
+
* Arguments for {@linkcode PluginGeomCreateApi.contourFromProfiles}.
|
|
1621
|
+
*
|
|
1622
|
+
* | Property | Type | Description |
|
|
1623
|
+
* |---|---|---|
|
|
1624
|
+
* | `outer` | {@linkcode ProfileHandle} | The outer boundary loop |
|
|
1625
|
+
* | `holes` | {@linkcode ProfileHandle}`[]` | Optional inner hole loops |
|
|
1626
|
+
*/
|
|
1627
|
+
export const PluginGeomCreateContourFromProfilesArgs = z.object({
|
|
1628
|
+
outer: ProfileHandle,
|
|
1629
|
+
holes: z.array(ProfileHandle).optional(),
|
|
1630
|
+
})
|
|
1631
|
+
|
|
1632
|
+
export type PluginGeomCreateContourFromProfilesArgs = z.infer<
|
|
1633
|
+
typeof PluginGeomCreateContourFromProfilesArgs
|
|
1634
|
+
>
|
|
1635
|
+
|
|
1636
|
+
/**
|
|
1637
|
+
* Arguments for {@linkcode PluginGeomCreateApi.brepFromFaces}.
|
|
1638
|
+
*
|
|
1639
|
+
* | Property | Type | Description |
|
|
1640
|
+
* |---|---|---|
|
|
1641
|
+
* | `faces` | {@linkcode Vec3Components}`[][]` | Face loops — each an ordered array of `{x, y, z}` points (≥3 points per face, ≥4 faces) |
|
|
1642
|
+
*/
|
|
1643
|
+
export const PluginGeomCreateBrepFromFacesArgs = z.object({
|
|
1644
|
+
faces: z.array(z.array(Vec3Components).min(3)).min(4),
|
|
1645
|
+
})
|
|
1646
|
+
|
|
1647
|
+
export type PluginGeomCreateBrepFromFacesArgs = z.infer<
|
|
1648
|
+
typeof PluginGeomCreateBrepFromFacesArgs
|
|
1649
|
+
>
|
|
1650
|
+
|
|
1651
|
+
/**
|
|
1652
|
+
* Arguments for {@linkcode PluginGeomCreateApi.brepFromExtrusion}.
|
|
1653
|
+
*
|
|
1654
|
+
* | Property | Type | Description |
|
|
1655
|
+
* |---|---|---|
|
|
1656
|
+
* | `contour` | {@linkcode ContourHandle} | The cross-section to extrude |
|
|
1657
|
+
* | `direction` | {@linkcode Vec3Components} | Extrusion direction (non-zero, finite components) |
|
|
1658
|
+
* | `amount` | `number` | Extrusion distance (finite, non-zero) |
|
|
1659
|
+
* | `options` | `object`? | Optional twist and taper: `twistInDegrees` (an angle, finite), `topScale` (a ratio, finite and positive) and `levels` (a count, 2..64) |
|
|
1660
|
+
*/
|
|
1661
|
+
export const PluginGeomCreateBrepFromExtrusionArgs = z.object({
|
|
1662
|
+
contour: ContourHandle,
|
|
1663
|
+
direction: z.object({
|
|
1664
|
+
x: z.number().finite(),
|
|
1665
|
+
y: z.number().finite(),
|
|
1666
|
+
z: z.number().finite(),
|
|
1667
|
+
}),
|
|
1668
|
+
amount: z
|
|
1669
|
+
.number()
|
|
1670
|
+
.finite()
|
|
1671
|
+
.refine((value) => value !== 0, { message: "amount must be non-zero" }),
|
|
1672
|
+
options: z
|
|
1673
|
+
.object({
|
|
1674
|
+
twistInDegrees: z.number().finite().optional(),
|
|
1675
|
+
topScale: z.number().finite().positive().optional(),
|
|
1676
|
+
levels: z.number().int().min(2).max(MAX_TWIST_LEVELS).optional(),
|
|
1677
|
+
})
|
|
1678
|
+
.optional(),
|
|
1679
|
+
})
|
|
1680
|
+
|
|
1681
|
+
export type PluginGeomCreateBrepFromExtrusionArgs = z.infer<
|
|
1682
|
+
typeof PluginGeomCreateBrepFromExtrusionArgs
|
|
1683
|
+
>
|
|
1684
|
+
|
|
1685
|
+
/**
|
|
1686
|
+
* Arguments for {@linkcode PluginGeomCreateApi.brepFromLoft}.
|
|
1687
|
+
*
|
|
1688
|
+
* | Property | Type | Description |
|
|
1689
|
+
* |---|---|---|
|
|
1690
|
+
* | `bottomContour` | {@linkcode ContourHandle} | The bottom cross-section |
|
|
1691
|
+
* | `topContour` | {@linkcode ContourHandle} | The top cross-section |
|
|
1692
|
+
* | `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) |
|
|
1693
|
+
* | `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"`) |
|
|
1694
|
+
*/
|
|
1695
|
+
export const PluginGeomCreateBrepFromLoftArgs = z.object({
|
|
1696
|
+
bottomContour: ContourHandle,
|
|
1697
|
+
topContour: ContourHandle,
|
|
1698
|
+
intermediateContours: z.array(ContourHandle).optional(),
|
|
1699
|
+
options: z
|
|
1700
|
+
.object({
|
|
1701
|
+
compatibility: z.enum(["strict", "auto"]).optional(),
|
|
1702
|
+
seamAlignment: z.enum(["authored", "auto"]).optional(),
|
|
1703
|
+
smoothing: z.enum(["ruled", "smooth"]).optional(),
|
|
1704
|
+
})
|
|
1705
|
+
.optional(),
|
|
1706
|
+
})
|
|
1707
|
+
|
|
1708
|
+
export type PluginGeomCreateBrepFromLoftArgs = z.infer<typeof PluginGeomCreateBrepFromLoftArgs>
|
|
1709
|
+
|
|
1710
|
+
/**
|
|
1711
|
+
* Arguments for {@linkcode PluginGeomCreateApi.brepFromMesh}.
|
|
1712
|
+
*
|
|
1713
|
+
* | Property | Type | Description |
|
|
1714
|
+
* |---|---|---|
|
|
1715
|
+
* | `positions` | {@linkcode Vec3Components}`[]` | Vertex positions (≥4) |
|
|
1716
|
+
* | `faces` | `number[][]` | Face loops of indices into `positions` (≥3 indices per face, ≥4 faces) |
|
|
1717
|
+
*/
|
|
1718
|
+
export const PluginGeomCreateBrepFromMeshArgs = z.object({
|
|
1719
|
+
positions: z.array(Vec3Components).min(4),
|
|
1720
|
+
faces: z.array(z.array(z.number()).min(3)).min(4),
|
|
1721
|
+
})
|
|
1722
|
+
|
|
1723
|
+
export type PluginGeomCreateBrepFromMeshArgs = z.infer<typeof PluginGeomCreateBrepFromMeshArgs>
|
|
1724
|
+
|
|
1725
|
+
/**
|
|
1726
|
+
* Arguments for the brep boolean constructors —
|
|
1727
|
+
* {@linkcode PluginGeomCreateApi.brepFromUnion},
|
|
1728
|
+
* {@linkcode PluginGeomCreateApi.brepFromSubtraction} (`a` minus `b`), and
|
|
1729
|
+
* {@linkcode PluginGeomCreateApi.brepFromIntersection}.
|
|
1730
|
+
*
|
|
1731
|
+
* | Property | Type | Description |
|
|
1732
|
+
* |---|---|---|
|
|
1733
|
+
* | `a` | {@linkcode BrepHandle} | First solid (the subtraction target) |
|
|
1734
|
+
* | `b` | {@linkcode BrepHandle} | Second solid (the subtraction tool) |
|
|
1735
|
+
*/
|
|
1736
|
+
export const PluginGeomCreateBrepBooleanArgs = z.object({
|
|
1737
|
+
a: BrepHandle,
|
|
1738
|
+
b: BrepHandle,
|
|
1739
|
+
})
|
|
1740
|
+
|
|
1741
|
+
export type PluginGeomCreateBrepBooleanArgs = z.infer<typeof PluginGeomCreateBrepBooleanArgs>
|
|
1742
|
+
|
|
1743
|
+
// Plain {x, y, z} record with finite components (brepFromExtrusion `direction` pattern).
|
|
1744
|
+
const FiniteVec3Components = z.object({
|
|
1745
|
+
x: z.number().finite(),
|
|
1746
|
+
y: z.number().finite(),
|
|
1747
|
+
z: z.number().finite(),
|
|
1748
|
+
})
|
|
1749
|
+
|
|
1750
|
+
/**
|
|
1751
|
+
* Arguments for {@linkcode PluginGeomCreateApi.brepFromFillet}.
|
|
1752
|
+
*
|
|
1753
|
+
* | Property | Type | Description |
|
|
1754
|
+
* |---|---|---|
|
|
1755
|
+
* | `brep` | {@linkcode BrepHandle} | The solid whose edges to round |
|
|
1756
|
+
* | `edges` | {@linkcode EdgeHandle}`[]` | The edges to fillet (one or more; more than 64 builds but carries no parameter record) |
|
|
1757
|
+
* | `radius` | `number` | Fillet radius (positive, finite); the start radius with `endRadius`, unused with `radii` |
|
|
1758
|
+
* | `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 |
|
|
1759
|
+
*/
|
|
1760
|
+
export const PluginGeomCreateBrepFromFilletArgs = z
|
|
1761
|
+
.object({
|
|
1762
|
+
brep: BrepHandle,
|
|
1763
|
+
edges: z.array(EdgeHandle).min(1),
|
|
1764
|
+
radius: z.number().finite().positive(),
|
|
1765
|
+
options: z
|
|
1766
|
+
.object({
|
|
1767
|
+
endRadius: z.number().finite().positive().optional(),
|
|
1768
|
+
radii: z
|
|
1769
|
+
.array(
|
|
1770
|
+
z.object({
|
|
1771
|
+
position: z.number().finite().min(0).max(1),
|
|
1772
|
+
radius: z.number().finite().positive(),
|
|
1773
|
+
}),
|
|
1774
|
+
)
|
|
1775
|
+
.min(2)
|
|
1776
|
+
.max(MAX_FILLET_LAW_SAMPLES)
|
|
1777
|
+
.optional(),
|
|
1778
|
+
})
|
|
1779
|
+
.optional(),
|
|
1780
|
+
})
|
|
1781
|
+
.superRefine((a, ctx) => {
|
|
1782
|
+
const { endRadius, radii } = a.options ?? {}
|
|
1783
|
+
if (endRadius === undefined && radii === undefined) return
|
|
1784
|
+
if (endRadius !== undefined && radii !== undefined) {
|
|
1785
|
+
ctx.addIssue({ code: "custom", message: "endRadius is mutually exclusive with radii" })
|
|
1786
|
+
}
|
|
1787
|
+
// The law belongs to the blend contour the one edge lies on, and `position`
|
|
1788
|
+
// is measured from that edge's start: a second edge would have no origin.
|
|
1789
|
+
if (a.edges.length !== 1) {
|
|
1790
|
+
ctx.addIssue({
|
|
1791
|
+
code: "custom",
|
|
1792
|
+
message: "a variable fillet takes exactly one edge — the blend contour it runs along",
|
|
1793
|
+
})
|
|
1794
|
+
}
|
|
1795
|
+
if (radii?.some((row, i) => i > 0 && row.position <= radii[i - 1].position)) {
|
|
1796
|
+
ctx.addIssue({ code: "custom", message: "radii positions must strictly increase" })
|
|
1797
|
+
}
|
|
1798
|
+
})
|
|
1799
|
+
|
|
1800
|
+
export type PluginGeomCreateBrepFromFilletArgs = z.infer<typeof PluginGeomCreateBrepFromFilletArgs>
|
|
1801
|
+
|
|
1802
|
+
/** An edge with the solid it belongs to. See {@linkcode OwnedEdge}. */
|
|
1803
|
+
export const OwnedEdge = z.object({
|
|
1804
|
+
edge: EdgeHandle,
|
|
1805
|
+
brep: BrepHandle,
|
|
1806
|
+
face: FaceHandle.optional(),
|
|
1807
|
+
})
|
|
1808
|
+
|
|
1809
|
+
/**
|
|
1810
|
+
* Arguments for {@linkcode PluginGeomCreateApi.brepFromPatch}.
|
|
1811
|
+
*
|
|
1812
|
+
* | Property | Type | Description |
|
|
1813
|
+
* |---|---|---|
|
|
1814
|
+
* | `boundary` | ({@linkcode CurveHandle} \| {@linkcode OwnedEdge})`[]` | 3..16 items forming one closed loop |
|
|
1815
|
+
* | `thickness` | `number` | Solid thickness in internal length units (positive, finite) |
|
|
1816
|
+
* | `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"`) |
|
|
1817
|
+
*/
|
|
1818
|
+
export const PluginGeomCreateBrepFromPatchArgs = z
|
|
1819
|
+
.object({
|
|
1820
|
+
boundary: z
|
|
1821
|
+
.array(z.union([CurveHandle, OwnedEdge]))
|
|
1822
|
+
.min(3)
|
|
1823
|
+
.max(MAX_PATCH_BOUNDARY_CURVES),
|
|
1824
|
+
thickness: z.number().finite().positive(),
|
|
1825
|
+
options: z
|
|
1826
|
+
.object({
|
|
1827
|
+
interiorPoints: z.array(FiniteVec3Components).max(MAX_PATCH_INTERIOR_POINTS).optional(),
|
|
1828
|
+
continuity: z.enum(["position", "tangent"]).optional(),
|
|
1829
|
+
side: z.enum(["below", "above"]).optional(),
|
|
1830
|
+
})
|
|
1831
|
+
.optional(),
|
|
1832
|
+
})
|
|
1833
|
+
.superRefine((a, ctx) => {
|
|
1834
|
+
if (a.options?.continuity !== "tangent") return
|
|
1835
|
+
// The kernel's filling call (`Add_2`) follows exactly ONE support face per
|
|
1836
|
+
// edge, but a solid edge touches two faces. So a tangent patch must say
|
|
1837
|
+
// which face to follow, for every item, and this is checked before the host
|
|
1838
|
+
// runs.
|
|
1839
|
+
if (a.boundary.some((item) => !("edge" in item) || item.face === undefined)) {
|
|
1840
|
+
ctx.addIssue({
|
|
1841
|
+
code: "custom",
|
|
1842
|
+
message:
|
|
1843
|
+
'continuity: "tangent" needs every boundary item to be an edge with its brep and the face to continue',
|
|
1844
|
+
})
|
|
1845
|
+
}
|
|
1846
|
+
})
|
|
1847
|
+
|
|
1848
|
+
export type PluginGeomCreateBrepFromPatchArgs = z.infer<typeof PluginGeomCreateBrepFromPatchArgs>
|
|
1849
|
+
|
|
1850
|
+
/**
|
|
1851
|
+
* Arguments for {@linkcode PluginGeomCreateApi.brepFromOffset}.
|
|
1852
|
+
*
|
|
1853
|
+
* | Property | Type | Description |
|
|
1854
|
+
* |---|---|---|
|
|
1855
|
+
* | `brep` | {@linkcode BrepHandle} | The solid to offset |
|
|
1856
|
+
* | `distance` | `number` | Offset distance (finite, non-zero; positive grows, negative shrinks) |
|
|
1857
|
+
*/
|
|
1858
|
+
export const PluginGeomCreateBrepFromOffsetArgs = z.object({
|
|
1859
|
+
brep: BrepHandle,
|
|
1860
|
+
distance: z
|
|
1861
|
+
.number()
|
|
1862
|
+
.finite()
|
|
1863
|
+
.refine((value) => value !== 0, { message: "distance must be non-zero" }),
|
|
1864
|
+
})
|
|
1865
|
+
|
|
1866
|
+
export type PluginGeomCreateBrepFromOffsetArgs = z.infer<typeof PluginGeomCreateBrepFromOffsetArgs>
|
|
1867
|
+
|
|
1868
|
+
/**
|
|
1869
|
+
* Arguments for {@linkcode PluginGeomCreateApi.brepFromShell}.
|
|
1870
|
+
*
|
|
1871
|
+
* | Property | Type | Description |
|
|
1872
|
+
* |---|---|---|
|
|
1873
|
+
* | `brep` | {@linkcode BrepHandle} | The solid to hollow |
|
|
1874
|
+
* | `openFaces` | {@linkcode FaceHandle}`[]` | The faces to remove as openings (one or more; more than 32 builds but carries no parameter record) |
|
|
1875
|
+
* | `thickness` | `number` | Wall thickness (positive, finite) |
|
|
1876
|
+
*/
|
|
1877
|
+
export const PluginGeomCreateBrepFromShellArgs = z.object({
|
|
1878
|
+
brep: BrepHandle,
|
|
1879
|
+
openFaces: z.array(FaceHandle).min(1),
|
|
1880
|
+
thickness: z.number().finite().positive(),
|
|
1881
|
+
})
|
|
1882
|
+
|
|
1883
|
+
export type PluginGeomCreateBrepFromShellArgs = z.infer<typeof PluginGeomCreateBrepFromShellArgs>
|
|
1884
|
+
|
|
1885
|
+
/**
|
|
1886
|
+
* Arguments for {@linkcode PluginGeomCreateApi.brepsFromSplit}.
|
|
1887
|
+
*
|
|
1888
|
+
* | Property | Type | Description |
|
|
1889
|
+
* |---|---|---|
|
|
1890
|
+
* | `brep` | {@linkcode BrepHandle} | The solid to split |
|
|
1891
|
+
* | `planeOrigin` | {@linkcode Vec3Components} | A point on the cutting plane (finite components) |
|
|
1892
|
+
* | `planeNormal` | {@linkcode Vec3Components} | The plane normal (non-zero, finite components) |
|
|
1893
|
+
*/
|
|
1894
|
+
export const PluginGeomCreateBrepsFromSplitArgs = z.object({
|
|
1895
|
+
brep: BrepHandle,
|
|
1896
|
+
planeOrigin: FiniteVec3Components,
|
|
1897
|
+
planeNormal: FiniteVec3Components,
|
|
1898
|
+
})
|
|
1899
|
+
|
|
1900
|
+
export type PluginGeomCreateBrepsFromSplitArgs = z.infer<typeof PluginGeomCreateBrepsFromSplitArgs>
|
|
1901
|
+
|
|
1902
|
+
/**
|
|
1903
|
+
* Arguments for {@linkcode PluginGeomCreateApi.brepsFromSplitByFace}.
|
|
1904
|
+
*
|
|
1905
|
+
* | Property | Type | Description |
|
|
1906
|
+
* |---|---|---|
|
|
1907
|
+
* | `brep` | {@linkcode BrepHandle} | The solid to cut |
|
|
1908
|
+
* | `toolFace` | {@linkcode FaceHandle} | The cutting face (read-only) |
|
|
1909
|
+
* | `toolBrep` | {@linkcode BrepHandle} | The solid `toolFace` belongs to (owner last) |
|
|
1910
|
+
*/
|
|
1911
|
+
export const PluginGeomCreateBrepsFromSplitByFaceArgs = z.object({
|
|
1912
|
+
brep: BrepHandle,
|
|
1913
|
+
toolFace: FaceHandle,
|
|
1914
|
+
toolBrep: BrepHandle,
|
|
1915
|
+
})
|
|
1916
|
+
|
|
1917
|
+
export type PluginGeomCreateBrepsFromSplitByFaceArgs = z.infer<
|
|
1918
|
+
typeof PluginGeomCreateBrepsFromSplitByFaceArgs
|
|
1919
|
+
>
|
|
1920
|
+
|
|
1921
|
+
/**
|
|
1922
|
+
* Arguments for {@linkcode PluginGeomCreateApi.curvesFromProjection}.
|
|
1923
|
+
*
|
|
1924
|
+
* | Property | Type | Description |
|
|
1925
|
+
* |---|---|---|
|
|
1926
|
+
* | `curve` | {@linkcode CurveHandle} | The curve to project |
|
|
1927
|
+
* | `face` | {@linkcode FaceHandle} | The face to project onto |
|
|
1928
|
+
* | `faceBrep` | {@linkcode BrepHandle} | The solid `face` belongs to (owner last) |
|
|
1929
|
+
*/
|
|
1930
|
+
export const PluginGeomCreateCurvesFromProjectionArgs = z.object({
|
|
1931
|
+
curve: CurveHandle,
|
|
1932
|
+
face: FaceHandle,
|
|
1933
|
+
faceBrep: BrepHandle,
|
|
1934
|
+
})
|
|
1935
|
+
|
|
1936
|
+
export type PluginGeomCreateCurvesFromProjectionArgs = z.infer<
|
|
1937
|
+
typeof PluginGeomCreateCurvesFromProjectionArgs
|
|
1938
|
+
>
|
|
1939
|
+
|
|
1940
|
+
/**
|
|
1941
|
+
* Arguments for {@linkcode PluginGeomCreateApi.brepFromChamfer}.
|
|
1942
|
+
*
|
|
1943
|
+
* | Property | Type | Description |
|
|
1944
|
+
* |---|---|---|
|
|
1945
|
+
* | `brep` | {@linkcode BrepHandle} | The solid whose edges to bevel |
|
|
1946
|
+
* | `edges` | {@linkcode EdgeHandle}`[]` | The edges to chamfer (one or more; more than 64 builds but carries no parameter record) |
|
|
1947
|
+
* | `distance` | `number` | Chamfer distance from the edge on each adjacent face (positive, finite) |
|
|
1948
|
+
*/
|
|
1949
|
+
export const PluginGeomCreateBrepFromChamferArgs = z.object({
|
|
1950
|
+
brep: BrepHandle,
|
|
1951
|
+
edges: z.array(EdgeHandle).min(1),
|
|
1952
|
+
distance: z.number().finite().positive(),
|
|
1953
|
+
})
|
|
1954
|
+
|
|
1955
|
+
export type PluginGeomCreateBrepFromChamferArgs = z.infer<
|
|
1956
|
+
typeof PluginGeomCreateBrepFromChamferArgs
|
|
1957
|
+
>
|
|
1958
|
+
|
|
1959
|
+
// Taper scale factor — bounded so a near-zero scale cannot pinch a section
|
|
1960
|
+
// into a degenerate sliver the downstream planarity gates would miss.
|
|
1961
|
+
const SweepScaleFactor = z.number().finite().min(1e-3).max(1e3)
|
|
1962
|
+
|
|
1963
|
+
/**
|
|
1964
|
+
* Arguments for {@linkcode PluginGeomCreateApi.brepFromSweep}.
|
|
1965
|
+
*
|
|
1966
|
+
* | Property | Type | Description |
|
|
1967
|
+
* |---|---|---|
|
|
1968
|
+
* | `profile` | {@linkcode ContourHandle} | The cross-section to sweep (hole-free) |
|
|
1969
|
+
* | `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) |
|
|
1970
|
+
* | `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) |
|
|
1971
|
+
*/
|
|
1972
|
+
export const PluginGeomCreateBrepFromSweepArgs = z
|
|
1973
|
+
.object({
|
|
1974
|
+
profile: ContourHandle,
|
|
1975
|
+
path: z.array(FiniteVec3Components).min(2),
|
|
1976
|
+
options: z
|
|
1977
|
+
.object({
|
|
1978
|
+
startScale: SweepScaleFactor.optional(),
|
|
1979
|
+
endScale: SweepScaleFactor.optional(),
|
|
1980
|
+
scales: z.array(SweepScaleFactor).optional(),
|
|
1981
|
+
transition: z
|
|
1982
|
+
.union([
|
|
1983
|
+
z.literal("miter"),
|
|
1984
|
+
z.literal("round"),
|
|
1985
|
+
z.object({ bevel: z.number().finite().min(1e-3).max(1e3) }),
|
|
1986
|
+
])
|
|
1987
|
+
.optional(),
|
|
1988
|
+
})
|
|
1989
|
+
.optional(),
|
|
1990
|
+
})
|
|
1991
|
+
.superRefine((a, ctx) => {
|
|
1992
|
+
const options = a.options
|
|
1993
|
+
if (!options || options.scales === undefined) return
|
|
1994
|
+
if (options.startScale !== undefined || options.endScale !== undefined) {
|
|
1995
|
+
ctx.addIssue({
|
|
1996
|
+
code: z.ZodIssueCode.custom,
|
|
1997
|
+
message: "scales is mutually exclusive with startScale/endScale",
|
|
1998
|
+
})
|
|
1999
|
+
}
|
|
2000
|
+
if (options.scales.length !== a.path.length) {
|
|
2001
|
+
ctx.addIssue({
|
|
2002
|
+
code: z.ZodIssueCode.custom,
|
|
2003
|
+
message: "scales must have exactly one entry per path point",
|
|
2004
|
+
})
|
|
2005
|
+
}
|
|
2006
|
+
})
|
|
2007
|
+
|
|
2008
|
+
export type PluginGeomCreateBrepFromSweepArgs = z.infer<typeof PluginGeomCreateBrepFromSweepArgs>
|
|
2009
|
+
|
|
2010
|
+
/**
|
|
2011
|
+
* Arguments for {@linkcode PluginGeomCreateApi.brepFromSweepAlongCurve}.
|
|
2012
|
+
*
|
|
2013
|
+
* | Property | Type | Description |
|
|
2014
|
+
* |---|---|---|
|
|
2015
|
+
* | `profile` | {@linkcode ContourHandle} | The cross-section to sweep (hole-free) |
|
|
2016
|
+
* | `path` | {@linkcode CurveHandle}`[]` | 1..64 curves, ordered, meeting end to end |
|
|
2017
|
+
* | `options` | `object`? | `orientation` — `"upright"` (default), `"frenet"` or `"fixed"`; `rail` — a second guide {@linkcode CurveHandle} |
|
|
2018
|
+
*/
|
|
2019
|
+
export const PluginGeomCreateBrepFromSweepAlongCurveArgs = z.object({
|
|
2020
|
+
profile: ContourHandle,
|
|
2021
|
+
path: z.array(CurveHandle).min(1).max(MAX_PATH_CURVES),
|
|
2022
|
+
options: z
|
|
2023
|
+
.object({
|
|
2024
|
+
orientation: z.enum(["frenet", "fixed", "upright"]).optional(),
|
|
2025
|
+
rail: CurveHandle.optional(),
|
|
2026
|
+
})
|
|
2027
|
+
.optional(),
|
|
2028
|
+
})
|
|
2029
|
+
|
|
2030
|
+
export type PluginGeomCreateBrepFromSweepAlongCurveArgs = z.infer<
|
|
2031
|
+
typeof PluginGeomCreateBrepFromSweepAlongCurveArgs
|
|
2032
|
+
>
|
|
2033
|
+
|
|
2034
|
+
/**
|
|
2035
|
+
* Arguments for {@linkcode PluginGeomCreateApi.brepFromRevolution}.
|
|
2036
|
+
*
|
|
2037
|
+
* | Property | Type | Description |
|
|
2038
|
+
* |---|---|---|
|
|
2039
|
+
* | `profile` | {@linkcode ContourHandle} | The cross-section to revolve (holes allowed) |
|
|
2040
|
+
* | `axisOrigin` | {@linkcode Vec3Components} | A point on the revolution axis (finite components; the axis must lie in the plane of the profile) |
|
|
2041
|
+
* | `axisDirection` | {@linkcode Vec3Components} | The axis direction (non-zero, finite components; the axis must lie in the plane of the profile) |
|
|
2042
|
+
* | `angleInDegrees` | `number`? | Revolution angle in degrees (0 < angle ≤ 360; default 360) |
|
|
2043
|
+
*/
|
|
2044
|
+
export const PluginGeomCreateBrepFromRevolutionArgs = z.object({
|
|
2045
|
+
profile: ContourHandle,
|
|
2046
|
+
axisOrigin: FiniteVec3Components,
|
|
2047
|
+
axisDirection: FiniteVec3Components,
|
|
2048
|
+
angleInDegrees: z.number().finite().positive().max(360).optional(),
|
|
2049
|
+
})
|
|
2050
|
+
|
|
2051
|
+
export type PluginGeomCreateBrepFromRevolutionArgs = z.infer<
|
|
2052
|
+
typeof PluginGeomCreateBrepFromRevolutionArgs
|
|
2053
|
+
>
|
|
2054
|
+
|
|
2055
|
+
/**
|
|
2056
|
+
* Arguments for {@linkcode PluginGeomCreateApi.brepFromSphere}.
|
|
2057
|
+
*
|
|
2058
|
+
* | Property | Type | Description |
|
|
2059
|
+
* |---|---|---|
|
|
2060
|
+
* | `centre` | {@linkcode Vec3Components} | Sphere centre (finite components) |
|
|
2061
|
+
* | `radius` | `number` | Sphere radius (finite; positivity is checked host-side so the error names the parameter) |
|
|
2062
|
+
*/
|
|
2063
|
+
export const PluginGeomCreateBrepFromSphereArgs = z.object({
|
|
2064
|
+
centre: FiniteVec3Components,
|
|
2065
|
+
radius: z.number().finite(),
|
|
2066
|
+
})
|
|
2067
|
+
|
|
2068
|
+
export type PluginGeomCreateBrepFromSphereArgs = z.infer<
|
|
2069
|
+
typeof PluginGeomCreateBrepFromSphereArgs
|
|
2070
|
+
>
|
|
2071
|
+
|
|
2072
|
+
/**
|
|
2073
|
+
* Arguments for {@linkcode PluginGeomCreateApi.brepFromCylinder}.
|
|
2074
|
+
*
|
|
2075
|
+
* | Property | Type | Description |
|
|
2076
|
+
* |---|---|---|
|
|
2077
|
+
* | `base` | {@linkcode Vec3Components} | Centre of the bottom cap (finite components) |
|
|
2078
|
+
* | `axis` | {@linkcode Vec3Components} | Axis direction (non-zero, finite components) |
|
|
2079
|
+
* | `radius` | `number` | Cylinder radius (finite, positive) |
|
|
2080
|
+
* | `height` | `number` | Height along `axis` (finite, positive) |
|
|
2081
|
+
*/
|
|
2082
|
+
export const PluginGeomCreateBrepFromCylinderArgs = z.object({
|
|
2083
|
+
base: FiniteVec3Components,
|
|
2084
|
+
axis: FiniteVec3Components,
|
|
2085
|
+
radius: z.number().finite(),
|
|
2086
|
+
height: z.number().finite(),
|
|
2087
|
+
})
|
|
2088
|
+
|
|
2089
|
+
export type PluginGeomCreateBrepFromCylinderArgs = z.infer<
|
|
2090
|
+
typeof PluginGeomCreateBrepFromCylinderArgs
|
|
2091
|
+
>
|
|
2092
|
+
|
|
2093
|
+
/**
|
|
2094
|
+
* Arguments for {@linkcode PluginGeomCreateApi.brepFromCone}.
|
|
2095
|
+
*
|
|
2096
|
+
* | Property | Type | Description |
|
|
2097
|
+
* |---|---|---|
|
|
2098
|
+
* | `base` | {@linkcode Vec3Components} | Centre of the bottom cap (finite components) |
|
|
2099
|
+
* | `axis` | {@linkcode Vec3Components} | Axis direction (non-zero, finite components) |
|
|
2100
|
+
* | `baseRadius` | `number` | Radius at the base (finite, positive) |
|
|
2101
|
+
* | `height` | `number` | Height along `axis` (finite, positive) |
|
|
2102
|
+
* | `topRadius` | `number`? | Radius at the top (finite, ≥ 0, ≠ `baseRadius`; default 0 = apex) |
|
|
2103
|
+
*/
|
|
2104
|
+
export const PluginGeomCreateBrepFromConeArgs = z
|
|
2105
|
+
.object({
|
|
2106
|
+
base: FiniteVec3Components,
|
|
2107
|
+
axis: FiniteVec3Components,
|
|
2108
|
+
baseRadius: z.number().finite(),
|
|
2109
|
+
height: z.number().finite(),
|
|
2110
|
+
topRadius: z.number().finite().optional(),
|
|
2111
|
+
})
|
|
2112
|
+
.refine((a) => (a.topRadius ?? 0) !== a.baseRadius, {
|
|
2113
|
+
message: "topRadius must differ from baseRadius — equal radii are a cylinder",
|
|
2114
|
+
})
|
|
2115
|
+
|
|
2116
|
+
export type PluginGeomCreateBrepFromConeArgs = z.infer<typeof PluginGeomCreateBrepFromConeArgs>
|
|
2117
|
+
|
|
2118
|
+
/**
|
|
2119
|
+
* Arguments for {@linkcode PluginGeomCreateApi.brepFromTorus}.
|
|
2120
|
+
*
|
|
2121
|
+
* | Property | Type | Description |
|
|
2122
|
+
* |---|---|---|
|
|
2123
|
+
* | `centre` | {@linkcode Vec3Components} | Torus centre (finite components) |
|
|
2124
|
+
* | `axis` | {@linkcode Vec3Components} | Plane normal of the ring (non-zero, finite components) |
|
|
2125
|
+
* | `majorRadius` | `number` | Ring radius, centre to tube centre (finite, positive) |
|
|
2126
|
+
* | `minorRadius` | `number` | Tube radius (finite, positive, strictly less than `majorRadius`) |
|
|
2127
|
+
*/
|
|
2128
|
+
export const PluginGeomCreateBrepFromTorusArgs = z
|
|
2129
|
+
.object({
|
|
2130
|
+
centre: FiniteVec3Components,
|
|
2131
|
+
axis: FiniteVec3Components,
|
|
2132
|
+
majorRadius: z.number().finite(),
|
|
2133
|
+
minorRadius: z.number().finite(),
|
|
2134
|
+
})
|
|
2135
|
+
.refine((a) => a.minorRadius < a.majorRadius, {
|
|
2136
|
+
message: "minorRadius must be smaller than majorRadius — the torus would self-intersect",
|
|
2137
|
+
})
|
|
2138
|
+
|
|
2139
|
+
export type PluginGeomCreateBrepFromTorusArgs = z.infer<typeof PluginGeomCreateBrepFromTorusArgs>
|