Skip to main content

geop_ops_surface/
lib.rs

1//! Surface modelling: faces standing on their own — sheets — built from
2//! edges, offset, thickened, joined, trimmed and extended, as operations of
3//! a program (see [`geop_core_editor::part_operation`]):
4//!
5//! - [`BoundarySurface`]: the ruled face between two edges, or a closed
6//!   loop of edges filled — a flat face for a flat loop, a Coons patch for
7//!   four edges, optionally tangent to flat faces along them, and a patch
8//!   of quadrilaterals around a center for any other number.
9//! - [`NetworkSurface`]: the face through a network of curves crossing
10//!   each other, `u` curves and `v` curves, interpolating every one.
11//! - [`OffsetSurface`]: faces copied a distance along their normals.
12//! - [`Thicken`]: a sheet made a solid of one thickness, on either side of
13//!   it or on both.
14//! - [`Knit`]: sheets whose edges meet joined into one, and into a solid
15//!   once they close up.
16//! - [`TrimSurface`]: a sheet cut back to one side of a face.
17//! - [`ExtendSurface`]: a face standing on its own carried on past one of
18//!   its edges.
19//!
20//! What a sheet is offset and thickened with is the shell's machinery
21//! ([`geop_lib_shell::shell()`]): a sheet thickened is a sheet shelled.
22
23pub mod boundary;
24#[cfg(test)]
25mod editor_tests;
26#[cfg(any(test, feature = "examples"))]
27pub mod examples;
28pub mod extend;
29mod icons;
30pub mod knit;
31pub mod network;
32pub mod offset;
33#[cfg(test)]
34mod program_tests;
35pub mod thicken;
36pub mod trim;
37
38pub use boundary::{BoundarySurface, BoundarySurfaceArgs};
39pub use extend::{ExtendSurface, ExtendSurfaceArgs};
40pub use knit::{Knit, KnitArgs};
41pub use network::{NetworkSurface, NetworkSurfaceArgs};
42pub use offset::{OffsetSurface, OffsetSurfaceArgs};
43pub use thicken::{Thicken, ThickenArgs, ThickenSide};
44pub use trim::{TrimKeep, TrimSurface, TrimSurfaceArgs};
45
46use geop_core_geometry::nurb_curve::NurbCurve3D;
47use geop_core_math::{
48    geop_error::{GeopError, GeopResult},
49    vector::Vector3,
50};
51use geop_ops_model::Chain;
52
53/// A sheet to build, and the names of what it is made of.
54pub type SheetSpec = (
55    geop_core_topology::build::BodySpec,
56    geop_ops_model::BodyNames,
57);
58
59/// One curve picked to span a surface through: an edge — of a face or of a
60/// wire — or a sketch's curve, with the names of its ends. An edge's name
61/// is its own, its ends its vertices'; a sketch `K`'s curve `c3` is `K,c3`,
62/// its ends `K,p1` (see [`geop_ops_model::sketch3d::CurveSource`]).
63#[derive(Clone, Debug)]
64struct NamedCurve {
65    name: String,
66    curve: NurbCurve3D,
67    start: (String, Vector3),
68    end: (String, Vector3),
69}
70
71impl NamedCurve {
72    /// The one curve of `chain`, as a curve picked resolves; an error if it
73    /// is more than one.
74    fn of(chain: &Chain<NurbCurve3D>) -> GeopResult<Self> {
75        let [curve] = chain.curves.as_slice() else {
76            return Err(GeopError::new(format!(
77                "{} is {} curves, not one",
78                chain.name,
79                chain.curves.len()
80            )));
81        };
82        let joints = chain.joints()?;
83        let end = joints.len() - 1;
84        Ok(Self {
85            name: chain.curve_names[0].clone(),
86            curve: curve.clone(),
87            start: (chain.joint_names[0].clone(), joints[0]),
88            end: (chain.joint_names[end].clone(), joints[end]),
89        })
90    }
91}
92
93use geop_core_editor::registry::Registry;
94
95/// Adds what this crate offers an editor to `r`: surfaces: boundary,
96/// offset, thickened, knit, trimmed, extended and network surfaces.
97pub fn register(r: Registry) -> GeopResult<Registry> {
98    let r = r
99        .operation(BoundarySurface)?
100        .operation(OffsetSurface)?
101        .operation(Thicken)?
102        .operation(Knit)?
103        .operation(TrimSurface)?
104        .operation(ExtendSurface)?
105        .operation(NetworkSurface)?;
106    #[cfg(any(test, feature = "examples"))]
107    let r = r.examples(examples::set())?;
108    Ok(r)
109}
110
111/// What the tests share: the model's elements by name.
112#[cfg(test)]
113pub(crate) mod test_refs {
114    use geop_core_program::element::ElementReference;
115    use geop_ops_model::sketch3d::CurveSource;
116    use geop_ops_model::{NamedModel, model};
117
118    /// The model's element named `name`.
119    pub fn named<K>(name: impl Into<String>) -> ElementReference<NamedModel, K> {
120        ElementReference::new(model(), name)
121    }
122
123    /// The edge named `name`, as a curve picked.
124    pub fn edge_curve(name: impl Into<String>) -> CurveSource {
125        CurveSource::Edge(named(name))
126    }
127}