diff --git a/modeling-cmds/openapi/api.json b/modeling-cmds/openapi/api.json index 8c98f1cb..f181b2c2 100644 --- a/modeling-cmds/openapi/api.json +++ b/modeling-cmds/openapi/api.json @@ -665,6 +665,65 @@ } ] }, + "AssemblyConstraint": { + "description": "How to constrain bodies in an assembly.", + "oneOf": [ + { + "description": "Makes two entities occupy the same line/plane or places a point on a surface.", + "type": "object", + "properties": { + "coincident": { + "type": "object", + "properties": { + "targets": { + "description": "IDs of two mate frames in the assembly.", + "type": "array", + "items": { + "type": "string", + "format": "uuid" + }, + "minItems": 2, + "maxItems": 2 + } + }, + "required": [ + "targets" + ] + } + }, + "required": [ + "coincident" + ], + "additionalProperties": false + }, + { + "description": "Aligns cylindrical, conical, or spherical surfaces to a common center.", + "type": "object", + "properties": { + "concentric": { + "type": "object", + "properties": { + "targets": { + "description": "Which edge? IDs of two mate frames in the assembly. Must be >= 2 items.", + "type": "array", + "items": { + "type": "string", + "format": "uuid" + } + } + }, + "required": [ + "targets" + ] + } + }, + "required": [ + "concentric" + ], + "additionalProperties": false + } + ] + }, "Axis": { "description": "Co-ordinate axis specifier.\n\nSee [cglearn.eu] for background reading.\n\n[cglearn.eu]: https://cglearn.eu/pub/computer-graphics/introduction-to-geometry#material-coordinate-systems-1", "oneOf": [ @@ -2532,6 +2591,78 @@ "type": "number", "format": "double" }, + "MateFrameOn": { + "description": "What to create a mate frame on", + "oneOf": [ + { + "description": "Mate frame at the centroid of this face.", + "type": "object", + "properties": { + "face_centroid": { + "type": "object", + "properties": { + "where_on_face": { + "description": "Where on the given face?", + "allOf": [ + { + "$ref": "#/components/schemas/PointOnFace" + } + ] + }, + "which_face": { + "description": "Which face?", + "type": "string", + "format": "uuid" + } + }, + "required": [ + "where_on_face", + "which_face" + ] + } + }, + "required": [ + "face_centroid" + ], + "additionalProperties": false + }, + { + "description": "Mate frame along this edge.", + "type": "object", + "properties": { + "edge": { + "type": "object", + "properties": { + "where_on_edge": { + "description": "Where on the given edge?", + "allOf": [ + { + "$ref": "#/components/schemas/WhereOnEdge" + } + ] + }, + "which_edge": { + "description": "Which edge?", + "allOf": [ + { + "$ref": "#/components/schemas/EdgeSpecifier" + } + ] + } + }, + "required": [ + "where_on_edge", + "which_edge" + ] + } + }, + "required": [ + "edge" + ], + "additionalProperties": false + } + ] + }, "MbdSymbol": { "description": "MBD symbol type", "type": "string", @@ -8190,6 +8321,99 @@ "path_id", "type" ] + }, + { + "description": "Create a new assembly", + "type": "object", + "properties": { + "children": { + "description": "Which entities, if any, to move into this assembly.", + "type": "array", + "items": { + "type": "string", + "format": "uuid" + } + }, + "type": { + "type": "string", + "enum": [ + "assembly_create" + ] + } + }, + "required": [ + "type" + ] + }, + { + "description": "Add children to the assembly", + "type": "object", + "properties": { + "children": { + "description": "Which entities, to move into this assembly.", + "type": "array", + "items": { + "type": "string", + "format": "uuid" + } + }, + "type": { + "type": "string", + "enum": [ + "assembly_add_children" + ] + } + }, + "required": [ + "type" + ] + }, + { + "description": "Create a mate frame", + "type": "object", + "properties": { + "on": { + "description": "What to create the mate frame on.", + "allOf": [ + { + "$ref": "#/components/schemas/MateFrameOn" + } + ] + }, + "type": { + "type": "string", + "enum": [ + "mate_frame_create" + ] + } + }, + "required": [ + "on", + "type" + ] + }, + { + "description": "Add constraints to an assembly.", + "type": "object", + "properties": { + "constraints": { + "description": "Which constraints to apply.", + "type": "array", + "items": { + "$ref": "#/components/schemas/AssemblyConstraint" + } + }, + "type": { + "type": "string", + "enum": [ + "assembly_add_constraints" + ] + } + }, + "required": [ + "constraints", + "type" + ] } ] }, @@ -9118,6 +9342,57 @@ "z" ] }, + "PointOnFace": { + "description": "Identifies a point on a specific face.", + "oneOf": [ + { + "description": "Centermost point of the face.", + "type": "object", + "properties": { + "centroid": { + "type": "object" + } + }, + "required": [ + "centroid" + ], + "additionalProperties": false + }, + { + "description": "Somewhere along the face.", + "type": "object", + "properties": { + "at_parameter": { + "type": "object", + "properties": { + "u": { + "description": "Value for the face's 2D parametric equation.", + "type": "number", + "format": "double", + "minimum": 0.0, + "maximum": 1.0 + }, + "v": { + "description": "Value for the face's 2D parametric equation.", + "type": "number", + "format": "double", + "minimum": 0.0, + "maximum": 1.0 + } + }, + "required": [ + "u", + "v" + ] + } + }, + "required": [ + "at_parameter" + ], + "additionalProperties": false + } + ] + }, "PrimitiveTopologyFallback": { "description": "Optional fallback when primary UUIDs are missing from the client artifact graph (e.g. stale or engine-only ids). Identifies the same topology via a **parent** entity UUID and a **primitive index** on that parent.\n\nSemantics by selection kind (aligned with engine BREP topology):\n\n- **Face / Edge (3D)**: `parent_id` is the owning [`EntityType::Solid3D`] body UUID; `primitive_index` matches the index returned by **EntityGetPrimitiveIndex** for that face or edge (and matches **EntityGetParentId** → parent + **EntityGetPrimitiveIndex** → index). - **Vertex (3D)**: same `parent_id` (solid); `primitive_index` is the BREP vertex index on that solid. - **Solid2dEdge**: `parent_id` is the **Solid2D** profile UUID; `primitive_index` is the curve index within that profile. - **Segment**: `parent_id` is the **Path** UUID; `primitive_index` is the curve index within that path.\n\nOther [`EntityReference`] variants may omit this field or leave it unset when not applicable.", "type": "object", @@ -10178,6 +10453,49 @@ } ] }, + "WhereOnEdge": { + "description": "Identifies a point on a specific edge.", + "oneOf": [ + { + "description": "Midpoint along the edge.", + "type": "object", + "properties": { + "midpoint": { + "type": "object" + } + }, + "required": [ + "midpoint" + ], + "additionalProperties": false + }, + { + "description": "Somewhere along the edge's length.", + "type": "object", + "properties": { + "at_parameter": { + "type": "object", + "properties": { + "t": { + "description": "Value which, substituted into the edge's parametric equation, gives a point. Must be between 0 and 1 (inclusive).", + "type": "number", + "format": "double", + "minimum": 0.0, + "maximum": 1.0 + } + }, + "required": [ + "t" + ] + } + }, + "required": [ + "at_parameter" + ], + "additionalProperties": false + } + ] + }, "WorldCoordinateSystem": { "type": "string", "enum": [ diff --git a/modeling-cmds/src/def_enum.rs b/modeling-cmds/src/def_enum.rs index df4fce5f..76d2dead 100644 --- a/modeling-cmds/src/def_enum.rs +++ b/modeling-cmds/src/def_enum.rs @@ -25,6 +25,8 @@ define_modeling_cmd_enum! { length_unit::LengthUnit, shared::{ Angle, + AssemblyConstraint, + MateFrameOn, RegionVersion, BlendType, BodyType, @@ -2422,7 +2424,7 @@ define_modeling_cmd_enum! { /// /// Most successful unions come from solids who's faces do not overlap /// aka non-coplanar. - /// + /// /// Failure cases: /// * A common failure is unsupported coincident faces try to be unioned. /// @@ -2491,7 +2493,7 @@ define_modeling_cmd_enum! { /// aka non-coplanar. /// /// Prefer one `tool` over multiple when calling this feature. - /// + /// /// Failure cases: /// * A common failure is unsupported coplanar faces try to be unioned. /// @@ -2838,6 +2840,53 @@ define_modeling_cmd_enum! { /// Which path to query pub path_id: ModelingCmdId, } + + /// Create a new assembly + #[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema, ModelingCmdVariant, Builder)] + #[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))] + #[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] + #[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))] + #[cfg_attr(not(feature = "unstable_exhaustive"), non_exhaustive)] + pub struct AssemblyCreate { + /// Which entities, if any, to move into this assembly. + #[serde(default, skip_serializing_if = "Vec::is_empty")] + pub children: Vec, + } + + /// Add children to the assembly + #[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema, ModelingCmdVariant, Builder)] + #[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))] + #[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] + #[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))] + #[cfg_attr(not(feature = "unstable_exhaustive"), non_exhaustive)] + pub struct AssemblyAddChildren { + /// Which entities, to move into this assembly. + #[serde(default, skip_serializing_if = "Vec::is_empty")] + pub children: Vec, + } + + /// Create a mate frame + #[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema, ModelingCmdVariant, Builder)] + #[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))] + #[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] + #[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))] + #[cfg_attr(not(feature = "unstable_exhaustive"), non_exhaustive)] + pub struct MateFrameCreate { + /// What to create the mate frame on. + pub on: MateFrameOn, + } + + /// Add constraints to an assembly. + #[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema, ModelingCmdVariant, Builder)] + #[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))] + #[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] + #[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))] + #[cfg_attr(not(feature = "unstable_exhaustive"), non_exhaustive)] + pub struct AssemblyAddConstraints { + /// Which constraints to apply. + pub constraints: Vec, + } + } } diff --git a/modeling-cmds/src/ok_response.rs b/modeling-cmds/src/ok_response.rs index 779b6c19..6179bd5f 100644 --- a/modeling-cmds/src/ok_response.rs +++ b/modeling-cmds/src/ok_response.rs @@ -25,6 +25,7 @@ define_ok_modeling_cmd_response_enum! { CameraViewState, BodyType, EntityReference, + SolvedAssemblyItem, }; use std::collections::HashMap; @@ -1427,5 +1428,31 @@ define_ok_modeling_cmd_response_enum! { /// How many regions the Toolpaths library thinks exist pub region_count: u16, } + + /// The response from the 'AssemblyCreate'. + #[derive(Debug, Serialize, Deserialize, Clone, PartialEq, JsonSchema, ModelingCmdOutput)] + #[cfg_attr(not(feature = "unstable_exhaustive"), non_exhaustive)] + pub struct AssemblyCreate { + } + + /// The response from the 'AssemblyAddChildren'. + #[derive(Debug, Serialize, Deserialize, Clone, PartialEq, JsonSchema, ModelingCmdOutput)] + #[cfg_attr(not(feature = "unstable_exhaustive"), non_exhaustive)] + pub struct AssemblyAddChildren { + } + + /// The response from the 'MateFrameCreate'. + #[derive(Debug, Serialize, Deserialize, Clone, PartialEq, JsonSchema, ModelingCmdOutput)] + #[cfg_attr(not(feature = "unstable_exhaustive"), non_exhaustive)] + pub struct MateFrameCreate { + } + + /// The response from the 'AssemblyAddConstraints'. + #[derive(Debug, Serialize, Deserialize, Clone, PartialEq, JsonSchema, ModelingCmdOutput)] + #[cfg_attr(not(feature = "unstable_exhaustive"), non_exhaustive)] + pub struct AssemblyAddConstraints { + /// For each item in the assembly, map its ID to its solution + pub solution: HashMap, + } } } diff --git a/modeling-cmds/src/shared.rs b/modeling-cmds/src/shared.rs index c1c6e20a..09a643c8 100644 --- a/modeling-cmds/src/shared.rs +++ b/modeling-cmds/src/shared.rs @@ -2248,3 +2248,109 @@ pub enum CurveTypeDebug { /// Circle with a center and radius. Circle, } + +/// What to create a mate frame on +#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, JsonSchema)] +#[serde(rename_all = "snake_case")] +#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))] +#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] +#[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))] +#[cfg_attr(not(feature = "unstable_exhaustive"), non_exhaustive)] +pub enum MateFrameOn { + /// Mate frame at the centroid of this face. + FaceCentroid { + /// Which face? + which_face: Uuid, + /// Where on the given face? + where_on_face: PointOnFace, + }, + /// Mate frame along this edge. + Edge { + /// Which edge? + which_edge: EdgeSpecifier, + /// Where on the given edge? + where_on_edge: WhereOnEdge, + }, +} + +/// Identifies a point on a specific face. +#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, JsonSchema)] +#[serde(rename_all = "snake_case")] +#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))] +#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] +#[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))] +#[cfg_attr(not(feature = "unstable_exhaustive"), non_exhaustive)] +pub enum PointOnFace { + /// Centermost point of the face. + Centroid {}, + /// Somewhere along the face. + AtParameter { + /// Value for the face's 2D parametric equation. + #[schemars(range(min = 0.0, max = 1.0))] + u: f64, + /// Value for the face's 2D parametric equation. + #[schemars(range(min = 0.0, max = 1.0))] + v: f64, + }, +} + +/// Identifies a point on a specific edge. +#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, JsonSchema)] +#[serde(rename_all = "snake_case")] +#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))] +#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] +#[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))] +#[cfg_attr(not(feature = "unstable_exhaustive"), non_exhaustive)] +pub enum WhereOnEdge { + /// Midpoint along the edge. + Midpoint {}, + /// Somewhere along the edge's length. + AtParameter { + /// Value which, substituted into the edge's parametric equation, + /// gives a point. Must be between 0 and 1 (inclusive). + #[schemars(range(min = 0.0, max = 1.0))] + t: f64, + }, +} + +/// How to constrain bodies in an assembly. +#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, JsonSchema)] +#[serde(rename_all = "snake_case")] +#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))] +#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] +#[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))] +#[cfg_attr(not(feature = "unstable_exhaustive"), non_exhaustive)] +pub enum AssemblyConstraint { + /// Makes two entities occupy the same line/plane or places a point on a surface. + Coincident { + /// IDs of two mate frames in the assembly. + targets: [Uuid; 2], + }, + /// Aligns cylindrical, conical, or spherical surfaces to a common center. + Concentric { + /// Which edge? + /// IDs of two mate frames in the assembly. + /// Must be >= 2 items. + #[schemars(range(min = 2))] + targets: Vec, + }, +} + +/// Result of constraining an item in an assembly. +/// This is in the coordinate system of the assembly's parent. +#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, JsonSchema)] +#[serde(rename_all = "snake_case")] +#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))] +#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] +#[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))] +#[cfg_attr(not(feature = "unstable_exhaustive"), non_exhaustive)] +pub struct SolvedAssemblyItem { + /// How to translate the item. + pub translate_by: Point3d, + /// How to rotate the item. + pub roll: Angle, + /// How to rotate the item. + pub pitch: Angle, + /// How to rotate the item. + pub yaw: Angle, +}