Skip to main content

kittycad_modeling_cmds/
shared.rs

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