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}