fj_kernel/operations/build/
edge.rs

1use fj_interop::ext::ArrayExt;
2use fj_math::{Arc, Point, Scalar};
3
4use crate::{
5    geometry::curve::Curve,
6    objects::{GlobalEdge, HalfEdge, Surface, Vertex},
7    operations::Insert,
8    services::Services,
9};
10
11/// Build a [`HalfEdge`]
12pub trait BuildHalfEdge {
13    /// Create a half-edge that is not joined to another
14    fn unjoined(
15        curve: Curve,
16        boundary: [Point<1>; 2],
17        services: &mut Services,
18    ) -> HalfEdge {
19        let start_vertex = Vertex::new().insert(services);
20        let global_form = GlobalEdge::new().insert(services);
21
22        HalfEdge::new(curve, boundary, start_vertex, global_form)
23    }
24
25    /// Create an arc
26    ///
27    /// # Panics
28    ///
29    /// Panics if the given angle is not within the range (-2pi, 2pi) radians.
30    fn arc(
31        start: impl Into<Point<2>>,
32        end: impl Into<Point<2>>,
33        angle_rad: impl Into<Scalar>,
34        services: &mut Services,
35    ) -> HalfEdge {
36        let angle_rad = angle_rad.into();
37        if angle_rad <= -Scalar::TAU || angle_rad >= Scalar::TAU {
38            panic!("arc angle must be in the range (-2pi, 2pi) radians");
39        }
40
41        let arc = Arc::from_endpoints_and_angle(start, end, angle_rad);
42
43        let curve =
44            Curve::circle_from_center_and_radius(arc.center, arc.radius);
45        let boundary =
46            [arc.start_angle, arc.end_angle].map(|coord| Point::from([coord]));
47
48        HalfEdge::unjoined(curve, boundary, services)
49    }
50
51    /// Create a circle
52    fn circle(radius: impl Into<Scalar>, services: &mut Services) -> HalfEdge {
53        let curve = Curve::circle_from_radius(radius);
54        let boundary =
55            [Scalar::ZERO, Scalar::TAU].map(|coord| Point::from([coord]));
56
57        HalfEdge::unjoined(curve, boundary, services)
58    }
59
60    /// Create a line segment
61    fn line_segment(
62        points_surface: [impl Into<Point<2>>; 2],
63        boundary: Option<[Point<1>; 2]>,
64        services: &mut Services,
65    ) -> HalfEdge {
66        let boundary =
67            boundary.unwrap_or_else(|| [[0.], [1.]].map(Point::from));
68        let curve = Curve::line_from_points_with_coords(
69            boundary.zip_ext(points_surface),
70        );
71
72        HalfEdge::unjoined(curve, boundary, services)
73    }
74
75    /// Create a line segment from global points
76    fn line_segment_from_global_points(
77        points_global: [impl Into<Point<3>>; 2],
78        surface: &Surface,
79        boundary: Option<[Point<1>; 2]>,
80        services: &mut Services,
81    ) -> HalfEdge {
82        let points_surface = points_global
83            .map(|point| surface.geometry().project_global_point(point));
84        HalfEdge::line_segment(points_surface, boundary, services)
85    }
86}
87
88impl BuildHalfEdge for HalfEdge {}