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