Skip to content

Commit

Permalink
Merge pull request #418 from hannobraun/builder
Browse files Browse the repository at this point in the history
Extend builder API, use it to simplify approximation tests
  • Loading branch information
hannobraun authored Apr 1, 2022
2 parents 6f83081 + cdf7b3c commit a53c275
Show file tree
Hide file tree
Showing 5 changed files with 85 additions and 45 deletions.
20 changes: 2 additions & 18 deletions fj-kernel/src/algorithms/approximation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ mod tests {
use crate::{
geometry::Surface,
shape::Shape,
topology::{Cycle, Edge, Face, Vertex},
topology::{Cycle, Face, Vertex},
};

use super::Approximation;
Expand Down Expand Up @@ -162,23 +162,7 @@ mod tests {
let c = Point::from([3., 5., 8.]);
let d = Point::from([5., 8., 13.]);

let v1 = Vertex::build(&mut shape).from_point(a)?;
let v2 = Vertex::build(&mut shape).from_point(b)?;
let v3 = Vertex::build(&mut shape).from_point(c)?;
let v4 = Vertex::build(&mut shape).from_point(d)?;

let ab = Edge::build(&mut shape)
.line_segment_from_vertices([v1.clone(), v2.clone()])?;
let bc = Edge::build(&mut shape)
.line_segment_from_vertices([v2, v3.clone()])?;
let cd = Edge::build(&mut shape)
.line_segment_from_vertices([v3, v4.clone()])?;
let da =
Edge::build(&mut shape).line_segment_from_vertices([v4, v1])?;

let abcd = shape.insert(Cycle {
edges: vec![ab, bc, cd, da],
})?;
let abcd = Cycle::build(&mut shape).polygon([a, b, c, d])?;

let surface = shape.insert(Surface::x_y_plane())?;
let face = Face::Face {
Expand Down
28 changes: 10 additions & 18 deletions fj-kernel/src/algorithms/sweep.rs
Original file line number Diff line number Diff line change
Expand Up @@ -326,7 +326,7 @@ mod tests {
use crate::{
geometry::{Surface, SweptCurve},
shape::{Handle, Shape},
topology::{Cycle, Edge, Face, Vertex},
topology::{Cycle, Edge, Face},
};

use super::sweep_shape;
Expand Down Expand Up @@ -377,32 +377,24 @@ mod tests {
}

impl Triangle {
fn new([a, b, c]: [impl Into<Point<3>>; 3]) -> anyhow::Result<Self> {
fn new(points: [impl Into<Point<3>>; 3]) -> anyhow::Result<Self> {
let mut shape = Shape::new();

let a = shape.insert(a.into())?;
let b = shape.insert(b.into())?;
let c = shape.insert(c.into())?;
let [a, b, c] = points.map(|point| point.into());

let a = shape.insert(Vertex { point: a })?;
let b = shape.insert(Vertex { point: b })?;
let c = shape.insert(Vertex { point: c })?;

let ab = Edge::build(&mut shape)
.line_segment_from_vertices([a.clone(), b.clone()])?;
let bc = Edge::build(&mut shape)
.line_segment_from_vertices([b.clone(), c.clone()])?;
let ca = Edge::build(&mut shape)
.line_segment_from_vertices([c.clone(), a.clone()])?;
let ab =
Edge::build(&mut shape).line_segment_from_points([a, b])?;
let bc =
Edge::build(&mut shape).line_segment_from_points([b, c])?;
let ca =
Edge::build(&mut shape).line_segment_from_points([c, a])?;

let cycles = shape.insert(Cycle {
edges: vec![ab, bc, ca],
})?;

let surface = shape.insert(Surface::SweptCurve(
SweptCurve::plane_from_points(
[a, b, c].map(|vertex| vertex.get().point()),
),
SweptCurve::plane_from_points([a, b, c]),
))?;
let abc = Face::Face {
surface,
Expand Down
8 changes: 3 additions & 5 deletions fj-kernel/src/shape/topology.rs
Original file line number Diff line number Diff line change
Expand Up @@ -191,15 +191,13 @@ mod tests {
}

fn add_edge(&mut self) -> anyhow::Result<Handle<Edge>> {
let vertices = [(); 2].map(|()| {
let points = [(); 2].map(|()| {
let point = self.next_point;
self.next_point.x += Scalar::ONE;

let point = self.insert(point).unwrap();
self.insert(Vertex { point }).unwrap()
point
});
let edge = Edge::build(&mut self.inner)
.line_segment_from_vertices(vertices)?;
.line_segment_from_points(points)?;

Ok(edge)
}
Expand Down
67 changes: 64 additions & 3 deletions fj-kernel/src/topology/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use crate::{
shape::{Handle, Shape, ValidationResult},
};

use super::{Edge, Vertex};
use super::{Cycle, Edge, Vertex};

/// API for building a [`Vertex`]
pub struct VertexBuilder<'r> {
Expand All @@ -19,12 +19,15 @@ impl<'r> VertexBuilder<'r> {
}

/// 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 from_point(
self,
point: impl Into<Point<3>>,
) -> ValidationResult<Vertex> {
let point = self.shape.insert(point.into())?;
let vertex = self.shape.insert(Vertex { point })?;
let point = self.shape.get_handle_or_insert(point.into())?;
let vertex = self.shape.get_handle_or_insert(Vertex { point })?;

Ok(vertex)
}
Expand Down Expand Up @@ -55,6 +58,25 @@ impl<'r> EdgeBuilder<'r> {
Ok(edge)
}

/// Build a line segment from two points
pub fn line_segment_from_points(
self,
vertices: [impl Into<Point<3>>; 2],
) -> ValidationResult<Edge> {
// Can be cleaned up with `try_map`, once that is stable:
// https://doc.rust-lang.org/std/primitive.array.html#method.try_map
let vertices =
vertices.map(|point| Vertex::build(self.shape).from_point(point));
let vertices = match vertices {
[Ok(a), Ok(b)] => Ok([a, b]),
[Err(err), _] | [_, Err(err)] => Err(err),
}?;

let edge = self.line_segment_from_vertices(vertices)?;

Ok(edge)
}

/// Build a line segment from two vertices
pub fn line_segment_from_vertices(
self,
Expand All @@ -71,3 +93,42 @@ impl<'r> EdgeBuilder<'r> {
Ok(edge)
}
}

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

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

/// Build a polygon from a list of points
pub fn polygon(
self,
points: impl IntoIterator<Item = impl Into<Point<3>>>,
) -> ValidationResult<Cycle> {
// A polygon is closed, so we need to add the first point at the end
// again, for the next step.
let mut points: Vec<_> = points.into_iter().map(Into::into).collect();
if let Some(point) = points.first().cloned() {
points.push(point);
}

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

let edge =
Edge::build(self.shape).line_segment_from_points(points)?;
edges.push(edge);
}

self.shape.insert(Cycle { edges })
}
}
7 changes: 6 additions & 1 deletion fj-kernel/src/topology/edges.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use crate::{
shape::{Handle, Shape},
};

use super::{vertices::Vertex, EdgeBuilder};
use super::{builder::CycleBuilder, vertices::Vertex, EdgeBuilder};

/// A cycle of connected edges
///
Expand All @@ -29,6 +29,11 @@ pub struct Cycle {
}

impl Cycle {
/// Build a cycle using the [`CycleBuilder`] API
pub fn build(shape: &mut Shape) -> CycleBuilder {
CycleBuilder::new(shape)
}

/// Access the edges that this cycle refers to
///
/// This is a convenience method that saves the caller from dealing with the
Expand Down

0 comments on commit a53c275

Please sign in to comment.