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