kittycad_modeling_cmds/
shared.rs

1use enum_iterator::Sequence;
2use parse_display_derive::{Display, FromStr};
3pub use point::{Point2d, Point3d, Point4d, Quaternion};
4use schemars::{schema::SchemaObject, JsonSchema};
5use serde::{Deserialize, Serialize};
6use uuid::Uuid;
7
8#[cfg(feature = "cxx")]
9use crate::impl_extern_type;
10use crate::{length_unit::LengthUnit, output::ExtrusionFaceInfo, units::UnitAngle};
11
12mod point;
13
14/// What kind of cut to do
15#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize, JsonSchema, Default)]
16#[serde(rename_all = "snake_case")]
17#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
18#[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))]
19pub enum CutType {
20    /// Round off an edge.
21    #[default]
22    Fillet,
23    /// Cut away an edge.
24    Chamfer,
25}
26
27/// What kind of cut to perform when cutting an edge.
28#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize, JsonSchema)]
29#[serde(rename_all = "snake_case")]
30#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
31#[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))]
32pub enum CutTypeV2 {
33    /// Round off an edge.
34    Fillet {
35        /// The radius of the fillet.
36        radius: LengthUnit,
37        /// The second length affects the edge length of the second face of the cut. This will
38        /// cause the fillet to take on the shape of a conic section, instead of an arc.
39        second_length: Option<LengthUnit>,
40    },
41    /// Cut away an edge.
42    Chamfer {
43        /// The distance from the edge to cut on each face.
44        distance: LengthUnit,
45        /// The second distance affects the edge length of the second face of the cut.
46        second_distance: Option<LengthUnit>,
47        /// The angle of the chamfer, default is 45deg.
48        angle: Option<Angle>,
49        /// If true, the second distance or angle is applied to the other face of the cut.
50        swap: bool,
51    },
52    /// A custom cut profile.
53    Custom {
54        /// The path that will be used for the custom profile.
55        path: Uuid,
56    },
57}
58
59/// A rotation defined by an axis, origin of rotation, and an angle.
60#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
61#[serde(rename_all = "snake_case")]
62#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
63#[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))]
64pub struct Rotation {
65    /// Rotation axis.
66    /// Defaults to (0, 0, 1) (i.e. the Z axis).
67    pub axis: Point3d<f64>,
68    /// Rotate this far about the rotation axis.
69    /// Defaults to zero (i.e. no rotation).
70    pub angle: Angle,
71    /// Origin of the rotation. If one isn't provided, the object will rotate about its own bounding box center.
72    pub origin: OriginType,
73}
74
75impl Default for Rotation {
76    /// z-axis, 0 degree angle, and local origin.
77    fn default() -> Self {
78        Self {
79            axis: z_axis(),
80            angle: Angle::default(),
81            origin: OriginType::Local,
82        }
83    }
84}
85
86/// Ways to transform each solid being replicated in a repeating pattern.
87#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
88#[serde(rename_all = "snake_case")]
89#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
90#[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))]
91pub struct Transform {
92    /// Translate the replica this far along each dimension.
93    /// Defaults to zero vector (i.e. same position as the original).
94    #[serde(default)]
95    pub translate: Point3d<LengthUnit>,
96    /// Scale the replica's size along each axis.
97    /// Defaults to (1, 1, 1) (i.e. the same size as the original).
98    #[serde(default = "same_scale")]
99    pub scale: Point3d<f64>,
100    /// Rotate the replica about the specified rotation axis and origin.
101    /// Defaults to no rotation.
102    #[serde(default)]
103    pub rotation: Rotation,
104    /// Whether to replicate the original solid in this instance.
105    #[serde(default = "bool_true")]
106    pub replicate: bool,
107}
108
109impl Default for Transform {
110    fn default() -> Self {
111        Self {
112            scale: same_scale(),
113            replicate: true,
114            translate: Default::default(),
115            rotation: Rotation::default(),
116        }
117    }
118}
119
120/// Options for annotations
121#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
122#[serde(rename_all = "snake_case")]
123#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
124#[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))]
125pub struct AnnotationOptions {
126    /// Text displayed on the annotation
127    pub text: Option<AnnotationTextOptions>,
128    /// How to style the start and end of the line
129    pub line_ends: Option<AnnotationLineEndOptions>,
130    /// Width of the annotation's line
131    pub line_width: Option<f32>,
132    /// Color to render the annotation
133    pub color: Option<Color>,
134    /// Position to put the annotation
135    pub position: Option<Point3d<f32>>,
136    /// Set as an MBD measured basic dimension annotation
137    pub dimension: Option<AnnotationBasicDimension>,
138    /// Set as an MBD Feature control annotation
139    pub feature_control: Option<AnnotationFeatureControl>,
140    /// Set as a feature tag annotation
141    pub feature_tag: Option<AnnotationFeatureTag>,
142}
143
144/// Options for annotation text
145#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
146#[serde(rename_all = "snake_case")]
147#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
148#[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))]
149pub struct AnnotationLineEndOptions {
150    /// How to style the start of the annotation line.
151    pub start: AnnotationLineEnd,
152    /// How to style the end of the annotation line.
153    pub end: AnnotationLineEnd,
154}
155
156/// Options for annotation text
157#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
158#[serde(rename_all = "snake_case")]
159#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
160#[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))]
161pub struct AnnotationTextOptions {
162    /// Alignment along the X axis
163    pub x: AnnotationTextAlignmentX,
164    /// Alignment along the Y axis
165    pub y: AnnotationTextAlignmentY,
166    /// Text displayed on the annotation
167    pub text: String,
168    /// Text font's point size
169    pub point_size: u32,
170}
171
172/// Parameters for defining an MBD Geometric control frame
173#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
174#[serde(rename_all = "snake_case")]
175#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
176#[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))]
177pub struct AnnotationMbdControlFrame {
178    ///Geometric symbol, the type of geometric control specified
179    pub symbol: MbdSymbol,
180    /// Diameter symbol (if required) whether the geometric control requires a cylindrical or diameter tolerance
181    pub diameter_symbol: Option<MbdSymbol>,
182    /// Tolerance value - the total tolerance of the geometric control.  The unit is based on the drawing standard.
183    pub tolerance: f64,
184    /// Feature of size or tolerance modifiers
185    pub modifier: Option<MbdSymbol>,
186    /// Primary datum
187    pub primary_datum: Option<char>,
188    /// Secondary datum
189    pub secondary_datum: Option<char>,
190    /// Tertiary datum
191    pub tertiary_datum: Option<char>,
192}
193
194/// Parameters for defining an MBD basic dimension
195#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
196#[serde(rename_all = "snake_case")]
197#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
198#[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))]
199pub struct AnnotationMbdBasicDimension {
200    /// Type of symbol to use for this dimension (if required)
201    pub symbol: Option<MbdSymbol>,
202    /// The explicitly defined dimension.  Only required if the measurement is not automatically calculated.
203    pub dimension: Option<f64>,
204    /// The tolerance of the dimension
205    pub tolerance: f64,
206}
207
208/// Parameters for defining an MBD Basic Dimension Annotation state which is measured between two positions in 3D
209#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
210#[serde(rename_all = "snake_case")]
211#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
212#[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))]
213pub struct AnnotationBasicDimension {
214    /// Entity to measure the dimension from
215    pub from_entity_id: Uuid,
216
217    /// Normalized position within the entity to position the dimension from
218    pub from_entity_pos: Point2d<f64>,
219
220    /// Entity to measure the dimension to
221    pub to_entity_id: Uuid,
222
223    /// Normalized position within the entity to position the dimension to
224    pub to_entity_pos: Point2d<f64>,
225
226    /// Basic dimension parameters (symbol and tolerance)
227    pub dimension: AnnotationMbdBasicDimension,
228
229    /// Orientation plane.  The annotation will lie in this plane which is positioned about the leader position as its origin.
230    pub plane_id: Uuid,
231
232    /// 2D Position offset of the annotation within the plane.
233    pub offset: Point2d<f64>,
234
235    /// Number of decimal places to use when displaying tolerance and dimension values
236    pub precision: u32,
237
238    /// The scale of the font label in 3D space
239    pub font_scale: f32,
240
241    /// The point size of the fonts used to generate the annotation label.  Very large values can negatively affect performance.
242    pub font_point_size: u32,
243}
244
245/// Parameters for defining an MBD Feature Control Annotation state
246#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
247#[serde(rename_all = "snake_case")]
248#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
249#[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))]
250pub struct AnnotationFeatureControl {
251    /// Entity to place the annotation leader from
252    pub entity_id: Uuid,
253
254    /// Normalized position within the entity to position the annotation leader from
255    pub entity_pos: Point2d<f64>,
256
257    /// Type of leader to use
258    pub leader_type: AnnotationLineEnd,
259
260    /// Basic dimensions
261    pub dimension: Option<AnnotationMbdBasicDimension>,
262
263    /// MBD Control frame for geometric control
264    pub control_frame: Option<AnnotationMbdControlFrame>,
265
266    /// Set if this annotation is defining a datum
267    pub defined_datum: Option<char>,
268
269    /// Prefix text which will appear before the basic dimension
270    pub prefix: Option<String>,
271
272    /// Suffix text which will appear after the basic dimension
273    pub suffix: Option<String>,
274
275    /// Orientation plane.  The annotation will lie in this plane which is positioned about the leader position as its origin.
276    pub plane_id: Uuid,
277
278    /// 2D Position offset of the annotation within the plane.
279    pub offset: Point2d<f64>,
280
281    /// Number of decimal places to use when displaying tolerance and dimension values
282    pub precision: u32,
283
284    /// The scale of the font label in 3D space
285    pub font_scale: f32,
286
287    /// The point size of the fonts used to generate the annotation label.  Very large values can negatively affect performance.
288    pub font_point_size: u32,
289}
290
291/// Parameters for defining an MBD Feature Tag Annotation state
292#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
293#[serde(rename_all = "snake_case")]
294#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
295#[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))]
296pub struct AnnotationFeatureTag {
297    /// Entity to place the annotation leader from
298    pub entity_id: Uuid,
299
300    /// Normalized position within the entity to position the annotation leader from
301    pub entity_pos: Point2d<f64>,
302
303    /// Type of leader to use
304    pub leader_type: AnnotationLineEnd,
305
306    /// Tag key
307    pub key: String,
308
309    /// Tag value
310    pub value: String,
311
312    /// Whether or not to display the key on the annotation label
313    pub show_key: bool,
314
315    /// Orientation plane.  The annotation will lie in this plane which is positioned about the leader position as its origin.
316    pub plane_id: Uuid,
317
318    /// 2D Position offset of the annotation within the plane.
319    pub offset: Point2d<f64>,
320
321    /// The scale of the font label in 3D space
322    pub font_scale: f32,
323
324    /// The point size of the fonts used to generate the annotation label.  Very large values can negatively affect performance.
325    pub font_point_size: u32,
326}
327
328/// The type of distance
329/// Distances can vary depending on
330/// the objects used as input.
331#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize, JsonSchema)]
332#[serde(rename_all = "snake_case", tag = "type")]
333#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
334#[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))]
335pub enum DistanceType {
336    /// Euclidean Distance.
337    Euclidean {},
338    /// The distance between objects along the specified axis
339    OnAxis {
340        /// Global axis
341        axis: GlobalAxis,
342    },
343}
344
345/// The type of origin
346#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize, JsonSchema, Default)]
347#[serde(rename_all = "snake_case", tag = "type")]
348#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
349#[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))]
350pub enum OriginType {
351    /// Local Origin (center of object bounding box).
352    #[default]
353    Local,
354    /// Global Origin (0, 0, 0).
355    Global,
356    /// Custom Origin (user specified point).
357    Custom {
358        /// Custom origin point.
359        origin: Point3d<f64>,
360    },
361}
362
363/// An RGBA color
364#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize, JsonSchema)]
365#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
366#[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))]
367pub struct Color {
368    /// Red
369    pub r: f32,
370    /// Green
371    pub g: f32,
372    /// Blue
373    pub b: f32,
374    /// Alpha
375    pub a: f32,
376}
377
378/// Horizontal Text alignment
379#[allow(missing_docs)]
380#[derive(
381    Display, FromStr, Copy, Eq, PartialEq, Debug, JsonSchema, Deserialize, Serialize, Sequence, Clone, Ord, PartialOrd,
382)]
383#[serde(rename_all = "lowercase")]
384#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
385#[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))]
386pub enum AnnotationTextAlignmentX {
387    Left,
388    Center,
389    Right,
390}
391
392/// Vertical Text alignment
393#[allow(missing_docs)]
394#[derive(
395    Display, FromStr, Copy, Eq, PartialEq, Debug, JsonSchema, Deserialize, Serialize, Sequence, Clone, Ord, PartialOrd,
396)]
397#[serde(rename_all = "lowercase")]
398#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
399#[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))]
400pub enum AnnotationTextAlignmentY {
401    Bottom,
402    Center,
403    Top,
404}
405
406/// Annotation line end type
407#[allow(missing_docs)]
408#[derive(
409    Display, FromStr, Copy, Eq, PartialEq, Debug, JsonSchema, Deserialize, Serialize, Sequence, Clone, Ord, PartialOrd,
410)]
411#[serde(rename_all = "lowercase")]
412#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
413#[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))]
414pub enum AnnotationLineEnd {
415    None,
416    Arrow,
417    Dot,
418}
419
420/// The type of annotation
421#[derive(
422    Display, FromStr, Copy, Eq, PartialEq, Debug, JsonSchema, Deserialize, Serialize, Sequence, Clone, Ord, PartialOrd,
423)]
424#[serde(rename_all = "lowercase")]
425#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
426#[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))]
427pub enum AnnotationType {
428    /// 2D annotation type (screen or planar space)
429    T2D,
430    /// 3D annotation type
431    T3D,
432}
433
434/// MBD standard
435#[derive(
436    Display, FromStr, Copy, Eq, PartialEq, Debug, JsonSchema, Deserialize, Serialize, Sequence, Clone, Ord, PartialOrd,
437)]
438#[serde(rename_all = "lowercase")]
439#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
440#[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))]
441pub enum MbdStandard {
442    /// ASME Y14.5 GD&T
443    AsmeY14_5,
444}
445
446//SEE MIKE BEFORE MAKING ANY CHANGES TO THIS ENUM
447/// MBD symbol type
448#[allow(missing_docs)]
449#[derive(
450    Default,
451    Display,
452    FromStr,
453    Copy,
454    Eq,
455    PartialEq,
456    Debug,
457    JsonSchema,
458    Deserialize,
459    Serialize,
460    Sequence,
461    Clone,
462    Ord,
463    PartialOrd,
464)]
465#[serde(rename_all = "lowercase")]
466#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
467#[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))]
468#[repr(u16)]
469pub enum MbdSymbol {
470    #[default]
471    None = 0,
472    ArcLength = 174,
473    Between = 175,
474    Degrees = 176,
475    PlusMinus = 177,
476    Angularity = 178,
477    Cylindricity = 179,
478    Roundness = 180,
479    Concentricity = 181,
480    Straightness = 182,
481    Parallelism = 183,
482    Flatness = 184,
483    ProfileOfLine = 185,
484    SurfaceProfile = 186,
485    Symmetry = 187,
486    Perpendicularity = 188,
487    Runout = 189,
488    TotalRunout = 190,
489    Position = 191,
490    CenterLine = 192,
491    PartingLine = 193,
492    IsoEnvelope = 195,
493    IsoEnvelopeNonY145M = 196,
494    FreeState = 197,
495    StatisticalTolerance = 198,
496    ContinuousFeature = 199,
497    Independency = 200,
498    Depth = 201,
499    Start = 202,
500    LeastCondition = 203,
501    MaxCondition = 204,
502    ConicalTaper = 205,
503    Projected = 206,
504    Slope = 207,
505    Micro = 208,
506    TangentPlane = 210,
507    Unilateral = 211,
508    SquareFeature = 212,
509    Countersink = 213,
510    SpotFace = 214,
511    Target = 215,
512    Diameter = 216,
513    Radius = 217,
514    SphericalRadius = 218,
515    SphericalDiameter = 219,
516    ControlledRadius = 220,
517    BoxStart = 123,
518    BoxBar = 162,
519    BoxBarBetween = 124,
520    LetterBackwardUnderline = 95,
521    PunctuationBackwardUnderline = 92,
522    ModifierBackwardUnderline = 126,
523    NumericBackwardUnderline = 96,
524    BoxEnd = 125,
525    DatumUp = 166,
526    DatumLeft = 168,
527    DatumRight = 167,
528    DatumDown = 165,
529    DatumTriangle = 295,
530    HalfSpace = 236,
531    QuarterSpace = 237,
532    EighthSpace = 238,
533    ModifierSpace = 239,
534}
535
536/// The type of camera drag interaction.
537#[derive(
538    Display, FromStr, Copy, Eq, PartialEq, Debug, JsonSchema, Deserialize, Serialize, Sequence, Clone, Ord, PartialOrd,
539)]
540#[serde(rename_all = "lowercase")]
541#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
542#[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))]
543pub enum CameraDragInteractionType {
544    /// Camera pan
545    Pan,
546    /// Camera rotate (spherical camera revolve/orbit)
547    Rotate,
548    /// Camera rotate (trackball with 3 degrees of freedom)
549    RotateTrackball,
550    /// Camera zoom (increase or decrease distance to reference point center)
551    Zoom,
552}
553
554/// A segment of a path.
555/// Paths are composed of many segments.
556#[derive(Debug, Clone, Copy, Serialize, Deserialize, JsonSchema, PartialEq)]
557#[serde(rename_all = "snake_case", tag = "type")]
558#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
559#[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))]
560pub enum PathSegment {
561    /// A straight line segment.
562    /// Goes from the current path "pen" to the given endpoint.
563    Line {
564        /// End point of the line.
565        end: Point3d<LengthUnit>,
566        ///Whether or not this line is a relative offset
567        relative: bool,
568    },
569    /// A circular arc segment.
570    /// Arcs can be drawn clockwise when start > end.
571    Arc {
572        /// Center of the circle
573        center: Point2d<LengthUnit>,
574        /// Radius of the circle
575        radius: LengthUnit,
576        /// Start of the arc along circle's perimeter.
577        start: Angle,
578        /// End of the arc along circle's perimeter.
579        end: Angle,
580        ///Whether or not this arc is a relative offset
581        relative: bool,
582    },
583    /// A cubic bezier curve segment.
584    /// Start at the end of the current line, go through control point 1 and 2, then end at a
585    /// given point.
586    Bezier {
587        /// First control point.
588        control1: Point3d<LengthUnit>,
589        /// Second control point.
590        control2: Point3d<LengthUnit>,
591        /// Final control point.
592        end: Point3d<LengthUnit>,
593        ///Whether or not this bezier is a relative offset
594        relative: bool,
595    },
596    /// Adds a tangent arc from current pen position with the given radius and angle.
597    TangentialArc {
598        /// Radius of the arc.
599        /// Not to be confused with Raiders of the Lost Ark.
600        radius: LengthUnit,
601        /// Offset of the arc. Negative values will arc clockwise.
602        offset: Angle,
603    },
604    /// Adds a tangent arc from current pen position to the new position.
605    /// Arcs will choose a clockwise or counter-clockwise direction based on the arc end position.
606    TangentialArcTo {
607        /// Where the arc should end.
608        /// Must lie in the same plane as the current path pen position.
609        /// Must not be colinear with current path pen position.
610        to: Point3d<LengthUnit>,
611        /// 0 will be interpreted as none/null.
612        angle_snap_increment: Option<Angle>,
613    },
614    ///Adds an arc from the current position that goes through the given interior point and ends at the given end position
615    ArcTo {
616        /// Interior point of the arc.
617        interior: Point3d<LengthUnit>,
618        /// End point of the arc.
619        end: Point3d<LengthUnit>,
620        ///Whether or not interior and end are relative to the previous path position
621        relative: bool,
622    },
623    ///Adds a circular involute from the current position that goes through the given end_radius
624    ///and is rotated around the current point by angle.
625    CircularInvolute {
626        ///The involute is described between two circles, start_radius is the radius of the inner
627        ///circle.
628        start_radius: LengthUnit,
629        ///The involute is described between two circles, end_radius is the radius of the outer
630        ///circle.
631        end_radius: LengthUnit,
632        ///The angle to rotate the involute by. A value of zero will produce a curve with a tangent
633        ///along the x-axis at the start point of the curve.
634        angle: Angle,
635        ///If reverse is true, the segment will start
636        ///from the end of the involute, otherwise it will start from that start.
637        reverse: bool,
638    },
639    ///Adds an elliptical arc segment.
640    Ellipse {
641        /// The center point of the ellipse.
642        center: Point2d<LengthUnit>,
643        /// Major axis of the ellipse.
644        major_axis: Point2d<LengthUnit>,
645        /// Minor radius of the ellipse.
646        minor_radius: LengthUnit,
647        /// Start of the path along the perimeter of the ellipse.
648        start_angle: Angle,
649        /// End of the path along the perimeter of the ellipse.
650        end_angle: Angle,
651    },
652    ///Adds a generic conic section specified by the end point, interior point and tangents at the
653    ///start and end of the section.
654    ConicTo {
655        /// Interior point that lies on the conic.
656        interior: Point2d<LengthUnit>,
657        /// End point of the conic.
658        end: Point2d<LengthUnit>,
659        /// Tangent at the start of the conic.
660        start_tangent: Point2d<LengthUnit>,
661        /// Tangent at the end of the conic.
662        end_tangent: Point2d<LengthUnit>,
663        /// Whether or not the interior and end points are relative to the previous path position.
664        relative: bool,
665    },
666}
667
668/// An angle, with a specific unit.
669#[derive(Clone, Copy, PartialEq, Debug, JsonSchema, Deserialize, Serialize)]
670#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
671#[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))]
672pub struct Angle {
673    /// What unit is the measurement?
674    pub unit: UnitAngle,
675    /// The size of the angle, measured in the chosen unit.
676    pub value: f64,
677}
678
679impl Angle {
680    /// Converts a given angle to degrees.
681    pub fn to_degrees(self) -> f64 {
682        match self.unit {
683            UnitAngle::Degrees => self.value,
684            UnitAngle::Radians => self.value.to_degrees(),
685        }
686    }
687    /// Converts a given angle to radians.
688    pub fn to_radians(self) -> f64 {
689        match self.unit {
690            UnitAngle::Degrees => self.value.to_radians(),
691            UnitAngle::Radians => self.value,
692        }
693    }
694    /// Create an angle in degrees.
695    pub const fn from_degrees(value: f64) -> Self {
696        Self {
697            unit: UnitAngle::Degrees,
698            value,
699        }
700    }
701    /// Create an angle in radians.
702    pub const fn from_radians(value: f64) -> Self {
703        Self {
704            unit: UnitAngle::Radians,
705            value,
706        }
707    }
708    /// 360 degrees.
709    pub const fn turn() -> Self {
710        Self::from_degrees(360.0)
711    }
712    /// 180 degrees.
713    pub const fn half_circle() -> Self {
714        Self::from_degrees(180.0)
715    }
716    /// 90 degrees.
717    pub const fn quarter_circle() -> Self {
718        Self::from_degrees(90.0)
719    }
720    /// 0 degrees.
721    pub const fn zero() -> Self {
722        Self::from_degrees(0.0)
723    }
724}
725
726/// 0 degrees.
727impl Default for Angle {
728    /// 0 degrees.
729    fn default() -> Self {
730        Self::zero()
731    }
732}
733
734impl PartialOrd for Angle {
735    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
736        match (self.unit, other.unit) {
737            // Avoid unnecessary floating point operations.
738            (UnitAngle::Degrees, UnitAngle::Degrees) => self.value.partial_cmp(&other.value),
739            (UnitAngle::Radians, UnitAngle::Radians) => self.value.partial_cmp(&other.value),
740            _ => self.to_degrees().partial_cmp(&other.to_degrees()),
741        }
742    }
743}
744
745impl std::ops::Add for Angle {
746    type Output = Self;
747
748    fn add(self, rhs: Self) -> Self::Output {
749        Self {
750            unit: UnitAngle::Degrees,
751            value: self.to_degrees() + rhs.to_degrees(),
752        }
753    }
754}
755
756impl std::ops::AddAssign for Angle {
757    fn add_assign(&mut self, rhs: Self) {
758        match self.unit {
759            UnitAngle::Degrees => {
760                self.value += rhs.to_degrees();
761            }
762            UnitAngle::Radians => {
763                self.value += rhs.to_radians();
764            }
765        }
766    }
767}
768
769/// The type of scene selection change
770#[derive(
771    Display, FromStr, Copy, Eq, PartialEq, Debug, JsonSchema, Deserialize, Serialize, Sequence, Clone, Ord, PartialOrd,
772)]
773#[serde(rename_all = "lowercase")]
774#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
775#[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))]
776pub enum SceneSelectionType {
777    /// Replaces the selection
778    Replace,
779    /// Adds to the selection
780    Add,
781    /// Removes from the selection
782    Remove,
783}
784
785/// The type of scene's active tool
786#[allow(missing_docs)]
787#[derive(
788    Display, FromStr, Copy, Eq, PartialEq, Debug, JsonSchema, Deserialize, Serialize, Sequence, Clone, Ord, PartialOrd,
789)]
790#[serde(rename_all = "snake_case")]
791#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
792#[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))]
793pub enum SceneToolType {
794    CameraRevolve,
795    Select,
796    Move,
797    SketchLine,
798    SketchTangentialArc,
799    SketchCurve,
800    SketchCurveMod,
801}
802
803/// The path component constraint bounds type
804#[allow(missing_docs)]
805#[derive(
806    Display,
807    FromStr,
808    Copy,
809    Eq,
810    PartialEq,
811    Debug,
812    JsonSchema,
813    Deserialize,
814    Serialize,
815    Sequence,
816    Clone,
817    Ord,
818    PartialOrd,
819    Default,
820)]
821#[serde(rename_all = "snake_case")]
822#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
823#[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))]
824pub enum PathComponentConstraintBound {
825    #[default]
826    Unconstrained,
827    PartiallyConstrained,
828    FullyConstrained,
829}
830
831/// The path component constraint type
832#[allow(missing_docs)]
833#[derive(
834    Display,
835    FromStr,
836    Copy,
837    Eq,
838    PartialEq,
839    Debug,
840    JsonSchema,
841    Deserialize,
842    Serialize,
843    Sequence,
844    Clone,
845    Ord,
846    PartialOrd,
847    Default,
848)]
849#[serde(rename_all = "snake_case")]
850#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
851#[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))]
852pub enum PathComponentConstraintType {
853    #[default]
854    Unconstrained,
855    Vertical,
856    Horizontal,
857    EqualLength,
858    Parallel,
859    AngleBetween,
860}
861
862/// The path component command type (within a Path)
863#[allow(missing_docs)]
864#[derive(
865    Display, FromStr, Copy, Eq, PartialEq, Debug, JsonSchema, Deserialize, Serialize, Sequence, Clone, Ord, PartialOrd,
866)]
867#[serde(rename_all = "snake_case")]
868#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
869#[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))]
870pub enum PathCommand {
871    MoveTo,
872    LineTo,
873    BezCurveTo,
874    NurbsCurveTo,
875    AddArc,
876}
877
878/// The type of entity
879#[allow(missing_docs)]
880#[derive(
881    Display, FromStr, Copy, Eq, PartialEq, Debug, JsonSchema, Deserialize, Serialize, Sequence, Clone, Ord, PartialOrd,
882)]
883#[serde(rename_all = "lowercase")]
884#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
885#[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))]
886#[repr(u8)]
887pub enum EntityType {
888    Entity,
889    Object,
890    Path,
891    Curve,
892    Solid2D,
893    Solid3D,
894    Edge,
895    Face,
896    Plane,
897    Vertex,
898}
899
900/// The type of Curve (embedded within path)
901#[allow(missing_docs)]
902#[derive(
903    Display, FromStr, Copy, Eq, PartialEq, Debug, JsonSchema, Deserialize, Serialize, Sequence, Clone, Ord, PartialOrd,
904)]
905#[serde(rename_all = "snake_case")]
906#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
907#[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))]
908pub enum CurveType {
909    Line,
910    Arc,
911    Nurbs,
912}
913
914/// A file to be exported to the client.
915#[derive(Debug, Serialize, Deserialize, JsonSchema, Clone)]
916#[cfg_attr(feature = "python", pyo3::pyclass, pyo3_stub_gen::derive::gen_stub_pyclass)]
917pub struct ExportFile {
918    /// The name of the file.
919    pub name: String,
920    /// The contents of the file, base64 encoded.
921    pub contents: crate::base64::Base64Data,
922}
923
924#[cfg(feature = "python")]
925#[pyo3_stub_gen::derive::gen_stub_pymethods]
926#[pyo3::pymethods]
927impl ExportFile {
928    #[getter]
929    fn contents(&self) -> Vec<u8> {
930        self.contents.0.clone()
931    }
932
933    #[getter]
934    fn name(&self) -> String {
935        self.name.clone()
936    }
937}
938
939/// The valid types of output file formats.
940#[derive(
941    Display, FromStr, Copy, Eq, PartialEq, Debug, JsonSchema, Deserialize, Serialize, Clone, Ord, PartialOrd, Sequence,
942)]
943#[serde(rename_all = "lowercase")]
944#[display(style = "lowercase")]
945#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
946#[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))]
947#[cfg_attr(feature = "python", pyo3::pyclass, pyo3_stub_gen::derive::gen_stub_pyclass_enum)]
948pub enum FileExportFormat {
949    /// Autodesk Filmbox (FBX) format. <https://en.wikipedia.org/wiki/FBX>
950    Fbx,
951    /// Binary glTF 2.0.
952    ///
953    /// This is a single binary with .glb extension.
954    ///
955    /// This is better if you want a compressed format as opposed to the human readable
956    /// glTF that lacks compression.
957    Glb,
958    /// glTF 2.0.
959    /// Embedded glTF 2.0 (pretty printed).
960    ///
961    /// Single JSON file with .gltf extension binary data encoded as
962    /// base64 data URIs.
963    ///
964    /// The JSON contents are pretty printed.
965    ///
966    /// It is human readable, single file, and you can view the
967    /// diff easily in a git commit.
968    Gltf,
969    /// The OBJ file format. <https://en.wikipedia.org/wiki/Wavefront_.obj_file>
970    /// It may or may not have an an attached material (mtl // mtllib) within the file,
971    /// but we interact with it as if it does not.
972    Obj,
973    /// The PLY file format. <https://en.wikipedia.org/wiki/PLY_(file_format)>
974    Ply,
975    /// The STEP file format. <https://en.wikipedia.org/wiki/ISO_10303-21>
976    Step,
977    /// The STL file format. <https://en.wikipedia.org/wiki/STL_(file_format)>
978    Stl,
979}
980
981/// The valid types of 2D output file formats.
982#[derive(
983    Display, FromStr, Copy, Eq, PartialEq, Debug, JsonSchema, Deserialize, Serialize, Clone, Ord, PartialOrd, Sequence,
984)]
985#[serde(rename_all = "lowercase")]
986#[display(style = "lowercase")]
987#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
988#[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))]
989pub enum FileExportFormat2d {
990    /// AutoCAD drawing interchange format.
991    Dxf,
992}
993
994/// The valid types of source file formats.
995#[derive(
996    Display, FromStr, Copy, Eq, PartialEq, Debug, JsonSchema, Deserialize, Serialize, Clone, Ord, PartialOrd, Sequence,
997)]
998#[serde(rename_all = "lowercase")]
999#[display(style = "lowercase")]
1000#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
1001#[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))]
1002pub enum FileImportFormat {
1003    /// Autodesk Filmbox (FBX) format. <https://en.wikipedia.org/wiki/FBX>
1004    Fbx,
1005    /// glTF 2.0.
1006    Gltf,
1007    /// The OBJ file format. <https://en.wikipedia.org/wiki/Wavefront_.obj_file>
1008    /// It may or may not have an an attached material (mtl // mtllib) within the file,
1009    /// but we interact with it as if it does not.
1010    Obj,
1011    /// The PLY file format. <https://en.wikipedia.org/wiki/PLY_(file_format)>
1012    Ply,
1013    /// SolidWorks part (SLDPRT) format.
1014    Sldprt,
1015    /// The STEP file format. <https://en.wikipedia.org/wiki/ISO_10303-21>
1016    Step,
1017    /// The STL file format. <https://en.wikipedia.org/wiki/STL_(file_format)>
1018    Stl,
1019}
1020
1021/// The type of error sent by the KittyCAD graphics engine.
1022#[derive(Display, FromStr, Copy, Eq, PartialEq, Debug, JsonSchema, Deserialize, Serialize, Clone, Ord, PartialOrd)]
1023#[serde(rename_all = "snake_case")]
1024#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
1025#[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))]
1026pub enum EngineErrorCode {
1027    /// User requested something geometrically or graphically impossible.
1028    /// Don't retry this request, as it's inherently impossible. Instead, read the error message
1029    /// and change your request.
1030    BadRequest = 1,
1031    /// Graphics engine failed to complete request, consider retrying
1032    InternalEngine,
1033}
1034
1035impl From<EngineErrorCode> for http::StatusCode {
1036    fn from(e: EngineErrorCode) -> Self {
1037        match e {
1038            EngineErrorCode::BadRequest => Self::BAD_REQUEST,
1039            EngineErrorCode::InternalEngine => Self::INTERNAL_SERVER_ERROR,
1040        }
1041    }
1042}
1043
1044/// Body type determining if the operation will create a solid or a surface.
1045#[derive(Default, Clone, Copy, Debug, Eq, PartialEq, Serialize, Deserialize, JsonSchema)]
1046#[serde(rename_all = "snake_case")]
1047#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
1048#[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))]
1049pub enum BodyType {
1050    ///Create a body that has two caps, creating a solid object.
1051    #[default]
1052    Solid,
1053    ///Create only the surface of the body without any caps.
1054    Surface,
1055}
1056
1057/// Extrusion method determining if the extrusion will be part of the existing object or an
1058/// entirely new object.
1059#[derive(Default, Clone, Copy, Debug, Eq, PartialEq, Serialize, Deserialize, JsonSchema)]
1060#[serde(rename_all = "snake_case")]
1061#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
1062#[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))]
1063pub enum ExtrudeMethod {
1064    /// Create a new object that is not connected to the object it is extruded from. This will
1065    /// result in two objects after the operation.
1066    New,
1067    /// This extrusion will be part of object it is extruded from. This will result in one object
1068    /// after the operation.
1069    #[default]
1070    Merge,
1071}
1072
1073/// Type of reference geometry to extrude to.
1074#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize, JsonSchema)]
1075#[serde(rename_all = "snake_case")]
1076#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
1077#[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))]
1078pub enum ExtrudeReference {
1079    /// Extrudes along the normal of the top face until it is as close to the entity as possible.
1080    /// An entity can be a solid, a path, a face, etc.
1081    EntityReference {
1082        /// The UUID of the entity to extrude to.
1083        entity_id: Uuid,
1084    },
1085    /// Extrudes until the top face is as close as possible to this given axis.
1086    Axis {
1087        /// The axis to extrude to.
1088        axis: Point3d<f64>,
1089        /// Point the axis goes through.
1090        /// Defaults to (0, 0, 0).
1091        #[serde(default)]
1092        point: Point3d<LengthUnit>,
1093    },
1094    /// Extrudes until the top face is as close as possible to this given point.
1095    Point {
1096        /// The point to extrude to.
1097        point: Point3d<LengthUnit>,
1098    },
1099}
1100
1101/// IDs for the extruded faces.
1102#[derive(Debug, PartialEq, Serialize, Deserialize, JsonSchema, Clone)]
1103#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
1104#[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))]
1105pub struct ExtrudedFaceInfo {
1106    /// The face made from the original 2D shape being extruded.
1107    /// If the solid is extruded from a shape which already has an ID
1108    /// (e.g. extruding something which was sketched on a face), this
1109    /// doesn't need to be sent.
1110    pub bottom: Option<Uuid>,
1111    /// Top face of the extrusion (parallel and further away from the original 2D shape being extruded).
1112    pub top: Uuid,
1113    /// Any intermediate sides between the top and bottom.
1114    pub sides: Vec<SideFace>,
1115}
1116
1117/// IDs for a side face, extruded from the path of some sketch/2D shape.
1118#[derive(Debug, PartialEq, Serialize, Deserialize, JsonSchema, Clone)]
1119#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
1120#[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))]
1121pub struct SideFace {
1122    /// ID of the path this face is being extruded from.
1123    pub path_id: Uuid,
1124    /// Desired ID for the resulting face.
1125    pub face_id: Uuid,
1126}
1127
1128/// Camera settings including position, center, fov etc
1129#[derive(Debug, Serialize, Deserialize, JsonSchema, Clone)]
1130#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
1131#[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))]
1132pub struct CameraSettings {
1133    ///Camera position (vantage)
1134    pub pos: Point3d,
1135
1136    ///Camera's look-at center (center-pos gives viewing vector)
1137    pub center: Point3d,
1138
1139    ///Camera's world-space up vector
1140    pub up: Point3d,
1141
1142    ///The Camera's orientation (in the form of a quaternion)
1143    pub orientation: Quaternion,
1144
1145    ///Camera's field-of-view angle (if ortho is false)
1146    pub fov_y: Option<f32>,
1147
1148    ///The camera's ortho scale (derived from viewing distance if ortho is true)
1149    pub ortho_scale: Option<f32>,
1150
1151    ///Whether or not the camera is in ortho mode
1152    pub ortho: bool,
1153}
1154
1155#[allow(missing_docs)]
1156#[repr(u8)]
1157#[derive(Default, Clone, Copy, Debug, Eq, PartialEq, Serialize, Deserialize, JsonSchema)]
1158#[serde(rename_all = "snake_case")]
1159#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
1160#[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))]
1161pub enum WorldCoordinateSystem {
1162    #[default]
1163    RightHandedUpZ,
1164    RightHandedUpY,
1165}
1166
1167#[allow(missing_docs)]
1168#[repr(C)]
1169#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize, JsonSchema)]
1170#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
1171#[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))]
1172pub struct CameraViewState {
1173    pub pivot_rotation: Quaternion,
1174    pub pivot_position: Point3d,
1175    pub eye_offset: f32,
1176    pub fov_y: f32,
1177    pub ortho_scale_factor: f32,
1178    pub is_ortho: bool,
1179    pub ortho_scale_enabled: bool,
1180    pub world_coord_system: WorldCoordinateSystem,
1181}
1182
1183impl Default for CameraViewState {
1184    fn default() -> Self {
1185        CameraViewState {
1186            pivot_rotation: Default::default(),
1187            pivot_position: Default::default(),
1188            eye_offset: 10.0,
1189            fov_y: 45.0,
1190            ortho_scale_factor: 1.6,
1191            is_ortho: false,
1192            ortho_scale_enabled: true,
1193            world_coord_system: Default::default(),
1194        }
1195    }
1196}
1197
1198#[cfg(feature = "cxx")]
1199impl_extern_type! {
1200    [Trivial]
1201    CameraViewState = "Endpoints::CameraViewState"
1202}
1203
1204impl From<CameraSettings> for crate::output::DefaultCameraZoom {
1205    fn from(settings: CameraSettings) -> Self {
1206        Self { settings }
1207    }
1208}
1209impl From<CameraSettings> for crate::output::CameraDragMove {
1210    fn from(settings: CameraSettings) -> Self {
1211        Self { settings }
1212    }
1213}
1214impl From<CameraSettings> for crate::output::CameraDragEnd {
1215    fn from(settings: CameraSettings) -> Self {
1216        Self { settings }
1217    }
1218}
1219impl From<CameraSettings> for crate::output::DefaultCameraGetSettings {
1220    fn from(settings: CameraSettings) -> Self {
1221        Self { settings }
1222    }
1223}
1224impl From<CameraSettings> for crate::output::ZoomToFit {
1225    fn from(settings: CameraSettings) -> Self {
1226        Self { settings }
1227    }
1228}
1229impl From<CameraSettings> for crate::output::OrientToFace {
1230    fn from(settings: CameraSettings) -> Self {
1231        Self { settings }
1232    }
1233}
1234impl From<CameraSettings> for crate::output::ViewIsometric {
1235    fn from(settings: CameraSettings) -> Self {
1236        Self { settings }
1237    }
1238}
1239
1240/// Defines a perspective view.
1241#[derive(Copy, PartialEq, Debug, JsonSchema, Deserialize, Serialize, Clone, PartialOrd, Default)]
1242#[serde(rename_all = "snake_case")]
1243#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
1244#[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))]
1245pub struct PerspectiveCameraParameters {
1246    /// Camera frustum vertical field of view.
1247    pub fov_y: Option<f32>,
1248    /// Camera frustum near plane.
1249    pub z_near: Option<f32>,
1250    /// Camera frustum far plane.
1251    pub z_far: Option<f32>,
1252}
1253
1254/// A type of camera movement applied after certain camera operations
1255#[derive(
1256    Default,
1257    Display,
1258    FromStr,
1259    Copy,
1260    Eq,
1261    PartialEq,
1262    Debug,
1263    JsonSchema,
1264    Deserialize,
1265    Serialize,
1266    Sequence,
1267    Clone,
1268    Ord,
1269    PartialOrd,
1270)]
1271#[serde(rename_all = "snake_case")]
1272#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
1273#[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))]
1274pub enum CameraMovement {
1275    /// Adjusts the camera position during the camera operation
1276    #[default]
1277    Vantage,
1278    /// Keeps the camera position in place
1279    None,
1280}
1281
1282/// The global axes.
1283#[derive(
1284    Display, FromStr, Copy, Eq, PartialEq, Debug, JsonSchema, Deserialize, Serialize, Sequence, Clone, Ord, PartialOrd,
1285)]
1286#[serde(rename_all = "lowercase")]
1287#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
1288#[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))]
1289pub enum GlobalAxis {
1290    /// The X axis
1291    X,
1292    /// The Y axis
1293    Y,
1294    /// The Z axis
1295    Z,
1296}
1297
1298/// Possible types of faces which can be extruded from a 3D solid.
1299#[derive(
1300    Display, FromStr, Copy, Eq, PartialEq, Debug, JsonSchema, Deserialize, Serialize, Sequence, Clone, Ord, PartialOrd,
1301)]
1302#[serde(rename_all = "snake_case")]
1303#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
1304#[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))]
1305#[repr(u8)]
1306pub enum ExtrusionFaceCapType {
1307    /// Uncapped.
1308    None,
1309    /// Capped on top.
1310    Top,
1311    /// Capped below.
1312    Bottom,
1313    /// Capped on both ends.
1314    Both,
1315}
1316
1317/// Post effect type
1318#[allow(missing_docs)]
1319#[derive(
1320    Display,
1321    FromStr,
1322    Copy,
1323    Eq,
1324    PartialEq,
1325    Debug,
1326    JsonSchema,
1327    Deserialize,
1328    Serialize,
1329    Sequence,
1330    Clone,
1331    Ord,
1332    PartialOrd,
1333    Default,
1334)]
1335#[serde(rename_all = "lowercase")]
1336#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
1337#[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))]
1338pub enum PostEffectType {
1339    Phosphor,
1340    Ssao,
1341    #[default]
1342    NoEffect,
1343}
1344
1345// Enum: Connect Rust Enums to Cpp
1346// add our native c++ names for our cxx::ExternType implementation
1347#[cfg(feature = "cxx")]
1348impl_extern_type! {
1349    [Trivial]
1350    // File
1351    FileImportFormat = "Enums::_FileImportFormat"
1352    FileExportFormat = "Enums::_FileExportFormat"
1353    // Camera
1354    CameraDragInteractionType = "Enums::_CameraDragInteractionType"
1355    // Scene
1356    SceneSelectionType = "Enums::_SceneSelectionType"
1357    SceneToolType = "Enums::_SceneToolType"
1358    BodyType = "Enums::_BodyType"
1359    EntityType = "Enums::_EntityType"
1360    AnnotationType = "Enums::_AnnotationType"
1361    AnnotationTextAlignmentX = "Enums::_AnnotationTextAlignmentX"
1362    AnnotationTextAlignmentY = "Enums::_AnnotationTextAlignmentY"
1363    AnnotationLineEnd = "Enums::_AnnotationLineEnd"
1364    MbdStandard = "Enums::_MBDStandard"
1365    MbdSymbol = "Enums::_MBDSymbol"
1366
1367    CurveType = "Enums::_CurveType"
1368    PathCommand = "Enums::_PathCommand"
1369    PathComponentConstraintBound = "Enums::_PathComponentConstraintBound"
1370    PathComponentConstraintType = "Enums::_PathComponentConstraintType"
1371    ExtrusionFaceCapType  = "Enums::_ExtrusionFaceCapType"
1372
1373    // Utils
1374    EngineErrorCode = "Enums::_ErrorCode"
1375    GlobalAxis = "Enums::_GlobalAxis"
1376    OriginType = "Enums::_OriginType"
1377
1378    // Graphics engine
1379    PostEffectType = "Enums::_PostEffectType"
1380}
1381
1382fn bool_true() -> bool {
1383    true
1384}
1385fn same_scale() -> Point3d<f64> {
1386    Point3d::uniform(1.0)
1387}
1388
1389fn z_axis() -> Point3d<f64> {
1390    Point3d { x: 0.0, y: 0.0, z: 1.0 }
1391}
1392
1393impl ExtrudedFaceInfo {
1394    /// Converts from the representation used in the Extrude modeling command,
1395    /// to a flat representation.
1396    pub fn list_faces(self) -> Vec<ExtrusionFaceInfo> {
1397        let mut face_infos: Vec<_> = self
1398            .sides
1399            .into_iter()
1400            .map(|side| ExtrusionFaceInfo {
1401                curve_id: Some(side.path_id),
1402                face_id: Some(side.face_id),
1403                cap: ExtrusionFaceCapType::None,
1404            })
1405            .collect();
1406        face_infos.push(ExtrusionFaceInfo {
1407            curve_id: None,
1408            face_id: Some(self.top),
1409            cap: ExtrusionFaceCapType::Top,
1410        });
1411        if let Some(bottom) = self.bottom {
1412            face_infos.push(ExtrusionFaceInfo {
1413                curve_id: None,
1414                face_id: Some(bottom),
1415                cap: ExtrusionFaceCapType::Bottom,
1416            });
1417        }
1418        face_infos
1419    }
1420}
1421
1422#[cfg(test)]
1423mod tests {
1424    use schemars::schema_for;
1425
1426    use super::*;
1427
1428    #[test]
1429    fn check_transformby_deprecated() {
1430        let s = schema_for!(TransformBy<Point3d>);
1431        let pretty = serde_json::to_string_pretty(&s).unwrap();
1432        println!("{pretty}");
1433        let tests: Vec<(OriginType, TransformBy<Point3d>)> = vec![
1434            // get_origin should fall back to `is_local`, because `origin` is none.
1435            (
1436                OriginType::Local,
1437                TransformBy {
1438                    property: Point3d::default(),
1439                    set: true,
1440                    #[allow(deprecated)] // still need to test deprecated code
1441                    is_local: true,
1442                    origin: None,
1443                },
1444            ),
1445            // get_origin should ignore `is_local`, because `origin` is given.
1446            // test the case where origin is not custom
1447            (
1448                OriginType::Local,
1449                TransformBy {
1450                    property: Point3d::default(),
1451                    set: true,
1452                    #[allow(deprecated)] // still need to test deprecated code
1453                    is_local: false,
1454                    origin: Some(OriginType::Local),
1455                },
1456            ),
1457            // get_origin should ignore `is_local`, because `origin` is given.
1458            // test the case where origin is custom.
1459            (
1460                OriginType::Custom {
1461                    origin: Point3d::uniform(2.0),
1462                },
1463                TransformBy {
1464                    property: Point3d::default(),
1465                    set: true,
1466                    #[allow(deprecated)] // still need to test deprecated code
1467                    is_local: false,
1468                    origin: Some(OriginType::Custom{origin: Point3d::uniform(2.0)}),
1469                },
1470            ),
1471        ];
1472        for (expected, input) in tests {
1473            let actual = input.get_origin();
1474            assert_eq!(actual, expected);
1475        }
1476    }
1477
1478    #[test]
1479    fn test_angle_comparison() {
1480        let a = Angle::from_degrees(90.0);
1481        assert!(a < Angle::from_degrees(91.0));
1482        assert!(a > Angle::from_degrees(89.0));
1483        assert!(a <= Angle::from_degrees(90.0));
1484        assert!(a >= Angle::from_degrees(90.0));
1485        let b = Angle::from_radians(std::f64::consts::FRAC_PI_4);
1486        assert!(b < Angle::from_radians(std::f64::consts::FRAC_PI_2));
1487        assert!(b > Angle::from_radians(std::f64::consts::FRAC_PI_8));
1488        assert!(b <= Angle::from_radians(std::f64::consts::FRAC_PI_4));
1489        assert!(b >= Angle::from_radians(std::f64::consts::FRAC_PI_4));
1490        // Mixed units.
1491        assert!(a > b);
1492        assert!(a >= b);
1493        assert!(b < a);
1494        assert!(b <= a);
1495        let c = Angle::from_radians(std::f64::consts::FRAC_PI_2 * 3.0);
1496        assert!(a < c);
1497        assert!(a <= c);
1498        assert!(c > a);
1499        assert!(c >= a);
1500    }
1501}
1502
1503/// How a property of an object should be transformed.
1504#[derive(Clone, Debug, PartialEq, Deserialize, Serialize, JsonSchema)]
1505#[schemars(rename = "TransformByFor{T}")]
1506#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
1507#[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))]
1508pub struct TransformBy<T> {
1509    /// The scale, or rotation, or translation.
1510    pub property: T,
1511    /// If true, overwrite the previous value with this.
1512    /// If false, the previous value will be modified.
1513    /// E.g. when translating, `set=true` will set a new location,
1514    /// and `set=false` will translate the current location by the given X/Y/Z.
1515    pub set: bool,
1516    /// If true, the transform is applied in local space.
1517    /// If false, the transform is applied in global space.
1518    #[deprecated(note = "Use the `origin` field instead.")]
1519    pub is_local: bool,
1520    /// What to use as the origin for the transformation.
1521    /// If not provided, will fall back to local or global origin, depending on
1522    /// whatever the `is_local` field was set to.
1523    #[serde(default)]
1524    pub origin: Option<OriginType>,
1525}
1526
1527impl<T> TransformBy<T> {
1528    /// Get the origin of this transformation.
1529    /// Reads from the `origin` field if it's set, otherwise
1530    /// falls back to the `is_local` field.
1531    pub fn get_origin(&self) -> OriginType {
1532        if let Some(origin) = self.origin {
1533            return origin;
1534        }
1535        #[expect(
1536            deprecated,
1537            reason = "Must fall back to the deprecated field if the API client isn't using the new field yet."
1538        )]
1539        if self.is_local {
1540            OriginType::Local
1541        } else {
1542            OriginType::Global
1543        }
1544    }
1545}
1546
1547/// Container that holds a translate, rotate and scale.
1548/// Defaults to no change, everything stays the same (i.e. the identity function).
1549#[derive(Clone, Debug, PartialEq, Deserialize, JsonSchema, Serialize, Default)]
1550#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
1551#[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))]
1552pub struct ComponentTransform {
1553    /// Translate component of the transform.
1554    pub translate: Option<TransformBy<Point3d<LengthUnit>>>,
1555    /// Rotate component of the transform.
1556    /// The rotation is specified as a roll, pitch, yaw.
1557    pub rotate_rpy: Option<TransformBy<Point3d<f64>>>,
1558    /// Rotate component of the transform.
1559    /// The rotation is specified as an axis and an angle (xyz are the components of the axis, w is
1560    /// the angle in degrees).
1561    pub rotate_angle_axis: Option<TransformBy<Point4d<f64>>>,
1562    /// Scale component of the transform.
1563    pub scale: Option<TransformBy<Point3d<f64>>>,
1564}
1565
1566///If bidirectional or symmetric operations are needed this enum encapsulates the required
1567///information.
1568#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
1569#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
1570#[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))]
1571pub enum Opposite<T> {
1572    /// No opposite. The operation will only occur on one side.
1573    #[default]
1574    None,
1575    /// Operation will occur from both sides, with the same value.
1576    Symmetric,
1577    /// Operation will occur from both sides, with this value for the opposite.
1578    Other(T),
1579}
1580
1581impl<T: JsonSchema> JsonSchema for Opposite<T> {
1582    fn schema_name() -> String {
1583        format!("OppositeFor{}", T::schema_name())
1584    }
1585
1586    fn schema_id() -> std::borrow::Cow<'static, str> {
1587        std::borrow::Cow::Owned(format!("{}::Opposite<{}>", module_path!(), T::schema_id()))
1588    }
1589
1590    fn json_schema(_: &mut schemars::gen::SchemaGenerator) -> schemars::schema::Schema {
1591        SchemaObject {
1592            instance_type: Some(schemars::schema::InstanceType::String.into()),
1593            ..Default::default()
1594        }
1595        .into()
1596    }
1597}
1598
1599/// What strategy (algorithm) should be used for cutting?
1600/// Defaults to Automatic.
1601#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize, JsonSchema, Default)]
1602#[serde(rename_all = "snake_case")]
1603#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
1604#[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))]
1605pub enum CutStrategy {
1606    /// Basic fillet cut. This has limitations, like the filletted edges
1607    /// can't touch each other. But it's very fast and simple.
1608    Basic,
1609    /// More complicated fillet cut. It works for more use-cases, like
1610    /// edges that touch each other. But it's slower than the Basic method.
1611    Csg,
1612    /// Tries the Basic method, and if that doesn't work, tries the CSG strategy.
1613    #[default]
1614    Automatic,
1615}
1616
1617/// What is the given geometry relative to?
1618#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize, JsonSchema, Default)]
1619#[serde(rename_all = "snake_case")]
1620#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
1621#[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))]
1622pub enum RelativeTo {
1623    /// Local/relative to a position centered within the plane being sketched on
1624    #[default]
1625    SketchPlane,
1626    /// Local/relative to the trajectory curve
1627    TrajectoryCurve,
1628}