fj_core/operations/build/
half_edge.rs1use fj_interop::ext::ArrayExt;
2use fj_math::{Arc, Point, Scalar};
3
4use crate::{
5 geometry::{CurveBoundary, HalfEdgeGeometry, SurfacePath},
6 objects::{Curve, HalfEdge, Vertex},
7 operations::insert::Insert,
8 storage::Handle,
9 Core,
10};
11
12pub trait BuildHalfEdge {
18 fn unjoined(
20 path: SurfacePath,
21 boundary: impl Into<CurveBoundary<Point<1>>>,
22 core: &mut Core,
23 ) -> HalfEdge {
24 let curve = Curve::new().insert(core);
25 let start_vertex = Vertex::new().insert(core);
26
27 HalfEdge::new(path, boundary, curve, start_vertex)
28 }
29
30 fn from_sibling(
32 sibling: &Handle<HalfEdge>,
33 start_vertex: Handle<Vertex>,
34 core: &mut Core,
35 ) -> Handle<HalfEdge> {
36 let half_edge = HalfEdge::new(
37 core.layers.geometry.of_half_edge(sibling).path,
38 sibling.boundary().reverse(),
39 sibling.curve().clone(),
40 start_vertex,
41 )
42 .insert(core);
43
44 core.layers.geometry.define_half_edge(
45 half_edge.clone(),
46 HalfEdgeGeometry {
47 path: core.layers.geometry.of_half_edge(sibling).path,
48 },
49 );
50
51 half_edge
52 }
53
54 fn arc(
60 start: impl Into<Point<2>>,
61 end: impl Into<Point<2>>,
62 angle_rad: impl Into<Scalar>,
63 core: &mut Core,
64 ) -> Handle<HalfEdge> {
65 let angle_rad = angle_rad.into();
66 if angle_rad <= -Scalar::TAU || angle_rad >= Scalar::TAU {
67 panic!("arc angle must be in the range (-2pi, 2pi) radians");
68 }
69
70 let arc = Arc::from_endpoints_and_angle(start, end, angle_rad);
71
72 let path =
73 SurfacePath::circle_from_center_and_radius(arc.center, arc.radius);
74 let boundary =
75 [arc.start_angle, arc.end_angle].map(|coord| Point::from([coord]));
76
77 let half_edge = HalfEdge::unjoined(path, boundary, core).insert(core);
78 core.layers
79 .geometry
80 .define_half_edge(half_edge.clone(), HalfEdgeGeometry { path });
81
82 half_edge
83 }
84
85 fn circle(
87 center: impl Into<Point<2>>,
88 radius: impl Into<Scalar>,
89 core: &mut Core,
90 ) -> Handle<HalfEdge> {
91 let path = SurfacePath::circle_from_center_and_radius(center, radius);
92 let boundary =
93 [Scalar::ZERO, Scalar::TAU].map(|coord| Point::from([coord]));
94
95 let half_edge = HalfEdge::unjoined(path, boundary, core).insert(core);
96 core.layers
97 .geometry
98 .define_half_edge(half_edge.clone(), HalfEdgeGeometry { path });
99
100 half_edge
101 }
102
103 fn line_segment(
105 points_surface: [impl Into<Point<2>>; 2],
106 boundary: Option<[Point<1>; 2]>,
107 core: &mut Core,
108 ) -> Handle<HalfEdge> {
109 let boundary =
110 boundary.unwrap_or_else(|| [[0.], [1.]].map(Point::from));
111 let path = SurfacePath::line_from_points_with_coords(
112 boundary.zip_ext(points_surface),
113 );
114
115 let half_edge = HalfEdge::unjoined(path, boundary, core).insert(core);
116 core.layers
117 .geometry
118 .define_half_edge(half_edge.clone(), HalfEdgeGeometry { path });
119
120 half_edge
121 }
122}
123
124impl BuildHalfEdge for HalfEdge {}