Skip to content

Commit

Permalink
Merge pull request #317 from hannobraun/diff
Browse files Browse the repository at this point in the history
Generate more correct shapes as result of 2D difference
  • Loading branch information
hannobraun authored Mar 9, 2022
2 parents f2f27e2 + 0445620 commit c4bcfdc
Show file tree
Hide file tree
Showing 6 changed files with 142 additions and 14 deletions.
51 changes: 48 additions & 3 deletions src/kernel/shape/cycles.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,36 @@ use crate::kernel::topology::edges::Cycle;

use super::{
handle::{Handle, Storage},
CyclesInner,
CyclesInner, EdgesInner,
};

/// The cycles of a shape
pub struct Cycles<'r> {
pub(super) edges: &'r mut EdgesInner,
pub(super) cycles: &'r mut CyclesInner,
}

impl Cycles<'_> {
/// Add a cycle to the shape
///
/// # Panics
///
/// Panics, if the edges of the cycles are not part of this shape.
///
/// # Implementation note
///
/// This method should at some point validate the cycle:
/// - That it refers to valid edges that are part of `Shape`.
/// The validation of the cycle should be extended to cover more cases:
/// - That those edges form a cycle.
/// - That the cycle is not self-overlapping.
/// - That there exists no duplicate cycle, with the same edges.
pub fn add(&mut self, cycle: Cycle) -> Handle<Cycle> {
for edge in &cycle.edges {
assert!(
self.edges.contains(edge.storage()),
"Cycle validation failed: {edge:?} is not part of the shape",
);
}

let storage = Storage::new(cycle);
let handle = storage.handle();
self.cycles.push(storage);
Expand All @@ -33,3 +44,37 @@ impl Cycles<'_> {
self.cycles.iter().map(|storage| storage.handle())
}
}

#[cfg(test)]
mod tests {
use crate::{
kernel::{shape::Shape, topology::edges::Cycle},
math::Point,
};

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

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

let edge = shape.edges().add_line_segment([a, b]);

shape.cycles().add(Cycle { edges: vec![edge] });
}

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

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

let edge = other.edges().add_line_segment([a, b]);

shape.cycles().add(Cycle { edges: vec![edge] });
}
}
50 changes: 47 additions & 3 deletions src/kernel/shape/edges.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,17 @@ use crate::{
use super::{
curves::Curves,
handle::{Handle, Storage},
EdgesInner, VerticesInner,
};

/// The edges of a shape
pub struct Edges {
pub struct Edges<'r> {
pub(super) curves: Curves,
pub(super) vertices: &'r mut VerticesInner,
pub(super) edges: &'r mut EdgesInner,
}

impl Edges {
impl Edges<'_> {
/// Add an edge to the shape
///
/// If vertices are provided in `vertices`, they must be on `curve`.
Expand All @@ -32,7 +35,21 @@ impl Edges {
/// the future, it can add the edge to the proper internal data structures,
/// and validate any constraints that apply to edge creation.
pub fn add(&mut self, edge: Edge) -> Handle<Edge> {
Storage::new(edge).handle()
for vertices in &edge.vertices {
for vertex in vertices {
assert!(
self.vertices.contains(vertex.storage()),
"Edge validation failed: {vertex:?} is not part of shape",
);
}
}

let storage = Storage::new(edge);
let handle = storage.handle();

self.edges.push(storage);

handle
}

/// Add a circle to the shape
Expand Down Expand Up @@ -67,3 +84,30 @@ impl Edges {
})
}
}

#[cfg(test)]
mod tests {
use crate::{kernel::shape::Shape, math::Point};

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

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

shape.edges().add_line_segment([a, b]);
}

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

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

shape.edges().add_line_segment([a, b]);
}
}
5 changes: 5 additions & 0 deletions src/kernel/shape/handle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,11 @@ impl<T> Handle<T> {
pub fn get(&self) -> &T {
self.0.deref()
}

/// Internal method to access the [`Storage`] this handle refers to
pub(super) fn storage(&self) -> &Storage<T> {
&self.0
}
}

impl<T> Deref for Handle<T> {
Expand Down
16 changes: 14 additions & 2 deletions src/kernel/shape/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,11 @@ pub mod vertices;

use crate::math::Scalar;

use super::topology::{edges::Cycle, faces::Face, vertices::Vertex};
use super::topology::{
edges::{Cycle, Edge},
faces::Face,
vertices::Vertex,
};

use self::{
curves::Curves, cycles::Cycles, edges::Edges, faces::Faces,
Expand All @@ -24,6 +28,7 @@ pub struct Shape {
min_distance: Scalar,

vertices: VerticesInner,
edges: EdgesInner,
cycles: CyclesInner,
faces: FacesInner,
}
Expand All @@ -38,6 +43,7 @@ impl Shape {
min_distance: Scalar::from_f64(5e-7), // 0.5 µm

vertices: VerticesInner::new(),
edges: EdgesInner::new(),
cycles: CyclesInner::new(),
faces: FacesInner::new(),
}
Expand Down Expand Up @@ -78,12 +84,17 @@ impl Shape {

/// Access the shape's edges
pub fn edges(&mut self) -> Edges {
Edges { curves: Curves }
Edges {
curves: Curves,
vertices: &mut self.vertices,
edges: &mut self.edges,
}
}

/// Access the shape's cycles
pub fn cycles(&mut self) -> Cycles {
Cycles {
edges: &mut self.edges,
cycles: &mut self.cycles,
}
}
Expand All @@ -97,5 +108,6 @@ impl Shape {
}

type VerticesInner = Vec<Storage<Vertex>>;
type EdgesInner = Vec<Storage<Edge>>;
type CyclesInner = Vec<Storage<Cycle>>;
type FacesInner = Vec<Storage<Face>>;
4 changes: 2 additions & 2 deletions src/kernel/shape/vertices.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ mod tests {
const MIN_DISTANCE: f64 = 5e-7;

#[test]
fn create_valid() {
fn add_valid() {
let mut shape = Shape::new().with_min_distance(MIN_DISTANCE);

shape.vertices().add(Point::from([0., 0., 0.]));
Expand All @@ -76,7 +76,7 @@ mod tests {
#[test]
#[ignore]
#[should_panic]
fn create_invalid() {
fn add_invalid() {
// Test is ignored, until vertex validation can be enabled for real.
// See implementation note on `Vertices::create`.

Expand Down
30 changes: 26 additions & 4 deletions src/kernel/shapes/difference_2d.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
use std::collections::HashMap;

use crate::{
debug::DebugInfo,
kernel::{
shape::Shape,
topology::{edges::Cycle, faces::Face},
topology::{
edges::{Cycle, Edge},
faces::Face,
},
},
math::{Aabb, Scalar},
};
Expand Down Expand Up @@ -42,10 +47,27 @@ impl ToShape for fj::Difference2d {
let cycles =
[&mut a, &mut b].map(|shape| shape.cycles().all().next().unwrap());

let mut vertices = HashMap::new();
for cycle in cycles {
shape.cycles().add(Cycle {
edges: cycle.edges.clone(),
});
let mut edges = Vec::new();
for edge in &cycle.edges {
let curve = shape.curves().add(*edge.curve.get());

let vertices = edge.vertices.clone().map(|vs| {
vs.map(|vertex| {
let vertex = *vertex.get();
vertices
.entry(vertex)
.or_insert_with(|| shape.vertices().add(vertex))
.clone()
})
});

let edge = shape.edges().add(Edge { curve, vertices });
edges.push(edge);
}

shape.cycles().add(Cycle { edges });
}

// Can't panic, as we just verified that both shapes have one face.
Expand Down

0 comments on commit c4bcfdc

Please sign in to comment.