Skip to main content

kittycad_modeling_cmds/
shared.rs

1use bon::Builder;
2use enum_iterator::Sequence;
3use parse_display_derive::{Display, FromStr};
4pub use point::{Point2d, Point3d, Point4d, Quaternion};
5use schemars::{schema::SchemaObject, JsonSchema};
6use serde::{Deserialize, Serialize};
7use uuid::Uuid;
8
9#[cfg(feature = "cxx")]
10use crate::impl_extern_type;
11use crate::{
12    def_enum::negative_one,
13    id::ModelingCmdId,
14    length_unit::LengthUnit,
15    output::ExtrusionFaceInfo,
16    units::{self, UnitAngle},
17};
18
19mod point;
20pub mod safe_filepath;
21
22/// An edge can be referenced by its uuid or by the faces that uniquely define it.
23#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema, Builder)]
24#[serde(rename_all = "snake_case")]
25#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
26#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
27#[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))]
28#[cfg_attr(not(feature = "unstable_exhaustive"), non_exhaustive)]
29pub struct EdgeSpecifier {
30    /// Side face ids that uniquely identify the edge.
31    pub side_faces: Vec<Uuid>,
32    /// Optional end face ids for ambiguous edge matches.
33    #[serde(default, skip_serializing_if = "Vec::is_empty")]
34    #[builder(default)]
35    pub end_faces: Vec<Uuid>,
36    /// Optional index for disambiguation when multiple edges share the same faces.
37    /// If not provided (None), all matching edges will be used.
38    /// If provided (Some(n)), only the edge at index n will be used.
39    #[serde(skip_serializing_if = "Option::is_none")]
40    pub index: Option<u32>,
41}
42
43/// Optional fallback when primary UUIDs are missing from the client artifact graph (e.g. stale or
44/// engine-only ids). Identifies the same topology via a **parent** entity UUID and a **primitive
45/// index** on that parent.
46///
47/// Semantics by selection kind (aligned with engine BREP topology):
48///
49/// - **Face / Edge (3D)**: `parent_id` is the owning [`EntityType::Solid3D`] body UUID; `primitive_index`
50///   matches the index returned by **EntityGetPrimitiveIndex** for that face or edge (and matches
51///   **EntityGetParentId** → parent + **EntityGetPrimitiveIndex** → index).
52/// - **Vertex (3D)**: same `parent_id` (solid); `primitive_index` is the BREP vertex index on that solid.
53/// - **Solid2dEdge**: `parent_id` is the **Solid2D** profile UUID; `primitive_index` is the curve index
54///   within that profile.
55/// - **Segment**: `parent_id` is the **Path** UUID; `primitive_index` is the curve index within that path.
56///
57/// Other [`EntityReference`] variants may omit this field or leave it unset when not applicable.
58#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema, Builder)]
59#[serde(rename_all = "snake_case")]
60#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
61#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
62#[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))]
63#[cfg_attr(not(feature = "unstable_exhaustive"), non_exhaustive)]
64pub struct PrimitiveTopologyFallback {
65    /// UUID of the parent entity that owns the primitive (solid3d, solid2d, or path).
66    pub parent_id: Uuid,
67    /// Index of the face, edge, vertex, profile curve, or path segment on `parent_id`.
68    pub primitive_index: u32,
69}
70
71/// An edge/vertex can be defined by the faces that it is connected to.
72#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
73#[serde(tag = "type", rename_all = "snake_case")]
74#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
75#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
76#[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))]
77pub enum EntityReference {
78    /// A uuid referencing a plane.
79    Plane {
80        /// Id of the plane being referenced.
81        plane_id: Uuid,
82        /// Optional primitive topology on a parent (not used for planes today).
83        #[serde(default, skip_serializing_if = "Option::is_none")]
84        topology_fallback: Option<PrimitiveTopologyFallback>,
85    },
86    /// A uuid referencing a face.
87    Face {
88        /// Id of the face being referenced.
89        face_id: Uuid,
90        /// Fallback: solid3d UUID + face index on that body when `face_id` cannot be resolved client-side.
91        #[serde(default, skip_serializing_if = "Option::is_none")]
92        topology_fallback: Option<PrimitiveTopologyFallback>,
93    },
94    /// A collection of ids that uniquely identify an edge.
95    Edge {
96        /// Flattened edge reference (side_faces, end_faces, index).
97        #[serde(flatten)]
98        inner: EdgeSpecifier,
99        /// Fallback: solid3d UUID + edge index on that body for 3D BREP edges (distinct from `inner.index`).
100        #[serde(default, skip_serializing_if = "Option::is_none")]
101        topology_fallback: Option<PrimitiveTopologyFallback>,
102    },
103    /// A collection of ids that uniquely identify an vertex.
104    Vertex {
105        /// Side face ids that identify the vertex.
106        side_faces: Vec<Uuid>,
107        /// Optional index among the filtered candidates.
108        #[serde(skip_serializing_if = "Option::is_none")]
109        index: Option<u32>,
110        /// Fallback: solid3d UUID + vertex index on that body.
111        #[serde(default, skip_serializing_if = "Option::is_none")]
112        topology_fallback: Option<PrimitiveTopologyFallback>,
113    },
114    /// A uuid referencing a solid2d (profile).
115    Solid2d {
116        /// Id of the solid2d being referenced.
117        solid2d_id: Uuid,
118        /// Typically omitted: `solid2d_id` is already the owning profile. Present for schema parity with other variants.
119        #[serde(default, skip_serializing_if = "Option::is_none")]
120        topology_fallback: Option<PrimitiveTopologyFallback>,
121    },
122    /// A uuid referencing a solid3d (body).
123    Solid3d {
124        /// Id of the solid3d being referenced.
125        solid3d_id: Uuid,
126        /// Typically omitted: `solid3d_id` is already the owning body. Present for schema parity with other variants.
127        #[serde(default, skip_serializing_if = "Option::is_none")]
128        topology_fallback: Option<PrimitiveTopologyFallback>,
129    },
130    /// A uuid referencing an edge on a solid2d (profile) - used for raw sketch/profile edges.
131    /// This is distinct from the face-based Edge reference which is used for BRep/swept body edges.
132    Solid2dEdge {
133        /// Id of the edge being referenced.
134        edge_id: Uuid,
135        /// Fallback: solid2d UUID + curve index in that profile.
136        #[serde(default, skip_serializing_if = "Option::is_none")]
137        topology_fallback: Option<PrimitiveTopologyFallback>,
138    },
139    /// A single segment (curve) within a path.
140    Segment {
141        /// Id of the path containing the segment.
142        path_id: Uuid,
143        /// Id of the segment (curve) being referenced.
144        segment_id: Uuid,
145        /// Fallback: path UUID + segment curve index.
146        #[serde(default, skip_serializing_if = "Option::is_none")]
147        topology_fallback: Option<PrimitiveTopologyFallback>,
148    },
149    /// A closed sketch region/profile area.
150    Region {
151        /// Id of the region being referenced.
152        region_id: Uuid,
153        /// Fallback: path UUID + region index on that path.
154        #[serde(default, skip_serializing_if = "Option::is_none")]
155        topology_fallback: Option<PrimitiveTopologyFallback>,
156    },
157}
158
159/// What kind of cut to do
160#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize, JsonSchema, Default)]
161#[serde(rename_all = "snake_case")]
162#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
163#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
164#[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))]
165pub enum CutType {
166    /// Round off an edge.
167    #[default]
168    Fillet,
169    /// Cut away an edge.
170    Chamfer,
171}
172
173/// What to use as a direction when one is needed (e.g. for an extrusion).
174#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize, JsonSchema)]
175#[serde(rename_all = "snake_case")]
176#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
177#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
178#[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))]
179pub enum DirectionType {
180    /// Uses the direction of an edge, if linear
181    Edge {
182        /// Edge ID.
183        id: Uuid,
184    },
185    /// Uses the provided vector as the direction.
186    Axis {
187        /// Direction.
188        direction: Point3d<f64>,
189    },
190}
191
192/// What to reflect mirrored geometry across
193#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize, JsonSchema)]
194#[serde(rename_all = "snake_case")]
195#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
196#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
197#[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))]
198pub enum MirrorAcross {
199    /// Reflect across an edge
200    /// If used with a 3D mirror, the edge will define the normal of the mirror plane.
201    Edge {
202        /// Edge ID.
203        id: Uuid,
204    },
205    /// Reflect across an axis (that goes through a point)
206    /// If used with a 3D mirror, the axis will define the normal of the mirror plane.
207    Axis {
208        /// Axis to use as mirror.
209        axis: Point3d<f64>,
210        /// Point through which the mirror axis passes.
211        point: Point3d<LengthUnit>,
212    },
213    /// Reflect across a plane (which gives two axes)
214    /// Cannot be used with 2D mirrors.
215    Plane {
216        /// Plane ID.
217        id: Uuid,
218    },
219}
220
221/// What kind of cut to perform when cutting an edge.
222#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize, JsonSchema)]
223#[serde(rename_all = "snake_case")]
224#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
225#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
226#[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))]
227#[cfg_attr(not(feature = "unstable_exhaustive"), non_exhaustive)]
228pub enum CutTypeV2 {
229    /// Round off an edge.
230    Fillet {
231        /// The radius of the fillet.
232        radius: LengthUnit,
233        /// The second length affects the edge length of the second face of the cut. This will
234        /// cause the fillet to take on the shape of a conic section, instead of an arc.
235        second_length: Option<LengthUnit>,
236    },
237    /// Cut away an edge.
238    Chamfer {
239        /// The distance from the edge to cut on each face.
240        distance: LengthUnit,
241        /// The second distance affects the edge length of the second face of the cut.
242        second_distance: Option<LengthUnit>,
243        /// The angle of the chamfer, default is 45deg.
244        angle: Option<Angle>,
245        /// If true, the second distance or angle is applied to the other face of the cut.
246        swap: bool,
247    },
248    /// A custom cut profile.
249    Custom {
250        /// The path that will be used for the custom profile.
251        path: Uuid,
252    },
253}
254
255/// A rotation defined by an axis, origin of rotation, and an angle.
256#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema, Builder)]
257#[serde(rename_all = "snake_case")]
258#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
259#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
260#[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))]
261#[cfg_attr(not(feature = "unstable_exhaustive"), non_exhaustive)]
262pub struct Rotation {
263    /// Rotation axis.
264    /// Defaults to (0, 0, 1) (i.e. the Z axis).
265    pub axis: Point3d<f64>,
266    /// Rotate this far about the rotation axis.
267    /// Defaults to zero (i.e. no rotation).
268    pub angle: Angle,
269    /// Origin of the rotation. If one isn't provided, the object will rotate about its own bounding box center.
270    pub origin: OriginType,
271}
272
273impl Default for Rotation {
274    /// z-axis, 0 degree angle, and local origin.
275    fn default() -> Self {
276        Self {
277            axis: z_axis(),
278            angle: Angle::default(),
279            origin: OriginType::Local,
280        }
281    }
282}
283
284/// Ways to transform each solid being replicated in a repeating pattern.
285#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema, Builder)]
286#[serde(rename_all = "snake_case")]
287#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
288#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
289#[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))]
290#[cfg_attr(not(feature = "unstable_exhaustive"), non_exhaustive)]
291pub struct Transform {
292    /// Translate the replica this far along each dimension.
293    /// Defaults to zero vector (i.e. same position as the original).
294    #[serde(default)]
295    #[builder(default)]
296    pub translate: Point3d<LengthUnit>,
297    /// Scale the replica's size along each axis.
298    /// Defaults to (1, 1, 1) (i.e. the same size as the original).
299    #[serde(default = "same_scale")]
300    #[builder(default = same_scale())]
301    pub scale: Point3d<f64>,
302    /// Rotate the replica about the specified rotation axis and origin.
303    /// Defaults to no rotation.
304    #[serde(default)]
305    #[builder(default)]
306    pub rotation: Rotation,
307    /// Whether to replicate the original solid in this instance.
308    #[serde(default = "bool_true")]
309    #[builder(default = bool_true())]
310    pub replicate: bool,
311}
312
313impl Default for Transform {
314    fn default() -> Self {
315        Self {
316            scale: same_scale(),
317            replicate: true,
318            translate: Default::default(),
319            rotation: Rotation::default(),
320        }
321    }
322}
323
324/// Options for annotations
325#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema, Builder)]
326#[serde(rename_all = "snake_case")]
327#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
328#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
329#[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))]
330#[cfg_attr(not(feature = "unstable_exhaustive"), non_exhaustive)]
331pub struct AnnotationOptions {
332    /// Text displayed on the annotation
333    pub text: Option<AnnotationTextOptions>,
334    /// How to style the start and end of the line
335    pub line_ends: Option<AnnotationLineEndOptions>,
336    /// Width of the annotation's line
337    pub line_width: Option<f32>,
338    /// Color to render the annotation
339    pub color: Option<Color>,
340    /// Position to put the annotation
341    pub position: Option<Point3d<f32>>,
342    /// Length Units to use for this individual annotation.  If not provided, the units set by SetSceneUnits will be used.
343    #[serde(default, skip_serializing_if = "Option::is_none")]
344    pub units: Option<units::UnitLength>,
345    /// Set as an MBD measured basic dimension annotation
346    pub dimension: Option<AnnotationBasicDimension>,
347    /// Set as an MBD Feature control annotation
348    pub feature_control: Option<AnnotationFeatureControl>,
349    /// Set as a feature tag annotation
350    pub feature_tag: Option<AnnotationFeatureTag>,
351}
352
353/// Options for annotation text
354#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema, Builder)]
355#[serde(rename_all = "snake_case")]
356#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
357#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
358#[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))]
359#[cfg_attr(not(feature = "unstable_exhaustive"), non_exhaustive)]
360pub struct AnnotationLineEndOptions {
361    /// How to style the start of the annotation line.
362    pub start: AnnotationLineEnd,
363    /// How to style the end of the annotation line.
364    pub end: AnnotationLineEnd,
365}
366
367/// Options for annotation text
368#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema, Builder)]
369#[serde(rename_all = "snake_case")]
370#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
371#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
372#[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))]
373#[cfg_attr(not(feature = "unstable_exhaustive"), non_exhaustive)]
374pub struct AnnotationTextOptions {
375    /// Alignment along the X axis
376    pub x: AnnotationTextAlignmentX,
377    /// Alignment along the Y axis
378    pub y: AnnotationTextAlignmentY,
379    /// Text displayed on the annotation
380    pub text: String,
381    /// Text font's point size
382    pub point_size: u32,
383}
384
385/// Parameters for defining an MBD Geometric control frame
386#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema, Builder)]
387#[serde(rename_all = "snake_case")]
388#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
389#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
390#[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))]
391#[cfg_attr(not(feature = "unstable_exhaustive"), non_exhaustive)]
392pub struct AnnotationMbdControlFrame {
393    ///Geometric symbol, the type of geometric control specified
394    pub symbol: MbdSymbol,
395    /// Diameter symbol (if required) whether the geometric control requires a cylindrical or diameter tolerance
396    pub diameter_symbol: Option<MbdSymbol>,
397    /// Tolerance value - the total tolerance of the geometric control.  The unit is based on the drawing standard.
398    pub tolerance: f64,
399    /// Feature of size or tolerance modifiers
400    pub modifier: Option<MbdSymbol>,
401    /// Primary datum
402    pub primary_datum: Option<char>,
403    /// Secondary datum
404    pub secondary_datum: Option<char>,
405    /// Tertiary datum
406    pub tertiary_datum: Option<char>,
407}
408
409/// Parameters for defining an MBD basic dimension
410#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema, Builder)]
411#[serde(rename_all = "snake_case")]
412#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
413#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
414#[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))]
415#[cfg_attr(not(feature = "unstable_exhaustive"), non_exhaustive)]
416pub struct AnnotationMbdBasicDimension {
417    /// Type of symbol to use for this dimension (if required)
418    pub symbol: Option<MbdSymbol>,
419    /// The explicitly defined dimension.  Only required if the measurement is not automatically calculated.
420    pub dimension: Option<f64>,
421    /// The tolerance of the dimension
422    pub tolerance: f64,
423}
424
425/// Parameters for defining an MBD Basic Dimension Annotation state which is measured between two positions in 3D
426#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema, Builder)]
427#[serde(rename_all = "snake_case")]
428#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
429#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
430#[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))]
431#[cfg_attr(not(feature = "unstable_exhaustive"), non_exhaustive)]
432pub struct AnnotationBasicDimension {
433    /// Entity to measure the dimension from
434    #[serde(default, skip_serializing_if = "Option::is_none")]
435    pub from_entity_id: Option<Uuid>,
436
437    /// Edge reference to use to measure the dimension from
438    /// If both `from_entity_id` and `from_edge_reference` are provided, `from_edge_reference` takes precedence.
439    #[serde(default, skip_serializing_if = "Option::is_none")]
440    pub from_edge_reference: Option<EdgeSpecifier>,
441
442    /// Normalized position within the entity to position the dimension from
443    pub from_entity_pos: Point2d<f64>,
444
445    /// Entity to measure the dimension to
446    #[serde(default, skip_serializing_if = "Option::is_none")]
447    pub to_entity_id: Option<Uuid>,
448
449    /// Edge reference to use to measure the dimension from
450    /// If both `to_entity_id` and `to_edge_reference` are provided, `to_edge_reference` takes precedence.
451    #[serde(default, skip_serializing_if = "Option::is_none")]
452    pub to_edge_reference: Option<EdgeSpecifier>,
453
454    /// Normalized position within the entity to position the dimension to
455    pub to_entity_pos: Point2d<f64>,
456
457    /// Basic dimension parameters (symbol and tolerance)
458    pub dimension: AnnotationMbdBasicDimension,
459
460    /// Orientation plane.  The annotation will lie in this plane which is positioned about the leader position as its origin.
461    pub plane_id: Uuid,
462
463    /// 2D Position offset of the annotation within the plane.
464    pub offset: Point2d<f64>,
465
466    /// Number of decimal places to use when displaying tolerance and dimension values
467    pub precision: u32,
468
469    /// The scale of the font label in 3D space
470    pub font_scale: f32,
471
472    /// The point size of the fonts used to generate the annotation label.  Very large values can negatively affect performance.
473    pub font_point_size: u32,
474
475    /// The scale of the dimension arrows. Defaults to 1.
476    #[serde(default = "one")]
477    pub arrow_scale: f32,
478}
479
480/// Parameters for defining an MBD Feature Control Annotation state
481#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema, Builder)]
482#[serde(rename_all = "snake_case")]
483#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
484#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
485#[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))]
486#[cfg_attr(not(feature = "unstable_exhaustive"), non_exhaustive)]
487pub struct AnnotationFeatureControl {
488    /// Entity to place the annotation leader from
489    #[serde(default, skip_serializing_if = "Option::is_none")]
490    pub entity_id: Option<Uuid>,
491
492    /// Edge reference to use to place the annotation leader from
493    /// If both `entity_id` and `edge_reference` are provided, `edge_reference` takes precedence.
494    #[serde(default, skip_serializing_if = "Option::is_none")]
495    pub edge_reference: Option<EdgeSpecifier>,
496
497    /// Normalized position within the entity to position the annotation leader from
498    pub entity_pos: Point2d<f64>,
499
500    /// Type of leader to use
501    pub leader_type: AnnotationLineEnd,
502
503    /// Basic dimensions
504    pub dimension: Option<AnnotationMbdBasicDimension>,
505
506    /// MBD Control frame for geometric control
507    pub control_frame: Option<AnnotationMbdControlFrame>,
508
509    /// Set if this annotation is defining a datum
510    pub defined_datum: Option<char>,
511
512    /// Prefix text which will appear before the basic dimension
513    pub prefix: Option<String>,
514
515    /// Suffix text which will appear after the basic dimension
516    pub suffix: Option<String>,
517
518    /// Orientation plane.  The annotation will lie in this plane which is positioned about the leader position as its origin.
519    pub plane_id: Uuid,
520
521    /// 2D Position offset of the annotation within the plane.
522    pub offset: Point2d<f64>,
523
524    /// Number of decimal places to use when displaying tolerance and dimension values
525    pub precision: u32,
526
527    /// The scale of the font label in 3D space
528    pub font_scale: f32,
529
530    /// The point size of the fonts used to generate the annotation label.  Very large values can negatively affect performance.
531    pub font_point_size: u32,
532
533    /// The scale of the leader (dot or arrow). Defaults to 1.
534    #[serde(default = "one")]
535    pub leader_scale: f32,
536}
537
538/// Parameters for defining an MBD Feature Tag Annotation state
539#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema, Builder)]
540#[serde(rename_all = "snake_case")]
541#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
542#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
543#[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))]
544#[cfg_attr(not(feature = "unstable_exhaustive"), non_exhaustive)]
545pub struct AnnotationFeatureTag {
546    /// Entity to place the annotation leader from
547    #[serde(default, skip_serializing_if = "Option::is_none")]
548    pub entity_id: Option<Uuid>,
549
550    /// Edge reference to use to place the annotation leader from
551    /// If both `entity_id` and `edge_reference` are provided, `edge_reference` takes precedence.
552    #[serde(default, skip_serializing_if = "Option::is_none")]
553    pub edge_reference: Option<EdgeSpecifier>,
554
555    /// Normalized position within the entity to position the annotation leader from
556    pub entity_pos: Point2d<f64>,
557
558    /// Type of leader to use
559    pub leader_type: AnnotationLineEnd,
560
561    /// Tag key
562    pub key: String,
563
564    /// Tag value
565    pub value: String,
566
567    /// Whether or not to display the key on the annotation label
568    pub show_key: bool,
569
570    /// Orientation plane.  The annotation will lie in this plane which is positioned about the leader position as its origin.
571    pub plane_id: Uuid,
572
573    /// 2D Position offset of the annotation within the plane.
574    pub offset: Point2d<f64>,
575
576    /// The scale of the font label in 3D space
577    pub font_scale: f32,
578
579    /// The point size of the fonts used to generate the annotation label.  Very large values can negatively affect performance.
580    pub font_point_size: u32,
581
582    /// The scale of the leader (dot or arrow). Defaults to 1.
583    #[serde(default = "one")]
584    pub leader_scale: f32,
585}
586
587/// The type of distance
588/// Distances can vary depending on
589/// the objects used as input.
590#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize, JsonSchema)]
591#[serde(rename_all = "snake_case", tag = "type")]
592#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
593#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
594#[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))]
595#[cfg_attr(not(feature = "unstable_exhaustive"), non_exhaustive)]
596pub enum DistanceType {
597    /// Euclidean Distance.
598    Euclidean {},
599    /// The distance between objects along the specified axis
600    OnAxis {
601        /// Global axis
602        axis: GlobalAxis,
603    },
604}
605
606/// The type of origin
607#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize, JsonSchema, Default)]
608#[serde(rename_all = "snake_case", tag = "type")]
609#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
610#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
611#[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))]
612#[cfg_attr(not(feature = "unstable_exhaustive"), non_exhaustive)]
613pub enum OriginType {
614    /// Local Origin ([0, 0, 0] in object space).
615    #[default]
616    Local,
617    /// Global Origin ([0, 0, 0] in world space).
618    Global,
619    /// Custom Origin (user specified point in world space).
620    Custom {
621        /// Custom origin point.
622        origin: Point3d<f64>,
623    },
624}
625
626/// An RGBA color
627#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize, JsonSchema, Builder)]
628#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
629#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
630#[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))]
631#[cfg_attr(not(feature = "unstable_exhaustive"), non_exhaustive)]
632pub struct Color {
633    /// Red
634    pub r: f32,
635    /// Green
636    pub g: f32,
637    /// Blue
638    pub b: f32,
639    /// Alpha
640    pub a: f32,
641}
642
643impl Color {
644    /// Assign the red, green, blue and alpha (transparency) channels.
645    pub fn from_rgba(r: f32, g: f32, b: f32, a: f32) -> Self {
646        Self { r, g, b, a }
647    }
648}
649
650/// Horizontal Text alignment
651#[allow(missing_docs)]
652#[derive(
653    Display, FromStr, Copy, Eq, PartialEq, Debug, JsonSchema, Deserialize, Serialize, Sequence, Clone, Ord, PartialOrd,
654)]
655#[serde(rename_all = "lowercase")]
656#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
657#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
658#[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))]
659#[cfg_attr(not(feature = "unstable_exhaustive"), non_exhaustive)]
660pub enum AnnotationTextAlignmentX {
661    Left,
662    Center,
663    Right,
664}
665
666/// Vertical Text alignment
667#[allow(missing_docs)]
668#[derive(
669    Display, FromStr, Copy, Eq, PartialEq, Debug, JsonSchema, Deserialize, Serialize, Sequence, Clone, Ord, PartialOrd,
670)]
671#[serde(rename_all = "lowercase")]
672#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
673#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
674#[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))]
675#[cfg_attr(not(feature = "unstable_exhaustive"), non_exhaustive)]
676pub enum AnnotationTextAlignmentY {
677    Bottom,
678    Center,
679    Top,
680}
681
682/// Annotation line end type
683#[allow(missing_docs)]
684#[derive(
685    Display, FromStr, Copy, Eq, PartialEq, Debug, JsonSchema, Deserialize, Serialize, Sequence, Clone, Ord, PartialOrd,
686)]
687#[serde(rename_all = "lowercase")]
688#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
689#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
690#[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))]
691#[cfg_attr(not(feature = "unstable_exhaustive"), non_exhaustive)]
692pub enum AnnotationLineEnd {
693    None,
694    Arrow,
695    Dot,
696}
697
698/// The type of annotation
699#[derive(
700    Display, FromStr, Copy, Eq, PartialEq, Debug, JsonSchema, Deserialize, Serialize, Sequence, Clone, Ord, PartialOrd,
701)]
702#[serde(rename_all = "lowercase")]
703#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
704#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
705#[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))]
706#[cfg_attr(not(feature = "unstable_exhaustive"), non_exhaustive)]
707pub enum AnnotationType {
708    /// 2D annotation type (screen or planar space)
709    T2D,
710    /// 3D annotation type
711    T3D,
712}
713
714/// MBD standard
715#[derive(
716    Display, FromStr, Copy, Eq, PartialEq, Debug, JsonSchema, Deserialize, Serialize, Sequence, Clone, Ord, PartialOrd,
717)]
718#[serde(rename_all = "lowercase")]
719#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
720#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
721#[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))]
722#[cfg_attr(not(feature = "unstable_exhaustive"), non_exhaustive)]
723pub enum MbdStandard {
724    /// ASME Y14.5 GD&T
725    AsmeY14_5,
726}
727
728//SEE MIKE BEFORE MAKING ANY CHANGES TO THIS ENUM
729/// MBD symbol type
730#[allow(missing_docs)]
731#[derive(
732    Default,
733    Display,
734    FromStr,
735    Copy,
736    Eq,
737    PartialEq,
738    Debug,
739    JsonSchema,
740    Deserialize,
741    Serialize,
742    Sequence,
743    Clone,
744    Ord,
745    PartialOrd,
746)]
747#[serde(rename_all = "lowercase")]
748#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
749#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
750#[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))]
751#[repr(u16)]
752#[cfg_attr(not(feature = "unstable_exhaustive"), non_exhaustive)]
753pub enum MbdSymbol {
754    #[default]
755    None = 0,
756    ArcLength = 174,
757    Between = 175,
758    Degrees = 176,
759    PlusMinus = 177,
760    Angularity = 178,
761    Cylindricity = 179,
762    Roundness = 180,
763    Concentricity = 181,
764    Straightness = 182,
765    Parallelism = 183,
766    Flatness = 184,
767    ProfileOfLine = 185,
768    SurfaceProfile = 186,
769    Symmetry = 187,
770    Perpendicularity = 188,
771    Runout = 189,
772    TotalRunout = 190,
773    Position = 191,
774    CenterLine = 192,
775    PartingLine = 193,
776    IsoEnvelope = 195,
777    IsoEnvelopeNonY145M = 196,
778    FreeState = 197,
779    StatisticalTolerance = 198,
780    ContinuousFeature = 199,
781    Independency = 200,
782    Depth = 201,
783    Start = 202,
784    LeastCondition = 203,
785    MaxCondition = 204,
786    ConicalTaper = 205,
787    Projected = 206,
788    Slope = 207,
789    Micro = 208,
790    TangentPlane = 210,
791    Unilateral = 211,
792    SquareFeature = 212,
793    Countersink = 213,
794    SpotFace = 214,
795    Target = 215,
796    Diameter = 216,
797    Radius = 217,
798    SphericalRadius = 218,
799    SphericalDiameter = 219,
800    ControlledRadius = 220,
801    BoxStart = 123,
802    BoxBar = 162,
803    BoxBarBetween = 124,
804    LetterBackwardUnderline = 95,
805    PunctuationBackwardUnderline = 92,
806    ModifierBackwardUnderline = 126,
807    NumericBackwardUnderline = 96,
808    BoxEnd = 125,
809    DatumUp = 166,
810    DatumLeft = 168,
811    DatumRight = 167,
812    DatumDown = 165,
813    DatumTriangle = 295,
814    HalfSpace = 236,
815    QuarterSpace = 237,
816    EighthSpace = 238,
817    ModifierSpace = 239,
818}
819
820/// The type of camera drag interaction.
821#[derive(
822    Display, FromStr, Copy, Eq, PartialEq, Debug, JsonSchema, Deserialize, Serialize, Sequence, Clone, Ord, PartialOrd,
823)]
824#[serde(rename_all = "lowercase")]
825#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
826#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
827#[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))]
828#[cfg_attr(not(feature = "unstable_exhaustive"), non_exhaustive)]
829pub enum CameraDragInteractionType {
830    /// Camera pan
831    Pan,
832    /// Camera rotate (spherical camera revolve/orbit)
833    Rotate,
834    /// Camera rotate (trackball with 3 degrees of freedom)
835    RotateTrackball,
836    /// Camera zoom (increase or decrease distance to reference point center)
837    Zoom,
838}
839
840/// A segment of a path.
841/// Paths are composed of many segments.
842#[derive(Debug, Clone, Copy, Serialize, Deserialize, JsonSchema, PartialEq)]
843#[serde(rename_all = "snake_case", tag = "type")]
844#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
845#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
846#[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))]
847#[cfg_attr(not(feature = "unstable_exhaustive"), non_exhaustive)]
848pub enum PathSegment {
849    /// A straight line segment.
850    /// Goes from the current path "pen" to the given endpoint.
851    Line {
852        /// End point of the line.
853        end: Point3d<LengthUnit>,
854        ///Whether or not this line is a relative offset
855        relative: bool,
856    },
857    /// A circular arc segment.
858    /// Arcs can be drawn clockwise when start > end.
859    Arc {
860        /// Center of the circle
861        center: Point2d<LengthUnit>,
862        /// Radius of the circle
863        radius: LengthUnit,
864        /// Start of the arc along circle's perimeter.
865        start: Angle,
866        /// End of the arc along circle's perimeter.
867        end: Angle,
868        ///Whether or not this arc is a relative offset
869        relative: bool,
870    },
871    /// A cubic bezier curve segment.
872    /// Start at the end of the current line, go through control point 1 and 2, then end at a
873    /// given point.
874    Bezier {
875        /// First control point.
876        control1: Point3d<LengthUnit>,
877        /// Second control point.
878        control2: Point3d<LengthUnit>,
879        /// Final control point.
880        end: Point3d<LengthUnit>,
881        ///Whether or not this bezier is a relative offset
882        relative: bool,
883    },
884    /// Adds a tangent arc from current pen position with the given radius and angle.
885    TangentialArc {
886        /// Radius of the arc.
887        /// Not to be confused with Raiders of the Lost Ark.
888        radius: LengthUnit,
889        /// Offset of the arc. Negative values will arc clockwise.
890        offset: Angle,
891    },
892    /// Adds a tangent arc from current pen position to the new position.
893    /// Arcs will choose a clockwise or counter-clockwise direction based on the arc end position.
894    TangentialArcTo {
895        /// Where the arc should end.
896        /// Must lie in the same plane as the current path pen position.
897        /// Must not be colinear with current path pen position.
898        to: Point3d<LengthUnit>,
899        /// 0 will be interpreted as none/null.
900        angle_snap_increment: Option<Angle>,
901    },
902    ///Adds an arc from the current position that goes through the given interior point and ends at the given end position
903    ArcTo {
904        /// Interior point of the arc.
905        interior: Point3d<LengthUnit>,
906        /// End point of the arc.
907        end: Point3d<LengthUnit>,
908        ///Whether or not interior and end are relative to the previous path position
909        relative: bool,
910    },
911    ///Adds a circular involute from the current position that goes through the given end_radius
912    ///and is rotated around the current point by angle.
913    CircularInvolute {
914        ///The involute is described between two circles, start_radius is the radius of the inner
915        ///circle.
916        start_radius: LengthUnit,
917        ///The involute is described between two circles, end_radius is the radius of the outer
918        ///circle.
919        end_radius: LengthUnit,
920        ///The angle to rotate the involute by. A value of zero will produce a curve with a tangent
921        ///along the x-axis at the start point of the curve.
922        angle: Angle,
923        ///If reverse is true, the segment will start
924        ///from the end of the involute, otherwise it will start from that start.
925        reverse: bool,
926    },
927    ///Adds an elliptical arc segment.
928    Ellipse {
929        /// The center point of the ellipse.
930        center: Point2d<LengthUnit>,
931        /// Major axis of the ellipse.
932        major_axis: Point2d<LengthUnit>,
933        /// Minor radius of the ellipse.
934        minor_radius: LengthUnit,
935        /// Start of the path along the perimeter of the ellipse.
936        start_angle: Angle,
937        /// End of the path along the perimeter of the ellipse.
938        end_angle: Angle,
939    },
940    ///Adds a generic conic section specified by the end point, interior point and tangents at the
941    ///start and end of the section.
942    ConicTo {
943        /// Interior point that lies on the conic.
944        interior: Point2d<LengthUnit>,
945        /// End point of the conic.
946        end: Point2d<LengthUnit>,
947        /// Tangent at the start of the conic.
948        start_tangent: Point2d<LengthUnit>,
949        /// Tangent at the end of the conic.
950        end_tangent: Point2d<LengthUnit>,
951        /// Whether or not the interior and end points are relative to the previous path position.
952        relative: bool,
953    },
954}
955
956/// An angle, with a specific unit.
957#[derive(Clone, Copy, PartialEq, Debug, JsonSchema, Deserialize, Serialize)]
958#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
959#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
960#[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))]
961#[cfg_attr(not(feature = "unstable_exhaustive"), non_exhaustive)]
962pub struct Angle {
963    /// What unit is the measurement?
964    pub unit: UnitAngle,
965    /// The size of the angle, measured in the chosen unit.
966    pub value: f64,
967}
968
969impl Angle {
970    /// Converts a given angle to degrees.
971    pub fn to_degrees(self) -> f64 {
972        match self.unit {
973            UnitAngle::Degrees => self.value,
974            UnitAngle::Radians => self.value.to_degrees(),
975        }
976    }
977    /// Converts a given angle to radians.
978    pub fn to_radians(self) -> f64 {
979        match self.unit {
980            UnitAngle::Degrees => self.value.to_radians(),
981            UnitAngle::Radians => self.value,
982        }
983    }
984    /// Create an angle in degrees.
985    pub const fn from_degrees(value: f64) -> Self {
986        Self {
987            unit: UnitAngle::Degrees,
988            value,
989        }
990    }
991    /// Create an angle in radians.
992    pub const fn from_radians(value: f64) -> Self {
993        Self {
994            unit: UnitAngle::Radians,
995            value,
996        }
997    }
998    /// 360 degrees.
999    pub const fn turn() -> Self {
1000        Self::from_degrees(360.0)
1001    }
1002    /// 180 degrees.
1003    pub const fn half_circle() -> Self {
1004        Self::from_degrees(180.0)
1005    }
1006    /// 90 degrees.
1007    pub const fn quarter_circle() -> Self {
1008        Self::from_degrees(90.0)
1009    }
1010    /// 0 degrees.
1011    pub const fn zero() -> Self {
1012        Self::from_degrees(0.0)
1013    }
1014}
1015
1016/// 0 degrees.
1017impl Default for Angle {
1018    /// 0 degrees.
1019    fn default() -> Self {
1020        Self::zero()
1021    }
1022}
1023
1024impl PartialOrd for Angle {
1025    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
1026        match (self.unit, other.unit) {
1027            // Avoid unnecessary floating point operations.
1028            (UnitAngle::Degrees, UnitAngle::Degrees) => self.value.partial_cmp(&other.value),
1029            (UnitAngle::Radians, UnitAngle::Radians) => self.value.partial_cmp(&other.value),
1030            _ => self.to_degrees().partial_cmp(&other.to_degrees()),
1031        }
1032    }
1033}
1034
1035impl std::ops::Add for Angle {
1036    type Output = Self;
1037
1038    fn add(self, rhs: Self) -> Self::Output {
1039        Self {
1040            unit: UnitAngle::Degrees,
1041            value: self.to_degrees() + rhs.to_degrees(),
1042        }
1043    }
1044}
1045
1046impl std::ops::AddAssign for Angle {
1047    fn add_assign(&mut self, rhs: Self) {
1048        match self.unit {
1049            UnitAngle::Degrees => {
1050                self.value += rhs.to_degrees();
1051            }
1052            UnitAngle::Radians => {
1053                self.value += rhs.to_radians();
1054            }
1055        }
1056    }
1057}
1058
1059/// The type of scene selection change
1060#[derive(
1061    Display, FromStr, Copy, Eq, PartialEq, Debug, JsonSchema, Deserialize, Serialize, Sequence, Clone, Ord, PartialOrd,
1062)]
1063#[serde(rename_all = "lowercase")]
1064#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
1065#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
1066#[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))]
1067#[cfg_attr(not(feature = "unstable_exhaustive"), non_exhaustive)]
1068pub enum SceneSelectionType {
1069    /// Replaces the selection
1070    Replace,
1071    /// Adds to the selection
1072    Add,
1073    /// Removes from the selection
1074    Remove,
1075}
1076
1077/// The type of scene's active tool
1078#[allow(missing_docs)]
1079#[derive(
1080    Display, FromStr, Copy, Eq, PartialEq, Debug, JsonSchema, Deserialize, Serialize, Sequence, Clone, Ord, PartialOrd,
1081)]
1082#[serde(rename_all = "snake_case")]
1083#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
1084#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
1085#[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))]
1086#[cfg_attr(not(feature = "unstable_exhaustive"), non_exhaustive)]
1087pub enum SceneToolType {
1088    CameraRevolve,
1089    Select,
1090    Move,
1091    SketchLine,
1092    SketchTangentialArc,
1093    SketchCurve,
1094    SketchCurveMod,
1095}
1096
1097/// The path component constraint bounds type
1098#[allow(missing_docs)]
1099#[derive(
1100    Display,
1101    FromStr,
1102    Copy,
1103    Eq,
1104    PartialEq,
1105    Debug,
1106    JsonSchema,
1107    Deserialize,
1108    Serialize,
1109    Sequence,
1110    Clone,
1111    Ord,
1112    PartialOrd,
1113    Default,
1114)]
1115#[serde(rename_all = "snake_case")]
1116#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
1117#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
1118#[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))]
1119#[cfg_attr(not(feature = "unstable_exhaustive"), non_exhaustive)]
1120pub enum PathComponentConstraintBound {
1121    #[default]
1122    Unconstrained,
1123    PartiallyConstrained,
1124    FullyConstrained,
1125}
1126
1127/// The path component constraint type
1128#[allow(missing_docs)]
1129#[derive(
1130    Display,
1131    FromStr,
1132    Copy,
1133    Eq,
1134    PartialEq,
1135    Debug,
1136    JsonSchema,
1137    Deserialize,
1138    Serialize,
1139    Sequence,
1140    Clone,
1141    Ord,
1142    PartialOrd,
1143    Default,
1144)]
1145#[serde(rename_all = "snake_case")]
1146#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
1147#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
1148#[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))]
1149#[cfg_attr(not(feature = "unstable_exhaustive"), non_exhaustive)]
1150pub enum PathComponentConstraintType {
1151    #[default]
1152    Unconstrained,
1153    Vertical,
1154    Horizontal,
1155    EqualLength,
1156    Parallel,
1157    AngleBetween,
1158}
1159
1160/// The path component command type (within a Path)
1161#[allow(missing_docs)]
1162#[derive(
1163    Display, FromStr, Copy, Eq, PartialEq, Debug, JsonSchema, Deserialize, Serialize, Sequence, Clone, Ord, PartialOrd,
1164)]
1165#[serde(rename_all = "snake_case")]
1166#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
1167#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
1168#[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))]
1169#[cfg_attr(not(feature = "unstable_exhaustive"), non_exhaustive)]
1170pub enum PathCommand {
1171    MoveTo,
1172    LineTo,
1173    BezCurveTo,
1174    NurbsCurveTo,
1175    AddArc,
1176}
1177
1178/// The type of entity
1179#[allow(missing_docs)]
1180#[derive(
1181    Display, FromStr, Copy, Eq, PartialEq, Debug, JsonSchema, Deserialize, Serialize, Sequence, Clone, Ord, PartialOrd,
1182)]
1183#[serde(rename_all = "lowercase")]
1184#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
1185#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
1186#[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))]
1187#[repr(u8)]
1188#[cfg_attr(not(feature = "unstable_exhaustive"), non_exhaustive)]
1189pub enum EntityType {
1190    Entity,
1191    Object,
1192    Path,
1193    Segment,
1194    Curve,
1195    Solid2D,
1196    Solid3D,
1197    Edge,
1198    Face,
1199    Plane,
1200    Vertex,
1201    Region,
1202}
1203
1204/// The type of Curve (embedded within path)
1205#[allow(missing_docs)]
1206#[derive(
1207    Display, FromStr, Copy, Eq, PartialEq, Debug, JsonSchema, Deserialize, Serialize, Sequence, Clone, Ord, PartialOrd,
1208)]
1209#[serde(rename_all = "snake_case")]
1210#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
1211#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
1212#[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))]
1213#[cfg_attr(not(feature = "unstable_exhaustive"), non_exhaustive)]
1214pub enum CurveType {
1215    Line,
1216    Arc,
1217    Nurbs,
1218}
1219
1220/// A file to be exported to the client.
1221#[derive(Debug, Serialize, Deserialize, JsonSchema, Clone, PartialEq, Builder)]
1222#[cfg_attr(
1223    feature = "python",
1224    pyo3::pyclass(from_py_object),
1225    pyo3_stub_gen::derive::gen_stub_pyclass
1226)]
1227#[cfg_attr(not(feature = "unstable_exhaustive"), non_exhaustive)]
1228pub struct ExportFile {
1229    /// The name of the file.
1230    pub name: String,
1231    /// The contents of the file, base64 encoded.
1232    pub contents: crate::base64::Base64Data,
1233}
1234
1235#[cfg(feature = "python")]
1236#[pyo3_stub_gen::derive::gen_stub_pymethods]
1237#[pyo3::pymethods]
1238impl ExportFile {
1239    #[getter]
1240    fn contents(&self) -> Vec<u8> {
1241        self.contents.0.clone()
1242    }
1243
1244    #[getter]
1245    fn name(&self) -> String {
1246        self.name.clone()
1247    }
1248}
1249
1250/// The valid types of output file formats.
1251#[derive(
1252    Display, FromStr, Copy, Eq, PartialEq, Debug, JsonSchema, Deserialize, Serialize, Clone, Ord, PartialOrd, Sequence,
1253)]
1254#[serde(rename_all = "lowercase")]
1255#[display(style = "lowercase")]
1256#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
1257#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
1258#[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))]
1259#[cfg_attr(
1260    feature = "python",
1261    pyo3::pyclass(from_py_object),
1262    pyo3_stub_gen::derive::gen_stub_pyclass_enum
1263)]
1264#[cfg_attr(not(feature = "unstable_exhaustive"), non_exhaustive)]
1265pub enum FileExportFormat {
1266    /// Autodesk Filmbox (FBX) format. <https://en.wikipedia.org/wiki/FBX>
1267    Fbx,
1268    /// Binary glTF 2.0.
1269    ///
1270    /// This is a single binary with .glb extension.
1271    ///
1272    /// This is better if you want a compressed format as opposed to the human readable
1273    /// glTF that lacks compression.
1274    Glb,
1275    /// glTF 2.0.
1276    /// Embedded glTF 2.0 (pretty printed).
1277    ///
1278    /// Single JSON file with .gltf extension binary data encoded as
1279    /// base64 data URIs.
1280    ///
1281    /// The JSON contents are pretty printed.
1282    ///
1283    /// It is human readable, single file, and you can view the
1284    /// diff easily in a git commit.
1285    Gltf,
1286    /// The OBJ file format. <https://en.wikipedia.org/wiki/Wavefront_.obj_file>
1287    /// It may or may not have an an attached material (mtl // mtllib) within the file,
1288    /// but we interact with it as if it does not.
1289    Obj,
1290    /// The PLY file format. <https://en.wikipedia.org/wiki/PLY_(file_format)>
1291    Ply,
1292    /// The STEP file format. <https://en.wikipedia.org/wiki/ISO_10303-21>
1293    Step,
1294    /// The STL file format. <https://en.wikipedia.org/wiki/STL_(file_format)>
1295    Stl,
1296}
1297
1298/// The valid types of 2D output file formats.
1299#[derive(
1300    Display, FromStr, Copy, Eq, PartialEq, Debug, JsonSchema, Deserialize, Serialize, Clone, Ord, PartialOrd, Sequence,
1301)]
1302#[serde(rename_all = "lowercase")]
1303#[display(style = "lowercase")]
1304#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
1305#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
1306#[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))]
1307#[cfg_attr(not(feature = "unstable_exhaustive"), non_exhaustive)]
1308pub enum FileExportFormat2d {
1309    /// AutoCAD drawing interchange format.
1310    Dxf,
1311}
1312
1313/// The valid types of source file formats.
1314#[derive(
1315    Display, FromStr, Copy, Eq, PartialEq, Debug, JsonSchema, Deserialize, Serialize, Clone, Ord, PartialOrd, Sequence,
1316)]
1317#[serde(rename_all = "lowercase")]
1318#[display(style = "lowercase")]
1319#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
1320#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
1321#[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))]
1322#[cfg_attr(not(feature = "unstable_exhaustive"), non_exhaustive)]
1323pub enum FileImportFormat {
1324    /// ACIS part format.
1325    Acis,
1326    /// CATIA part format.
1327    Catia,
1328    /// PTC Creo part format.
1329    Creo,
1330    /// Autodesk Filmbox (FBX) format. <https://en.wikipedia.org/wiki/FBX>
1331    Fbx,
1332    /// glTF 2.0.
1333    Gltf,
1334    /// Autodesk Inventor part format.
1335    Inventor,
1336    /// Siemens NX part format.
1337    Nx,
1338    /// The OBJ file format. <https://en.wikipedia.org/wiki/Wavefront_.obj_file>
1339    /// It may or may not have an an attached material (mtl // mtllib) within the file,
1340    /// but we interact with it as if it does not.
1341    Obj,
1342    /// Parasolid part format.
1343    Parasolid,
1344    /// The PLY file format. <https://en.wikipedia.org/wiki/PLY_(file_format)>
1345    Ply,
1346    /// SolidWorks part (SLDPRT) format.
1347    Sldprt,
1348    /// The STEP file format. <https://en.wikipedia.org/wiki/ISO_10303-21>
1349    Step,
1350    /// The STL file format. <https://en.wikipedia.org/wiki/STL_(file_format)>
1351    Stl,
1352}
1353
1354/// The type of error sent by the KittyCAD graphics engine.
1355#[derive(Display, FromStr, Copy, Eq, PartialEq, Debug, JsonSchema, Deserialize, Serialize, Clone, Ord, PartialOrd)]
1356#[serde(rename_all = "snake_case")]
1357#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
1358#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
1359#[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))]
1360#[cfg_attr(not(feature = "unstable_exhaustive"), non_exhaustive)]
1361pub enum EngineErrorCode {
1362    /// User requested something geometrically or graphically impossible.
1363    /// Don't retry this request, as it's inherently impossible. Instead, read the error message
1364    /// and change your request.
1365    BadRequest = 1,
1366    /// Graphics engine failed to complete request, consider retrying
1367    InternalEngine,
1368}
1369
1370impl From<EngineErrorCode> for http::StatusCode {
1371    fn from(e: EngineErrorCode) -> Self {
1372        match e {
1373            EngineErrorCode::BadRequest => Self::BAD_REQUEST,
1374            EngineErrorCode::InternalEngine => Self::INTERNAL_SERVER_ERROR,
1375        }
1376    }
1377}
1378
1379/// What kind of blend to do
1380#[derive(Default, Clone, Copy, Debug, Eq, PartialEq, Serialize, Deserialize, JsonSchema)]
1381#[serde(rename_all = "snake_case")]
1382#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
1383#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
1384#[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))]
1385pub enum BlendType {
1386    /// Use the tangent of the surfaces to calculate the blend.
1387    #[default]
1388    Tangent,
1389}
1390
1391/// Body type determining if the operation will create a manifold (solid) body or a non-manifold collection of surfaces.
1392#[derive(Default, Clone, Copy, Debug, Eq, PartialEq, Serialize, Deserialize, JsonSchema)]
1393#[serde(rename_all = "snake_case")]
1394#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
1395#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
1396#[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))]
1397#[cfg_attr(not(feature = "unstable_exhaustive"), non_exhaustive)]
1398pub enum BodyType {
1399    ///Defines a body that is manifold.
1400    #[default]
1401    Solid,
1402    ///Defines a body that is non-manifold (an open collection of connected surfaces).
1403    Surface,
1404}
1405
1406/// Extrusion method determining if the extrusion will be part of the existing object or an
1407/// entirely new object.
1408#[derive(Default, Clone, Copy, Debug, Eq, PartialEq, Serialize, Deserialize, JsonSchema)]
1409#[serde(rename_all = "snake_case")]
1410#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
1411#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
1412#[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))]
1413#[cfg_attr(not(feature = "unstable_exhaustive"), non_exhaustive)]
1414pub enum ExtrudeMethod {
1415    /// Create a new object that is not connected to the object it is extruded from. This will
1416    /// result in two objects after the operation.
1417    New,
1418    /// This extrusion will be part of object it is extruded from. This will result in one object
1419    /// after the operation.
1420    #[default]
1421    Merge,
1422}
1423
1424/// Type of reference geometry to extrude to.
1425#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, JsonSchema)]
1426#[serde(rename_all = "snake_case")]
1427#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
1428#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
1429#[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))]
1430#[cfg_attr(not(feature = "unstable_exhaustive"), non_exhaustive)]
1431pub enum ExtrudeReference {
1432    /// Extrudes along the normal of the top face until it is as close to the entity as possible.
1433    /// An entity can be a solid, a path, a face, an edge (via `entity_reference`), etc.
1434    EntityReference {
1435        /// Legacy UUID of the entity to extrude to. If both `entity_id` and `entity_reference` are provided, `entity_reference` takes precedence.
1436        #[serde(default, skip_serializing_if = "Option::is_none")]
1437        entity_id: Option<Uuid>,
1438        /// Entity reference (e.g. edge by side_faces). If both `entity_id` and `entity_reference` are provided, `entity_reference` takes precedence.
1439        #[serde(default, skip_serializing_if = "Option::is_none")]
1440        entity_reference: Option<EntityReference>,
1441    },
1442    /// Extrudes until the top face is as close as possible to this given axis.
1443    Axis {
1444        /// The axis to extrude to.
1445        axis: Point3d<f64>,
1446        /// Point the axis goes through.
1447        /// Defaults to (0, 0, 0).
1448        #[serde(default)]
1449        point: Point3d<LengthUnit>,
1450    },
1451    /// Extrudes until the top face is as close as possible to this given point.
1452    Point {
1453        /// The point to extrude to.
1454        point: Point3d<LengthUnit>,
1455    },
1456}
1457
1458/// IDs for the extruded faces.
1459#[derive(Debug, PartialEq, Serialize, Deserialize, JsonSchema, Clone, Builder)]
1460#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
1461#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
1462#[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))]
1463#[cfg_attr(not(feature = "unstable_exhaustive"), non_exhaustive)]
1464pub struct ExtrudedFaceInfo {
1465    /// The face made from the original 2D shape being extruded.
1466    /// If the solid is extruded from a shape which already has an ID
1467    /// (e.g. extruding something which was sketched on a face), this
1468    /// doesn't need to be sent.
1469    pub bottom: Option<Uuid>,
1470    /// Top face of the extrusion (parallel and further away from the original 2D shape being extruded).
1471    pub top: Uuid,
1472    /// Any intermediate sides between the top and bottom.
1473    pub sides: Vec<SideFace>,
1474}
1475
1476/// IDs for a side face, extruded from the path of some sketch/2D shape.
1477#[derive(Debug, PartialEq, Serialize, Deserialize, JsonSchema, Clone, Builder)]
1478#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
1479#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
1480#[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))]
1481#[cfg_attr(not(feature = "unstable_exhaustive"), non_exhaustive)]
1482pub struct SideFace {
1483    /// ID of the path this face is being extruded from.
1484    pub path_id: Uuid,
1485    /// Desired ID for the resulting face.
1486    pub face_id: Uuid,
1487}
1488
1489/// Camera settings including position, center, fov etc
1490#[derive(Debug, Serialize, Deserialize, JsonSchema, Clone, PartialEq, Builder)]
1491#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
1492#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
1493#[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))]
1494#[cfg_attr(not(feature = "unstable_exhaustive"), non_exhaustive)]
1495pub struct CameraSettings {
1496    ///Camera position (vantage)
1497    pub pos: Point3d,
1498
1499    ///Camera's look-at center (center-pos gives viewing vector)
1500    pub center: Point3d,
1501
1502    ///Camera's world-space up vector
1503    pub up: Point3d,
1504
1505    ///The Camera's orientation (in the form of a quaternion)
1506    pub orientation: Quaternion,
1507
1508    ///Camera's field-of-view angle (if ortho is false)
1509    pub fov_y: Option<f32>,
1510
1511    ///The camera's ortho scale (derived from viewing distance if ortho is true)
1512    pub ortho_scale: Option<f32>,
1513
1514    ///Whether or not the camera is in ortho mode
1515    pub ortho: bool,
1516}
1517
1518#[allow(missing_docs)]
1519#[repr(u8)]
1520#[derive(Default, Clone, Copy, Debug, Eq, PartialEq, Serialize, Deserialize, JsonSchema)]
1521#[serde(rename_all = "snake_case")]
1522#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
1523#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
1524#[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))]
1525#[cfg_attr(not(feature = "unstable_exhaustive"), non_exhaustive)]
1526pub enum WorldCoordinateSystem {
1527    #[default]
1528    RightHandedUpZ,
1529    RightHandedUpY,
1530}
1531
1532#[allow(missing_docs)]
1533#[repr(C)]
1534#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize, JsonSchema, Builder)]
1535#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
1536#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
1537#[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))]
1538#[cfg_attr(not(feature = "unstable_exhaustive"), non_exhaustive)]
1539pub struct CameraViewState {
1540    pub pivot_rotation: Quaternion,
1541    pub pivot_position: Point3d,
1542    pub eye_offset: f32,
1543    pub fov_y: f32,
1544    pub ortho_scale_factor: f32,
1545    pub is_ortho: bool,
1546    pub ortho_scale_enabled: bool,
1547    pub world_coord_system: WorldCoordinateSystem,
1548}
1549
1550impl Default for CameraViewState {
1551    fn default() -> Self {
1552        CameraViewState {
1553            pivot_rotation: Default::default(),
1554            pivot_position: Default::default(),
1555            eye_offset: 10.0,
1556            fov_y: 45.0,
1557            ortho_scale_factor: 1.6,
1558            is_ortho: false,
1559            ortho_scale_enabled: true,
1560            world_coord_system: Default::default(),
1561        }
1562    }
1563}
1564
1565#[cfg(feature = "cxx")]
1566impl_extern_type! {
1567    [Trivial]
1568    CameraViewState = "Endpoints::CameraViewState"
1569}
1570
1571impl From<CameraSettings> for crate::output::DefaultCameraZoom {
1572    fn from(settings: CameraSettings) -> Self {
1573        Self { settings }
1574    }
1575}
1576impl From<CameraSettings> for crate::output::CameraDragMove {
1577    fn from(settings: CameraSettings) -> Self {
1578        Self { settings }
1579    }
1580}
1581impl From<CameraSettings> for crate::output::CameraDragEnd {
1582    fn from(settings: CameraSettings) -> Self {
1583        Self { settings }
1584    }
1585}
1586impl From<CameraSettings> for crate::output::DefaultCameraGetSettings {
1587    fn from(settings: CameraSettings) -> Self {
1588        Self { settings }
1589    }
1590}
1591impl From<CameraSettings> for crate::output::ZoomToFit {
1592    fn from(settings: CameraSettings) -> Self {
1593        Self { settings }
1594    }
1595}
1596impl From<CameraSettings> for crate::output::OrientToFace {
1597    fn from(settings: CameraSettings) -> Self {
1598        Self { settings }
1599    }
1600}
1601impl From<CameraSettings> for crate::output::ViewIsometric {
1602    fn from(settings: CameraSettings) -> Self {
1603        Self { settings }
1604    }
1605}
1606
1607/// Defines a perspective view.
1608#[derive(Copy, PartialEq, Debug, JsonSchema, Deserialize, Serialize, Clone, PartialOrd, Default, Builder)]
1609#[serde(rename_all = "snake_case")]
1610#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
1611#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
1612#[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))]
1613#[cfg_attr(not(feature = "unstable_exhaustive"), non_exhaustive)]
1614pub struct PerspectiveCameraParameters {
1615    /// Camera frustum vertical field of view.
1616    pub fov_y: Option<f32>,
1617    /// Camera frustum near plane.
1618    pub z_near: Option<f32>,
1619    /// Camera frustum far plane.
1620    pub z_far: Option<f32>,
1621}
1622
1623/// A type of camera movement applied after certain camera operations
1624#[derive(
1625    Default,
1626    Display,
1627    FromStr,
1628    Copy,
1629    Eq,
1630    PartialEq,
1631    Debug,
1632    JsonSchema,
1633    Deserialize,
1634    Serialize,
1635    Sequence,
1636    Clone,
1637    Ord,
1638    PartialOrd,
1639)]
1640#[serde(rename_all = "snake_case")]
1641#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
1642#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
1643#[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))]
1644#[cfg_attr(not(feature = "unstable_exhaustive"), non_exhaustive)]
1645pub enum CameraMovement {
1646    /// Adjusts the camera position during the camera operation
1647    #[default]
1648    Vantage,
1649    /// Keeps the camera position in place
1650    None,
1651}
1652
1653/// The global axes.
1654#[derive(
1655    Display, FromStr, Copy, Eq, PartialEq, Debug, JsonSchema, Deserialize, Serialize, Sequence, Clone, Ord, PartialOrd,
1656)]
1657#[serde(rename_all = "lowercase")]
1658#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
1659#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
1660#[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))]
1661#[cfg_attr(not(feature = "unstable_exhaustive"), non_exhaustive)]
1662pub enum GlobalAxis {
1663    /// The X axis
1664    X,
1665    /// The Y axis
1666    Y,
1667    /// The Z axis
1668    Z,
1669}
1670
1671/// Possible types of faces which can be extruded from a 3D solid.
1672#[derive(
1673    Display, FromStr, Copy, Eq, PartialEq, Debug, JsonSchema, Deserialize, Serialize, Sequence, Clone, Ord, PartialOrd,
1674)]
1675#[serde(rename_all = "snake_case")]
1676#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
1677#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
1678#[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))]
1679#[repr(u8)]
1680#[cfg_attr(not(feature = "unstable_exhaustive"), non_exhaustive)]
1681pub enum ExtrusionFaceCapType {
1682    /// Uncapped.
1683    None,
1684    /// Capped on top.
1685    Top,
1686    /// Capped below.
1687    Bottom,
1688    /// Capped on both ends.
1689    Both,
1690}
1691
1692/// Post effect type
1693#[allow(missing_docs)]
1694#[derive(
1695    Display,
1696    FromStr,
1697    Copy,
1698    Eq,
1699    PartialEq,
1700    Debug,
1701    JsonSchema,
1702    Deserialize,
1703    Serialize,
1704    Sequence,
1705    Clone,
1706    Ord,
1707    PartialOrd,
1708    Default,
1709)]
1710#[serde(rename_all = "lowercase")]
1711#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
1712#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
1713#[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))]
1714#[cfg_attr(not(feature = "unstable_exhaustive"), non_exhaustive)]
1715pub enum PostEffectType {
1716    Phosphor,
1717    Ssao,
1718    #[default]
1719    NoEffect,
1720}
1721
1722// Enum: Connect Rust Enums to Cpp
1723// add our native c++ names for our cxx::ExternType implementation
1724#[cfg(feature = "cxx")]
1725impl_extern_type! {
1726    [Trivial]
1727    // File
1728    FileImportFormat = "Enums::_FileImportFormat"
1729    FileExportFormat = "Enums::_FileExportFormat"
1730    // Camera
1731    CameraDragInteractionType = "Enums::_CameraDragInteractionType"
1732    // Scene
1733    SceneSelectionType = "Enums::_SceneSelectionType"
1734    SceneToolType = "Enums::_SceneToolType"
1735    BlendType = "Enums::_BlendType"
1736    BodyType = "Enums::_BodyType"
1737    EntityType = "Enums::_EntityType"
1738    AnnotationType = "Enums::_AnnotationType"
1739    AnnotationTextAlignmentX = "Enums::_AnnotationTextAlignmentX"
1740    AnnotationTextAlignmentY = "Enums::_AnnotationTextAlignmentY"
1741    AnnotationLineEnd = "Enums::_AnnotationLineEnd"
1742    MbdStandard = "Enums::_MBDStandard"
1743    MbdSymbol = "Enums::_MBDSymbol"
1744
1745    CurveType = "Enums::_CurveType"
1746    PathCommand = "Enums::_PathCommand"
1747    PathComponentConstraintBound = "Enums::_PathComponentConstraintBound"
1748    PathComponentConstraintType = "Enums::_PathComponentConstraintType"
1749    ExtrusionFaceCapType  = "Enums::_ExtrusionFaceCapType"
1750
1751    // Utils
1752    EngineErrorCode = "Enums::_ErrorCode"
1753    GlobalAxis = "Enums::_GlobalAxis"
1754    OriginType = "Enums::_OriginType"
1755
1756    // Graphics engine
1757    PostEffectType = "Enums::_PostEffectType"
1758}
1759
1760fn bool_true() -> bool {
1761    true
1762}
1763fn same_scale() -> Point3d<f64> {
1764    Point3d::uniform(1.0)
1765}
1766
1767fn z_axis() -> Point3d<f64> {
1768    Point3d { x: 0.0, y: 0.0, z: 1.0 }
1769}
1770
1771impl ExtrudedFaceInfo {
1772    /// Converts from the representation used in the Extrude modeling command,
1773    /// to a flat representation.
1774    pub fn list_faces(self) -> Vec<ExtrusionFaceInfo> {
1775        let mut face_infos: Vec<_> = self
1776            .sides
1777            .into_iter()
1778            .map(|side| ExtrusionFaceInfo {
1779                curve_id: Some(side.path_id),
1780                face_id: Some(side.face_id),
1781                cap: ExtrusionFaceCapType::None,
1782            })
1783            .collect();
1784        face_infos.push(ExtrusionFaceInfo {
1785            curve_id: None,
1786            face_id: Some(self.top),
1787            cap: ExtrusionFaceCapType::Top,
1788        });
1789        if let Some(bottom) = self.bottom {
1790            face_infos.push(ExtrusionFaceInfo {
1791                curve_id: None,
1792                face_id: Some(bottom),
1793                cap: ExtrusionFaceCapType::Bottom,
1794            });
1795        }
1796        face_infos
1797    }
1798}
1799
1800#[cfg(test)]
1801mod tests {
1802    use super::*;
1803
1804    #[test]
1805    fn test_angle_comparison() {
1806        let a = Angle::from_degrees(90.0);
1807        assert!(a < Angle::from_degrees(91.0));
1808        assert!(a > Angle::from_degrees(89.0));
1809        assert!(a <= Angle::from_degrees(90.0));
1810        assert!(a >= Angle::from_degrees(90.0));
1811        let b = Angle::from_radians(std::f64::consts::FRAC_PI_4);
1812        assert!(b < Angle::from_radians(std::f64::consts::FRAC_PI_2));
1813        assert!(b > Angle::from_radians(std::f64::consts::FRAC_PI_8));
1814        assert!(b <= Angle::from_radians(std::f64::consts::FRAC_PI_4));
1815        assert!(b >= Angle::from_radians(std::f64::consts::FRAC_PI_4));
1816        // Mixed units.
1817        assert!(a > b);
1818        assert!(a >= b);
1819        assert!(b < a);
1820        assert!(b <= a);
1821        let c = Angle::from_radians(std::f64::consts::FRAC_PI_2 * 3.0);
1822        assert!(a < c);
1823        assert!(a <= c);
1824        assert!(c > a);
1825        assert!(c >= a);
1826    }
1827}
1828
1829/// How a property of an object should be transformed.
1830#[derive(Clone, Debug, PartialEq, Deserialize, Serialize, JsonSchema, Builder)]
1831#[schemars(rename = "TransformByFor{T}")]
1832#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
1833#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
1834#[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))]
1835#[cfg_attr(not(feature = "unstable_exhaustive"), non_exhaustive)]
1836pub struct TransformBy<T> {
1837    /// The scale, or rotation, or translation.
1838    pub property: T,
1839    /// If true, overwrite the previous value with this.
1840    /// If false, the previous value will be modified.
1841    /// E.g. when translating, `set=true` will set a new location,
1842    /// and `set=false` will translate the current location by the given X/Y/Z.
1843    pub set: bool,
1844    /// What to use as the origin for the transformation.
1845    #[serde(default)]
1846    #[builder(default)]
1847    pub origin: OriginType,
1848}
1849
1850impl<T> TransformBy<T> {
1851    /// Get the origin of this transformation.
1852    /// Reads from the `origin` field if it's set, otherwise
1853    /// falls back to the `is_local` field.
1854    pub fn get_origin(&self) -> OriginType {
1855        self.origin
1856    }
1857}
1858
1859/// Container that holds a translate, rotate and scale.
1860/// Defaults to no change, everything stays the same (i.e. the identity function).
1861#[derive(Clone, Debug, PartialEq, Deserialize, JsonSchema, Serialize, Default, Builder)]
1862#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
1863#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
1864#[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))]
1865#[cfg_attr(not(feature = "unstable_exhaustive"), non_exhaustive)]
1866pub struct ComponentTransform {
1867    /// Translate component of the transform.
1868    pub translate: Option<TransformBy<Point3d<LengthUnit>>>,
1869    /// Rotate component of the transform.
1870    /// The rotation is specified as a roll, pitch, yaw.
1871    pub rotate_rpy: Option<TransformBy<Point3d<f64>>>,
1872    /// Rotate component of the transform.
1873    /// The rotation is specified as an axis and an angle (xyz are the components of the axis, w is
1874    /// the angle in degrees).
1875    pub rotate_angle_axis: Option<TransformBy<Point4d<f64>>>,
1876    /// Scale component of the transform.
1877    pub scale: Option<TransformBy<Point3d<f64>>>,
1878}
1879
1880///If bidirectional or symmetric operations are needed this enum encapsulates the required
1881///information.
1882#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
1883#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
1884#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
1885#[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))]
1886#[cfg_attr(not(feature = "unstable_exhaustive"), non_exhaustive)]
1887pub enum Opposite<T> {
1888    /// No opposite. The operation will only occur on one side.
1889    #[default]
1890    None,
1891    /// Operation will occur from both sides, with the same value.
1892    Symmetric,
1893    /// Operation will occur from both sides, with this value for the opposite.
1894    Other(T),
1895}
1896
1897impl<T: JsonSchema> JsonSchema for Opposite<T> {
1898    fn schema_name() -> String {
1899        format!("OppositeFor{}", T::schema_name())
1900    }
1901
1902    fn schema_id() -> std::borrow::Cow<'static, str> {
1903        std::borrow::Cow::Owned(format!("{}::Opposite<{}>", module_path!(), T::schema_id()))
1904    }
1905
1906    fn json_schema(_: &mut schemars::gen::SchemaGenerator) -> schemars::schema::Schema {
1907        SchemaObject {
1908            instance_type: Some(schemars::schema::InstanceType::String.into()),
1909            ..Default::default()
1910        }
1911        .into()
1912    }
1913}
1914
1915/// What strategy (algorithm) should be used for cutting?
1916/// Defaults to Automatic.
1917#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize, JsonSchema, Default)]
1918#[serde(rename_all = "snake_case")]
1919#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
1920#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
1921#[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))]
1922#[cfg_attr(not(feature = "unstable_exhaustive"), non_exhaustive)]
1923pub enum CutStrategy {
1924    /// Basic fillet cut. This has limitations, like the filletted edges
1925    /// can't touch each other. But it's very fast and simple.
1926    Basic,
1927    /// More complicated fillet cut. It works for more use-cases, like
1928    /// edges that touch each other. But it's slower than the Basic method.
1929    Csg,
1930    /// Tries the Basic method, and if that doesn't work, tries the CSG strategy.
1931    #[default]
1932    Automatic,
1933}
1934
1935/// What is the given geometry relative to?
1936#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize, JsonSchema, Default)]
1937#[serde(rename_all = "snake_case")]
1938#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
1939#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
1940#[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))]
1941#[cfg_attr(not(feature = "unstable_exhaustive"), non_exhaustive)]
1942pub enum RelativeTo {
1943    /// Local/relative to a position centered within the plane being sketched on
1944    #[default]
1945    SketchPlane,
1946    /// Local/relative to the trajectory curve
1947    TrajectoryCurve,
1948}
1949
1950/// The region a user clicked on.
1951#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize, JsonSchema, Builder)]
1952#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
1953#[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))]
1954#[cfg_attr(not(feature = "unstable_exhaustive"), non_exhaustive)]
1955pub struct SelectedRegion {
1956    /// First segment to follow to find the region.
1957    pub segment: Uuid,
1958    /// Second segment to follow to find the region.
1959    /// Intersects the first segment.
1960    pub intersection_segment: Uuid,
1961    /// At which intersection between `segment` and `intersection_segment`
1962    /// should we stop following the `segment` and start following `intersection_segment`?
1963    /// Defaults to -1, which means the last intersection.
1964    #[serde(default = "negative_one")]
1965    pub intersection_index: i32,
1966    /// By default (when this is false), curve counterclockwise at intersections.
1967    /// If this is true, instead curve clockwise.
1968    #[serde(default)]
1969    pub curve_clockwise: bool,
1970}
1971
1972impl Default for SelectedRegion {
1973    fn default() -> Self {
1974        Self {
1975            segment: Default::default(),
1976            intersection_segment: Default::default(),
1977            intersection_index: -1,
1978            curve_clockwise: Default::default(),
1979        }
1980    }
1981}
1982
1983/// An edge id and an upper and lower percentage bound of the edge.
1984#[derive(Builder, Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
1985#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
1986#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
1987#[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))]
1988#[cfg_attr(not(feature = "unstable_exhaustive"), non_exhaustive)]
1989pub struct FractionOfEdge {
1990    /// The id of the edge (legacy). If both `edge_id` and `edge_specifier` are provided, `edge_specifier` takes precedence.
1991    #[serde(default, skip_serializing_if = "Option::is_none")]
1992    pub edge_id: Option<Uuid>,
1993    /// Edge specifier (side_faces, end_faces, index) identifying the edge. If both `edge_id` and `edge_specifier` are provided, `edge_specifier` takes precedence.
1994    #[serde(default, skip_serializing_if = "Option::is_none")]
1995    pub edge_specifier: Option<EdgeSpecifier>,
1996    /// A value between [0.0, 1.0] (default 0.0) that is a percentage along the edge. This bound
1997    /// will control how much of the edge is used during the blend.
1998    /// If lower_bound is larger than upper_bound, the edge is effectively "flipped".
1999    #[serde(default)]
2000    #[builder(default)]
2001    #[schemars(range(min = 0, max = 1))]
2002    pub lower_bound: f32,
2003    /// A value between [0.0, 1.0] (default 1.0) that is a percentage along the edge. This bound
2004    /// will control how much of the edge is used during the blend.
2005    /// If lower_bound is larger than upper_bound, the edge is effectively "flipped".
2006    #[serde(default = "one")]
2007    #[builder(default = one())]
2008    #[schemars(range(min = 0, max = 1))]
2009    pub upper_bound: f32,
2010}
2011
2012/// An object id, that corresponds to a surface body, and a list of edges of the surface.
2013#[derive(Builder, Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
2014#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
2015#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
2016#[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))]
2017#[cfg_attr(not(feature = "unstable_exhaustive"), non_exhaustive)]
2018pub struct SurfaceEdgeReference {
2019    /// The id of the body.
2020    pub object_id: Uuid,
2021    /// A list of the edge ids that belong to the body.
2022    pub edges: Vec<FractionOfEdge>,
2023}
2024
2025/// List of bodies that were created by an operation.
2026#[derive(Builder, Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema, Default)]
2027#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
2028#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
2029#[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))]
2030#[cfg_attr(not(feature = "unstable_exhaustive"), non_exhaustive)]
2031pub struct BodiesCreated {
2032    /// All bodies created by this operation.
2033    pub bodies: Vec<BodyCreated>,
2034}
2035
2036impl BodiesCreated {
2037    /// Are there any bodies in this list?
2038    pub fn is_empty(&self) -> bool {
2039        self.bodies.is_empty()
2040    }
2041}
2042
2043/// List of bodies that were updated by an operation.
2044#[derive(Builder, Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema, Default)]
2045#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
2046#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
2047#[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))]
2048#[cfg_attr(not(feature = "unstable_exhaustive"), non_exhaustive)]
2049pub struct BodiesUpdated {
2050    /// All bodies created by this operation.
2051    pub bodies: Vec<BodyUpdated>,
2052}
2053
2054impl BodiesUpdated {
2055    /// Are there any bodies in this list?
2056    pub fn is_empty(&self) -> bool {
2057        self.bodies.is_empty()
2058    }
2059}
2060
2061/// Details of a body that was created.
2062#[derive(Builder, Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
2063#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
2064#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
2065#[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))]
2066#[cfg_attr(not(feature = "unstable_exhaustive"), non_exhaustive)]
2067pub struct BodyCreated {
2068    /// The body's ID.
2069    pub id: Uuid,
2070    /// Surfaces this body contains.
2071    pub surfaces: Vec<SurfaceCreated>,
2072}
2073
2074/// Details of a body that was updated.
2075#[derive(Builder, Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
2076#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
2077#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
2078#[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))]
2079#[cfg_attr(not(feature = "unstable_exhaustive"), non_exhaustive)]
2080pub struct BodyUpdated {
2081    /// The body's ID.
2082    pub id: Uuid,
2083    /// Surfaces added to this body.
2084    pub surfaces: Vec<SurfaceCreated>,
2085}
2086
2087/// Details of a surface that was created under some body.
2088#[derive(Builder, Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
2089#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
2090#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
2091#[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))]
2092#[cfg_attr(not(feature = "unstable_exhaustive"), non_exhaustive)]
2093pub struct SurfaceCreated {
2094    /// The surface's ID.
2095    pub id: Uuid,
2096    /// Which number face of the parent body is this?
2097    pub primitive_face_index: u32,
2098    /// Which segment IDs was this surface swept from?
2099    pub from_segments: Vec<Uuid>,
2100}
2101
2102/// Region-creation algorithm version.
2103#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema, Default)]
2104#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
2105#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
2106#[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))]
2107#[cfg_attr(not(feature = "unstable_exhaustive"), non_exhaustive)]
2108pub enum RegionVersion {
2109    /// The original region creation method. This should NOT be used anymore,
2110    /// but is maintained to avoid breaking old models.
2111    #[default]
2112    V0,
2113    /// Fixes the bug in V0 where creating a region would shuffle the mapping
2114    /// from segment names/IDs to actual segment geometry.
2115    V1,
2116}
2117
2118/// Edge cut algorithm version.
2119#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema, Copy)]
2120#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
2121#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
2122#[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))]
2123#[cfg_attr(not(feature = "unstable_exhaustive"), non_exhaustive)]
2124#[serde(rename_all = "snake_case")]
2125pub enum EdgeCutVersion {
2126    /// Let the engine choose whichever version it wants.
2127    V0,
2128    /// The original fillet algorithm Zoo 1.0 shipped with.
2129    /// Limitations: doesn't support rolling ball fillets, has several bugs
2130    /// that will not be fixed.
2131    V1,
2132    /// Adds support for rolling ball fillets.
2133    /// Fixes bugs from V1.
2134    /// Still experimental.
2135    V2,
2136}
2137
2138const DEFAULT_EDGE_CUT_VERSION: EdgeCutVersion = EdgeCutVersion::V1;
2139
2140impl EdgeCutVersion {
2141    /// Is this the default edge cut algorithm version?
2142    pub fn is_default(&self) -> bool {
2143        self == &DEFAULT_EDGE_CUT_VERSION
2144    }
2145}
2146
2147impl Default for EdgeCutVersion {
2148    fn default() -> Self {
2149        DEFAULT_EDGE_CUT_VERSION
2150    }
2151}
2152
2153/// Try to match an integer to a version number.
2154impl TryFrom<u32> for EdgeCutVersion {
2155    type Error = ();
2156
2157    fn try_from(version: u32) -> Result<Self, Self::Error> {
2158        match version {
2159            0 => Ok(Self::V0),
2160            1 => Ok(Self::V1),
2161            2 => Ok(Self::V2),
2162            _ => Err(()),
2163        }
2164    }
2165}
2166
2167impl RegionVersion {
2168    /// Is the version V0?
2169    pub fn is_zero(&self) -> bool {
2170        matches!(self, Self::V0)
2171    }
2172}
2173
2174impl From<BodyCreated> for BodyUpdated {
2175    fn from(body: BodyCreated) -> Self {
2176        Self {
2177            id: body.id,
2178            surfaces: body.surfaces,
2179        }
2180    }
2181}
2182
2183impl From<BodyUpdated> for BodyCreated {
2184    fn from(body: BodyUpdated) -> Self {
2185        Self {
2186            id: body.id,
2187            surfaces: body.surfaces,
2188        }
2189    }
2190}
2191
2192impl From<BodiesCreated> for BodiesUpdated {
2193    fn from(bodies: BodiesCreated) -> Self {
2194        Self {
2195            bodies: bodies.bodies.into_iter().map(Into::into).collect(),
2196        }
2197    }
2198}
2199
2200impl From<BodiesUpdated> for BodiesCreated {
2201    fn from(bodies: BodiesUpdated) -> Self {
2202        Self {
2203            bodies: bodies.bodies.into_iter().map(Into::into).collect(),
2204        }
2205    }
2206}
2207
2208fn one() -> f32 {
2209    1.0
2210}
2211
2212/// A debug-view of the segment of a curve.
2213#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, JsonSchema, Builder)]
2214pub struct CurveDebug {
2215    /// Start point of segment or circle.
2216    pub start: Option<Point2d<f64>>,
2217    /// End point of segment.
2218    pub end: Option<Point2d<f64>>,
2219    /// Center point of segment.
2220    pub center: Option<Point2d<f64>>,
2221    /// Midpoint on a three point arc
2222    pub mid: Option<Point2d<f64>>,
2223    /// What kind of segment is it (line, arc, etc)
2224    pub segment_type: CurveTypeDebug,
2225    /// ID for this segment.
2226    pub id: ModelingCmdId,
2227}
2228
2229/// What type of curve is being viewed?
2230#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, JsonSchema)]
2231pub enum CurveTypeDebug {
2232    /// Line with a start and end.
2233    Line,
2234    /// Arc with a start, end and center.
2235    ThreePointArc,
2236    /// Circle with a center and radius.
2237    Circle,
2238}