mirror of https://github.com/hannobraun/Fornjot
commit
74d745c644
|
@ -37,20 +37,18 @@ mod test {
|
||||||
use crate::{
|
use crate::{
|
||||||
geometry,
|
geometry,
|
||||||
objects::{Vertex, VerticesOfEdge},
|
objects::{Vertex, VerticesOfEdge},
|
||||||
shape::{LocalForm, Shape},
|
shape::LocalForm,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn approx_edge() {
|
fn approx_edge() {
|
||||||
let mut shape = Shape::new();
|
|
||||||
|
|
||||||
let a = Point::from([1., 2., 3.]);
|
let a = Point::from([1., 2., 3.]);
|
||||||
let b = Point::from([2., 3., 5.]);
|
let b = Point::from([2., 3., 5.]);
|
||||||
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::builder(&mut shape).build_from_point(a).get();
|
let v1 = Vertex::from_point(a);
|
||||||
let v2 = Vertex::builder(&mut shape).build_from_point(d).get();
|
let v2 = Vertex::from_point(d);
|
||||||
|
|
||||||
let vertices = VerticesOfEdge::from_vertices([
|
let vertices = VerticesOfEdge::from_vertices([
|
||||||
LocalForm::new(Point::from([0.]), v1),
|
LocalForm::new(Point::from([0.]), v1),
|
||||||
|
|
|
@ -84,7 +84,6 @@ mod tests {
|
||||||
use crate::{
|
use crate::{
|
||||||
geometry,
|
geometry,
|
||||||
objects::{Face, Surface},
|
objects::{Face, Surface},
|
||||||
shape::Shape,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{CycleApprox, FaceApprox, Tolerance};
|
use super::{CycleApprox, FaceApprox, Tolerance};
|
||||||
|
@ -95,8 +94,6 @@ mod tests {
|
||||||
|
|
||||||
let tolerance = Tolerance::from_scalar(Scalar::ONE)?;
|
let tolerance = Tolerance::from_scalar(Scalar::ONE)?;
|
||||||
|
|
||||||
let mut shape = Shape::new();
|
|
||||||
|
|
||||||
let a = Point::from([0., 0.]);
|
let a = Point::from([0., 0.]);
|
||||||
let b = Point::from([3., 0.]);
|
let b = Point::from([3., 0.]);
|
||||||
let c = Point::from([3., 3.]);
|
let c = Point::from([3., 3.]);
|
||||||
|
@ -107,7 +104,7 @@ mod tests {
|
||||||
let g = Point::from([2., 2.]);
|
let g = Point::from([2., 2.]);
|
||||||
let h = Point::from([1., 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_exterior_polygon([a, b, c, d])
|
||||||
.with_interior_polygon([e, f, g, h])
|
.with_interior_polygon([e, f, g, h])
|
||||||
.build();
|
.build();
|
||||||
|
@ -130,7 +127,7 @@ mod tests {
|
||||||
let g = geometry::Point::new(g, g);
|
let g = geometry::Point::new(g, g);
|
||||||
let h = geometry::Point::new(h, h);
|
let h = geometry::Point::new(h, h);
|
||||||
|
|
||||||
let approx = FaceApprox::new(&face.get(), tolerance);
|
let approx = FaceApprox::new(&face, tolerance);
|
||||||
let expected = FaceApprox {
|
let expected = FaceApprox {
|
||||||
points: set![a, b, c, d, e, f, g, h],
|
points: set![a, b, c, d, e, f, g, h],
|
||||||
exterior: CycleApprox {
|
exterior: CycleApprox {
|
||||||
|
|
|
@ -273,7 +273,6 @@ mod tests {
|
||||||
algorithms::Tolerance,
|
algorithms::Tolerance,
|
||||||
iter::ObjectIters,
|
iter::ObjectIters,
|
||||||
objects::{Face, Surface},
|
objects::{Face, Surface},
|
||||||
shape::Shape,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -362,12 +361,9 @@ mod tests {
|
||||||
) -> anyhow::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
let tolerance = Tolerance::from_scalar(Scalar::ONE)?;
|
let tolerance = Tolerance::from_scalar(Scalar::ONE)?;
|
||||||
|
|
||||||
let mut shape = Shape::new();
|
let sketch = Face::builder(Surface::xy_plane())
|
||||||
|
|
||||||
let sketch = Face::builder(Surface::xy_plane(), &mut shape)
|
|
||||||
.with_exterior_polygon([[0., 0.], [1., 0.], [0., 1.]])
|
.with_exterior_polygon([[0., 0.], [1., 0.], [0., 1.]])
|
||||||
.build()
|
.build();
|
||||||
.get();
|
|
||||||
|
|
||||||
let solid =
|
let solid =
|
||||||
super::sweep(vec![sketch], direction, tolerance, [255, 0, 0, 255]);
|
super::sweep(vec![sketch], direction, tolerance, [255, 0, 0, 255]);
|
||||||
|
@ -377,14 +373,12 @@ mod tests {
|
||||||
.map(|vertex| vertex.into())
|
.map(|vertex| vertex.into())
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
let mut shape = Shape::new();
|
|
||||||
let faces = expected_surfaces.into_iter().map(|surface| {
|
let faces = expected_surfaces.into_iter().map(|surface| {
|
||||||
let surface = Surface::plane_from_points(surface);
|
let surface = Surface::plane_from_points(surface);
|
||||||
|
|
||||||
Face::builder(surface, &mut shape)
|
Face::builder(surface)
|
||||||
.with_exterior_polygon(expected_vertices.clone())
|
.with_exterior_polygon(expected_vertices.clone())
|
||||||
.build()
|
.build()
|
||||||
.get()
|
|
||||||
});
|
});
|
||||||
|
|
||||||
for face in faces {
|
for face in faces {
|
||||||
|
|
|
@ -89,22 +89,18 @@ mod tests {
|
||||||
use crate::{
|
use crate::{
|
||||||
algorithms::Tolerance,
|
algorithms::Tolerance,
|
||||||
objects::{Face, Surface},
|
objects::{Face, Surface},
|
||||||
shape::Shape,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn simple() -> anyhow::Result<()> {
|
fn simple() -> anyhow::Result<()> {
|
||||||
let mut shape = Shape::new();
|
|
||||||
|
|
||||||
let a = [0., 0.];
|
let a = [0., 0.];
|
||||||
let b = [2., 0.];
|
let b = [2., 0.];
|
||||||
let c = [2., 2.];
|
let c = [2., 2.];
|
||||||
let d = [0., 1.];
|
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])
|
.with_exterior_polygon([a, b, c, d])
|
||||||
.build()
|
.build();
|
||||||
.get();
|
|
||||||
|
|
||||||
let a = Point::from(a).to_xyz();
|
let a = Point::from(a).to_xyz();
|
||||||
let b = Point::from(b).to_xyz();
|
let b = Point::from(b).to_xyz();
|
||||||
|
@ -123,8 +119,6 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn simple_hole() -> anyhow::Result<()> {
|
fn simple_hole() -> anyhow::Result<()> {
|
||||||
let mut shape = Shape::new();
|
|
||||||
|
|
||||||
let a = [0., 0.];
|
let a = [0., 0.];
|
||||||
let b = [4., 0.];
|
let b = [4., 0.];
|
||||||
let c = [4., 4.];
|
let c = [4., 4.];
|
||||||
|
@ -135,11 +129,10 @@ mod tests {
|
||||||
let g = [3., 3.];
|
let g = [3., 3.];
|
||||||
let h = [1., 2.];
|
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_exterior_polygon([a, b, c, d])
|
||||||
.with_interior_polygon([e, f, g, h])
|
.with_interior_polygon([e, f, g, h])
|
||||||
.build()
|
.build();
|
||||||
.get();
|
|
||||||
|
|
||||||
let triangles = triangulate(face)?;
|
let triangles = triangulate(face)?;
|
||||||
|
|
||||||
|
|
|
@ -1,191 +1,26 @@
|
||||||
//! Convenient API to build objects
|
//! Convenient API to build objects
|
||||||
|
|
||||||
use fj_math::{Circle, Line, Point, Scalar, Vector};
|
use fj_math::Point;
|
||||||
|
|
||||||
use crate::{
|
use crate::objects::{Cycle, Face, Surface};
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// API for building a [`Face`]
|
/// API for building a [`Face`]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub struct FaceBuilder<'r> {
|
pub struct FaceBuilder {
|
||||||
surface: Surface,
|
surface: Surface,
|
||||||
exterior: Option<Vec<Point<2>>>,
|
exterior: Option<Vec<Point<2>>>,
|
||||||
interiors: Vec<Vec<Point<2>>>,
|
interiors: Vec<Vec<Point<2>>>,
|
||||||
color: Option<[u8; 4]>,
|
color: Option<[u8; 4]>,
|
||||||
|
|
||||||
shape: &'r mut Shape,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'r> FaceBuilder<'r> {
|
impl FaceBuilder {
|
||||||
/// Construct a new instance of `FaceBuilder`
|
/// Construct a new instance of `FaceBuilder`
|
||||||
pub fn new(surface: Surface, shape: &'r mut Shape) -> Self {
|
pub fn new(surface: Surface) -> Self {
|
||||||
Self {
|
Self {
|
||||||
surface,
|
surface,
|
||||||
exterior: None,
|
exterior: None,
|
||||||
interiors: Vec::new(),
|
interiors: Vec::new(),
|
||||||
color: None,
|
color: None,
|
||||||
|
|
||||||
shape,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -222,27 +57,23 @@ impl<'r> FaceBuilder<'r> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Build the face
|
/// Build the face
|
||||||
pub fn build(self) -> Handle<Face> {
|
pub fn build(self) -> Face {
|
||||||
let surface = self.surface;
|
let surface = self.surface;
|
||||||
|
|
||||||
let mut exteriors = Vec::new();
|
let mut exteriors = Vec::new();
|
||||||
if let Some(points) = self.exterior {
|
if let Some(points) = self.exterior {
|
||||||
let cycle =
|
let cycle = Cycle::polygon_from_points(&self.surface, points);
|
||||||
Cycle::builder(self.surface, self.shape).build_polygon(points);
|
|
||||||
exteriors.push(cycle);
|
exteriors.push(cycle);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut interiors = Vec::new();
|
let mut interiors = Vec::new();
|
||||||
for points in self.interiors {
|
for points in self.interiors {
|
||||||
let cycle =
|
let cycle = Cycle::polygon_from_points(&self.surface, points);
|
||||||
Cycle::builder(self.surface, self.shape).build_polygon(points);
|
|
||||||
interiors.push(cycle);
|
interiors.push(cycle);
|
||||||
}
|
}
|
||||||
|
|
||||||
let color = self.color.unwrap_or([255, 0, 0, 255]);
|
let color = self.color.unwrap_or([255, 0, 0, 255]);
|
||||||
|
|
||||||
self.shape.get_handle_or_insert(Face::new(
|
Face::new(surface, exteriors, interiors, color)
|
||||||
surface, exteriors, interiors, color,
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -439,10 +439,7 @@ impl<T> Iterator for Iter<T> {
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::{
|
use crate::objects::{Curve, Cycle, Edge, Face, Surface, Vertex};
|
||||||
objects::{Curve, Cycle, Edge, Face, Surface, Vertex},
|
|
||||||
shape::Shape,
|
|
||||||
};
|
|
||||||
|
|
||||||
use super::ObjectIters as _;
|
use super::ObjectIters as _;
|
||||||
|
|
||||||
|
@ -460,10 +457,11 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn cycle() {
|
fn cycle() {
|
||||||
let mut shape = Shape::new();
|
let cycle = Cycle::polygon_from_points(
|
||||||
let cycle = Cycle::builder(Surface::xy_plane(), &mut shape)
|
&Surface::xy_plane(),
|
||||||
.build_polygon([[0., 0.], [1., 0.], [0., 1.]])
|
[[0., 0.], [1., 0.], [0., 1.]],
|
||||||
.canonical();
|
)
|
||||||
|
.canonical();
|
||||||
|
|
||||||
assert_eq!(3, cycle.curve_iter().count());
|
assert_eq!(3, cycle.curve_iter().count());
|
||||||
assert_eq!(1, cycle.cycle_iter().count());
|
assert_eq!(1, cycle.cycle_iter().count());
|
||||||
|
@ -475,10 +473,7 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn edge() {
|
fn edge() {
|
||||||
let mut shape = Shape::new();
|
let edge = Edge::line_segment_from_points([[0., 0., 0.], [1., 0., 0.]]);
|
||||||
let edge = Edge::builder(&mut shape)
|
|
||||||
.build_line_segment_from_points([[0., 0., 0.], [1., 0., 0.]])
|
|
||||||
.get();
|
|
||||||
|
|
||||||
assert_eq!(1, edge.curve_iter().count());
|
assert_eq!(1, edge.curve_iter().count());
|
||||||
assert_eq!(0, edge.cycle_iter().count());
|
assert_eq!(0, edge.cycle_iter().count());
|
||||||
|
@ -490,11 +485,9 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn face() {
|
fn face() {
|
||||||
let mut shape = Shape::new();
|
let face = Face::builder(Surface::xy_plane())
|
||||||
let face = Face::builder(Surface::xy_plane(), &mut shape)
|
|
||||||
.with_exterior_polygon([[0., 0.], [1., 0.], [0., 1.]])
|
.with_exterior_polygon([[0., 0.], [1., 0.], [0., 1.]])
|
||||||
.build()
|
.build();
|
||||||
.get();
|
|
||||||
|
|
||||||
assert_eq!(3, face.curve_iter().count());
|
assert_eq!(3, face.curve_iter().count());
|
||||||
assert_eq!(1, face.cycle_iter().count());
|
assert_eq!(1, face.cycle_iter().count());
|
||||||
|
@ -518,10 +511,7 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn vertex() {
|
fn vertex() {
|
||||||
let mut shape = Shape::new();
|
let vertex = Vertex::from_point([0., 0., 0.]);
|
||||||
let vertex = Vertex::builder(&mut shape)
|
|
||||||
.build_from_point([0., 0., 0.])
|
|
||||||
.get();
|
|
||||||
|
|
||||||
assert_eq!(0, vertex.curve_iter().count());
|
assert_eq!(0, vertex.curve_iter().count());
|
||||||
assert_eq!(0, vertex.cycle_iter().count());
|
assert_eq!(0, vertex.cycle_iter().count());
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
use crate::{
|
use fj_math::{Line, Point};
|
||||||
builder::CycleBuilder,
|
|
||||||
shape::{LocalForm, Shape},
|
|
||||||
};
|
|
||||||
|
|
||||||
use super::{Edge, Surface};
|
use crate::shape::LocalForm;
|
||||||
|
|
||||||
|
use super::{Curve, Edge, Surface};
|
||||||
|
|
||||||
/// A cycle of connected edges
|
/// A cycle of connected edges
|
||||||
///
|
///
|
||||||
|
@ -29,9 +28,50 @@ impl Cycle<3> {
|
||||||
Self { edges }
|
Self { edges }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Build a cycle using the [`CycleBuilder`] API
|
/// Create a polygon from a list of points
|
||||||
pub fn builder(surface: Surface, shape: &mut Shape) -> CycleBuilder {
|
pub fn polygon_from_points(
|
||||||
CycleBuilder::new(surface, shape)
|
surface: &Surface,
|
||||||
|
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| surface.point_from_surface_coords(point));
|
||||||
|
let edge_canonical =
|
||||||
|
Edge::line_segment_from_points(points_canonical);
|
||||||
|
|
||||||
|
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)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Access the edges that this cycle refers to
|
/// Access the edges that this cycle refers to
|
||||||
|
|
|
@ -1,11 +1,8 @@
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
use fj_math::Point;
|
use fj_math::{Circle, Line, Point, Scalar, Vector};
|
||||||
|
|
||||||
use crate::{
|
use crate::shape::LocalForm;
|
||||||
builder::EdgeBuilder,
|
|
||||||
shape::{LocalForm, Shape},
|
|
||||||
};
|
|
||||||
|
|
||||||
use super::{Curve, Vertex};
|
use super::{Curve, Vertex};
|
||||||
|
|
||||||
|
@ -53,10 +50,62 @@ impl<const D: usize> Edge<D> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Edge<2> {
|
||||||
|
/// Create a circle from the given radius
|
||||||
|
pub fn circle_from_radius(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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Edge<3> {
|
impl Edge<3> {
|
||||||
/// Build an edge using the [`EdgeBuilder`] API
|
/// Create a line segment from two points
|
||||||
pub fn builder(shape: &mut Shape) -> EdgeBuilder {
|
pub fn line_segment_from_points(
|
||||||
EdgeBuilder::new(shape)
|
vertices: [impl Into<Point<3>>; 2],
|
||||||
|
) -> Self {
|
||||||
|
let vertices = vertices.map(|point| {
|
||||||
|
let point = point.into();
|
||||||
|
Vertex { point }
|
||||||
|
});
|
||||||
|
|
||||||
|
Self::line_segment_from_vertices(vertices)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a line segment from two vertices
|
||||||
|
pub fn line_segment_from_vertices([a, b]: [Vertex; 2]) -> Self {
|
||||||
|
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 {
|
||||||
|
curve: LocalForm::canonical_only(curve),
|
||||||
|
vertices: VerticesOfEdge::from_vertices(vertices),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,10 +3,7 @@ use std::hash::{Hash, Hasher};
|
||||||
use fj_interop::mesh::Color;
|
use fj_interop::mesh::Color;
|
||||||
use fj_math::Triangle;
|
use fj_math::Triangle;
|
||||||
|
|
||||||
use crate::{
|
use crate::{builder::FaceBuilder, shape::LocalForm};
|
||||||
builder::FaceBuilder,
|
|
||||||
shape::{LocalForm, Shape},
|
|
||||||
};
|
|
||||||
|
|
||||||
use super::{Cycle, Surface};
|
use super::{Cycle, Surface};
|
||||||
|
|
||||||
|
@ -57,8 +54,8 @@ impl Face {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
/// Build a face using the [`FaceBuilder`] API
|
/// Build a face using the [`FaceBuilder`] API
|
||||||
pub fn builder(surface: Surface, shape: &mut Shape) -> FaceBuilder {
|
pub fn builder(surface: Surface) -> FaceBuilder {
|
||||||
FaceBuilder::new(surface, shape)
|
FaceBuilder::new(surface)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Access the boundary representation of the face
|
/// Access the boundary representation of the face
|
||||||
|
|
|
@ -2,8 +2,6 @@ use std::hash::Hash;
|
||||||
|
|
||||||
use fj_math::Point;
|
use fj_math::Point;
|
||||||
|
|
||||||
use crate::{builder::VertexBuilder, shape::Shape};
|
|
||||||
|
|
||||||
/// A vertex
|
/// A vertex
|
||||||
///
|
///
|
||||||
/// This struct exists to distinguish between vertices and points at the type
|
/// This struct exists to distinguish between vertices and points at the type
|
||||||
|
@ -27,8 +25,9 @@ pub struct Vertex {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Vertex {
|
impl Vertex {
|
||||||
/// Build a vertex using the [`VertexBuilder`] API
|
/// Construct a `Vertex` from a point
|
||||||
pub fn builder(shape: &mut Shape) -> VertexBuilder {
|
pub fn from_point(point: impl Into<Point<3>>) -> Self {
|
||||||
VertexBuilder::new(shape)
|
let point = point.into();
|
||||||
|
Self { point }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -273,36 +273,26 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn structural_cycle() {
|
fn structural_cycle() {
|
||||||
let mut shape = Shape::new();
|
let mut shape = Shape::new();
|
||||||
let mut other = Shape::new();
|
|
||||||
|
|
||||||
// Trying to refer to edge that is not from the same shape. Should fail.
|
// Trying to refer to edge that is not from the same shape. Should fail.
|
||||||
let edge = Edge::builder(&mut other)
|
let edge = Edge::line_segment_from_points([[0., 0., 0.], [1., 0., 0.]]);
|
||||||
.build_line_segment_from_points([[0., 0., 0.], [1., 0., 0.]])
|
|
||||||
.get();
|
|
||||||
shape.insert(Cycle::new(vec![edge.clone()]));
|
shape.insert(Cycle::new(vec![edge.clone()]));
|
||||||
let err =
|
let err =
|
||||||
validate(shape.clone(), &ValidationConfig::default()).unwrap_err();
|
validate(shape.clone(), &ValidationConfig::default()).unwrap_err();
|
||||||
assert!(err.missing_edge(&edge));
|
assert!(err.missing_edge(&edge));
|
||||||
|
|
||||||
// Referring to edge that *is* from the same shape. Should work.
|
// Referring to edge that *is* from the same shape. Should work.
|
||||||
let edge = Edge::builder(&mut shape)
|
let edge = Edge::line_segment_from_points([[0., 0., 0.], [1., 0., 0.]]);
|
||||||
.build_line_segment_from_points([[0., 0., 0.], [1., 0., 0.]])
|
|
||||||
.get();
|
|
||||||
shape.insert(Cycle::new(vec![edge]));
|
shape.insert(Cycle::new(vec![edge]));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn structural_edge() {
|
fn structural_edge() {
|
||||||
let mut shape = Shape::new();
|
let mut shape = Shape::new();
|
||||||
let mut other = Shape::new();
|
|
||||||
|
|
||||||
let curve = Curve::x_axis();
|
let curve = Curve::x_axis();
|
||||||
let a = Vertex::builder(&mut other)
|
let a = Vertex::from_point([1., 0., 0.]);
|
||||||
.build_from_point([1., 0., 0.])
|
let b = Vertex::from_point([2., 0., 0.]);
|
||||||
.get();
|
|
||||||
let b = Vertex::builder(&mut other)
|
|
||||||
.build_from_point([2., 0., 0.])
|
|
||||||
.get();
|
|
||||||
|
|
||||||
let a = LocalForm::new(Point::from([1.]), a);
|
let a = LocalForm::new(Point::from([1.]), a);
|
||||||
let b = LocalForm::new(Point::from([2.]), b);
|
let b = LocalForm::new(Point::from([2.]), b);
|
||||||
|
@ -319,12 +309,8 @@ mod tests {
|
||||||
assert!(err.missing_vertex(&b.canonical()));
|
assert!(err.missing_vertex(&b.canonical()));
|
||||||
|
|
||||||
let curve = Curve::x_axis();
|
let curve = Curve::x_axis();
|
||||||
let a = Vertex::builder(&mut shape)
|
let a = Vertex::from_point([1., 0., 0.]);
|
||||||
.build_from_point([1., 0., 0.])
|
let b = Vertex::from_point([2., 0., 0.]);
|
||||||
.get();
|
|
||||||
let b = Vertex::builder(&mut shape)
|
|
||||||
.build_from_point([2., 0., 0.])
|
|
||||||
.get();
|
|
||||||
|
|
||||||
let a = LocalForm::new(Point::from([1.]), a);
|
let a = LocalForm::new(Point::from([1.]), a);
|
||||||
let b = LocalForm::new(Point::from([2.]), b);
|
let b = LocalForm::new(Point::from([2.]), b);
|
||||||
|
@ -339,12 +325,11 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn structural_face() {
|
fn structural_face() {
|
||||||
let mut shape = Shape::new();
|
let mut shape = Shape::new();
|
||||||
let mut other = Shape::new();
|
|
||||||
|
|
||||||
let triangle = [[0., 0.], [1., 0.], [0., 1.]];
|
let triangle = [[0., 0.], [1., 0.], [0., 1.]];
|
||||||
|
|
||||||
let surface = Surface::xy_plane();
|
let surface = Surface::xy_plane();
|
||||||
let cycle = Cycle::builder(surface, &mut other).build_polygon(triangle);
|
let cycle = Cycle::polygon_from_points(&surface, triangle);
|
||||||
|
|
||||||
// Nothing has been added to `shape`. Should fail.
|
// Nothing has been added to `shape`. Should fail.
|
||||||
shape.insert(Face::new(
|
shape.insert(Face::new(
|
||||||
|
@ -359,7 +344,7 @@ mod tests {
|
||||||
assert!(err.missing_cycle(&cycle.canonical()));
|
assert!(err.missing_cycle(&cycle.canonical()));
|
||||||
|
|
||||||
let surface = Surface::xy_plane();
|
let surface = Surface::xy_plane();
|
||||||
let cycle = Cycle::builder(surface, &mut shape).build_polygon(triangle);
|
let cycle = Cycle::polygon_from_points(&surface, triangle);
|
||||||
|
|
||||||
// Everything has been added to `shape` now. Should work!
|
// Everything has been added to `shape` now. Should work!
|
||||||
shape.insert(Face::new(
|
shape.insert(Face::new(
|
||||||
|
|
|
@ -21,8 +21,7 @@ impl ToShape for fj::Circle {
|
||||||
// Circles have just a single round edge with no vertices. So none need
|
// Circles have just a single round edge with no vertices. So none need
|
||||||
// to be added here.
|
// to be added here.
|
||||||
|
|
||||||
let edge = Edge::builder(&mut tmp)
|
let edge = Edge::circle_from_radius(Scalar::from_f64(self.radius()));
|
||||||
.build_circle(Scalar::from_f64(self.radius()));
|
|
||||||
|
|
||||||
let cycle_local = Cycle {
|
let cycle_local = Cycle {
|
||||||
edges: vec![edge.clone()],
|
edges: vec![edge.clone()],
|
||||||
|
|
|
@ -2,7 +2,6 @@ use fj_interop::debug::DebugInfo;
|
||||||
use fj_kernel::{
|
use fj_kernel::{
|
||||||
algorithms::Tolerance,
|
algorithms::Tolerance,
|
||||||
objects::{Face, Surface},
|
objects::{Face, Surface},
|
||||||
shape::Shape,
|
|
||||||
validation::{validate, Validated, ValidationConfig, ValidationError},
|
validation::{validate, Validated, ValidationConfig, ValidationError},
|
||||||
};
|
};
|
||||||
use fj_math::{Aabb, Point};
|
use fj_math::{Aabb, Point};
|
||||||
|
@ -16,16 +15,13 @@ impl ToShape for fj::Sketch {
|
||||||
_: Tolerance,
|
_: Tolerance,
|
||||||
_: &mut DebugInfo,
|
_: &mut DebugInfo,
|
||||||
) -> Result<Validated<Vec<Face>>, ValidationError> {
|
) -> Result<Validated<Vec<Face>>, ValidationError> {
|
||||||
let mut tmp = Shape::new();
|
|
||||||
|
|
||||||
let surface = Surface::xy_plane();
|
let surface = Surface::xy_plane();
|
||||||
let points = self.to_points().into_iter().map(Point::from);
|
let points = self.to_points().into_iter().map(Point::from);
|
||||||
|
|
||||||
let sketch = Face::builder(surface, &mut tmp)
|
let sketch = Face::builder(surface)
|
||||||
.with_exterior_polygon(points)
|
.with_exterior_polygon(points)
|
||||||
.with_color(self.color())
|
.with_color(self.color())
|
||||||
.build()
|
.build();
|
||||||
.get();
|
|
||||||
|
|
||||||
validate(vec![sketch], config)
|
validate(vec![sketch], config)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue