@snaptrude/plugin-core 0.9.0 → 0.9.2

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.
Files changed (45) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/api-manifest.full.json +411 -2
  3. package/api-manifest.json +411 -2
  4. package/dist/api/core/geom/create/index.d.ts +406 -11
  5. package/dist/api/core/geom/create/index.d.ts.map +1 -1
  6. package/dist/api/core/geom/query/brep.d.ts +44 -0
  7. package/dist/api/core/geom/query/brep.d.ts.map +1 -1
  8. package/dist/api/core/io/terrain/index.d.ts +135 -0
  9. package/dist/api/core/io/terrain/index.d.ts.map +1 -1
  10. package/dist/api/presentation/annotate.d.ts +23 -4
  11. package/dist/api/presentation/annotate.d.ts.map +1 -1
  12. package/dist/api/presentation/diagrams.d.ts +64 -2
  13. package/dist/api/presentation/diagrams.d.ts.map +1 -1
  14. package/dist/api/presentation/index.d.ts +11 -1
  15. package/dist/api/presentation/index.d.ts.map +1 -1
  16. package/dist/api/presentation/placedViews.d.ts +772 -3
  17. package/dist/api/presentation/placedViews.d.ts.map +1 -1
  18. package/dist/api/presentation/shapes.d.ts +2 -2
  19. package/dist/api/presentation/sheets.d.ts +42 -0
  20. package/dist/api/presentation/sheets.d.ts.map +1 -1
  21. package/dist/api/presentation/slideshow.d.ts +125 -0
  22. package/dist/api/presentation/slideshow.d.ts.map +1 -0
  23. package/dist/api/presentation/tables.d.ts +81 -0
  24. package/dist/api/presentation/tables.d.ts.map +1 -0
  25. package/dist/api/program/site.d.ts +166 -2
  26. package/dist/api/program/site.d.ts.map +1 -1
  27. package/dist/api/workspace/index.d.ts +46 -1
  28. package/dist/api/workspace/index.d.ts.map +1 -1
  29. package/dist/index.cjs +890 -554
  30. package/dist/index.cjs.map +1 -1
  31. package/dist/index.js +850 -554
  32. package/dist/index.js.map +1 -1
  33. package/package.json +1 -1
  34. package/src/api/core/geom/create/index.ts +445 -10
  35. package/src/api/core/geom/query/brep.ts +45 -0
  36. package/src/api/core/io/terrain/index.ts +146 -0
  37. package/src/api/presentation/annotate.ts +27 -2
  38. package/src/api/presentation/diagrams.ts +67 -2
  39. package/src/api/presentation/index.ts +11 -1
  40. package/src/api/presentation/placedViews.ts +760 -3
  41. package/src/api/presentation/sheets.ts +54 -0
  42. package/src/api/presentation/slideshow.ts +134 -0
  43. package/src/api/presentation/tables.ts +84 -0
  44. package/src/api/program/site.ts +110 -2
  45. package/src/api/workspace/index.ts +48 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@snaptrude/plugin-core",
3
- "version": "0.9.0",
3
+ "version": "0.9.2",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.js",
@@ -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, BrepHandle, Vec3Components } 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
@@ -263,25 +263,36 @@ export abstract class PluginGeomCreateApi {
263
263
 
264
264
  /**
265
265
  * Create a closed solid **B-rep** by lofting between a bottom and a top
266
- * contour. Host API call — returns a {@linkcode BrepHandle}. Both contours
267
- * must have the same number of edges (and matching hole counts); side faces
268
- * connect corresponding edges by authored index. Corresponding edges must
269
- * stay coplanar a twisted loft would produce non-planar side faces and is
270
- * rejected. The contours are copiedthe input handles are never mutated.
266
+ * contour, optionally through intermediate cross-sections. Host API call —
267
+ * returns a {@linkcode BrepHandle}. All sections must have the same number
268
+ * of edges; side faces connect corresponding edges by authored index.
269
+ * Corresponding edges must stay coplanar segment to segment (matching hole
270
+ * counts allowed in the two-section form) a twisted loft would produce
271
+ * non-planar side faces and is rejected. With intermediates the loft is a
272
+ * chain of ruled segments folded into one solid: sections must be planar
273
+ * and hole-free, ordered bottom → intermediates → top. The contours are
274
+ * copied — the input handles are never mutated.
271
275
  *
272
276
  * Inspect the result via `core.geom.query.brep.*`, or commit it to the scene
273
277
  * with `design.create.massFromBrep`.
274
278
  *
275
279
  * @param bottomContour The bottom cross-section
276
- * @param topContour The top cross-section (same edge and hole counts as the bottom)
280
+ * @param topContour The top cross-section (same edge count as the bottom)
281
+ * @param intermediateContours Optional in-between cross-sections, ordered
282
+ * bottom to top (hole-free, same edge count as the bottom and top)
277
283
  * @returns The new solid as a {@linkcode BrepHandle}
278
- * @throws if the contours are coincident, their edge or hole counts differ,
279
- * a side face between corresponding edges would be non-planar, or the
280
- * contours cannot be lofted into a valid solid
284
+ * @throws VALIDATION if the contours are coincident, their edge or hole
285
+ * counts differ, any section has holes when intermediates are present
286
+ * (multi-section lofts take hole-free sections), a section is non-planar,
287
+ * or a side face between corresponding edges would be non-planar (a
288
+ * twisted section pair — the error names the offending sections)
289
+ * @throws OPERATION_FAILED if the lofted segments cannot be joined into a
290
+ * valid solid
281
291
  *
282
292
  * @examplePrompt Make a tapered tower from these two outlines
283
293
  * @examplePrompt Loft between a large base and a smaller top
284
294
  * @examplePrompt Create a frustum from two squares
295
+ * @examplePrompt Loft the tower through these three floor outlines
285
296
  *
286
297
  * # Example
287
298
  * ```ts
@@ -298,6 +309,7 @@ export abstract class PluginGeomCreateApi {
298
309
  public abstract brepFromLoft(
299
310
  bottomContour: ContourHandle,
300
311
  topContour: ContourHandle,
312
+ intermediateContours?: ContourHandle[],
301
313
  ): PluginApiReturn<BrepHandle>
302
314
 
303
315
  /**
@@ -431,6 +443,296 @@ export abstract class PluginGeomCreateApi {
431
443
  * ```
432
444
  */
433
445
  public abstract brepFromIntersection(a: BrepHandle, b: BrepHandle): PluginApiReturn<BrepHandle>
446
+
447
+ /**
448
+ * Rounds the given straight edges of a solid with a constant radius. Host
449
+ * API call — returns a new {@linkcode BrepHandle}; the input brep is
450
+ * read-only.
451
+ *
452
+ * v1 fillets straight edges only, and no two filleted edges may share a
453
+ * vertex — corner blends produce spherical patches Snaptrude cannot
454
+ * represent. Runs on the OpenCascade kernel (the first kernel call loads a
455
+ * wasm of tens of MB — expect a pause of seconds).
456
+ *
457
+ * Inspect the result via `core.geom.query.brep.*`, or commit it to the scene
458
+ * with `design.create.massFromBrep`.
459
+ *
460
+ * @param brep The solid whose edges to round
461
+ * @param edges The straight edges to fillet (≥1, all on `brep`, no two sharing a vertex)
462
+ * @param radius Fillet radius (positive, finite)
463
+ * @returns The filleted solid as a new {@linkcode BrepHandle}
464
+ * @throws VALIDATION if `edges` is empty, `radius` is not a positive finite
465
+ * number, an edge is not on `brep`, an edge is an arc (v1 fillets straight
466
+ * edges only), or two edges share a vertex (fillet non-adjacent edges)
467
+ * @throws OPERATION_FAILED if the kernel cannot build the fillet (the radius
468
+ * likely exceeds the adjacent face size — reduce it) or the result
469
+ * contains curved surfaces Snaptrude cannot represent
470
+ *
471
+ * @examplePrompt Round the edges of this mass
472
+ * @examplePrompt Fillet the corners of the podium with a 0.5m radius
473
+ * @examplePrompt Soften the vertical edges of this tower
474
+ *
475
+ * # Example
476
+ * ```ts
477
+ * const brep = await snaptrude.core.geom.create.brepFromExtrusion(contour, { x: 0, y: 1, z: 0 }, 3)
478
+ * const edges = await snaptrude.core.geom.query.brep.listEdges(brep)
479
+ * const rounded = await snaptrude.core.geom.create.brepFromFillet(brep, [edges[0]], 0.3)
480
+ * ```
481
+ */
482
+ public abstract brepFromFillet(
483
+ brep: BrepHandle,
484
+ edges: EdgeHandle[],
485
+ radius: number,
486
+ ): PluginApiReturn<BrepHandle>
487
+
488
+ /**
489
+ * Grows or shrinks a solid by offsetting every face — positive distance
490
+ * moves faces outward, negative moves them inward. Host API call — returns
491
+ * a new {@linkcode BrepHandle}; the input brep is read-only.
492
+ *
493
+ * Runs on the OpenCascade kernel (the first kernel call loads a wasm of
494
+ * tens of MB — expect a pause of seconds).
495
+ *
496
+ * Inspect the result via `core.geom.query.brep.*`, or commit it to the scene
497
+ * with `design.create.massFromBrep`.
498
+ *
499
+ * @param brep The solid to offset
500
+ * @param distance Offset distance (finite, non-zero; positive grows, negative shrinks)
501
+ * @returns The offset solid as a new {@linkcode BrepHandle}
502
+ * @throws VALIDATION if `distance` is not finite, is too small to offset
503
+ * anything, or an inward distance consumes the solid entirely
504
+ * @throws OPERATION_FAILED if the kernel cannot build the offset or the
505
+ * result contains curved surfaces Snaptrude cannot represent
506
+ *
507
+ * @examplePrompt Grow this solid by 0.5m in every direction
508
+ * @examplePrompt Shrink this mass by 200mm
509
+ * @examplePrompt Offset the building envelope outward by 1m
510
+ *
511
+ * # Example
512
+ * ```ts
513
+ * const brep = await snaptrude.core.geom.create.brepFromExtrusion(contour, { x: 0, y: 1, z: 0 }, 3)
514
+ * const grown = await snaptrude.core.geom.create.brepFromOffset(brep, 0.5)
515
+ * ```
516
+ */
517
+ public abstract brepFromOffset(brep: BrepHandle, distance: number): PluginApiReturn<BrepHandle>
518
+
519
+ /**
520
+ * Hollows a solid into constant-thickness walls, removing the given faces
521
+ * as openings. Host API call — returns a new {@linkcode BrepHandle}; the
522
+ * input brep is read-only. The outer surface is kept and the walls grow
523
+ * inward.
524
+ *
525
+ * Runs on the OpenCascade kernel (the first kernel call loads a wasm of
526
+ * tens of MB — expect a pause of seconds).
527
+ *
528
+ * Inspect the result via `core.geom.query.brep.*`, or commit it to the scene
529
+ * with `design.create.massFromBrep`.
530
+ *
531
+ * @param brep The solid to hollow
532
+ * @param openFaces The faces to remove as openings (≥1, all on `brep`)
533
+ * @param thickness Wall thickness (positive, finite, smaller than half the solid's smallest span)
534
+ * @returns The hollowed solid as a new {@linkcode BrepHandle}
535
+ * @throws VALIDATION if `openFaces` is empty, a face is not on `brep`,
536
+ * `thickness` is not a positive finite number, or the thickness is too
537
+ * large (it must be smaller than half the solid's smallest span)
538
+ * @throws OPERATION_FAILED if the kernel cannot build the shell or the
539
+ * result contains curved surfaces Snaptrude cannot represent
540
+ *
541
+ * @examplePrompt Hollow this mass into 200mm walls
542
+ * @examplePrompt Shell this form with the top face open
543
+ * @examplePrompt Turn this solid tower into a tube open at both ends
544
+ *
545
+ * # Example
546
+ * ```ts
547
+ * const brep = await snaptrude.core.geom.create.brepFromExtrusion(contour, { x: 0, y: 1, z: 0 }, 3)
548
+ * const faces = await snaptrude.core.geom.query.brep.listFaces(brep)
549
+ * const hollow = await snaptrude.core.geom.create.brepFromShell(brep, [faces[0]], 0.2)
550
+ * ```
551
+ */
552
+ public abstract brepFromShell(
553
+ brep: BrepHandle,
554
+ openFaces: FaceHandle[],
555
+ thickness: number,
556
+ ): PluginApiReturn<BrepHandle>
557
+
558
+ /**
559
+ * Cuts a solid by an infinite plane and returns one brep per resulting
560
+ * piece — a single piece if the plane misses the solid. Host API call —
561
+ * returns new {@linkcode BrepHandle}s; the input brep is read-only. The
562
+ * plane is defined by a point on it and its normal direction.
563
+ *
564
+ * Runs on the OpenCascade kernel (the first kernel call loads a wasm of
565
+ * tens of MB — expect a pause of seconds).
566
+ *
567
+ * Inspect each result via `core.geom.query.brep.*`, or commit them to the
568
+ * scene with `design.create.massFromBrep`.
569
+ *
570
+ * @param brep The solid to split
571
+ * @param planeOrigin A point on the cutting plane as plain `{x, y, z}` components
572
+ * @param planeNormal The plane normal as plain `{x, y, z}` components (non-zero)
573
+ * @returns The resulting pieces as {@linkcode BrepHandle}`[]` (one per solid)
574
+ * @throws VALIDATION if `planeNormal` is zero-length or the origin/normal
575
+ * components are not finite
576
+ * @throws OPERATION_FAILED if the kernel cannot split the solid
577
+ *
578
+ * @examplePrompt Cut this building at 12m height
579
+ * @examplePrompt Split the tower from the podium with a horizontal plane
580
+ * @examplePrompt Slice this mass along a vertical plane
581
+ *
582
+ * # Example
583
+ * ```ts
584
+ * const pieces = await snaptrude.core.geom.create.brepsFromSplit(
585
+ * towerBrep,
586
+ * { x: 0, y: 12, z: 0 },
587
+ * { x: 0, y: 1, z: 0 },
588
+ * )
589
+ * console.log("pieces:", pieces.length)
590
+ * ```
591
+ */
592
+ public abstract brepsFromSplit(
593
+ brep: BrepHandle,
594
+ planeOrigin: Vec3Components,
595
+ planeNormal: Vec3Components,
596
+ ): PluginApiReturn<BrepHandle[]>
597
+
598
+ /**
599
+ * Bevels the given straight edges of a solid with a symmetric planar cut.
600
+ * Host API call — returns a new {@linkcode BrepHandle}; the input brep is
601
+ * read-only.
602
+ *
603
+ * v1 chamfers straight edges only, and no two chamfered edges may share a
604
+ * vertex. Runs on the OpenCascade kernel (the first kernel call loads a
605
+ * wasm of tens of MB — expect a pause of seconds).
606
+ *
607
+ * Inspect the result via `core.geom.query.brep.*`, or commit it to the scene
608
+ * with `design.create.massFromBrep`.
609
+ *
610
+ * @param brep The solid whose edges to bevel
611
+ * @param edges The straight edges to chamfer (≥1, all on `brep`, no two sharing a vertex)
612
+ * @param distance Chamfer distance from the edge on each adjacent face (positive, finite)
613
+ * @returns The chamfered solid as a new {@linkcode BrepHandle}
614
+ * @throws VALIDATION if `edges` is empty, `distance` is not a positive
615
+ * finite number, an edge is not on `brep`, an edge is an arc (v1 chamfers
616
+ * straight edges only), or two edges share a vertex (chamfer non-adjacent
617
+ * edges)
618
+ * @throws OPERATION_FAILED if the kernel cannot build the chamfer (the
619
+ * distance likely exceeds the adjacent face size — reduce it)
620
+ *
621
+ * @examplePrompt Bevel these edges by 100mm
622
+ * @examplePrompt Chamfer the top edges of the plinth
623
+ * @examplePrompt Cut a 45-degree flat along the corners of this mass
624
+ *
625
+ * # Example
626
+ * ```ts
627
+ * const brep = await snaptrude.core.geom.create.brepFromExtrusion(contour, { x: 0, y: 1, z: 0 }, 3)
628
+ * const edges = await snaptrude.core.geom.query.brep.listEdges(brep)
629
+ * const beveled = await snaptrude.core.geom.create.brepFromChamfer(brep, [edges[0]], 0.1)
630
+ * ```
631
+ */
632
+ public abstract brepFromChamfer(
633
+ brep: BrepHandle,
634
+ edges: EdgeHandle[],
635
+ distance: number,
636
+ ): PluginApiReturn<BrepHandle>
637
+
638
+ /**
639
+ * Sweeps a planar profile along an open polyline path, with mitred corners
640
+ * at each bend. Host API call — returns a new {@linkcode BrepHandle}; the
641
+ * input contour is read-only. The profile must be hole-free and must not
642
+ * lie in a plane containing the first path segment's direction.
643
+ *
644
+ * Runs on the OpenCascade kernel (the first kernel call loads a wasm of
645
+ * tens of MB — expect a pause of seconds).
646
+ *
647
+ * Inspect the result via `core.geom.query.brep.*`, or commit it to the scene
648
+ * with `design.create.massFromBrep`.
649
+ *
650
+ * @param profile The cross-section to sweep (hole-free contour)
651
+ * @param path The polyline path as plain `{x, y, z}` points (≥2, open — first ≠ last)
652
+ * @returns The swept solid as a new {@linkcode BrepHandle}
653
+ * @throws VALIDATION if the profile has holes, the path has fewer than 2
654
+ * points, consecutive path points coincide, the path is closed (open
655
+ * paths only in v1), a coordinate is not finite, or the profile plane
656
+ * contains the first path segment's direction (degenerate sweep)
657
+ * @throws OPERATION_FAILED if the kernel cannot sweep the profile into a
658
+ * valid solid or a transition patch is a curved surface Snaptrude cannot
659
+ * represent
660
+ *
661
+ * @examplePrompt Sweep this profile along the corridor path
662
+ * @examplePrompt Extrude the railing section along this route
663
+ * @examplePrompt Run a duct profile through these points
664
+ *
665
+ * # Example
666
+ * ```ts
667
+ * const rect = await snaptrude.core.geom.create.profileRect(0.4, 0.4)
668
+ * const profile = await snaptrude.core.geom.create.contourFromProfile(rect)
669
+ * // profileRect lies in the XZ plane, so the path must START out of that
670
+ * // plane (here: straight up), then it can run horizontally.
671
+ * const duct = await snaptrude.core.geom.create.brepFromSweep(profile, [
672
+ * { x: 0, y: 0, z: 0 },
673
+ * { x: 0, y: 2.8, z: 0 },
674
+ * { x: 10, y: 2.8, z: 0 },
675
+ * ])
676
+ * ```
677
+ */
678
+ public abstract brepFromSweep(
679
+ profile: ContourHandle,
680
+ path: Vec3Components[],
681
+ ): PluginApiReturn<BrepHandle>
682
+
683
+ /**
684
+ * Revolves a planar profile about an axis to make a solid of revolution — a
685
+ * full turn by default. Host API call — returns a new
686
+ * {@linkcode BrepHandle}; the input contour is read-only. Holes in the
687
+ * profile are allowed. Profile segments must stay parallel or perpendicular
688
+ * to the axis — inclined or arc segments would revolve into surfaces
689
+ * Snaptrude cannot represent.
690
+ *
691
+ * Runs on the OpenCascade kernel (the first kernel call loads a wasm of
692
+ * tens of MB — expect a pause of seconds).
693
+ *
694
+ * Inspect the result via `core.geom.query.brep.*`, or commit it to the scene
695
+ * with `design.create.massFromBrep`.
696
+ *
697
+ * @param profile The cross-section to revolve (planar contour, holes allowed)
698
+ * @param axisOrigin A point on the revolution axis as plain `{x, y, z}` components
699
+ * @param axisDirection The axis direction as plain `{x, y, z}` components (non-zero)
700
+ * @param angleInDegrees Optional revolution angle in degrees (0 < angle ≤ 360; default 360)
701
+ * @returns The revolved solid as a new {@linkcode BrepHandle}
702
+ * @throws VALIDATION if `axisDirection` is zero-length, `angleInDegrees` is
703
+ * not in (0, 360], the axis passes through the profile interior, or a
704
+ * coordinate is not finite
705
+ * @throws OPERATION_FAILED if the kernel cannot revolve the profile or the
706
+ * result contains curved surfaces Snaptrude cannot represent (keep
707
+ * profile segments parallel or perpendicular to the axis)
708
+ *
709
+ * @examplePrompt Create a dome from this section
710
+ * @examplePrompt Revolve this profile 360 degrees around the vertical axis
711
+ * @examplePrompt Build a rotunda by revolving this wall section
712
+ *
713
+ * # Example
714
+ * ```ts
715
+ * // A cylinder: revolve a 2m-wide, 3m-tall rectangle about the Y axis at its edge
716
+ * const rect = await snaptrude.core.geom.create.profileFromLinePoints([
717
+ * await snaptrude.core.math.vec3.new(0, 0, 0),
718
+ * await snaptrude.core.math.vec3.new(2, 0, 0),
719
+ * await snaptrude.core.math.vec3.new(2, 3, 0),
720
+ * await snaptrude.core.math.vec3.new(0, 3, 0),
721
+ * ])
722
+ * const profile = await snaptrude.core.geom.create.contourFromProfile(rect)
723
+ * const cylinder = await snaptrude.core.geom.create.brepFromRevolution(
724
+ * profile,
725
+ * { x: 0, y: 0, z: 0 },
726
+ * { x: 0, y: 1, z: 0 },
727
+ * )
728
+ * ```
729
+ */
730
+ public abstract brepFromRevolution(
731
+ profile: ContourHandle,
732
+ axisOrigin: Vec3Components,
733
+ axisDirection: Vec3Components,
734
+ angleInDegrees?: number,
735
+ ): PluginApiReturn<BrepHandle>
434
736
  }
435
737
 
436
738
  /**
@@ -594,10 +896,12 @@ export type PluginGeomCreateBrepFromExtrusionArgs = z.infer<
594
896
  * |---|---|---|
595
897
  * | `bottomContour` | {@linkcode ContourHandle} | The bottom cross-section |
596
898
  * | `topContour` | {@linkcode ContourHandle} | The top cross-section |
899
+ * | `intermediateContours` | {@linkcode ContourHandle}`[]`? | Optional in-between cross-sections, ordered bottom to top |
597
900
  */
598
901
  export const PluginGeomCreateBrepFromLoftArgs = z.object({
599
902
  bottomContour: ContourHandle,
600
903
  topContour: ContourHandle,
904
+ intermediateContours: z.array(ContourHandle).optional(),
601
905
  })
602
906
 
603
907
  export type PluginGeomCreateBrepFromLoftArgs = z.infer<typeof PluginGeomCreateBrepFromLoftArgs>
@@ -634,3 +938,134 @@ export const PluginGeomCreateBrepBooleanArgs = z.object({
634
938
  })
635
939
 
636
940
  export type PluginGeomCreateBrepBooleanArgs = z.infer<typeof PluginGeomCreateBrepBooleanArgs>
941
+
942
+ // Plain {x, y, z} record with finite components (brepFromExtrusion `direction` pattern).
943
+ const FiniteVec3Components = z.object({
944
+ x: z.number().finite(),
945
+ y: z.number().finite(),
946
+ z: z.number().finite(),
947
+ })
948
+
949
+ /**
950
+ * Arguments for {@linkcode PluginGeomCreateApi.brepFromFillet}.
951
+ *
952
+ * | Property | Type | Description |
953
+ * |---|---|---|
954
+ * | `brep` | {@linkcode BrepHandle} | The solid whose edges to round |
955
+ * | `edges` | {@linkcode EdgeHandle}`[]` | The straight edges to fillet (≥1) |
956
+ * | `radius` | `number` | Fillet radius (positive, finite) |
957
+ */
958
+ export const PluginGeomCreateBrepFromFilletArgs = z.object({
959
+ brep: BrepHandle,
960
+ edges: z.array(EdgeHandle).min(1),
961
+ radius: z.number().finite().positive(),
962
+ })
963
+
964
+ export type PluginGeomCreateBrepFromFilletArgs = z.infer<typeof PluginGeomCreateBrepFromFilletArgs>
965
+
966
+ /**
967
+ * Arguments for {@linkcode PluginGeomCreateApi.brepFromOffset}.
968
+ *
969
+ * | Property | Type | Description |
970
+ * |---|---|---|
971
+ * | `brep` | {@linkcode BrepHandle} | The solid to offset |
972
+ * | `distance` | `number` | Offset distance (finite, non-zero; positive grows, negative shrinks) |
973
+ */
974
+ export const PluginGeomCreateBrepFromOffsetArgs = z.object({
975
+ brep: BrepHandle,
976
+ distance: z
977
+ .number()
978
+ .finite()
979
+ .refine((value) => value !== 0, { message: "distance must be non-zero" }),
980
+ })
981
+
982
+ export type PluginGeomCreateBrepFromOffsetArgs = z.infer<typeof PluginGeomCreateBrepFromOffsetArgs>
983
+
984
+ /**
985
+ * Arguments for {@linkcode PluginGeomCreateApi.brepFromShell}.
986
+ *
987
+ * | Property | Type | Description |
988
+ * |---|---|---|
989
+ * | `brep` | {@linkcode BrepHandle} | The solid to hollow |
990
+ * | `openFaces` | {@linkcode FaceHandle}`[]` | The faces to remove as openings (≥1) |
991
+ * | `thickness` | `number` | Wall thickness (positive, finite) |
992
+ */
993
+ export const PluginGeomCreateBrepFromShellArgs = z.object({
994
+ brep: BrepHandle,
995
+ openFaces: z.array(FaceHandle).min(1),
996
+ thickness: z.number().finite().positive(),
997
+ })
998
+
999
+ export type PluginGeomCreateBrepFromShellArgs = z.infer<typeof PluginGeomCreateBrepFromShellArgs>
1000
+
1001
+ /**
1002
+ * Arguments for {@linkcode PluginGeomCreateApi.brepsFromSplit}.
1003
+ *
1004
+ * | Property | Type | Description |
1005
+ * |---|---|---|
1006
+ * | `brep` | {@linkcode BrepHandle} | The solid to split |
1007
+ * | `planeOrigin` | {@linkcode Vec3Components} | A point on the cutting plane (finite components) |
1008
+ * | `planeNormal` | {@linkcode Vec3Components} | The plane normal (non-zero, finite components) |
1009
+ */
1010
+ export const PluginGeomCreateBrepsFromSplitArgs = z.object({
1011
+ brep: BrepHandle,
1012
+ planeOrigin: FiniteVec3Components,
1013
+ planeNormal: FiniteVec3Components,
1014
+ })
1015
+
1016
+ export type PluginGeomCreateBrepsFromSplitArgs = z.infer<typeof PluginGeomCreateBrepsFromSplitArgs>
1017
+
1018
+ /**
1019
+ * Arguments for {@linkcode PluginGeomCreateApi.brepFromChamfer}.
1020
+ *
1021
+ * | Property | Type | Description |
1022
+ * |---|---|---|
1023
+ * | `brep` | {@linkcode BrepHandle} | The solid whose edges to bevel |
1024
+ * | `edges` | {@linkcode EdgeHandle}`[]` | The straight edges to chamfer (≥1) |
1025
+ * | `distance` | `number` | Chamfer distance from the edge on each adjacent face (positive, finite) |
1026
+ */
1027
+ export const PluginGeomCreateBrepFromChamferArgs = z.object({
1028
+ brep: BrepHandle,
1029
+ edges: z.array(EdgeHandle).min(1),
1030
+ distance: z.number().finite().positive(),
1031
+ })
1032
+
1033
+ export type PluginGeomCreateBrepFromChamferArgs = z.infer<
1034
+ typeof PluginGeomCreateBrepFromChamferArgs
1035
+ >
1036
+
1037
+ /**
1038
+ * Arguments for {@linkcode PluginGeomCreateApi.brepFromSweep}.
1039
+ *
1040
+ * | Property | Type | Description |
1041
+ * |---|---|---|
1042
+ * | `profile` | {@linkcode ContourHandle} | The cross-section to sweep (hole-free) |
1043
+ * | `path` | {@linkcode Vec3Components}`[]` | The open polyline path (≥2 points, finite components) |
1044
+ */
1045
+ export const PluginGeomCreateBrepFromSweepArgs = z.object({
1046
+ profile: ContourHandle,
1047
+ path: z.array(FiniteVec3Components).min(2),
1048
+ })
1049
+
1050
+ export type PluginGeomCreateBrepFromSweepArgs = z.infer<typeof PluginGeomCreateBrepFromSweepArgs>
1051
+
1052
+ /**
1053
+ * Arguments for {@linkcode PluginGeomCreateApi.brepFromRevolution}.
1054
+ *
1055
+ * | Property | Type | Description |
1056
+ * |---|---|---|
1057
+ * | `profile` | {@linkcode ContourHandle} | The cross-section to revolve (holes allowed) |
1058
+ * | `axisOrigin` | {@linkcode Vec3Components} | A point on the revolution axis (finite components) |
1059
+ * | `axisDirection` | {@linkcode Vec3Components} | The axis direction (non-zero, finite components) |
1060
+ * | `angleInDegrees` | `number`? | Revolution angle in degrees (0 < angle ≤ 360; default 360) |
1061
+ */
1062
+ export const PluginGeomCreateBrepFromRevolutionArgs = z.object({
1063
+ profile: ContourHandle,
1064
+ axisOrigin: FiniteVec3Components,
1065
+ axisDirection: FiniteVec3Components,
1066
+ angleInDegrees: z.number().finite().positive().max(360).optional(),
1067
+ })
1068
+
1069
+ export type PluginGeomCreateBrepFromRevolutionArgs = z.infer<
1070
+ typeof PluginGeomCreateBrepFromRevolutionArgs
1071
+ >
@@ -328,6 +328,37 @@ export abstract class PluginGeomQueryBrepApi {
328
328
  * ```
329
329
  */
330
330
  public abstract isEqual(brepA: BrepHandle, brepB: BrepHandle): PluginApiReturn<boolean>
331
+
332
+ /**
333
+ * Measures the minimum distance between two solids, with the closest witness
334
+ * point on each. Touching or overlapping solids report a distance of 0 with
335
+ * contact points.
336
+ *
337
+ * @param brepA First solid
338
+ * @param brepB Second solid
339
+ * @returns `{ distance, pointA, pointB }` — the minimum distance and the
340
+ * closest points on `brepA` and `brepB` as {@linkcode Vec3Components}
341
+ * @throws OPERATION_FAILED if the kernel cannot compute the distance
342
+ *
343
+ * @examplePrompt What is the clearance between these two masses?
344
+ * @examplePrompt How far apart are the tower and the neighbouring building?
345
+ * @examplePrompt Find the closest points between these two solids
346
+ *
347
+ * # Example
348
+ * ```ts
349
+ * const [a, b] = await snaptrude.design.query.listMasses()
350
+ * const brepA = await snaptrude.design.query.geometry.getBrep(a)
351
+ * const brepB = await snaptrude.design.query.geometry.getBrep(b)
352
+ * if (brepA && brepB) {
353
+ * const { distance, pointA, pointB } = await snaptrude.core.geom.query.brep.getDistance(brepA, brepB)
354
+ * console.log("clearance:", distance)
355
+ * }
356
+ * ```
357
+ */
358
+ public abstract getDistance(
359
+ brepA: BrepHandle,
360
+ brepB: BrepHandle
361
+ ): PluginApiReturn<{ distance: number; pointA: Vec3Components; pointB: Vec3Components }>
331
362
  }
332
363
 
333
364
  const brepArg = z.object({ brep: BrepHandle })
@@ -442,3 +473,17 @@ export const PluginGeomQueryBrepIsEqualArgs = z.object({
442
473
  brepB: BrepHandle,
443
474
  })
444
475
  export type PluginGeomQueryBrepIsEqualArgs = z.infer<typeof PluginGeomQueryBrepIsEqualArgs>
476
+
477
+ /**
478
+ * Arguments for {@linkcode PluginGeomQueryBrepApi.getDistance}.
479
+ *
480
+ * | Property | Type | Description |
481
+ * |---|---|---|
482
+ * | `brepA` | {@linkcode BrepHandle} | First solid |
483
+ * | `brepB` | {@linkcode BrepHandle} | Second solid |
484
+ */
485
+ export const PluginGeomQueryBrepGetDistanceArgs = z.object({
486
+ brepA: BrepHandle,
487
+ brepB: BrepHandle,
488
+ })
489
+ export type PluginGeomQueryBrepGetDistanceArgs = z.infer<typeof PluginGeomQueryBrepGetDistanceArgs>