use fj_math::{Point, Scalar};
use crate::{
objects::{
Curve, GlobalCurve, GlobalEdge, GlobalVertex, HalfEdge, Surface,
SurfaceVertex, Vertex,
},
partial::{HasPartial, MaybePartial, PartialCurve},
stores::{Handle, HandleWrapper, Stores},
};
#[derive(Clone, Debug, Default, Eq, PartialEq, Hash, Ord, PartialOrd)]
pub struct PartialHalfEdge {
pub surface: Option<Handle<Surface>>,
pub curve: Option<MaybePartial<Handle<Curve>>>,
pub vertices: Option<[MaybePartial<Vertex>; 2]>,
pub global_form: Option<MaybePartial<GlobalEdge>>,
}
impl PartialHalfEdge {
pub fn with_surface(mut self, surface: Option<Handle<Surface>>) -> Self {
if let Some(surface) = surface {
self.surface = Some(surface);
}
self
}
pub fn with_curve(
mut self,
curve: Option<impl Into<MaybePartial<Handle<Curve>>>>,
) -> Self {
if let Some(curve) = curve {
self.curve = Some(curve.into());
}
self
}
pub fn with_vertices(
mut self,
vertices: Option<[impl Into<MaybePartial<Vertex>>; 2]>,
) -> Self {
if let Some(vertices) = vertices {
self.vertices = Some(vertices.map(Into::into));
}
self
}
pub fn with_global_form(
mut self,
global_form: Option<impl Into<MaybePartial<GlobalEdge>>>,
) -> Self {
if let Some(global_form) = global_form {
self.global_form = Some(global_form.into());
}
self
}
pub fn as_circle_from_radius(mut self, radius: impl Into<Scalar>) -> Self {
let curve = Handle::<Curve>::partial()
.with_surface(self.surface.clone())
.as_circle_from_radius(radius);
let vertices = {
let [a_curve, b_curve] =
[Scalar::ZERO, Scalar::TAU].map(|coord| Point::from([coord]));
let global_vertex = Handle::<GlobalVertex>::partial()
.from_curve_and_position(curve.clone(), a_curve);
[a_curve, b_curve].map(|point_curve| {
Vertex::partial()
.with_position(Some(point_curve))
.with_curve(Some(curve.clone()))
.with_global_form(Some(global_vertex.clone()))
})
};
self.curve = Some(curve.into());
self.vertices = Some(vertices.map(Into::into));
self
}
pub fn as_line_segment_from_points(
self,
points: [impl Into<Point<2>>; 2],
) -> Self {
let surface = self.surface.clone();
self.with_vertices(Some(points.map(|point| {
Vertex::partial().with_surface_form(Some(
SurfaceVertex::partial()
.with_surface(surface.clone())
.with_position(Some(point)),
))
})))
.as_line_segment()
}
pub fn as_line_segment(mut self) -> Self {
fn extract_global_curve(
partial: &PartialHalfEdge,
) -> Option<HandleWrapper<GlobalCurve>> {
fn extract_global_curve_from_curve(
partial: &PartialHalfEdge,
) -> Option<Handle<GlobalCurve>> {
partial.curve.as_ref()?.global_form()
}
fn extract_global_curve_from_global_form(
partial: &PartialHalfEdge,
) -> Option<Handle<GlobalCurve>> {
Some(partial.global_form.as_ref()?.curve()?.clone())
}
extract_global_curve_from_curve(partial)
.or_else(|| extract_global_curve_from_global_form(partial))
.map(Into::into)
}
let [from, to] = self
.vertices
.clone()
.expect("Can't infer line segment without vertices");
let [from_surface, to_surface] = [&from, &to].map(|vertex| {
vertex
.surface_form()
.expect("Can't infer line segment without two surface vertices")
});
let surface = self
.surface
.as_ref()
.or_else(|| from_surface.surface())
.or_else(|| to_surface.surface())
.expect("Can't infer line segment without a surface")
.clone();
let points = [&from_surface, &to_surface].map(|vertex| {
vertex
.position()
.expect("Can't infer line segment without surface position")
});
let curve = PartialCurve {
global_form: extract_global_curve(&self),
..PartialCurve::default()
}
.with_surface(Some(surface))
.as_line_from_points(points);
let vertices = [(from, 0.), (to, 1.)].map(|(vertex, position)| {
vertex.update_partial(|vertex| {
vertex
.with_position(Some([position]))
.with_curve(Some(curve.clone()))
})
});
self.curve = Some(curve.into());
self.vertices = Some(vertices);
self
}
pub fn build(self, stores: &Stores) -> HalfEdge {
let surface = self.surface;
let curve = self
.curve
.expect("Can't build `HalfEdge` without curve")
.update_partial(|curve| curve.with_surface(surface))
.into_full(stores);
let vertices = self
.vertices
.expect("Can't build `HalfEdge` without vertices")
.map(|vertex| {
vertex
.update_partial(|vertex| {
vertex.with_curve(Some(curve.clone()))
})
.into_full(stores)
});
let global_form = self
.global_form
.unwrap_or_else(|| {
GlobalEdge::partial()
.from_curve_and_vertices(&curve, &vertices)
.into()
})
.into_full(stores);
HalfEdge::new(vertices, global_form)
}
}
impl From<&HalfEdge> for PartialHalfEdge {
fn from(half_edge: &HalfEdge) -> Self {
Self {
surface: Some(half_edge.curve().surface().clone()),
curve: Some(half_edge.curve().clone().into()),
vertices: Some(half_edge.vertices().clone().map(Into::into)),
global_form: Some(half_edge.global_form().clone().into()),
}
}
}
#[derive(Clone, Debug, Default, Eq, PartialEq, Hash, Ord, PartialOrd)]
pub struct PartialGlobalEdge {
pub curve: Option<HandleWrapper<GlobalCurve>>,
pub vertices: Option<[Handle<GlobalVertex>; 2]>,
}
impl PartialGlobalEdge {
pub fn with_curve(mut self, curve: Option<Handle<GlobalCurve>>) -> Self {
if let Some(curve) = curve {
self.curve = Some(curve.into());
}
self
}
pub fn with_vertices(
mut self,
vertices: Option<[Handle<GlobalVertex>; 2]>,
) -> Self {
if let Some(vertices) = vertices {
self.vertices = Some(vertices);
}
self
}
pub fn from_curve_and_vertices(
self,
curve: &Curve,
vertices: &[Vertex; 2],
) -> Self {
self.with_curve(Some(curve.global_form().clone()))
.with_vertices(Some(
vertices.clone().map(|vertex| vertex.global_form().clone()),
))
}
pub fn build(self, _: &Stores) -> GlobalEdge {
let curve = self
.curve
.expect("Can't build `GlobalEdge` without `GlobalCurve`");
let vertices = self
.vertices
.expect("Can't build `GlobalEdge` without vertices");
GlobalEdge::new(curve, vertices)
}
}
impl From<&GlobalEdge> for PartialGlobalEdge {
fn from(global_edge: &GlobalEdge) -> Self {
Self {
curve: Some(global_edge.curve().clone().into()),
vertices: Some(
global_edge.vertices().access_in_normalized_order().clone(),
),
}
}
}