Skip to content

Commit

Permalink
Merge pull request #1665 from hannobraun/builder
Browse files Browse the repository at this point in the history
Rewrite `HalfEdgeBuilder`
  • Loading branch information
hannobraun authored Mar 10, 2023
2 parents 2add4db + 92da422 commit 5ef5994
Show file tree
Hide file tree
Showing 5 changed files with 92 additions and 112 deletions.
15 changes: 8 additions & 7 deletions crates/fj-kernel/src/algorithms/approx/edge.rs
Original file line number Diff line number Diff line change
Expand Up @@ -267,7 +267,7 @@ mod tests {
builder::{CycleBuilder, HalfEdgeBuilder},
geometry::{curve::GlobalPath, surface::SurfaceGeometry},
insert::Insert,
objects::{HalfEdge, Surface},
objects::Surface,
partial::{PartialCycle, PartialObject},
services::Services,
};
Expand Down Expand Up @@ -332,13 +332,12 @@ mod tests {
v: [0., 0., 1.].into(),
})
.insert(&mut services.objects);
let half_edge = HalfEdge::make_line_segment(
let half_edge = HalfEdgeBuilder::line_segment(
[[0., 1.], [TAU, 1.]],
Some(range.boundary),
None,
None,
&mut services.objects,
);
)
.build(&mut services.objects)
.insert(&mut services.objects);

let tolerance = 1.;
let approx = (&half_edge, surface.deref()).approx(tolerance);
Expand All @@ -362,7 +361,9 @@ mod tests {
let mut services = Services::new();

let surface = services.objects.surfaces.xz_plane();
let half_edge = HalfEdge::make_circle(1., &mut services.objects);
let half_edge = HalfEdgeBuilder::circle(1.)
.build(&mut services.objects)
.insert(&mut services.objects);

let tolerance = 1.;
let approx = (&half_edge, surface.deref()).approx(tolerance);
Expand Down
22 changes: 15 additions & 7 deletions crates/fj-kernel/src/algorithms/sweep/edge.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,13 +88,21 @@ impl Sweep for (Handle<HalfEdge>, &Handle<Vertex>, &Surface, Color) {
.zip_ext(vertices)
.zip_ext(global_edges)
.map(|((((boundary, start), end), start_vertex), global_edge)| {
let half_edge = HalfEdge::make_line_segment(
[start, end],
Some(boundary),
Some(start_vertex),
global_edge,
objects,
);
let half_edge = {
let builder = HalfEdgeBuilder::line_segment(
[start, end],
Some(boundary),
)
.with_start_vertex(start_vertex);

let builder = if let Some(global_edge) = global_edge {
builder.with_global_form(global_edge)
} else {
builder
};

builder.build(objects).insert(objects)
};

face.exterior.write().add_half_edge(half_edge.clone());

Expand Down
22 changes: 8 additions & 14 deletions crates/fj-kernel/src/builder/cycle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use fj_math::Point;

use crate::{
geometry::curve::Curve,
insert::Insert,
objects::{HalfEdge, Objects},
partial::PartialCycle,
services::Service,
Expand Down Expand Up @@ -63,13 +64,9 @@ impl CycleBuilder for PartialCycle {
P: Clone + Into<Point<2>>,
{
points.map_with_next(|start, end| {
let half_edge = HalfEdge::make_line_segment(
[start, end],
None,
None,
None,
objects,
);
let half_edge = HalfEdgeBuilder::line_segment([start, end], None)
.build(objects)
.insert(objects);

self.add_half_edge(half_edge.clone());

Expand All @@ -86,13 +83,10 @@ impl CycleBuilder for PartialCycle {
O: ObjectArgument<(Handle<HalfEdge>, Curve, [Point<1>; 2])>,
{
edges.map_with_prev(|(_, curve, boundary), (prev, _, _)| {
let half_edge = HalfEdge::make_half_edge(
curve,
boundary,
Some(prev.start_vertex().clone()),
None,
objects,
);
let half_edge = HalfEdgeBuilder::new(curve, boundary)
.with_start_vertex(prev.start_vertex().clone())
.build(objects)
.insert(objects);

self.add_half_edge(half_edge.clone());

Expand Down
125 changes: 53 additions & 72 deletions crates/fj-kernel/src/builder/edge.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,62 +10,34 @@ use crate::{
};

/// Builder API for [`HalfEdge`]
pub trait HalfEdgeBuilder {
/// Create a circle
fn make_circle(
radius: impl Into<Scalar>,
objects: &mut Service<Objects>,
) -> Handle<HalfEdge>;
pub struct HalfEdgeBuilder {
curve: Curve,
boundary: [Point<1>; 2],
start_vertex: Option<Handle<Vertex>>,
global_form: Option<Handle<GlobalEdge>>,
}

impl HalfEdgeBuilder {
/// Create an instance of `HalfEdgeBuilder`
pub fn new(curve: Curve, boundary: [Point<1>; 2]) -> Self {
Self {
curve,
boundary,
start_vertex: None,
global_form: None,
}
}

/// Create an arc
///
/// # Panics
///
/// Panics if the given angle is not within the range (-2pi, 2pi) radians.
fn make_arc(
start: impl Into<Point<2>>,
end: impl Into<Point<2>>,
angle_rad: impl Into<Scalar>,
objects: &mut Service<Objects>,
) -> Handle<HalfEdge>;

/// Create a line segment
fn make_line_segment(
points_surface: [impl Into<Point<2>>; 2],
boundary: Option<[Point<1>; 2]>,
start_vertex: Option<Handle<Vertex>>,
global_form: Option<Handle<GlobalEdge>>,
objects: &mut Service<Objects>,
) -> Handle<HalfEdge>;

/// Create a half-edge
fn make_half_edge(
curve: Curve,
boundary: [Point<1>; 2],
start_vertex: Option<Handle<Vertex>>,
global_form: Option<Handle<GlobalEdge>>,
objects: &mut Service<Objects>,
) -> Handle<HalfEdge>;
}

impl HalfEdgeBuilder for HalfEdge {
fn make_circle(
radius: impl Into<Scalar>,
objects: &mut Service<Objects>,
) -> Handle<HalfEdge> {
let curve = Curve::circle_from_radius(radius);
let boundary =
[Scalar::ZERO, Scalar::TAU].map(|coord| Point::from([coord]));

Self::make_half_edge(curve, boundary, None, None, objects)
}

fn make_arc(
pub fn arc(
start: impl Into<Point<2>>,
end: impl Into<Point<2>>,
angle_rad: impl Into<Scalar>,
objects: &mut Service<Objects>,
) -> Handle<HalfEdge> {
) -> Self {
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");
Expand All @@ -78,44 +50,53 @@ impl HalfEdgeBuilder for HalfEdge {
let boundary =
[arc.start_angle, arc.end_angle].map(|coord| Point::from([coord]));

Self::make_half_edge(curve, boundary, None, None, objects)
Self::new(curve, boundary)
}

fn make_line_segment(
/// Create a circle
pub fn circle(radius: impl Into<Scalar>) -> Self {
let curve = Curve::circle_from_radius(radius);
let boundary =
[Scalar::ZERO, Scalar::TAU].map(|coord| Point::from([coord]));

Self::new(curve, boundary)
}

/// Create a line segment
pub fn line_segment(
points_surface: [impl Into<Point<2>>; 2],
boundary: Option<[Point<1>; 2]>,
start_vertex: Option<Handle<Vertex>>,
global_form: Option<Handle<GlobalEdge>>,
objects: &mut Service<Objects>,
) -> Handle<HalfEdge> {
) -> Self {
let boundary =
boundary.unwrap_or_else(|| [[0.], [1.]].map(Point::from));
let curve = Curve::line_from_points_with_coords(
boundary.zip_ext(points_surface),
);

Self::make_half_edge(
curve,
boundary,
start_vertex,
global_form,
objects,
)
Self::new(curve, boundary)
}

/// Build the half-edge with a specific start vertex
pub fn with_start_vertex(mut self, start_vertex: Handle<Vertex>) -> Self {
self.start_vertex = Some(start_vertex);
self
}

fn make_half_edge(
curve: Curve,
boundary: [Point<1>; 2],
start_vertex: Option<Handle<Vertex>>,
global_form: Option<Handle<GlobalEdge>>,
objects: &mut Service<Objects>,
) -> Handle<HalfEdge> {
/// Build the half-edge with a specific global form
pub fn with_global_form(mut self, global_form: Handle<GlobalEdge>) -> Self {
self.global_form = Some(global_form);
self
}

/// Create a half-edge
pub fn build(self, objects: &mut Service<Objects>) -> HalfEdge {
HalfEdge::new(
curve,
boundary,
start_vertex.unwrap_or_else(|| Vertex::new().insert(objects)),
global_form.unwrap_or_else(|| GlobalEdge::new().insert(objects)),
self.curve,
self.boundary,
self.start_vertex
.unwrap_or_else(|| Vertex::new().insert(objects)),
self.global_form
.unwrap_or_else(|| GlobalEdge::new().insert(objects)),
)
.insert(objects)
}
}
20 changes: 8 additions & 12 deletions crates/fj-operations/src/sketch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use fj_interop::{debug::DebugInfo, mesh::Color};
use fj_kernel::{
builder::{CycleBuilder, HalfEdgeBuilder},
insert::Insert,
objects::{HalfEdge, Objects, Sketch},
objects::{Objects, Sketch},
partial::{
Partial, PartialCycle, PartialFace, PartialObject, PartialSketch,
},
Expand All @@ -27,7 +27,9 @@ impl Shape for fj::Sketch {

let face = match self.chain() {
fj::Chain::Circle(circle) => {
let half_edge = HalfEdge::make_circle(circle.radius(), objects);
let half_edge = HalfEdgeBuilder::circle(circle.radius())
.build(objects)
.insert(objects);
let exterior = {
let mut cycle = PartialCycle::new(objects);
cycle.half_edges.push(half_edge);
Expand Down Expand Up @@ -63,24 +65,18 @@ impl Shape for fj::Sketch {
for ((start, route), (end, _)) in segments {
let half_edge = match route {
fj::SketchSegmentRoute::Direct => {
HalfEdge::make_line_segment(
HalfEdgeBuilder::line_segment(
[start, end],
None,
None,
None,
objects,
)
}
fj::SketchSegmentRoute::Arc { angle } => {
HalfEdge::make_arc(
start,
end,
angle.rad(),
objects,
)
HalfEdgeBuilder::arc(start, end, angle.rad())
}
};

let half_edge =
half_edge.build(objects).insert(objects);
cycle.add_half_edge(half_edge);
}

Expand Down

0 comments on commit 5ef5994

Please sign in to comment.