Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Generate more correct shapes as result of 2D difference #317

Merged
merged 7 commits into from
Mar 9, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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