kittycad_modeling_cmds/
shared.rs

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