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 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211
use std::fmt;
use crate::builder::EdgeBuilder;
use super::{Curve, GlobalCurve, GlobalVertex, Vertex};
/// An edge
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)]
pub struct Edge {
curve: Curve,
vertices: VerticesOfEdge<Vertex>,
global: GlobalEdge,
}
impl Edge {
/// Build an edge using [`EdgeBuilder`]
pub fn build() -> EdgeBuilder {
EdgeBuilder
}
/// Create a new instance of `Edge`
///
/// If you only have a curve and the edge vertices, please check out
/// [`Edge::from_curve_and_vertices`], which is a convenience wrapper around
/// this method, which creates an instance of [`GlobalEdge`].
///
/// # Panics
///
/// Panics, if the provided [`GlobalEdge`] instance doesn't refer to the
/// same [`GlobalCurve`] and [`GlobalVertex`] instances that the other
/// objects that are passed refer to.
pub fn new(
curve: Curve,
vertices: VerticesOfEdge<Vertex>,
global: GlobalEdge,
) -> Self {
assert_eq!(curve.global(), global.curve());
assert_eq!(&vertices.to_global(), global.vertices());
Self {
curve,
vertices,
global,
}
}
/// Create a new instance of `Edge` from a curve and vertices
///
/// The [`GlobalEdge`] instance is created from the provided curve and
/// vertices. Please refer to [`Edge::new`], if you already have a
/// [`GlobalEdge`] instance that you can provide.
pub fn from_curve_and_vertices(
curve: Curve,
vertices: VerticesOfEdge<Vertex>,
) -> Self {
let global = GlobalEdge::new(*curve.global(), vertices.to_global());
Self::new(curve, vertices, global)
}
/// Access the curve that defines the edge's geometry
///
/// The edge can be a segment of the curve that is bounded by two vertices,
/// or if the curve is continuous (i.e. connects to itself), the edge could
/// be defined by the whole curve, and have no bounding vertices.
pub fn curve(&self) -> &Curve {
&self.curve
}
/// Access the vertices that bound the edge on the curve
///
/// An edge has either two bounding vertices or none. The latter is possible
/// if the edge's curve is continuous (i.e. connects to itself), and defines
/// the whole edge.
pub fn vertices(&self) -> &VerticesOfEdge<Vertex> {
&self.vertices
}
/// Access the global form of this edge
pub fn global(&self) -> &GlobalEdge {
&self.global
}
}
impl fmt::Display for Edge {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self.vertices().0 {
Some(vertices) => {
let [a, b] = vertices.map(|vertex| vertex.position());
write!(f, "edge from {:?} to {:?}", a, b)?
}
None => write!(f, "continuous edge")?,
}
write!(f, " on {:?}", self.curve().global())?;
Ok(())
}
}
/// An edge, defined in global (3D) coordinates
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)]
pub struct GlobalEdge {
curve: GlobalCurve,
vertices: VerticesOfEdge<GlobalVertex>,
}
impl GlobalEdge {
/// Create a new instance
pub fn new(
curve: GlobalCurve,
vertices: VerticesOfEdge<GlobalVertex>,
) -> Self {
Self { curve, vertices }
}
/// Access the curve that defines the edge's geometry
///
/// The edge can be a segment of the curve that is bounded by two vertices,
/// or if the curve is continuous (i.e. connects to itself), the edge could
/// be defined by the whole curve, and have no bounding vertices.
pub fn curve(&self) -> &GlobalCurve {
&self.curve
}
/// Access the vertices that bound the edge on the curve
///
/// An edge has either two bounding vertices or none. The latter is possible
/// if the edge's curve is continuous (i.e. connects to itself), and defines
/// the whole edge.
pub fn vertices(&self) -> &VerticesOfEdge<GlobalVertex> {
&self.vertices
}
}
/// The vertices that bound an edge
///
/// This struct is generic over the actual vertex type used, but typically, `T`
/// will either be [`Vertex`] or [`GlobalVertex`].
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)]
pub struct VerticesOfEdge<T>(Option<[T; 2]>);
impl<T> VerticesOfEdge<T> {
/// Construct an instance of `VerticesOfEdge` from two vertices
pub fn from_vertices(vertices: [T; 2]) -> Self {
Self(Some(vertices))
}
/// Construct an instance of `VerticesOfEdge` without vertices
pub fn none() -> Self {
Self(None)
}
/// Access the vertices
pub fn get(&self) -> Option<[&T; 2]> {
self.0.as_ref().map(|vertices| {
// Can be cleaned up once `each_ref` is stable:
// https://doc.rust-lang.org/std/primitive.array.html#method.each_ref
let [a, b] = vertices;
[a, b]
})
}
/// Access the two vertices
///
/// # Panics
///
/// Panics, if the edge has no vertices.
pub fn get_or_panic(&self) -> [&T; 2] {
self.get().expect("Expected edge to have vertices")
}
/// Iterate over the vertices
pub fn iter(&self) -> impl Iterator<Item = &T> {
self.0.iter().flatten()
}
/// Map each vertex using the provided function
pub fn map<F>(self, f: F) -> Self
where
F: FnMut(T) -> T,
{
Self(self.convert(f))
}
/// Convert each vertex using the provided function
pub fn convert<F, U>(self, f: F) -> Option<[U; 2]>
where
F: FnMut(T) -> U,
{
self.0.map(|vertices| vertices.map(f))
}
}
impl VerticesOfEdge<Vertex> {
/// Reverse the order of vertices
///
/// Makes sure that the local coordinates are still correct.
pub fn reverse(self) -> Self {
Self(self.0.map(|[a, b]| {
[
Vertex::new(-b.position(), *b.global()),
Vertex::new(-a.position(), *a.global()),
]
}))
}
/// Convert this instance into its global variant
pub fn to_global(&self) -> VerticesOfEdge<GlobalVertex> {
VerticesOfEdge(self.convert(|vertex| *vertex.global()))
}
}