Skip to main content

kittycad_modeling_cmds/
shared.rs

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