kittycad_modeling_cmds/
shared.rs

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