use fj_interop::ext::ArrayExt;
use fj_math::{Arc, Point, Scalar};
use crate::{
geometry::{CurveBoundary, HalfEdgeGeometry, SurfacePath},
objects::{Curve, HalfEdge, Vertex},
operations::insert::Insert,
storage::Handle,
Core,
};
pub trait BuildHalfEdge {
fn unjoined(
path: SurfacePath,
boundary: impl Into<CurveBoundary<Point<1>>>,
core: &mut Core,
) -> HalfEdge {
let curve = Curve::new().insert(core);
let start_vertex = Vertex::new().insert(core);
HalfEdge::new(path, boundary, curve, start_vertex)
}
fn from_sibling(
sibling: &Handle<HalfEdge>,
start_vertex: Handle<Vertex>,
core: &mut Core,
) -> Handle<HalfEdge> {
let half_edge = HalfEdge::new(
core.layers.geometry.of_half_edge(sibling).path,
sibling.boundary().reverse(),
sibling.curve().clone(),
start_vertex,
)
.insert(core);
core.layers.geometry.define_half_edge(
half_edge.clone(),
HalfEdgeGeometry {
path: core.layers.geometry.of_half_edge(sibling).path,
},
);
half_edge
}
fn arc(
start: impl Into<Point<2>>,
end: impl Into<Point<2>>,
angle_rad: impl Into<Scalar>,
core: &mut Core,
) -> Handle<HalfEdge> {
let angle_rad = angle_rad.into();
if angle_rad <= -Scalar::TAU || angle_rad >= Scalar::TAU {
panic!("arc angle must be in the range (-2pi, 2pi) radians");
}
let arc = Arc::from_endpoints_and_angle(start, end, angle_rad);
let path =
SurfacePath::circle_from_center_and_radius(arc.center, arc.radius);
let boundary =
[arc.start_angle, arc.end_angle].map(|coord| Point::from([coord]));
let half_edge = HalfEdge::unjoined(path, boundary, core).insert(core);
core.layers
.geometry
.define_half_edge(half_edge.clone(), HalfEdgeGeometry { path });
half_edge
}
fn circle(
center: impl Into<Point<2>>,
radius: impl Into<Scalar>,
core: &mut Core,
) -> Handle<HalfEdge> {
let path = SurfacePath::circle_from_center_and_radius(center, radius);
let boundary =
[Scalar::ZERO, Scalar::TAU].map(|coord| Point::from([coord]));
let half_edge = HalfEdge::unjoined(path, boundary, core).insert(core);
core.layers
.geometry
.define_half_edge(half_edge.clone(), HalfEdgeGeometry { path });
half_edge
}
fn line_segment(
points_surface: [impl Into<Point<2>>; 2],
boundary: Option<[Point<1>; 2]>,
core: &mut Core,
) -> Handle<HalfEdge> {
let boundary =
boundary.unwrap_or_else(|| [[0.], [1.]].map(Point::from));
let path = SurfacePath::line_from_points_with_coords(
boundary.zip_ext(points_surface),
);
let half_edge = HalfEdge::unjoined(path, boundary, core).insert(core);
core.layers
.geometry
.define_half_edge(half_edge.clone(), HalfEdgeGeometry { path });
half_edge
}
}
impl BuildHalfEdge for HalfEdge {}