use std::fmt;
use pretty_assertions::{assert_eq, assert_ne};
use crate::stores::{Handle, HandleWrapper};
use super::{Curve, GlobalCurve, GlobalVertex, Vertex};
#[derive(Clone, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)]
pub struct HalfEdge {
vertices: [Vertex; 2],
global_form: GlobalEdge,
}
impl HalfEdge {
pub fn new([a, b]: [Vertex; 2], global_form: GlobalEdge) -> Self {
assert_eq!(
a.curve().id(),
b.curve().id(),
"An edge's vertices must be defined in the same curve",
);
let curve = a.curve();
assert_eq!(
curve.global_form().id(),
global_form.curve().id(),
"The global form of a half-edge's curve must match the curve of \
the half-edge's global form"
);
assert_eq!(
&VerticesInNormalizedOrder::new(
[&a, &b].map(|vertex| vertex.global_form().clone())
),
global_form.vertices(),
"The global forms of a half-edge's vertices must match the \
vertices of the half-edge's global form"
);
assert_ne!(
a.position(),
b.position(),
"Vertices of an edge must not be coincident on curve"
);
Self {
vertices: [a, b],
global_form,
}
}
pub fn curve(&self) -> &Handle<Curve> {
let [vertex, _] = self.vertices();
vertex.curve()
}
pub fn vertices(&self) -> &[Vertex; 2] {
&self.vertices
}
pub fn global_form(&self) -> &GlobalEdge {
&self.global_form
}
}
impl fmt::Display for HalfEdge {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let [a, b] = self.vertices().clone().map(|vertex| vertex.position());
write!(f, "edge from {:?} to {:?}", a, b)?;
write!(f, " on {:?}", self.curve().global_form())?;
Ok(())
}
}
#[derive(Clone, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)]
pub struct GlobalEdge {
curve: HandleWrapper<GlobalCurve>,
vertices: VerticesInNormalizedOrder,
}
impl GlobalEdge {
pub fn new(
curve: impl Into<HandleWrapper<GlobalCurve>>,
vertices: [Handle<GlobalVertex>; 2],
) -> Self {
let curve = curve.into();
let vertices = VerticesInNormalizedOrder::new(vertices);
Self { curve, vertices }
}
pub fn curve(&self) -> &Handle<GlobalCurve> {
&self.curve
}
pub fn vertices(&self) -> &VerticesInNormalizedOrder {
&self.vertices
}
}
#[derive(Clone, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)]
pub struct VerticesInNormalizedOrder([Handle<GlobalVertex>; 2]);
impl VerticesInNormalizedOrder {
pub fn new([a, b]: [Handle<GlobalVertex>; 2]) -> Self {
let vertices = if a < b { [a, b] } else { [b, a] };
Self(vertices)
}
pub fn access_in_normalized_order(&self) -> &[Handle<GlobalVertex>; 2] {
&self.0
}
}
#[cfg(test)]
mod tests {
use pretty_assertions::assert_eq;
use crate::{objects::Surface, partial::HasPartial, stores::Stores};
use super::HalfEdge;
#[test]
fn global_edge_equality() {
let stores = Stores::new();
let surface = stores.surfaces.insert(Surface::xy_plane());
let a = [0., 0.];
let b = [1., 0.];
let a_to_b = HalfEdge::partial()
.with_surface(Some(surface.clone()))
.as_line_segment_from_points([a, b])
.build(&stores);
let b_to_a = HalfEdge::partial()
.with_surface(Some(surface))
.as_line_segment_from_points([b, a])
.build(&stores);
assert_eq!(a_to_b.global_form(), b_to_a.global_form());
}
}