Skip to main content

kittycad_modeling_cmds/
shared.rs

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