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