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