geop_ops_parts/operation/mod.rs
1//! The operations a [`crate::Program`] is made of.
2//!
3//! Each is a unit struct implementing [`Operation`], with an `Args` struct
4//! holding everything it needs. Arguments are plain design data — `f64`
5//! lengths, sketches — and refer to existing entities of the part only by
6//! name, never by an internal id: an id only means something inside the one
7//! build that produced it, a name means the same thing in every build of
8//! the same program (see `geop_core_part`'s crate docs).
9//!
10//! Entities a step builds on directly — a sketch's plane, what a datum is
11//! built from — are [`EntityRef`]s: a vertex, edge, face or datum by name,
12//! or the origin, a world axis or a base plane.
13//!
14//! [`PartOperation`] is any one of them together with its arguments: what a
15//! program step holds, and what serializes as `{"operation": "extrude",
16//! "args": {...}}`.
17
18mod add_sketch;
19mod boolean;
20mod datum;
21mod entity;
22mod extrude;
23mod handle;
24mod revolve;
25mod schema;
26#[cfg(test)]
27mod tests;
28
29pub use add_sketch::{AddSketch, AddSketchArgs};
30pub use boolean::{Boolean, BooleanArgs, Combine};
31pub use datum::{
32 AddDatum, AddDatumArgs, CONSTRUCTIONS, Construction, SelectionFit, inspect_selection,
33};
34pub use entity::{EntityRef, Geometry, Role, WorldAxis, resolve_plane};
35pub use extrude::{Extrude, ExtrudeArgs};
36pub use handle::{ArgPath, Handle, HandleGroup, HandleMotion, arg_path};
37pub use revolve::{Revolve, RevolveArgs};
38pub use schema::{ArgKind, ArgSchema, ConstructionSchema, OperationArgs, OperationSchema};
39
40use geop_core_math::{geop_error::GeopResult, scalars::Scalar};
41use geop_core_part::Part;
42use geop_ops_parts_derive::Operations;
43use serde::{Deserialize, Serialize};
44
45/// One kind of operation on a [`Part`].
46pub trait Operation<S: Scalar> {
47 /// Everything the operation needs, as plain, serializable design data.
48 type Args;
49
50 /// Applies the operation as the program step `operation_id`, consuming
51 /// `part` and returning the part it produces. Everything the operation
52 /// creates is named after `operation_id` (see `geop_core_part`), so the
53 /// id has to be unique within a program.
54 ///
55 /// On error no part is returned — a caller that still needs the
56 /// original should clone it first.
57 fn apply(&self, part: Part<S>, operation_id: &str, args: &Self::Args) -> GeopResult<Part<S>>;
58
59 /// The step's handles (see [`Handle`]), given the part `before` it —
60 /// what it is applied to. None, unless the operation offers some.
61 fn handles(&self, before: &Part<S>, args: &Self::Args) -> GeopResult<Vec<Handle>> {
62 let _ = (before, args);
63 Ok(Vec::new())
64 }
65}
66
67/// An operation together with its arguments, not yet applied to any part.
68///
69/// Every operation is registered here, as `Name(NameArgs)` with `Name` its
70/// [`Operation`]: `#[derive(Operations)]` generates the dispatch
71/// ([`PartOperation::apply`]), the conversions from each `NameArgs`, and
72/// [`PartOperation::schemas`], which is how an editor learns what
73/// operations there are and what they take.
74#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, Operations)]
75#[serde(tag = "operation", content = "args", rename_all = "snake_case")]
76pub enum PartOperation {
77 /// Draw a sketch on a base plane or on a planar face.
78 #[operation(label = "Sketch")]
79 AddSketch(AddSketchArgs),
80 /// Sweep a sketch's regions along its plane's normal into a solid.
81 Extrude(ExtrudeArgs),
82 /// Sweep a sketch's regions a full turn around one of its lines.
83 Revolve(RevolveArgs),
84 /// Unite, intersect or subtract two solids.
85 Boolean(BooleanArgs),
86 /// Add reference geometry — a point, an axis or a plane — built from
87 /// selected points, edges and planes.
88 #[operation(label = "Reference")]
89 AddDatum(AddDatumArgs),
90}