Skip to content

Commit

Permalink
Merge pull request #737 from hannobraun/builder
Browse files Browse the repository at this point in the history
Simplify builder API
  • Loading branch information
hannobraun authored Jun 28, 2022
2 parents 2ecf632 + 758fbe9 commit 74d745c
Show file tree
Hide file tree
Showing 13 changed files with 154 additions and 286 deletions.
8 changes: 3 additions & 5 deletions crates/fj-kernel/src/algorithms/approx/edges.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,20 +37,18 @@ mod test {
use crate::{
geometry,
objects::{Vertex, VerticesOfEdge},
shape::{LocalForm, Shape},
shape::LocalForm,
};

#[test]
fn approx_edge() {
let mut shape = Shape::new();

let a = Point::from([1., 2., 3.]);
let b = Point::from([2., 3., 5.]);
let c = Point::from([3., 5., 8.]);
let d = Point::from([5., 8., 13.]);

let v1 = Vertex::builder(&mut shape).build_from_point(a).get();
let v2 = Vertex::builder(&mut shape).build_from_point(d).get();
let v1 = Vertex::from_point(a);
let v2 = Vertex::from_point(d);

let vertices = VerticesOfEdge::from_vertices([
LocalForm::new(Point::from([0.]), v1),
Expand Down
7 changes: 2 additions & 5 deletions crates/fj-kernel/src/algorithms/approx/faces.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,6 @@ mod tests {
use crate::{
geometry,
objects::{Face, Surface},
shape::Shape,
};

use super::{CycleApprox, FaceApprox, Tolerance};
Expand All @@ -95,8 +94,6 @@ mod tests {

let tolerance = Tolerance::from_scalar(Scalar::ONE)?;

let mut shape = Shape::new();

let a = Point::from([0., 0.]);
let b = Point::from([3., 0.]);
let c = Point::from([3., 3.]);
Expand All @@ -107,7 +104,7 @@ mod tests {
let g = Point::from([2., 2.]);
let h = Point::from([1., 2.]);

let face = Face::builder(Surface::xy_plane(), &mut shape)
let face = Face::builder(Surface::xy_plane())
.with_exterior_polygon([a, b, c, d])
.with_interior_polygon([e, f, g, h])
.build();
Expand All @@ -130,7 +127,7 @@ mod tests {
let g = geometry::Point::new(g, g);
let h = geometry::Point::new(h, h);

let approx = FaceApprox::new(&face.get(), tolerance);
let approx = FaceApprox::new(&face, tolerance);
let expected = FaceApprox {
points: set![a, b, c, d, e, f, g, h],
exterior: CycleApprox {
Expand Down
12 changes: 3 additions & 9 deletions crates/fj-kernel/src/algorithms/sweep.rs
Original file line number Diff line number Diff line change
Expand Up @@ -273,7 +273,6 @@ mod tests {
algorithms::Tolerance,
iter::ObjectIters,
objects::{Face, Surface},
shape::Shape,
};

#[test]
Expand Down Expand Up @@ -362,12 +361,9 @@ mod tests {
) -> anyhow::Result<()> {
let tolerance = Tolerance::from_scalar(Scalar::ONE)?;

let mut shape = Shape::new();

let sketch = Face::builder(Surface::xy_plane(), &mut shape)
let sketch = Face::builder(Surface::xy_plane())
.with_exterior_polygon([[0., 0.], [1., 0.], [0., 1.]])
.build()
.get();
.build();

let solid =
super::sweep(vec![sketch], direction, tolerance, [255, 0, 0, 255]);
Expand All @@ -377,14 +373,12 @@ mod tests {
.map(|vertex| vertex.into())
.collect();

let mut shape = Shape::new();
let faces = expected_surfaces.into_iter().map(|surface| {
let surface = Surface::plane_from_points(surface);

Face::builder(surface, &mut shape)
Face::builder(surface)
.with_exterior_polygon(expected_vertices.clone())
.build()
.get()
});

for face in faces {
Expand Down
15 changes: 4 additions & 11 deletions crates/fj-kernel/src/algorithms/triangulation/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,22 +89,18 @@ mod tests {
use crate::{
algorithms::Tolerance,
objects::{Face, Surface},
shape::Shape,
};

#[test]
fn simple() -> anyhow::Result<()> {
let mut shape = Shape::new();

let a = [0., 0.];
let b = [2., 0.];
let c = [2., 2.];
let d = [0., 1.];

let face = Face::builder(Surface::xy_plane(), &mut shape)
let face = Face::builder(Surface::xy_plane())
.with_exterior_polygon([a, b, c, d])
.build()
.get();
.build();

let a = Point::from(a).to_xyz();
let b = Point::from(b).to_xyz();
Expand All @@ -123,8 +119,6 @@ mod tests {

#[test]
fn simple_hole() -> anyhow::Result<()> {
let mut shape = Shape::new();

let a = [0., 0.];
let b = [4., 0.];
let c = [4., 4.];
Expand All @@ -135,11 +129,10 @@ mod tests {
let g = [3., 3.];
let h = [1., 2.];

let face = Face::builder(Surface::xy_plane(), &mut shape)
let face = Face::builder(Surface::xy_plane())
.with_exterior_polygon([a, b, c, d])
.with_interior_polygon([e, f, g, h])
.build()
.get();
.build();

let triangles = triangulate(face)?;

Expand Down
187 changes: 9 additions & 178 deletions crates/fj-kernel/src/builder.rs
Original file line number Diff line number Diff line change
@@ -1,191 +1,26 @@
//! Convenient API to build objects
use fj_math::{Circle, Line, Point, Scalar, Vector};
use fj_math::Point;

use crate::{
objects::{Curve, Cycle, Edge, Face, Surface, Vertex, VerticesOfEdge},
shape::{Handle, LocalForm, Shape},
};

/// API for building a [`Vertex`]
#[must_use]
pub struct VertexBuilder<'r> {
shape: &'r mut Shape,
}

impl<'r> VertexBuilder<'r> {
/// Construct a new instance of `VertexBuilder`
pub fn new(shape: &'r mut Shape) -> Self {
Self { shape }
}

/// Build a [`Vertex`] from a point
///
/// If an identical point or vertex are already part of the shape, those
/// objects are re-used.
pub fn build_from_point(
self,
point: impl Into<Point<3>>,
) -> Handle<Vertex> {
let point = point.into();
self.shape.get_handle_or_insert(Vertex { point })
}
}

/// API for building an [`Edge`]
#[must_use]
pub struct EdgeBuilder<'r> {
shape: &'r mut Shape,
}

impl<'r> EdgeBuilder<'r> {
/// Construct a new instance of `EdgeBuilder`
pub fn new(shape: &'r mut Shape) -> Self {
Self { shape }
}

/// Build a circle from a radius
pub fn build_circle(self, radius: Scalar) -> LocalForm<Edge<2>, Edge<3>> {
let curve_local = Curve::Circle(Circle {
center: Point::origin(),
a: Vector::from([radius, Scalar::ZERO]),
b: Vector::from([Scalar::ZERO, radius]),
});
let curve_canonical = Curve::Circle(Circle {
center: Point::origin(),
a: Vector::from([radius, Scalar::ZERO, Scalar::ZERO]),
b: Vector::from([Scalar::ZERO, radius, Scalar::ZERO]),
});

let edge_local = Edge {
curve: LocalForm::new(curve_local, curve_canonical),
vertices: VerticesOfEdge::none(),
};
let edge_canonical = Edge {
curve: LocalForm::canonical_only(curve_canonical),
vertices: VerticesOfEdge::none(),
};

LocalForm::new(edge_local, edge_canonical)
}

/// Build a line segment from two points
pub fn build_line_segment_from_points(
self,
vertices: [impl Into<Point<3>>; 2],
) -> Handle<Edge<3>> {
let vertices = vertices.map(|point| {
let point = point.into();
Vertex { point }
});

self.build_line_segment_from_vertices(vertices)
}

/// Build a line segment from two vertices
pub fn build_line_segment_from_vertices(
self,
[a, b]: [Vertex; 2],
) -> Handle<Edge<3>> {
let curve = {
let points = [a, b].map(|vertex| vertex.point);
Curve::Line(Line::from_points(points))
};

let vertices = [
LocalForm::new(Point::from([0.]), a),
LocalForm::new(Point::from([1.]), b),
];

self.shape.get_handle_or_insert(Edge {
curve: LocalForm::canonical_only(curve),
vertices: VerticesOfEdge::from_vertices(vertices),
})
}
}

/// API for building a [`Cycle`]
#[must_use]
pub struct CycleBuilder<'r> {
surface: Surface,
shape: &'r mut Shape,
}

impl<'r> CycleBuilder<'r> {
/// Construct a new instance of `CycleBuilder`
pub fn new(surface: Surface, shape: &'r mut Shape) -> Self {
Self { surface, shape }
}

/// Build a polygon from a list of points
pub fn build_polygon(
self,
points: impl IntoIterator<Item = impl Into<Point<2>>>,
) -> LocalForm<Cycle<2>, Cycle<3>> {
let mut points: Vec<_> = points.into_iter().map(Into::into).collect();

// A polygon is closed, so we need to add the first point at the end
// again, for the next step.
if let Some(point) = points.first().cloned() {
points.push(point);
}

let mut edges = Vec::new();
for points in points.windows(2) {
// Can't panic, as we passed `2` to `windows`.
//
// Can be cleaned up, once `array_windows` is stable.
let points = [points[0], points[1]];

let points_canonical = points
.map(|point| self.surface.point_from_surface_coords(point));
let edge_canonical = Edge::builder(self.shape)
.build_line_segment_from_points(points_canonical)
.get();

let edge_local = Edge {
curve: LocalForm::new(
Curve::Line(Line::from_points(points)),
edge_canonical.curve.canonical(),
),
vertices: edge_canonical.vertices.clone(),
};

edges.push(LocalForm::new(edge_local, edge_canonical));
}

let local = Cycle {
edges: edges.clone(),
};

let edges_canonical = edges.into_iter().map(|edge| edge.canonical());
let canonical = Cycle::new(edges_canonical);

LocalForm::new(local, canonical)
}
}
use crate::objects::{Cycle, Face, Surface};

/// API for building a [`Face`]
#[must_use]
pub struct FaceBuilder<'r> {
pub struct FaceBuilder {
surface: Surface,
exterior: Option<Vec<Point<2>>>,
interiors: Vec<Vec<Point<2>>>,
color: Option<[u8; 4]>,

shape: &'r mut Shape,
}

impl<'r> FaceBuilder<'r> {
impl FaceBuilder {
/// Construct a new instance of `FaceBuilder`
pub fn new(surface: Surface, shape: &'r mut Shape) -> Self {
pub fn new(surface: Surface) -> Self {
Self {
surface,
exterior: None,
interiors: Vec::new(),
color: None,

shape,
}
}

Expand Down Expand Up @@ -222,27 +57,23 @@ impl<'r> FaceBuilder<'r> {
}

/// Build the face
pub fn build(self) -> Handle<Face> {
pub fn build(self) -> Face {
let surface = self.surface;

let mut exteriors = Vec::new();
if let Some(points) = self.exterior {
let cycle =
Cycle::builder(self.surface, self.shape).build_polygon(points);
let cycle = Cycle::polygon_from_points(&self.surface, points);
exteriors.push(cycle);
}

let mut interiors = Vec::new();
for points in self.interiors {
let cycle =
Cycle::builder(self.surface, self.shape).build_polygon(points);
let cycle = Cycle::polygon_from_points(&self.surface, points);
interiors.push(cycle);
}

let color = self.color.unwrap_or([255, 0, 0, 255]);

self.shape.get_handle_or_insert(Face::new(
surface, exteriors, interiors, color,
))
Face::new(surface, exteriors, interiors, color)
}
}
Loading

0 comments on commit 74d745c

Please sign in to comment.