fj_core/objects/kinds/
half_edge.rs

1use fj_math::Point;
2
3use crate::{
4    geometry::{CurveBoundary, SurfacePath},
5    objects::{Curve, Vertex},
6    storage::{Handle, HandleWrapper},
7};
8
9/// # A directed half-edge, defined in a surface's 2D space
10///
11/// ## Structure
12///
13/// A `HalfEdge` is defined by the [`Curve`] it is on, its boundary on the
14/// curve, and the [`Vertex`] instances that bound it on the curve. To keep the
15/// data structures simple (by avoiding redundancy), each `HalfEdge` only refers
16/// to its start vertex. The vertex where it ends is referred to by the next
17/// `HalfEdge` in the [`Cycle`] that the `HalfEdge` is a part of.
18///
19///
20/// ## Validity
21///
22/// A valid `HalfEdge` must have a non-zero length, meaning its bounding
23/// vertices must not be coincident.
24///
25/// In a valid [`Shell`], `HalfEdge`s form coincident pairs, where the faces of
26/// the shell touch. The other `HalfEdge` in such a pair is called the sibling.
27///
28/// A `HalfEdge` and its sibling are equal but opposite. Specifically this means
29/// that both refer to the same curve; that the sibling has the same, but
30/// inverted, boundary; and that both are bound by the same vertices, though
31/// their start vertices are different.
32///
33///
34/// [`Cycle`]: crate::objects::Cycle
35/// [`Shell`]: crate::objects::Shell
36#[derive(Clone, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)]
37pub struct HalfEdge {
38    path: SurfacePath,
39    boundary: CurveBoundary<Point<1>>,
40    curve: HandleWrapper<Curve>,
41    start_vertex: HandleWrapper<Vertex>,
42}
43
44impl HalfEdge {
45    /// Create an instance of `Edge`
46    pub fn new(
47        path: SurfacePath,
48        boundary: impl Into<CurveBoundary<Point<1>>>,
49        curve: Handle<Curve>,
50        start_vertex: Handle<Vertex>,
51    ) -> Self {
52        Self {
53            path,
54            boundary: boundary.into(),
55            curve: curve.into(),
56            start_vertex: start_vertex.into(),
57        }
58    }
59
60    /// Access the curve that defines the edge's geometry
61    pub fn path(&self) -> SurfacePath {
62        self.path
63    }
64
65    /// Access the boundary points of the edge on the curve
66    pub fn boundary(&self) -> CurveBoundary<Point<1>> {
67        self.boundary
68    }
69
70    /// Access the curve of the edge
71    pub fn curve(&self) -> &Handle<Curve> {
72        &self.curve
73    }
74
75    /// Access the vertex from where this edge starts
76    pub fn start_vertex(&self) -> &Handle<Vertex> {
77        &self.start_vertex
78    }
79
80    /// Compute the surface position where the edge starts
81    pub fn start_position(&self) -> Point<2> {
82        // Computing the surface position from the curve position is fine.
83        // `Edge` "owns" its start position. There is no competing code that
84        // could compute the surface position from slightly different data.
85
86        let [start, _] = self.boundary.inner;
87        self.path.point_from_path_coords(start)
88    }
89}