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