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