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