Merge pull request #418 from hannobraun/builder

Extend builder API, use it to simplify approximation tests
This commit is contained in:
Hanno Braun 2022-04-01 18:58:25 +02:00 committed by GitHub
commit a53c275ddd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 85 additions and 45 deletions

View File

@ -120,7 +120,7 @@ mod tests {
use crate::{ use crate::{
geometry::Surface, geometry::Surface,
shape::Shape, shape::Shape,
topology::{Cycle, Edge, Face, Vertex}, topology::{Cycle, Face, Vertex},
}; };
use super::Approximation; use super::Approximation;
@ -162,23 +162,7 @@ mod tests {
let c = Point::from([3., 5., 8.]); let c = Point::from([3., 5., 8.]);
let d = Point::from([5., 8., 13.]); let d = Point::from([5., 8., 13.]);
let v1 = Vertex::build(&mut shape).from_point(a)?; let abcd = Cycle::build(&mut shape).polygon([a, b, c, d])?;
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 surface = shape.insert(Surface::x_y_plane())?; let surface = shape.insert(Surface::x_y_plane())?;
let face = Face::Face { let face = Face::Face {

View File

@ -326,7 +326,7 @@ mod tests {
use crate::{ use crate::{
geometry::{Surface, SweptCurve}, geometry::{Surface, SweptCurve},
shape::{Handle, Shape}, shape::{Handle, Shape},
topology::{Cycle, Edge, Face, Vertex}, topology::{Cycle, Edge, Face},
}; };
use super::sweep_shape; use super::sweep_shape;
@ -377,32 +377,24 @@ mod tests {
} }
impl Triangle { 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 mut shape = Shape::new();
let a = shape.insert(a.into())?; let [a, b, c] = points.map(|point| point.into());
let b = shape.insert(b.into())?;
let c = shape.insert(c.into())?;
let a = shape.insert(Vertex { point: a })?; let ab =
let b = shape.insert(Vertex { point: b })?; Edge::build(&mut shape).line_segment_from_points([a, b])?;
let c = shape.insert(Vertex { point: c })?; let bc =
Edge::build(&mut shape).line_segment_from_points([b, c])?;
let ab = Edge::build(&mut shape) let ca =
.line_segment_from_vertices([a.clone(), b.clone()])?; Edge::build(&mut shape).line_segment_from_points([c, a])?;
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 cycles = shape.insert(Cycle { let cycles = shape.insert(Cycle {
edges: vec![ab, bc, ca], edges: vec![ab, bc, ca],
})?; })?;
let surface = shape.insert(Surface::SweptCurve( let surface = shape.insert(Surface::SweptCurve(
SweptCurve::plane_from_points( SweptCurve::plane_from_points([a, b, c]),
[a, b, c].map(|vertex| vertex.get().point()),
),
))?; ))?;
let abc = Face::Face { let abc = Face::Face {
surface, surface,

View File

@ -191,15 +191,13 @@ mod tests {
} }
fn add_edge(&mut self) -> anyhow::Result<Handle<Edge>> { fn add_edge(&mut self) -> anyhow::Result<Handle<Edge>> {
let vertices = [(); 2].map(|()| { let points = [(); 2].map(|()| {
let point = self.next_point; let point = self.next_point;
self.next_point.x += Scalar::ONE; self.next_point.x += Scalar::ONE;
point
let point = self.insert(point).unwrap();
self.insert(Vertex { point }).unwrap()
}); });
let edge = Edge::build(&mut self.inner) let edge = Edge::build(&mut self.inner)
.line_segment_from_vertices(vertices)?; .line_segment_from_points(points)?;
Ok(edge) Ok(edge)
} }

View File

@ -5,7 +5,7 @@ use crate::{
shape::{Handle, Shape, ValidationResult}, shape::{Handle, Shape, ValidationResult},
}; };
use super::{Edge, Vertex}; use super::{Cycle, Edge, Vertex};
/// API for building a [`Vertex`] /// API for building a [`Vertex`]
pub struct VertexBuilder<'r> { pub struct VertexBuilder<'r> {
@ -19,12 +19,15 @@ impl<'r> VertexBuilder<'r> {
} }
/// Build a [`Vertex`] from a point /// 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( pub fn from_point(
self, self,
point: impl Into<Point<3>>, point: impl Into<Point<3>>,
) -> ValidationResult<Vertex> { ) -> ValidationResult<Vertex> {
let point = self.shape.insert(point.into())?; let point = self.shape.get_handle_or_insert(point.into())?;
let vertex = self.shape.insert(Vertex { point })?; let vertex = self.shape.get_handle_or_insert(Vertex { point })?;
Ok(vertex) Ok(vertex)
} }
@ -55,6 +58,25 @@ impl<'r> EdgeBuilder<'r> {
Ok(edge) 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 /// Build a line segment from two vertices
pub fn line_segment_from_vertices( pub fn line_segment_from_vertices(
self, self,
@ -71,3 +93,42 @@ impl<'r> EdgeBuilder<'r> {
Ok(edge) 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 })
}
}

View File

@ -5,7 +5,7 @@ use crate::{
shape::{Handle, Shape}, shape::{Handle, Shape},
}; };
use super::{vertices::Vertex, EdgeBuilder}; use super::{builder::CycleBuilder, vertices::Vertex, EdgeBuilder};
/// A cycle of connected edges /// A cycle of connected edges
/// ///
@ -29,6 +29,11 @@ pub struct Cycle {
} }
impl 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 /// Access the edges that this cycle refers to
/// ///
/// This is a convenience method that saves the caller from dealing with the /// This is a convenience method that saves the caller from dealing with the