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