@snaptrude/plugin-core 0.0.0-dev-20260708130115 → 0.0.0-dev-20260827194031
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +152 -1
- package/api-manifest.json +3643 -276
- package/dist/api/analysis/daylight.d.ts +603 -0
- package/dist/api/analysis/daylight.d.ts.map +1 -0
- package/dist/api/analysis/heatmaps.d.ts +658 -0
- package/dist/api/analysis/heatmaps.d.ts.map +1 -0
- package/dist/api/analysis/illuminance.d.ts +145 -0
- package/dist/api/analysis/illuminance.d.ts.map +1 -0
- package/dist/api/analysis/index.d.ts +59 -0
- package/dist/api/analysis/index.d.ts.map +1 -0
- package/dist/api/analysis/shadows.d.ts +165 -0
- package/dist/api/analysis/shadows.d.ts.map +1 -0
- package/dist/api/analysis/solar.d.ts +249 -0
- package/dist/api/analysis/solar.d.ts.map +1 -0
- package/dist/api/analysis/sunlightHours.d.ts +208 -0
- package/dist/api/analysis/sunlightHours.d.ts.map +1 -0
- package/dist/api/analysis/sunpath.d.ts +80 -0
- package/dist/api/analysis/sunpath.d.ts.map +1 -0
- package/dist/api/analysis/weather.d.ts +193 -0
- package/dist/api/analysis/weather.d.ts.map +1 -0
- package/dist/api/core/camera/index.d.ts +261 -0
- package/dist/api/core/camera/index.d.ts.map +1 -0
- package/dist/api/core/comment/index.d.ts +105 -2
- package/dist/api/core/comment/index.d.ts.map +1 -1
- package/dist/api/core/geom/create/index.d.ts +840 -14
- package/dist/api/core/geom/create/index.d.ts.map +1 -1
- package/dist/api/core/geom/delete/index.d.ts +8 -2
- package/dist/api/core/geom/delete/index.d.ts.map +1 -1
- package/dist/api/core/geom/query/arc.d.ts +5 -5
- package/dist/api/core/geom/query/brep.d.ts +130 -18
- package/dist/api/core/geom/query/brep.d.ts.map +1 -1
- package/dist/api/core/geom/query/circle.d.ts +18 -18
- package/dist/api/core/geom/query/contour.d.ts +20 -20
- package/dist/api/core/geom/query/curve.d.ts +49 -49
- package/dist/api/core/geom/query/edge.d.ts +5 -5
- package/dist/api/core/geom/query/face.d.ts +16 -16
- package/dist/api/core/geom/query/halfedge.d.ts +8 -8
- package/dist/api/core/geom/query/profile.d.ts +19 -19
- package/dist/api/core/geom/query/vertex.d.ts +8 -8
- package/dist/api/core/geom/update/contour.d.ts +14 -14
- package/dist/api/core/geom/update/curve.d.ts +7 -7
- package/dist/api/core/geom/update/profile.d.ts +16 -16
- package/dist/api/core/handles/index.d.ts +210 -0
- package/dist/api/core/handles/index.d.ts.map +1 -0
- package/dist/api/core/index.d.ts +34 -0
- package/dist/api/core/index.d.ts.map +1 -1
- package/dist/api/core/io/export/index.d.ts +134 -0
- package/dist/api/core/io/export/index.d.ts.map +1 -0
- package/dist/api/core/io/import/index.d.ts +453 -0
- package/dist/api/core/io/import/index.d.ts.map +1 -0
- package/dist/api/core/io/index.d.ts +40 -0
- package/dist/api/core/io/index.d.ts.map +1 -0
- package/dist/api/core/io/job/index.d.ts +139 -0
- package/dist/api/core/io/job/index.d.ts.map +1 -0
- package/dist/api/core/io/query/index.d.ts +74 -0
- package/dist/api/core/io/query/index.d.ts.map +1 -0
- package/dist/api/core/io/terrain/index.d.ts +341 -0
- package/dist/api/core/io/terrain/index.d.ts.map +1 -0
- package/dist/api/core/io/underlay/index.d.ts +805 -0
- package/dist/api/core/io/underlay/index.d.ts.map +1 -0
- package/dist/api/core/layers.d.ts +7 -7
- package/dist/api/core/mode/index.d.ts +99 -0
- package/dist/api/core/mode/index.d.ts.map +1 -0
- package/dist/api/core/project/index.d.ts +68 -1
- package/dist/api/core/project/index.d.ts.map +1 -1
- package/dist/api/core/proposals/index.d.ts +531 -0
- package/dist/api/core/proposals/index.d.ts.map +1 -0
- package/dist/api/core/storeys/index.d.ts +265 -0
- package/dist/api/core/storeys/index.d.ts.map +1 -0
- package/dist/api/core/tags.d.ts +24 -0
- package/dist/api/core/tags.d.ts.map +1 -1
- package/dist/api/core/user.d.ts +44 -0
- package/dist/api/core/user.d.ts.map +1 -0
- package/dist/api/core/zoom/index.d.ts +4 -0
- package/dist/api/core/zoom/index.d.ts.map +1 -1
- package/dist/api/design/boolean/index.d.ts +4 -4
- package/dist/api/design/create/index.d.ts +568 -45
- package/dist/api/design/create/index.d.ts.map +1 -1
- package/dist/api/design/delete/index.d.ts +3 -0
- package/dist/api/design/delete/index.d.ts.map +1 -1
- package/dist/api/design/doors/index.d.ts +195 -0
- package/dist/api/design/doors/index.d.ts.map +1 -1
- package/dist/api/design/edit/index.d.ts +1 -1
- package/dist/api/design/erase/index.d.ts +2 -2
- package/dist/api/design/family.d.ts +493 -0
- package/dist/api/design/family.d.ts.map +1 -0
- package/dist/api/design/furniture/index.d.ts +181 -8
- package/dist/api/design/furniture/index.d.ts.map +1 -1
- package/dist/api/design/index.d.ts +98 -0
- package/dist/api/design/index.d.ts.map +1 -1
- package/dist/api/design/lock.d.ts +26 -0
- package/dist/api/design/lock.d.ts.map +1 -1
- package/dist/api/design/materials/index.d.ts +270 -16
- package/dist/api/design/materials/index.d.ts.map +1 -1
- package/dist/api/design/query/geometry/index.d.ts +112 -0
- package/dist/api/design/query/geometry/index.d.ts.map +1 -1
- package/dist/api/design/query/index.d.ts +289 -11
- package/dist/api/design/query/index.d.ts.map +1 -1
- package/dist/api/design/query/referenceLines.d.ts +45 -0
- package/dist/api/design/query/referenceLines.d.ts.map +1 -0
- package/dist/api/design/query/spaces.d.ts +181 -8
- package/dist/api/design/query/spaces.d.ts.map +1 -1
- package/dist/api/design/selection/index.d.ts +144 -0
- package/dist/api/design/selection/index.d.ts.map +1 -1
- package/dist/api/design/transform/index.d.ts +172 -10
- package/dist/api/design/transform/index.d.ts.map +1 -1
- package/dist/api/design/types/index.d.ts +181 -0
- package/dist/api/design/types/index.d.ts.map +1 -0
- package/dist/api/design/update/index.d.ts +553 -2
- package/dist/api/design/update/index.d.ts.map +1 -1
- package/dist/api/design/visibility.d.ts +126 -0
- package/dist/api/design/visibility.d.ts.map +1 -0
- package/dist/api/design/windows/index.d.ts +113 -2
- package/dist/api/design/windows/index.d.ts.map +1 -1
- package/dist/api/entity/buildableEnvelope.d.ts +4 -0
- package/dist/api/entity/buildableEnvelope.d.ts.map +1 -1
- package/dist/api/entity/referenceLine.d.ts +10 -2
- package/dist/api/entity/referenceLine.d.ts.map +1 -1
- package/dist/api/entity/space.d.ts +21 -21
- package/dist/api/entity/story.d.ts +242 -15
- package/dist/api/entity/story.d.ts.map +1 -1
- package/dist/api/index.d.ts +10 -0
- package/dist/api/index.d.ts.map +1 -1
- package/dist/api/presentation/aiInspiration.d.ts +25 -25
- package/dist/api/presentation/annotate.d.ts +467 -0
- package/dist/api/presentation/annotate.d.ts.map +1 -0
- package/dist/api/presentation/diagrams.d.ts +111 -8
- package/dist/api/presentation/diagrams.d.ts.map +1 -1
- package/dist/api/presentation/export.d.ts +108 -0
- package/dist/api/presentation/export.d.ts.map +1 -0
- package/dist/api/presentation/import.d.ts +55 -4
- package/dist/api/presentation/import.d.ts.map +1 -1
- package/dist/api/presentation/index.d.ts +58 -1
- package/dist/api/presentation/index.d.ts.map +1 -1
- package/dist/api/presentation/placedViews.d.ts +1139 -0
- package/dist/api/presentation/placedViews.d.ts.map +1 -0
- package/dist/api/presentation/shapes.d.ts +481 -0
- package/dist/api/presentation/shapes.d.ts.map +1 -0
- package/dist/api/presentation/sheets.d.ts +452 -13
- package/dist/api/presentation/sheets.d.ts.map +1 -1
- package/dist/api/presentation/slideshow.d.ts +125 -0
- package/dist/api/presentation/slideshow.d.ts.map +1 -0
- package/dist/api/presentation/tables.d.ts +81 -0
- package/dist/api/presentation/tables.d.ts.map +1 -0
- package/dist/api/presentation/views.d.ts +367 -7
- package/dist/api/presentation/views.d.ts.map +1 -1
- package/dist/api/program/areas.d.ts +102 -12
- package/dist/api/program/areas.d.ts.map +1 -1
- package/dist/api/program/cores.d.ts +3 -99
- package/dist/api/program/cores.d.ts.map +1 -1
- package/dist/api/program/index.d.ts +7 -15
- package/dist/api/program/index.d.ts.map +1 -1
- package/dist/api/program/layout.d.ts +346 -11
- package/dist/api/program/layout.d.ts.map +1 -1
- package/dist/api/program/site.d.ts +469 -13
- package/dist/api/program/site.d.ts.map +1 -1
- package/dist/api/program/spreadsheet.d.ts +365 -41
- package/dist/api/program/spreadsheet.d.ts.map +1 -1
- package/dist/api/workspace/index.d.ts +505 -0
- package/dist/api/workspace/index.d.ts.map +1 -0
- package/dist/errors/codes.d.ts +34 -0
- package/dist/errors/codes.d.ts.map +1 -0
- package/dist/errors/envelope.d.ts +56 -0
- package/dist/errors/envelope.d.ts.map +1 -0
- package/dist/errors/index.d.ts +6 -0
- package/dist/errors/index.d.ts.map +1 -0
- package/dist/errors/plugin-error.d.ts +69 -0
- package/dist/errors/plugin-error.d.ts.map +1 -0
- package/dist/handles.d.ts +97 -25
- package/dist/handles.d.ts.map +1 -1
- package/dist/host-utils.d.ts +4 -0
- package/dist/host-utils.d.ts.map +1 -1
- package/dist/index.cjs +4605 -1423
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4191 -1412
- package/dist/index.js.map +1 -1
- package/package.json +4 -2
- package/scripts/generate-manifest.mjs +45 -0
- package/scripts/generate-manifest.test.mjs +103 -4
- package/src/api/analysis/daylight.ts +470 -0
- package/src/api/analysis/heatmaps.ts +683 -0
- package/src/api/analysis/illuminance.ts +155 -0
- package/src/api/analysis/index.ts +61 -0
- package/src/api/analysis/shadows.ts +183 -0
- package/src/api/analysis/solar.ts +237 -0
- package/src/api/analysis/sunlightHours.ts +211 -0
- package/src/api/analysis/sunpath.ts +83 -0
- package/src/api/analysis/weather.ts +179 -0
- package/src/api/core/camera/index.ts +268 -0
- package/src/api/core/comment/index.ts +120 -2
- package/src/api/core/geom/create/index.ts +912 -1
- package/src/api/core/geom/delete/index.ts +6 -0
- package/src/api/core/geom/query/brep.ts +119 -0
- package/src/api/core/handles/index.ts +233 -0
- package/src/api/core/index.ts +34 -0
- package/src/api/core/io/export/index.ts +126 -0
- package/src/api/core/io/import/index.ts +496 -0
- package/src/api/core/io/index.ts +42 -0
- package/src/api/core/io/job/index.ts +140 -0
- package/src/api/core/io/query/index.ts +71 -0
- package/src/api/core/io/terrain/index.ts +360 -0
- package/src/api/core/io/underlay/index.ts +705 -0
- package/src/api/core/mode/index.ts +96 -0
- package/src/api/core/project/index.ts +62 -1
- package/src/api/core/proposals/index.ts +569 -0
- package/src/api/core/storeys/index.ts +294 -0
- package/src/api/core/tags.ts +27 -0
- package/src/api/core/user.ts +46 -0
- package/src/api/core/zoom/index.ts +4 -0
- package/src/api/design/create/index.ts +670 -30
- package/src/api/design/delete/index.ts +3 -0
- package/src/api/design/doors/index.ts +208 -0
- package/src/api/design/erase/index.ts +1 -1
- package/src/api/design/family.ts +544 -0
- package/src/api/design/furniture/index.ts +197 -8
- package/src/api/design/index.ts +102 -0
- package/src/api/design/lock.ts +27 -0
- package/src/api/design/materials/index.ts +334 -27
- package/src/api/design/query/geometry/index.ts +125 -3
- package/src/api/design/query/index.ts +219 -7
- package/src/api/design/query/referenceLines.ts +52 -0
- package/src/api/design/query/spaces.ts +143 -0
- package/src/api/design/selection/index.ts +129 -0
- package/src/api/design/transform/index.ts +170 -9
- package/src/api/design/types/index.ts +156 -0
- package/src/api/design/update/index.ts +631 -3
- package/src/api/design/visibility.ts +143 -0
- package/src/api/design/windows/index.ts +128 -2
- package/src/api/entity/buildableEnvelope.ts +4 -0
- package/src/api/entity/referenceLine.ts +8 -0
- package/src/api/entity/story.ts +259 -15
- package/src/api/index.ts +10 -0
- package/src/api/presentation/annotate.ts +385 -0
- package/src/api/presentation/diagrams.ts +118 -8
- package/src/api/presentation/export.ts +108 -0
- package/src/api/presentation/import.ts +51 -4
- package/src/api/presentation/index.ts +66 -1
- package/src/api/presentation/placedViews.ts +1120 -0
- package/src/api/presentation/shapes.ts +274 -0
- package/src/api/presentation/sheets.ts +400 -13
- package/src/api/presentation/slideshow.ts +134 -0
- package/src/api/presentation/tables.ts +84 -0
- package/src/api/presentation/views.ts +376 -8
- package/src/api/program/areas.ts +88 -15
- package/src/api/program/cores.ts +3 -91
- package/src/api/program/index.ts +7 -15
- package/src/api/program/layout.ts +365 -11
- package/src/api/program/site.ts +435 -13
- package/src/api/program/spreadsheet.ts +376 -35
- package/src/api/workspace/index.ts +563 -0
- package/src/errors/codes.ts +136 -0
- package/src/errors/envelope.ts +75 -0
- package/src/errors/index.ts +21 -0
- package/src/errors/plugin-error.ts +134 -0
- package/src/handles.ts +123 -13
- package/src/host-utils.ts +4 -0
- package/src/index.ts +1 -0
- package/test/errors.test.mjs +184 -0
- package/tsconfig.json +7 -2
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as z from "zod"
|
|
2
2
|
import { PluginApiReturn } from "../../../../types"
|
|
3
|
-
import { Vec3Handle, LineHandle, ArcHandle, CircleHandle, CurveHandle, ProfileHandle, ContourHandle } from "../../../../handles"
|
|
3
|
+
import { Vec3Handle, LineHandle, ArcHandle, CircleHandle, CurveHandle, ProfileHandle, ContourHandle, BrepHandle, FaceHandle, EdgeHandle, Vec3Components } from "../../../../handles"
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Curve creation — construct new geometric curves from point handles (all-handle
|
|
@@ -177,6 +177,653 @@ export abstract class PluginGeomCreateApi {
|
|
|
177
177
|
outer: ProfileHandle,
|
|
178
178
|
holes?: ProfileHandle[],
|
|
179
179
|
): PluginApiReturn<ContourHandle>
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Create a closed solid **B-rep** from explicit face loops. Host API call —
|
|
183
|
+
* returns a {@linkcode BrepHandle}. Faces are plain arrays of `{x, y, z}`
|
|
184
|
+
* point components, NOT point handles (bulk-data precedent:
|
|
185
|
+
* `design.query.geometry.getTriangulatedMeshes`), in raw Babylon units.
|
|
186
|
+
*
|
|
187
|
+
* Each face is one planar loop of at least 3 points; at least 4 faces are
|
|
188
|
+
* required. Loops may be authored in any consistent winding — the host
|
|
189
|
+
* validates edge coherence (every edge shared by exactly two faces, in
|
|
190
|
+
* opposite directions) and fixes the global orientation so faces point
|
|
191
|
+
* outward. Faces must be planar and the solid must be closed; holes in faces
|
|
192
|
+
* are not supported (v1).
|
|
193
|
+
*
|
|
194
|
+
* Inspect the result via `core.geom.query.brep.*`, or commit it to the scene
|
|
195
|
+
* with `design.create.massFromBrep`.
|
|
196
|
+
*
|
|
197
|
+
* @param faces Face loops — each an ordered array of `{x, y, z}` points (≥3 points per face, ≥4 faces)
|
|
198
|
+
* @returns The new solid as a {@linkcode BrepHandle}
|
|
199
|
+
* @throws if a face is degenerate or non-planar, an edge is not shared by
|
|
200
|
+
* exactly two faces (open shell, non-manifold, or inconsistent winding), or
|
|
201
|
+
* the faces do not form a valid closed solid
|
|
202
|
+
*
|
|
203
|
+
* @examplePrompt Create a brep from faces
|
|
204
|
+
* @examplePrompt Build a custom solid from a set of faces
|
|
205
|
+
* @examplePrompt Make a pyramid from triangular faces
|
|
206
|
+
*
|
|
207
|
+
* # Example
|
|
208
|
+
* ```ts
|
|
209
|
+
* // A pyramid: square base + 4 triangular sides
|
|
210
|
+
* const apex = { x: 0, y: 4, z: 0 }
|
|
211
|
+
* const a = { x: -2, y: 0, z: -2 }
|
|
212
|
+
* const b = { x: 2, y: 0, z: -2 }
|
|
213
|
+
* const c = { x: 2, y: 0, z: 2 }
|
|
214
|
+
* const d = { x: -2, y: 0, z: 2 }
|
|
215
|
+
* const brep = await snaptrude.core.geom.create.brepFromFaces([
|
|
216
|
+
* [a, d, c, b], // base
|
|
217
|
+
* [a, b, apex],
|
|
218
|
+
* [b, c, apex],
|
|
219
|
+
* [c, d, apex],
|
|
220
|
+
* [d, a, apex],
|
|
221
|
+
* ])
|
|
222
|
+
* const faceCount = await snaptrude.core.geom.query.brep.getFaceCount(brep) // 5
|
|
223
|
+
* ```
|
|
224
|
+
*/
|
|
225
|
+
public abstract brepFromFaces(faces: Vec3Components[][]): PluginApiReturn<BrepHandle>
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* Create a closed solid **B-rep** by extruding a contour along a direction.
|
|
229
|
+
* Host API call — returns a {@linkcode BrepHandle}. The direction is
|
|
230
|
+
* normalised by the host, so `amount` is the extrusion distance in raw
|
|
231
|
+
* Babylon units (negative extrudes the opposite way). The contour is copied —
|
|
232
|
+
* the input handle is never mutated. Holes and arc/circle profiles extrude
|
|
233
|
+
* natively (a circle profile yields a cylinder).
|
|
234
|
+
*
|
|
235
|
+
* Inspect the result via `core.geom.query.brep.*`, or commit it to the scene
|
|
236
|
+
* with `design.create.massFromBrep`.
|
|
237
|
+
*
|
|
238
|
+
* @param contour The cross-section to extrude (outer profile + optional holes)
|
|
239
|
+
* @param direction Extrusion direction as plain `{x, y, z}` components (non-zero, normalised by the host)
|
|
240
|
+
* @param amount Extrusion distance (non-zero; negative extrudes opposite to `direction`)
|
|
241
|
+
* @returns The new solid as a {@linkcode BrepHandle}
|
|
242
|
+
* @throws if the extrusion is degenerate (zero amount, zero direction, or a
|
|
243
|
+
* direction lying in the contour plane) or the contour cannot be extruded
|
|
244
|
+
* into a valid solid
|
|
245
|
+
*
|
|
246
|
+
* @examplePrompt Extrude this profile 3 metres up
|
|
247
|
+
* @examplePrompt Make a solid by extruding this outline
|
|
248
|
+
* @examplePrompt Create a cylinder from a circle profile
|
|
249
|
+
*
|
|
250
|
+
* # Example
|
|
251
|
+
* ```ts
|
|
252
|
+
* const rect = await snaptrude.core.geom.create.profileRect(4, 3)
|
|
253
|
+
* const contour = await snaptrude.core.geom.create.contourFromProfile(rect)
|
|
254
|
+
* const brep = await snaptrude.core.geom.create.brepFromExtrusion(contour, { x: 0, y: 1, z: 0 }, 3)
|
|
255
|
+
* const faceCount = await snaptrude.core.geom.query.brep.getFaceCount(brep) // 6
|
|
256
|
+
* ```
|
|
257
|
+
*/
|
|
258
|
+
public abstract brepFromExtrusion(
|
|
259
|
+
contour: ContourHandle,
|
|
260
|
+
direction: Vec3Components,
|
|
261
|
+
amount: number,
|
|
262
|
+
): PluginApiReturn<BrepHandle>
|
|
263
|
+
|
|
264
|
+
/**
|
|
265
|
+
* Create a closed solid **B-rep** by lofting between a bottom and a top
|
|
266
|
+
* contour, optionally through intermediate cross-sections. Host API call —
|
|
267
|
+
* returns a {@linkcode BrepHandle}. Sections with different edge counts are
|
|
268
|
+
* auto-matched: vertices are deterministically inserted on the smaller
|
|
269
|
+
* sections at the larger section's perimeter positions, so the same input
|
|
270
|
+
* always yields the same solid. For straight-edge (all-line) sections the
|
|
271
|
+
* seam is auto-aligned too — winding and start-vertex correspondence are
|
|
272
|
+
* chosen to avoid a twist, so outlines authored from any starting corner
|
|
273
|
+
* loft cleanly; arc-bearing sections keep the authored correspondence
|
|
274
|
+
* unchanged. A pair whose side faces would be non-planar under every
|
|
275
|
+
* correspondence still builds for hole-free straight-edged pairs — planar
|
|
276
|
+
* side quads stay quads and warped ones split into planar triangles (the
|
|
277
|
+
* triangulated lane); arc-bearing or holed twisted pairs are rejected, as is
|
|
278
|
+
* auto-matching that would pair an arc with a straight edge. Matching hole
|
|
279
|
+
* counts are allowed in the two-section form. With intermediates the loft
|
|
280
|
+
* is a chain of ruled segments folded into one solid: sections must be
|
|
281
|
+
* planar and hole-free, ordered bottom → intermediates → top. The contours
|
|
282
|
+
* are copied — the input handles are never mutated.
|
|
283
|
+
*
|
|
284
|
+
* Inspect the result via `core.geom.query.brep.*`, or commit it to the scene
|
|
285
|
+
* with `design.create.massFromBrep`.
|
|
286
|
+
*
|
|
287
|
+
* @param bottomContour The bottom cross-section
|
|
288
|
+
* @param topContour The top cross-section (edge count may differ from the
|
|
289
|
+
* bottom — sections are auto-matched)
|
|
290
|
+
* @param intermediateContours Optional in-between cross-sections, ordered
|
|
291
|
+
* bottom to top (hole-free; edge counts may differ — every section is
|
|
292
|
+
* normalized to the largest)
|
|
293
|
+
* @param options Optional behavior switches. `compatibility` — `"auto"`
|
|
294
|
+
* (default) inserts vertices to match differing edge counts; `"strict"`
|
|
295
|
+
* skips normalization and throws VALIDATION when outer edge counts (or,
|
|
296
|
+
* in the two-section form, hole-pair counts) differ. `seamAlignment` —
|
|
297
|
+
* `"auto"` (default) searches seam rotations on straight-edge sections to
|
|
298
|
+
* avoid a twist; `"authored"` keeps the authored start-vertex
|
|
299
|
+
* correspondence unchanged (a twisted correspondence then builds through
|
|
300
|
+
* the triangulated lane for hole-free straight-edged pairs).
|
|
301
|
+
* `{ compatibility: "strict", seamAlignment: "authored" }` reproduces
|
|
302
|
+
* pre-0.9.4 lofting exactly.
|
|
303
|
+
* @returns The new solid as a {@linkcode BrepHandle}
|
|
304
|
+
* @throws VALIDATION if the contours are coincident, their hole counts
|
|
305
|
+
* differ, any section has holes when intermediates are present
|
|
306
|
+
* (multi-section lofts take hole-free sections), a section is non-planar,
|
|
307
|
+
* sections are too dissimilar to auto-match, auto-matching would pair an
|
|
308
|
+
* arc with a straight edge, or — for arc-bearing or holed pairs only — no vertex correspondence avoids a twist (a
|
|
309
|
+
* side face between corresponding edges would be non-planar — the error
|
|
310
|
+
* names the offending sections); with `compatibility: "strict"`, if
|
|
311
|
+
* section edge counts (or hole-pair counts) differ — the error names the
|
|
312
|
+
* sections and counts and points at `compatibility: "auto"`
|
|
313
|
+
* @throws OPERATION_FAILED if the lofted segments cannot be joined into a
|
|
314
|
+
* valid solid
|
|
315
|
+
*
|
|
316
|
+
* @examplePrompt Make a tapered tower from these two outlines
|
|
317
|
+
* @examplePrompt Loft between a large base and a smaller top
|
|
318
|
+
* @examplePrompt Create a frustum from two squares
|
|
319
|
+
* @examplePrompt Loft the tower through these three floor outlines
|
|
320
|
+
* @examplePrompt Loft a four-sided base to a five-sided top
|
|
321
|
+
* @examplePrompt Loft these outlines even though their corners don't line up
|
|
322
|
+
* @examplePrompt Loft these outlines exactly as authored, corner to corner
|
|
323
|
+
* @examplePrompt Fail the loft if my sections don't have matching edge counts
|
|
324
|
+
*
|
|
325
|
+
* # Example
|
|
326
|
+
* ```ts
|
|
327
|
+
* // A square frustum: 4m base lofted to a 2m top, 3m up
|
|
328
|
+
* const base = await snaptrude.core.geom.create.profileRect(4, 4)
|
|
329
|
+
* const top = await snaptrude.core.geom.create.profileRect(2, 2, await snaptrude.core.math.vec3.new(0, 3, 0))
|
|
330
|
+
* const brep = await snaptrude.core.geom.create.brepFromLoft(
|
|
331
|
+
* await snaptrude.core.geom.create.contourFromProfile(base),
|
|
332
|
+
* await snaptrude.core.geom.create.contourFromProfile(top),
|
|
333
|
+
* )
|
|
334
|
+
* const faceCount = await snaptrude.core.geom.query.brep.getFaceCount(brep) // 6
|
|
335
|
+
* ```
|
|
336
|
+
*/
|
|
337
|
+
public abstract brepFromLoft(
|
|
338
|
+
bottomContour: ContourHandle,
|
|
339
|
+
topContour: ContourHandle,
|
|
340
|
+
intermediateContours?: ContourHandle[],
|
|
341
|
+
options?: { compatibility?: "strict" | "auto"; seamAlignment?: "authored" | "auto" },
|
|
342
|
+
): PluginApiReturn<BrepHandle>
|
|
343
|
+
|
|
344
|
+
/**
|
|
345
|
+
* Create a closed solid **B-rep** from indexed mesh data: a vertex position
|
|
346
|
+
* array plus face loops of indices into it. Host API call — returns a
|
|
347
|
+
* {@linkcode BrepHandle}. The indexed form of
|
|
348
|
+
* {@linkcode PluginGeomCreateApi.brepFromFaces} — same validation (planar
|
|
349
|
+
* faces, closed manifold solid, every edge shared by exactly two faces) after
|
|
350
|
+
* the indices are expanded to point loops.
|
|
351
|
+
*
|
|
352
|
+
* Inspect the result via `core.geom.query.brep.*`, or commit it to the scene
|
|
353
|
+
* with `design.create.massFromBrep`.
|
|
354
|
+
*
|
|
355
|
+
* @param positions Vertex positions as plain `{x, y, z}` components (≥4)
|
|
356
|
+
* @param faces Face loops — each an ordered array of indices into `positions` (≥3 indices per face, ≥4 faces)
|
|
357
|
+
* @returns The new solid as a {@linkcode BrepHandle}
|
|
358
|
+
* @throws if an index is not an integer within `positions` bounds, a face is
|
|
359
|
+
* degenerate or non-planar, or the faces do not form a valid closed solid
|
|
360
|
+
*
|
|
361
|
+
* @examplePrompt Create a brep from mesh vertices and indices
|
|
362
|
+
* @examplePrompt Turn this indexed mesh into a solid
|
|
363
|
+
* @examplePrompt Build a solid from vertex positions and face indices
|
|
364
|
+
*
|
|
365
|
+
* # Example
|
|
366
|
+
* ```ts
|
|
367
|
+
* // A tetrahedron from 4 vertices and 4 triangular faces
|
|
368
|
+
* const positions = [
|
|
369
|
+
* { x: 0, y: 0, z: 0 },
|
|
370
|
+
* { x: 4, y: 0, z: 0 },
|
|
371
|
+
* { x: 2, y: 0, z: 4 },
|
|
372
|
+
* { x: 2, y: 3, z: 1.5 },
|
|
373
|
+
* ]
|
|
374
|
+
* const brep = await snaptrude.core.geom.create.brepFromMesh(positions, [
|
|
375
|
+
* [0, 2, 1], // base
|
|
376
|
+
* [0, 1, 3],
|
|
377
|
+
* [1, 2, 3],
|
|
378
|
+
* [2, 0, 3],
|
|
379
|
+
* ])
|
|
380
|
+
* const vertexCount = await snaptrude.core.geom.query.brep.getVertexCount(brep) // 4
|
|
381
|
+
* ```
|
|
382
|
+
*/
|
|
383
|
+
public abstract brepFromMesh(
|
|
384
|
+
positions: Vec3Components[],
|
|
385
|
+
faces: number[][],
|
|
386
|
+
): PluginApiReturn<BrepHandle>
|
|
387
|
+
|
|
388
|
+
/**
|
|
389
|
+
* Create a closed solid **B-rep** as the boolean **union** of two breps
|
|
390
|
+
* (`a ∪ b`). Host API call — returns a new {@linkcode BrepHandle}. Inputs are
|
|
391
|
+
* read-only and may be authored breps (any `core.geom.create` brep
|
|
392
|
+
* constructor) or scene-derived breps from `design.query.geometry.getBrep`;
|
|
393
|
+
* coordinates are combined as-is, so both inputs must share a frame. The
|
|
394
|
+
* result must be a single solid — disjoint inputs are rejected.
|
|
395
|
+
*
|
|
396
|
+
* The first boolean call loads the OpenCascade geometry kernel (a wasm of
|
|
397
|
+
* tens of MB — expect a pause of seconds); subsequent calls are fast.
|
|
398
|
+
*
|
|
399
|
+
* @param a First solid
|
|
400
|
+
* @param b Second solid
|
|
401
|
+
* @returns The union as a new {@linkcode BrepHandle}
|
|
402
|
+
* @throws if the inputs do not overlap or touch (the union would be disjoint
|
|
403
|
+
* solids) or the result cannot be built as a valid single solid
|
|
404
|
+
*
|
|
405
|
+
* @examplePrompt Union these two solids
|
|
406
|
+
* @examplePrompt Merge these breps into one mass
|
|
407
|
+
* @examplePrompt Combine the tower and the podium into a single solid
|
|
408
|
+
*
|
|
409
|
+
* # Example
|
|
410
|
+
* ```ts
|
|
411
|
+
* const a = await snaptrude.core.geom.create.brepFromExtrusion(baseContour, { x: 0, y: 1, z: 0 }, 3)
|
|
412
|
+
* const b = await snaptrude.core.geom.create.brepFromExtrusion(overlappingContour, { x: 0, y: 1, z: 0 }, 5)
|
|
413
|
+
* const merged = await snaptrude.core.geom.create.brepFromUnion(a, b)
|
|
414
|
+
* ```
|
|
415
|
+
*/
|
|
416
|
+
public abstract brepFromUnion(a: BrepHandle, b: BrepHandle): PluginApiReturn<BrepHandle>
|
|
417
|
+
|
|
418
|
+
/**
|
|
419
|
+
* Create a closed solid **B-rep** as the boolean **subtraction** of two
|
|
420
|
+
* breps: **`a` minus `b`** — `b` is cut away from `a`. Host API call —
|
|
421
|
+
* returns a new {@linkcode BrepHandle}. Argument order matters:
|
|
422
|
+
* `brepFromSubtraction(a, b)` removes `b`'s volume from `a`. Inputs are
|
|
423
|
+
* read-only and may be authored or scene-derived breps (see
|
|
424
|
+
* {@linkcode PluginGeomCreateApi.brepFromUnion}); coordinates are combined
|
|
425
|
+
* as-is.
|
|
426
|
+
*
|
|
427
|
+
* The first boolean call loads the OpenCascade geometry kernel (a wasm of
|
|
428
|
+
* tens of MB — expect a pause of seconds); subsequent calls are fast.
|
|
429
|
+
*
|
|
430
|
+
* @param a The solid to subtract from
|
|
431
|
+
* @param b The solid to remove from `a`
|
|
432
|
+
* @returns `a` minus `b` as a new {@linkcode BrepHandle}
|
|
433
|
+
* @throws if `b` consumes `a` entirely (empty result), the result splits into
|
|
434
|
+
* disjoint solids, or it cannot be built as a valid single solid
|
|
435
|
+
*
|
|
436
|
+
* @examplePrompt Subtract the courtyard from the building mass
|
|
437
|
+
* @examplePrompt Cut this solid out of that one
|
|
438
|
+
* @examplePrompt Punch a hole through the slab with this box
|
|
439
|
+
*
|
|
440
|
+
* # Example
|
|
441
|
+
* ```ts
|
|
442
|
+
* // buildingBrep minus courtyardBrep — order matters
|
|
443
|
+
* const carved = await snaptrude.core.geom.create.brepFromSubtraction(buildingBrep, courtyardBrep)
|
|
444
|
+
* ```
|
|
445
|
+
*/
|
|
446
|
+
public abstract brepFromSubtraction(a: BrepHandle, b: BrepHandle): PluginApiReturn<BrepHandle>
|
|
447
|
+
|
|
448
|
+
/**
|
|
449
|
+
* Create a closed solid **B-rep** as the boolean **intersection** of two
|
|
450
|
+
* breps (`a ∩ b` — the shared volume only). Host API call — returns a new
|
|
451
|
+
* {@linkcode BrepHandle}. Inputs are read-only and may be authored or
|
|
452
|
+
* scene-derived breps (see {@linkcode PluginGeomCreateApi.brepFromUnion});
|
|
453
|
+
* coordinates are combined as-is.
|
|
454
|
+
*
|
|
455
|
+
* The first boolean call loads the OpenCascade geometry kernel (a wasm of
|
|
456
|
+
* tens of MB — expect a pause of seconds); subsequent calls are fast.
|
|
457
|
+
*
|
|
458
|
+
* @param a First solid
|
|
459
|
+
* @param b Second solid
|
|
460
|
+
* @returns The shared volume as a new {@linkcode BrepHandle}
|
|
461
|
+
* @throws if the inputs do not overlap (empty intersection), the result
|
|
462
|
+
* splits into disjoint solids, or it cannot be built as a valid single
|
|
463
|
+
* solid
|
|
464
|
+
*
|
|
465
|
+
* @examplePrompt Keep only the overlap of these two solids
|
|
466
|
+
* @examplePrompt Intersect these two masses
|
|
467
|
+
* @examplePrompt Clip the tower to the zoning envelope
|
|
468
|
+
*
|
|
469
|
+
* # Example
|
|
470
|
+
* ```ts
|
|
471
|
+
* const overlap = await snaptrude.core.geom.create.brepFromIntersection(towerBrep, envelopeBrep)
|
|
472
|
+
* ```
|
|
473
|
+
*/
|
|
474
|
+
public abstract brepFromIntersection(a: BrepHandle, b: BrepHandle): PluginApiReturn<BrepHandle>
|
|
475
|
+
|
|
476
|
+
/**
|
|
477
|
+
* Rounds the given straight edges of a solid with a constant radius. Host
|
|
478
|
+
* API call — returns a new {@linkcode BrepHandle}; the input brep is
|
|
479
|
+
* read-only.
|
|
480
|
+
*
|
|
481
|
+
* v1 fillets straight edges only, and no two filleted edges may share a
|
|
482
|
+
* vertex — corner blends produce spherical patches Snaptrude cannot
|
|
483
|
+
* represent. Runs on the OpenCascade kernel (the first kernel call loads a
|
|
484
|
+
* wasm of tens of MB — expect a pause of seconds).
|
|
485
|
+
*
|
|
486
|
+
* Inspect the result via `core.geom.query.brep.*`, or commit it to the scene
|
|
487
|
+
* with `design.create.massFromBrep`.
|
|
488
|
+
*
|
|
489
|
+
* @param brep The solid whose edges to round
|
|
490
|
+
* @param edges The straight edges to fillet (≥1, all on `brep`, no two sharing a vertex)
|
|
491
|
+
* @param radius Fillet radius (positive, finite)
|
|
492
|
+
* @returns The filleted solid as a new {@linkcode BrepHandle}
|
|
493
|
+
* @throws VALIDATION if `edges` is empty, `radius` is not a positive finite
|
|
494
|
+
* number, an edge is not on `brep`, an edge is an arc (v1 fillets straight
|
|
495
|
+
* edges only), or two edges share a vertex (fillet non-adjacent edges)
|
|
496
|
+
* @throws OPERATION_FAILED if the kernel cannot build the fillet (the radius
|
|
497
|
+
* likely exceeds the adjacent face size — reduce it) or the result
|
|
498
|
+
* contains curved surfaces Snaptrude cannot represent
|
|
499
|
+
*
|
|
500
|
+
* @examplePrompt Round the edges of this mass
|
|
501
|
+
* @examplePrompt Fillet the corners of the podium with a 0.5m radius
|
|
502
|
+
* @examplePrompt Soften the vertical edges of this tower
|
|
503
|
+
*
|
|
504
|
+
* # Example
|
|
505
|
+
* ```ts
|
|
506
|
+
* const brep = await snaptrude.core.geom.create.brepFromExtrusion(contour, { x: 0, y: 1, z: 0 }, 3)
|
|
507
|
+
* const edges = await snaptrude.core.geom.query.brep.listEdges(brep)
|
|
508
|
+
* const rounded = await snaptrude.core.geom.create.brepFromFillet(brep, [edges[0]], 0.3)
|
|
509
|
+
* ```
|
|
510
|
+
*/
|
|
511
|
+
public abstract brepFromFillet(
|
|
512
|
+
brep: BrepHandle,
|
|
513
|
+
edges: EdgeHandle[],
|
|
514
|
+
radius: number,
|
|
515
|
+
): PluginApiReturn<BrepHandle>
|
|
516
|
+
|
|
517
|
+
/**
|
|
518
|
+
* Grows or shrinks a solid by offsetting every face — positive distance
|
|
519
|
+
* moves faces outward, negative moves them inward. Host API call — returns
|
|
520
|
+
* a new {@linkcode BrepHandle}; the input brep is read-only.
|
|
521
|
+
*
|
|
522
|
+
* Runs on the OpenCascade kernel (the first kernel call loads a wasm of
|
|
523
|
+
* tens of MB — expect a pause of seconds).
|
|
524
|
+
*
|
|
525
|
+
* Inspect the result via `core.geom.query.brep.*`, or commit it to the scene
|
|
526
|
+
* with `design.create.massFromBrep`.
|
|
527
|
+
*
|
|
528
|
+
* @param brep The solid to offset
|
|
529
|
+
* @param distance Offset distance (finite, non-zero; positive grows, negative shrinks)
|
|
530
|
+
* @returns The offset solid as a new {@linkcode BrepHandle}
|
|
531
|
+
* @throws VALIDATION if `distance` is not finite, is too small to offset
|
|
532
|
+
* anything, or an inward distance consumes the solid entirely
|
|
533
|
+
* @throws OPERATION_FAILED if the kernel cannot build the offset or the
|
|
534
|
+
* result contains curved surfaces Snaptrude cannot represent
|
|
535
|
+
*
|
|
536
|
+
* @examplePrompt Grow this solid by 0.5m in every direction
|
|
537
|
+
* @examplePrompt Shrink this mass by 200mm
|
|
538
|
+
* @examplePrompt Offset the building envelope outward by 1m
|
|
539
|
+
*
|
|
540
|
+
* # Example
|
|
541
|
+
* ```ts
|
|
542
|
+
* const brep = await snaptrude.core.geom.create.brepFromExtrusion(contour, { x: 0, y: 1, z: 0 }, 3)
|
|
543
|
+
* const grown = await snaptrude.core.geom.create.brepFromOffset(brep, 0.5)
|
|
544
|
+
* ```
|
|
545
|
+
*/
|
|
546
|
+
public abstract brepFromOffset(brep: BrepHandle, distance: number): PluginApiReturn<BrepHandle>
|
|
547
|
+
|
|
548
|
+
/**
|
|
549
|
+
* Hollows a solid into constant-thickness walls, removing the given faces
|
|
550
|
+
* as openings. Host API call — returns a new {@linkcode BrepHandle}; the
|
|
551
|
+
* input brep is read-only. The outer surface is kept and the walls grow
|
|
552
|
+
* inward.
|
|
553
|
+
*
|
|
554
|
+
* Runs on the OpenCascade kernel (the first kernel call loads a wasm of
|
|
555
|
+
* tens of MB — expect a pause of seconds).
|
|
556
|
+
*
|
|
557
|
+
* Inspect the result via `core.geom.query.brep.*`, or commit it to the scene
|
|
558
|
+
* with `design.create.massFromBrep`.
|
|
559
|
+
*
|
|
560
|
+
* @param brep The solid to hollow
|
|
561
|
+
* @param openFaces The faces to remove as openings (≥1, all on `brep`)
|
|
562
|
+
* @param thickness Wall thickness (positive, finite, smaller than half the solid's smallest span)
|
|
563
|
+
* @returns The hollowed solid as a new {@linkcode BrepHandle}
|
|
564
|
+
* @throws VALIDATION if `openFaces` is empty, a face is not on `brep`,
|
|
565
|
+
* `thickness` is not a positive finite number, or the thickness is too
|
|
566
|
+
* large (it must be smaller than half the solid's smallest span)
|
|
567
|
+
* @throws OPERATION_FAILED if the kernel cannot build the shell or the
|
|
568
|
+
* result contains curved surfaces Snaptrude cannot represent
|
|
569
|
+
*
|
|
570
|
+
* @examplePrompt Hollow this mass into 200mm walls
|
|
571
|
+
* @examplePrompt Shell this form with the top face open
|
|
572
|
+
* @examplePrompt Turn this solid tower into a tube open at both ends
|
|
573
|
+
*
|
|
574
|
+
* # Example
|
|
575
|
+
* ```ts
|
|
576
|
+
* const brep = await snaptrude.core.geom.create.brepFromExtrusion(contour, { x: 0, y: 1, z: 0 }, 3)
|
|
577
|
+
* const faces = await snaptrude.core.geom.query.brep.listFaces(brep)
|
|
578
|
+
* const hollow = await snaptrude.core.geom.create.brepFromShell(brep, [faces[0]], 0.2)
|
|
579
|
+
* ```
|
|
580
|
+
*/
|
|
581
|
+
public abstract brepFromShell(
|
|
582
|
+
brep: BrepHandle,
|
|
583
|
+
openFaces: FaceHandle[],
|
|
584
|
+
thickness: number,
|
|
585
|
+
): PluginApiReturn<BrepHandle>
|
|
586
|
+
|
|
587
|
+
/**
|
|
588
|
+
* Cuts a solid by an infinite plane and returns one brep per resulting
|
|
589
|
+
* piece — a single piece if the plane misses the solid. Host API call —
|
|
590
|
+
* returns new {@linkcode BrepHandle}s; the input brep is read-only. The
|
|
591
|
+
* plane is defined by a point on it and its normal direction.
|
|
592
|
+
*
|
|
593
|
+
* Runs on the OpenCascade kernel (the first kernel call loads a wasm of
|
|
594
|
+
* tens of MB — expect a pause of seconds).
|
|
595
|
+
*
|
|
596
|
+
* Inspect each result via `core.geom.query.brep.*`, or commit them to the
|
|
597
|
+
* scene with `design.create.massFromBrep`.
|
|
598
|
+
*
|
|
599
|
+
* @param brep The solid to split
|
|
600
|
+
* @param planeOrigin A point on the cutting plane as plain `{x, y, z}` components
|
|
601
|
+
* @param planeNormal The plane normal as plain `{x, y, z}` components (non-zero)
|
|
602
|
+
* @returns The resulting pieces as {@linkcode BrepHandle}`[]` (one per solid)
|
|
603
|
+
* @throws VALIDATION if `planeNormal` is zero-length or the origin/normal
|
|
604
|
+
* components are not finite
|
|
605
|
+
* @throws OPERATION_FAILED if the kernel cannot split the solid
|
|
606
|
+
*
|
|
607
|
+
* @examplePrompt Cut this building at 12m height
|
|
608
|
+
* @examplePrompt Split the tower from the podium with a horizontal plane
|
|
609
|
+
* @examplePrompt Slice this mass along a vertical plane
|
|
610
|
+
*
|
|
611
|
+
* # Example
|
|
612
|
+
* ```ts
|
|
613
|
+
* const pieces = await snaptrude.core.geom.create.brepsFromSplit(
|
|
614
|
+
* towerBrep,
|
|
615
|
+
* { x: 0, y: 12, z: 0 },
|
|
616
|
+
* { x: 0, y: 1, z: 0 },
|
|
617
|
+
* )
|
|
618
|
+
* console.log("pieces:", pieces.length)
|
|
619
|
+
* ```
|
|
620
|
+
*/
|
|
621
|
+
public abstract brepsFromSplit(
|
|
622
|
+
brep: BrepHandle,
|
|
623
|
+
planeOrigin: Vec3Components,
|
|
624
|
+
planeNormal: Vec3Components,
|
|
625
|
+
): PluginApiReturn<BrepHandle[]>
|
|
626
|
+
|
|
627
|
+
/**
|
|
628
|
+
* Bevels the given straight edges of a solid with a symmetric planar cut.
|
|
629
|
+
* Host API call — returns a new {@linkcode BrepHandle}; the input brep is
|
|
630
|
+
* read-only.
|
|
631
|
+
*
|
|
632
|
+
* v1 chamfers straight edges only, and no two chamfered edges may share a
|
|
633
|
+
* vertex. Runs on the OpenCascade kernel (the first kernel call loads a
|
|
634
|
+
* wasm of tens of MB — expect a pause of seconds).
|
|
635
|
+
*
|
|
636
|
+
* Inspect the result via `core.geom.query.brep.*`, or commit it to the scene
|
|
637
|
+
* with `design.create.massFromBrep`.
|
|
638
|
+
*
|
|
639
|
+
* @param brep The solid whose edges to bevel
|
|
640
|
+
* @param edges The straight edges to chamfer (≥1, all on `brep`, no two sharing a vertex)
|
|
641
|
+
* @param distance Chamfer distance from the edge on each adjacent face (positive, finite)
|
|
642
|
+
* @returns The chamfered solid as a new {@linkcode BrepHandle}
|
|
643
|
+
* @throws VALIDATION if `edges` is empty, `distance` is not a positive
|
|
644
|
+
* finite number, an edge is not on `brep`, an edge is an arc (v1 chamfers
|
|
645
|
+
* straight edges only), or two edges share a vertex (chamfer non-adjacent
|
|
646
|
+
* edges)
|
|
647
|
+
* @throws OPERATION_FAILED if the kernel cannot build the chamfer (the
|
|
648
|
+
* distance likely exceeds the adjacent face size — reduce it)
|
|
649
|
+
*
|
|
650
|
+
* @examplePrompt Bevel these edges by 100mm
|
|
651
|
+
* @examplePrompt Chamfer the top edges of the plinth
|
|
652
|
+
* @examplePrompt Cut a 45-degree flat along the corners of this mass
|
|
653
|
+
*
|
|
654
|
+
* # Example
|
|
655
|
+
* ```ts
|
|
656
|
+
* const brep = await snaptrude.core.geom.create.brepFromExtrusion(contour, { x: 0, y: 1, z: 0 }, 3)
|
|
657
|
+
* const edges = await snaptrude.core.geom.query.brep.listEdges(brep)
|
|
658
|
+
* const beveled = await snaptrude.core.geom.create.brepFromChamfer(brep, [edges[0]], 0.1)
|
|
659
|
+
* ```
|
|
660
|
+
*/
|
|
661
|
+
public abstract brepFromChamfer(
|
|
662
|
+
brep: BrepHandle,
|
|
663
|
+
edges: EdgeHandle[],
|
|
664
|
+
distance: number,
|
|
665
|
+
): PluginApiReturn<BrepHandle>
|
|
666
|
+
|
|
667
|
+
/**
|
|
668
|
+
* Sweeps a planar profile along a polyline path, with mitred corners at
|
|
669
|
+
* each bend. Host API call — returns a new {@linkcode BrepHandle}; the
|
|
670
|
+
* input contour is read-only. The profile must be hole-free and must not
|
|
671
|
+
* lie in a plane containing the first path segment's direction. Repeating
|
|
672
|
+
* the first point as the last closes the path into a ring solid (a picture
|
|
673
|
+
* frame): closed paths must be flat and straight-segmented and take a
|
|
674
|
+
* straight-edged (arc-free) profile — the ring's cross-section is the
|
|
675
|
+
* authored profile projected along the first leg onto the first mitre
|
|
676
|
+
* plane, so a profile not perpendicular to the first leg appears sheared.
|
|
677
|
+
* An optional scale law tapers the sweep: `startScale`/`endScale`
|
|
678
|
+
* interpolate linearly by arc length, or `scales` gives one factor per path
|
|
679
|
+
* point (scaling is about the profile centroid). A uniform scale (all
|
|
680
|
+
* factors equal) works on any path today's sweep accepts; a varying scale
|
|
681
|
+
* takes straight (collinear) open paths with straight-edged profiles —
|
|
682
|
+
* tapering across a bend or along an arc edge would create faces Snaptrude
|
|
683
|
+
* cannot represent and throws (sweep each straight run separately and union
|
|
684
|
+
* the results instead). An optional `transition` picks the corner
|
|
685
|
+
* treatment: `"miter"` (default) is today's sharp mitred bend;
|
|
686
|
+
* `{ bevel: b }` chamfers each turning corner by cutting `b` back along
|
|
687
|
+
* both adjacent legs (works on open and closed paths — each leg must be
|
|
688
|
+
* long enough for its cuts). On a corner-less path `transition` has no effect, and the
|
|
689
|
+
* varying-scale lane takes straight paths, so it never sees a corner.
|
|
690
|
+
*
|
|
691
|
+
* Open paths run on the OpenCascade kernel (the first kernel call loads a
|
|
692
|
+
* wasm of tens of MB — expect a pause of seconds); closed paths are
|
|
693
|
+
* computed host-side and never load the kernel.
|
|
694
|
+
*
|
|
695
|
+
* Inspect the result via `core.geom.query.brep.*`, or commit it to the scene
|
|
696
|
+
* with `design.create.massFromBrep`.
|
|
697
|
+
*
|
|
698
|
+
* @param profile The cross-section to sweep (hole-free contour)
|
|
699
|
+
* @param path The polyline path as plain `{x, y, z}` points (≥2; repeat the
|
|
700
|
+
* first point as the last to close the path into a ring)
|
|
701
|
+
* @param options Optional scale law and corner transition. Scale law:
|
|
702
|
+
* `startScale`/`endScale` (linear taper by arc length) or `scales` (one
|
|
703
|
+
* factor per path point; mutually exclusive with
|
|
704
|
+
* `startScale`/`endScale`); every factor must be finite and within
|
|
705
|
+
* 1e-3..1e3. `transition`: `"miter"` (default, sharp corners) or
|
|
706
|
+
* `{ bevel: b }` (chamfered corners, `b` finite within 1e-3..1e3; open
|
|
707
|
+
* and closed paths)
|
|
708
|
+
* @returns The swept solid as a new {@linkcode BrepHandle}
|
|
709
|
+
* @throws VALIDATION if the profile has holes, the path has fewer than 2
|
|
710
|
+
* points, consecutive path points coincide, a coordinate is not finite,
|
|
711
|
+
* or the profile plane contains the first path segment's direction
|
|
712
|
+
* (degenerate sweep); for closed paths, if the ring has fewer than 3
|
|
713
|
+
* distinct corners, the path is non-planar, a corner doubles back, the
|
|
714
|
+
* profile has an arc edge, or the profile is too large for a mitred
|
|
715
|
+
* corner; for scale options, if a factor is outside 1e-3..1e3, `scales`
|
|
716
|
+
* is combined with `startScale`/`endScale`, `scales` does not match the
|
|
717
|
+
* path length, or a varying scale is used on a bent or closed path or
|
|
718
|
+
* with an arc-edged profile; for `{ bevel }`, if a leg is too short for
|
|
719
|
+
* the cuts its beveled corners take from it or a corner nearly doubles
|
|
720
|
+
* back so its chamfer collapses (the errors name the corner)
|
|
721
|
+
* @throws OPERATION_FAILED if the kernel cannot sweep the profile into a
|
|
722
|
+
* valid solid or a transition patch is a curved surface Snaptrude cannot
|
|
723
|
+
* represent
|
|
724
|
+
*
|
|
725
|
+
* @examplePrompt Sweep this profile along the corridor path
|
|
726
|
+
* @examplePrompt Extrude the railing section along this route
|
|
727
|
+
* @examplePrompt Run a duct profile through these points
|
|
728
|
+
* @examplePrompt Sweep a frame profile around a closed rectangular loop
|
|
729
|
+
* @examplePrompt Taper this duct from 1x1 to 2x2 along its run
|
|
730
|
+
* @examplePrompt Sweep a column section that narrows toward the top
|
|
731
|
+
* @examplePrompt Chamfer the corners of this swept frame by 200mm
|
|
732
|
+
*
|
|
733
|
+
* # Example
|
|
734
|
+
* ```ts
|
|
735
|
+
* const rect = await snaptrude.core.geom.create.profileRect(0.4, 0.4)
|
|
736
|
+
* const profile = await snaptrude.core.geom.create.contourFromProfile(rect)
|
|
737
|
+
* // profileRect lies in the XZ plane, so the path must START out of that
|
|
738
|
+
* // plane (here: straight up), then it can run horizontally.
|
|
739
|
+
* const duct = await snaptrude.core.geom.create.brepFromSweep(profile, [
|
|
740
|
+
* { x: 0, y: 0, z: 0 },
|
|
741
|
+
* { x: 0, y: 2.8, z: 0 },
|
|
742
|
+
* { x: 10, y: 2.8, z: 0 },
|
|
743
|
+
* ])
|
|
744
|
+
* // A closed ring (picture frame): repeat the first point as the last
|
|
745
|
+
* const frame = await snaptrude.core.geom.create.brepFromSweep(profile, [
|
|
746
|
+
* { x: 0, y: 0, z: 0 },
|
|
747
|
+
* { x: 0, y: 3, z: 0 },
|
|
748
|
+
* { x: 4, y: 3, z: 0 },
|
|
749
|
+
* { x: 4, y: 0, z: 0 },
|
|
750
|
+
* { x: 0, y: 0, z: 0 },
|
|
751
|
+
* ])
|
|
752
|
+
* // A tapered straight run: 0.4x0.4 at the start, 0.8x0.8 at the end
|
|
753
|
+
* const flue = await snaptrude.core.geom.create.brepFromSweep(
|
|
754
|
+
* profile,
|
|
755
|
+
* [
|
|
756
|
+
* { x: 0, y: 0, z: 0 },
|
|
757
|
+
* { x: 0, y: 10, z: 0 },
|
|
758
|
+
* ],
|
|
759
|
+
* { startScale: 1, endScale: 2 },
|
|
760
|
+
* )
|
|
761
|
+
* ```
|
|
762
|
+
*/
|
|
763
|
+
public abstract brepFromSweep(
|
|
764
|
+
profile: ContourHandle,
|
|
765
|
+
path: Vec3Components[],
|
|
766
|
+
options?: {
|
|
767
|
+
startScale?: number
|
|
768
|
+
endScale?: number
|
|
769
|
+
scales?: number[]
|
|
770
|
+
transition?: "miter" | { bevel: number }
|
|
771
|
+
},
|
|
772
|
+
): PluginApiReturn<BrepHandle>
|
|
773
|
+
|
|
774
|
+
/**
|
|
775
|
+
* Revolves a planar profile about an axis to make a solid of revolution — a
|
|
776
|
+
* full turn by default. Host API call — returns a new
|
|
777
|
+
* {@linkcode BrepHandle}; the input contour is read-only. Holes in the
|
|
778
|
+
* profile are allowed. Profile segments must stay parallel or perpendicular
|
|
779
|
+
* to the axis — inclined or arc segments would revolve into surfaces
|
|
780
|
+
* Snaptrude cannot represent.
|
|
781
|
+
*
|
|
782
|
+
* Runs on the OpenCascade kernel (the first kernel call loads a wasm of
|
|
783
|
+
* tens of MB — expect a pause of seconds).
|
|
784
|
+
*
|
|
785
|
+
* Inspect the result via `core.geom.query.brep.*`, or commit it to the scene
|
|
786
|
+
* with `design.create.massFromBrep`.
|
|
787
|
+
*
|
|
788
|
+
* @param profile The cross-section to revolve (planar contour, holes allowed)
|
|
789
|
+
* @param axisOrigin A point on the revolution axis as plain `{x, y, z}` components
|
|
790
|
+
* @param axisDirection The axis direction as plain `{x, y, z}` components (non-zero)
|
|
791
|
+
* @param angleInDegrees Optional revolution angle in degrees (0 < angle ≤ 360; default 360)
|
|
792
|
+
* @returns The revolved solid as a new {@linkcode BrepHandle}
|
|
793
|
+
* @throws VALIDATION if `axisDirection` is zero-length, `angleInDegrees` is
|
|
794
|
+
* not in (0, 360], the axis passes through the profile interior, or a
|
|
795
|
+
* coordinate is not finite
|
|
796
|
+
* @throws OPERATION_FAILED if the kernel cannot revolve the profile or the
|
|
797
|
+
* result contains curved surfaces Snaptrude cannot represent (keep
|
|
798
|
+
* profile segments parallel or perpendicular to the axis)
|
|
799
|
+
*
|
|
800
|
+
* @examplePrompt Create a dome from this section
|
|
801
|
+
* @examplePrompt Revolve this profile 360 degrees around the vertical axis
|
|
802
|
+
* @examplePrompt Build a rotunda by revolving this wall section
|
|
803
|
+
*
|
|
804
|
+
* # Example
|
|
805
|
+
* ```ts
|
|
806
|
+
* // A cylinder: revolve a 2m-wide, 3m-tall rectangle about the Y axis at its edge
|
|
807
|
+
* const rect = await snaptrude.core.geom.create.profileFromLinePoints([
|
|
808
|
+
* await snaptrude.core.math.vec3.new(0, 0, 0),
|
|
809
|
+
* await snaptrude.core.math.vec3.new(2, 0, 0),
|
|
810
|
+
* await snaptrude.core.math.vec3.new(2, 3, 0),
|
|
811
|
+
* await snaptrude.core.math.vec3.new(0, 3, 0),
|
|
812
|
+
* ])
|
|
813
|
+
* const profile = await snaptrude.core.geom.create.contourFromProfile(rect)
|
|
814
|
+
* const cylinder = await snaptrude.core.geom.create.brepFromRevolution(
|
|
815
|
+
* profile,
|
|
816
|
+
* { x: 0, y: 0, z: 0 },
|
|
817
|
+
* { x: 0, y: 1, z: 0 },
|
|
818
|
+
* )
|
|
819
|
+
* ```
|
|
820
|
+
*/
|
|
821
|
+
public abstract brepFromRevolution(
|
|
822
|
+
profile: ContourHandle,
|
|
823
|
+
axisOrigin: Vec3Components,
|
|
824
|
+
axisDirection: Vec3Components,
|
|
825
|
+
angleInDegrees?: number,
|
|
826
|
+
): PluginApiReturn<BrepHandle>
|
|
180
827
|
}
|
|
181
828
|
|
|
182
829
|
/**
|
|
@@ -291,3 +938,267 @@ export const PluginGeomCreateContourFromProfilesArgs = z.object({
|
|
|
291
938
|
export type PluginGeomCreateContourFromProfilesArgs = z.infer<
|
|
292
939
|
typeof PluginGeomCreateContourFromProfilesArgs
|
|
293
940
|
>
|
|
941
|
+
|
|
942
|
+
/**
|
|
943
|
+
* Arguments for {@linkcode PluginGeomCreateApi.brepFromFaces}.
|
|
944
|
+
*
|
|
945
|
+
* | Property | Type | Description |
|
|
946
|
+
* |---|---|---|
|
|
947
|
+
* | `faces` | {@linkcode Vec3Components}`[][]` | Face loops — each an ordered array of `{x, y, z}` points (≥3 points per face, ≥4 faces) |
|
|
948
|
+
*/
|
|
949
|
+
export const PluginGeomCreateBrepFromFacesArgs = z.object({
|
|
950
|
+
faces: z.array(z.array(Vec3Components).min(3)).min(4),
|
|
951
|
+
})
|
|
952
|
+
|
|
953
|
+
export type PluginGeomCreateBrepFromFacesArgs = z.infer<
|
|
954
|
+
typeof PluginGeomCreateBrepFromFacesArgs
|
|
955
|
+
>
|
|
956
|
+
|
|
957
|
+
/**
|
|
958
|
+
* Arguments for {@linkcode PluginGeomCreateApi.brepFromExtrusion}.
|
|
959
|
+
*
|
|
960
|
+
* | Property | Type | Description |
|
|
961
|
+
* |---|---|---|
|
|
962
|
+
* | `contour` | {@linkcode ContourHandle} | The cross-section to extrude |
|
|
963
|
+
* | `direction` | {@linkcode Vec3Components} | Extrusion direction (non-zero, finite components) |
|
|
964
|
+
* | `amount` | `number` | Extrusion distance (finite, non-zero) |
|
|
965
|
+
*/
|
|
966
|
+
export const PluginGeomCreateBrepFromExtrusionArgs = z.object({
|
|
967
|
+
contour: ContourHandle,
|
|
968
|
+
direction: z.object({
|
|
969
|
+
x: z.number().finite(),
|
|
970
|
+
y: z.number().finite(),
|
|
971
|
+
z: z.number().finite(),
|
|
972
|
+
}),
|
|
973
|
+
amount: z
|
|
974
|
+
.number()
|
|
975
|
+
.finite()
|
|
976
|
+
.refine((value) => value !== 0, { message: "amount must be non-zero" }),
|
|
977
|
+
})
|
|
978
|
+
|
|
979
|
+
export type PluginGeomCreateBrepFromExtrusionArgs = z.infer<
|
|
980
|
+
typeof PluginGeomCreateBrepFromExtrusionArgs
|
|
981
|
+
>
|
|
982
|
+
|
|
983
|
+
/**
|
|
984
|
+
* Arguments for {@linkcode PluginGeomCreateApi.brepFromLoft}.
|
|
985
|
+
*
|
|
986
|
+
* | Property | Type | Description |
|
|
987
|
+
* |---|---|---|
|
|
988
|
+
* | `bottomContour` | {@linkcode ContourHandle} | The bottom cross-section |
|
|
989
|
+
* | `topContour` | {@linkcode ContourHandle} | The top cross-section |
|
|
990
|
+
* | `intermediateContours` | {@linkcode ContourHandle}`[]`? | Optional in-between cross-sections, ordered bottom to top |
|
|
991
|
+
* | `options` | `object`? | Optional behavior switches: `compatibility` (`"strict"` throws on mismatched edge counts instead of auto-matching; default `"auto"`) and `seamAlignment` (`"authored"` keeps the authored correspondence instead of searching seam rotations; default `"auto"`) |
|
|
992
|
+
*/
|
|
993
|
+
export const PluginGeomCreateBrepFromLoftArgs = z.object({
|
|
994
|
+
bottomContour: ContourHandle,
|
|
995
|
+
topContour: ContourHandle,
|
|
996
|
+
intermediateContours: z.array(ContourHandle).optional(),
|
|
997
|
+
options: z
|
|
998
|
+
.object({
|
|
999
|
+
compatibility: z.enum(["strict", "auto"]).optional(),
|
|
1000
|
+
seamAlignment: z.enum(["authored", "auto"]).optional(),
|
|
1001
|
+
})
|
|
1002
|
+
.optional(),
|
|
1003
|
+
})
|
|
1004
|
+
|
|
1005
|
+
export type PluginGeomCreateBrepFromLoftArgs = z.infer<typeof PluginGeomCreateBrepFromLoftArgs>
|
|
1006
|
+
|
|
1007
|
+
/**
|
|
1008
|
+
* Arguments for {@linkcode PluginGeomCreateApi.brepFromMesh}.
|
|
1009
|
+
*
|
|
1010
|
+
* | Property | Type | Description |
|
|
1011
|
+
* |---|---|---|
|
|
1012
|
+
* | `positions` | {@linkcode Vec3Components}`[]` | Vertex positions (≥4) |
|
|
1013
|
+
* | `faces` | `number[][]` | Face loops of indices into `positions` (≥3 indices per face, ≥4 faces) |
|
|
1014
|
+
*/
|
|
1015
|
+
export const PluginGeomCreateBrepFromMeshArgs = z.object({
|
|
1016
|
+
positions: z.array(Vec3Components).min(4),
|
|
1017
|
+
faces: z.array(z.array(z.number()).min(3)).min(4),
|
|
1018
|
+
})
|
|
1019
|
+
|
|
1020
|
+
export type PluginGeomCreateBrepFromMeshArgs = z.infer<typeof PluginGeomCreateBrepFromMeshArgs>
|
|
1021
|
+
|
|
1022
|
+
/**
|
|
1023
|
+
* Arguments for the brep boolean constructors —
|
|
1024
|
+
* {@linkcode PluginGeomCreateApi.brepFromUnion},
|
|
1025
|
+
* {@linkcode PluginGeomCreateApi.brepFromSubtraction} (`a` minus `b`), and
|
|
1026
|
+
* {@linkcode PluginGeomCreateApi.brepFromIntersection}.
|
|
1027
|
+
*
|
|
1028
|
+
* | Property | Type | Description |
|
|
1029
|
+
* |---|---|---|
|
|
1030
|
+
* | `a` | {@linkcode BrepHandle} | First solid (the subtraction target) |
|
|
1031
|
+
* | `b` | {@linkcode BrepHandle} | Second solid (the subtraction tool) |
|
|
1032
|
+
*/
|
|
1033
|
+
export const PluginGeomCreateBrepBooleanArgs = z.object({
|
|
1034
|
+
a: BrepHandle,
|
|
1035
|
+
b: BrepHandle,
|
|
1036
|
+
})
|
|
1037
|
+
|
|
1038
|
+
export type PluginGeomCreateBrepBooleanArgs = z.infer<typeof PluginGeomCreateBrepBooleanArgs>
|
|
1039
|
+
|
|
1040
|
+
// Plain {x, y, z} record with finite components (brepFromExtrusion `direction` pattern).
|
|
1041
|
+
const FiniteVec3Components = z.object({
|
|
1042
|
+
x: z.number().finite(),
|
|
1043
|
+
y: z.number().finite(),
|
|
1044
|
+
z: z.number().finite(),
|
|
1045
|
+
})
|
|
1046
|
+
|
|
1047
|
+
/**
|
|
1048
|
+
* Arguments for {@linkcode PluginGeomCreateApi.brepFromFillet}.
|
|
1049
|
+
*
|
|
1050
|
+
* | Property | Type | Description |
|
|
1051
|
+
* |---|---|---|
|
|
1052
|
+
* | `brep` | {@linkcode BrepHandle} | The solid whose edges to round |
|
|
1053
|
+
* | `edges` | {@linkcode EdgeHandle}`[]` | The straight edges to fillet (≥1) |
|
|
1054
|
+
* | `radius` | `number` | Fillet radius (positive, finite) |
|
|
1055
|
+
*/
|
|
1056
|
+
export const PluginGeomCreateBrepFromFilletArgs = z.object({
|
|
1057
|
+
brep: BrepHandle,
|
|
1058
|
+
edges: z.array(EdgeHandle).min(1),
|
|
1059
|
+
radius: z.number().finite().positive(),
|
|
1060
|
+
})
|
|
1061
|
+
|
|
1062
|
+
export type PluginGeomCreateBrepFromFilletArgs = z.infer<typeof PluginGeomCreateBrepFromFilletArgs>
|
|
1063
|
+
|
|
1064
|
+
/**
|
|
1065
|
+
* Arguments for {@linkcode PluginGeomCreateApi.brepFromOffset}.
|
|
1066
|
+
*
|
|
1067
|
+
* | Property | Type | Description |
|
|
1068
|
+
* |---|---|---|
|
|
1069
|
+
* | `brep` | {@linkcode BrepHandle} | The solid to offset |
|
|
1070
|
+
* | `distance` | `number` | Offset distance (finite, non-zero; positive grows, negative shrinks) |
|
|
1071
|
+
*/
|
|
1072
|
+
export const PluginGeomCreateBrepFromOffsetArgs = z.object({
|
|
1073
|
+
brep: BrepHandle,
|
|
1074
|
+
distance: z
|
|
1075
|
+
.number()
|
|
1076
|
+
.finite()
|
|
1077
|
+
.refine((value) => value !== 0, { message: "distance must be non-zero" }),
|
|
1078
|
+
})
|
|
1079
|
+
|
|
1080
|
+
export type PluginGeomCreateBrepFromOffsetArgs = z.infer<typeof PluginGeomCreateBrepFromOffsetArgs>
|
|
1081
|
+
|
|
1082
|
+
/**
|
|
1083
|
+
* Arguments for {@linkcode PluginGeomCreateApi.brepFromShell}.
|
|
1084
|
+
*
|
|
1085
|
+
* | Property | Type | Description |
|
|
1086
|
+
* |---|---|---|
|
|
1087
|
+
* | `brep` | {@linkcode BrepHandle} | The solid to hollow |
|
|
1088
|
+
* | `openFaces` | {@linkcode FaceHandle}`[]` | The faces to remove as openings (≥1) |
|
|
1089
|
+
* | `thickness` | `number` | Wall thickness (positive, finite) |
|
|
1090
|
+
*/
|
|
1091
|
+
export const PluginGeomCreateBrepFromShellArgs = z.object({
|
|
1092
|
+
brep: BrepHandle,
|
|
1093
|
+
openFaces: z.array(FaceHandle).min(1),
|
|
1094
|
+
thickness: z.number().finite().positive(),
|
|
1095
|
+
})
|
|
1096
|
+
|
|
1097
|
+
export type PluginGeomCreateBrepFromShellArgs = z.infer<typeof PluginGeomCreateBrepFromShellArgs>
|
|
1098
|
+
|
|
1099
|
+
/**
|
|
1100
|
+
* Arguments for {@linkcode PluginGeomCreateApi.brepsFromSplit}.
|
|
1101
|
+
*
|
|
1102
|
+
* | Property | Type | Description |
|
|
1103
|
+
* |---|---|---|
|
|
1104
|
+
* | `brep` | {@linkcode BrepHandle} | The solid to split |
|
|
1105
|
+
* | `planeOrigin` | {@linkcode Vec3Components} | A point on the cutting plane (finite components) |
|
|
1106
|
+
* | `planeNormal` | {@linkcode Vec3Components} | The plane normal (non-zero, finite components) |
|
|
1107
|
+
*/
|
|
1108
|
+
export const PluginGeomCreateBrepsFromSplitArgs = z.object({
|
|
1109
|
+
brep: BrepHandle,
|
|
1110
|
+
planeOrigin: FiniteVec3Components,
|
|
1111
|
+
planeNormal: FiniteVec3Components,
|
|
1112
|
+
})
|
|
1113
|
+
|
|
1114
|
+
export type PluginGeomCreateBrepsFromSplitArgs = z.infer<typeof PluginGeomCreateBrepsFromSplitArgs>
|
|
1115
|
+
|
|
1116
|
+
/**
|
|
1117
|
+
* Arguments for {@linkcode PluginGeomCreateApi.brepFromChamfer}.
|
|
1118
|
+
*
|
|
1119
|
+
* | Property | Type | Description |
|
|
1120
|
+
* |---|---|---|
|
|
1121
|
+
* | `brep` | {@linkcode BrepHandle} | The solid whose edges to bevel |
|
|
1122
|
+
* | `edges` | {@linkcode EdgeHandle}`[]` | The straight edges to chamfer (≥1) |
|
|
1123
|
+
* | `distance` | `number` | Chamfer distance from the edge on each adjacent face (positive, finite) |
|
|
1124
|
+
*/
|
|
1125
|
+
export const PluginGeomCreateBrepFromChamferArgs = z.object({
|
|
1126
|
+
brep: BrepHandle,
|
|
1127
|
+
edges: z.array(EdgeHandle).min(1),
|
|
1128
|
+
distance: z.number().finite().positive(),
|
|
1129
|
+
})
|
|
1130
|
+
|
|
1131
|
+
export type PluginGeomCreateBrepFromChamferArgs = z.infer<
|
|
1132
|
+
typeof PluginGeomCreateBrepFromChamferArgs
|
|
1133
|
+
>
|
|
1134
|
+
|
|
1135
|
+
// Taper scale factor — bounded so a near-zero scale cannot pinch a section
|
|
1136
|
+
// into a degenerate sliver the downstream planarity gates would miss.
|
|
1137
|
+
const SweepScaleFactor = z.number().finite().min(1e-3).max(1e3)
|
|
1138
|
+
|
|
1139
|
+
/**
|
|
1140
|
+
* Arguments for {@linkcode PluginGeomCreateApi.brepFromSweep}.
|
|
1141
|
+
*
|
|
1142
|
+
* | Property | Type | Description |
|
|
1143
|
+
* |---|---|---|
|
|
1144
|
+
* | `profile` | {@linkcode ContourHandle} | The cross-section to sweep (hole-free) |
|
|
1145
|
+
* | `path` | {@linkcode Vec3Components}`[]` | The polyline path (≥2 points, finite components; 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) |
|
|
1146
|
+
* | `options` | `object`? | Optional scale law: `startScale`/`endScale` (linear taper by arc length) or per-point `scales` (mutually exclusive; factors finite, 1e-3..1e3; `scales.length` must equal `path.length`). Optional corner `transition`: `"miter"` (default) or `{ bevel }` (chamfered corners; finite, 1e-3..1e3) |
|
|
1147
|
+
*/
|
|
1148
|
+
export const PluginGeomCreateBrepFromSweepArgs = z
|
|
1149
|
+
.object({
|
|
1150
|
+
profile: ContourHandle,
|
|
1151
|
+
path: z.array(FiniteVec3Components).min(2),
|
|
1152
|
+
options: z
|
|
1153
|
+
.object({
|
|
1154
|
+
startScale: SweepScaleFactor.optional(),
|
|
1155
|
+
endScale: SweepScaleFactor.optional(),
|
|
1156
|
+
scales: z.array(SweepScaleFactor).optional(),
|
|
1157
|
+
transition: z
|
|
1158
|
+
.union([
|
|
1159
|
+
z.literal("miter"),
|
|
1160
|
+
z.object({ bevel: z.number().finite().min(1e-3).max(1e3) }),
|
|
1161
|
+
])
|
|
1162
|
+
.optional(),
|
|
1163
|
+
})
|
|
1164
|
+
.optional(),
|
|
1165
|
+
})
|
|
1166
|
+
.superRefine((a, ctx) => {
|
|
1167
|
+
const options = a.options
|
|
1168
|
+
if (!options || options.scales === undefined) return
|
|
1169
|
+
if (options.startScale !== undefined || options.endScale !== undefined) {
|
|
1170
|
+
ctx.addIssue({
|
|
1171
|
+
code: z.ZodIssueCode.custom,
|
|
1172
|
+
message: "scales is mutually exclusive with startScale/endScale",
|
|
1173
|
+
})
|
|
1174
|
+
}
|
|
1175
|
+
if (options.scales.length !== a.path.length) {
|
|
1176
|
+
ctx.addIssue({
|
|
1177
|
+
code: z.ZodIssueCode.custom,
|
|
1178
|
+
message: "scales must have exactly one entry per path point",
|
|
1179
|
+
})
|
|
1180
|
+
}
|
|
1181
|
+
})
|
|
1182
|
+
|
|
1183
|
+
export type PluginGeomCreateBrepFromSweepArgs = z.infer<typeof PluginGeomCreateBrepFromSweepArgs>
|
|
1184
|
+
|
|
1185
|
+
/**
|
|
1186
|
+
* Arguments for {@linkcode PluginGeomCreateApi.brepFromRevolution}.
|
|
1187
|
+
*
|
|
1188
|
+
* | Property | Type | Description |
|
|
1189
|
+
* |---|---|---|
|
|
1190
|
+
* | `profile` | {@linkcode ContourHandle} | The cross-section to revolve (holes allowed) |
|
|
1191
|
+
* | `axisOrigin` | {@linkcode Vec3Components} | A point on the revolution axis (finite components) |
|
|
1192
|
+
* | `axisDirection` | {@linkcode Vec3Components} | The axis direction (non-zero, finite components) |
|
|
1193
|
+
* | `angleInDegrees` | `number`? | Revolution angle in degrees (0 < angle ≤ 360; default 360) |
|
|
1194
|
+
*/
|
|
1195
|
+
export const PluginGeomCreateBrepFromRevolutionArgs = z.object({
|
|
1196
|
+
profile: ContourHandle,
|
|
1197
|
+
axisOrigin: FiniteVec3Components,
|
|
1198
|
+
axisDirection: FiniteVec3Components,
|
|
1199
|
+
angleInDegrees: z.number().finite().positive().max(360).optional(),
|
|
1200
|
+
})
|
|
1201
|
+
|
|
1202
|
+
export type PluginGeomCreateBrepFromRevolutionArgs = z.infer<
|
|
1203
|
+
typeof PluginGeomCreateBrepFromRevolutionArgs
|
|
1204
|
+
>
|