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