Skip to content

Commit

Permalink
Merge pull request #254 from hannobraun/shape
Browse files Browse the repository at this point in the history
Simplify creation of boundary representation
  • Loading branch information
hannobraun authored Feb 25, 2022
2 parents 9a69cf6 + bdc91b2 commit 4e311cd
Show file tree
Hide file tree
Showing 12 changed files with 290 additions and 309 deletions.
81 changes: 0 additions & 81 deletions src/kernel/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,84 +3,3 @@ pub mod geometry;
pub mod shapes;
pub mod topology;
pub mod triangulation;

use crate::{
debug::DebugInfo,
math::{Aabb, Scalar},
};

use self::topology::{edges::Edges, faces::Faces, vertices::Vertices};

/// Implemented by all shapes
pub trait Shape {
/// Access the axis-aligned bounding box of a shape
///
/// If a shape is empty, its [`Aabb`]'s `min` and `max` points must be equal
/// (but are otherwise not specified).
fn bounding_volume(&self) -> Aabb<3>;

/// Compute triangles to approximate the shape's faces
///
/// The shape defined by the approximated triangles must be fully contained
/// within the actual shape.
///
/// `tolerance` defines by how far this triangulation is allowed to deviate
/// from the faces' actual dimensions.
fn faces(&self, tolerance: Scalar, debug: &mut DebugInfo) -> Faces;

/// Access the edges of the shape
fn edges(&self) -> Edges;

/// Return the shape's vertices
fn vertices(&self) -> Vertices;
}

macro_rules! dispatch {
($($method:ident($($arg_name:ident: $arg_ty:ty,)*) -> $ret:ty;)*) => {
impl Shape for fj::Shape {
$(
fn $method(&self, $($arg_name: $arg_ty,)*) -> $ret {
match self {
Self::Shape2d(shape) => shape.$method($($arg_name,)*),
Self::Shape3d(shape) => shape.$method($($arg_name,)*),
}
}
)*
}

impl Shape for fj::Shape2d {
$(
fn $method(&self, $($arg_name: $arg_ty,)*) -> $ret {
match self {
Self::Circle(shape) => shape.$method($($arg_name,)*),
Self::Difference(shape) => shape.$method($($arg_name,)*),
Self::Sketch(shape) => shape.$method($($arg_name,)*),
}
}
)*
}

impl Shape for fj::Shape3d {
$(
fn $method(&self, $($arg_name: $arg_ty,)*) -> $ret {
match self {
Self::Difference(shape) => shape.$method($($arg_name,)*),
Self::Sweep(shape) => shape.$method($($arg_name,)*),
Self::Transform(shape) => shape.$method($($arg_name,)*),
Self::Union(shape) => shape.$method($($arg_name,)*),
}
}
)*
}
};
}

dispatch! {
bounding_volume() -> Aabb<3>;
faces(
tolerance: Scalar,
debug: &mut DebugInfo,
) -> Faces;
edges() -> Edges;
vertices() -> Vertices;
}
39 changes: 21 additions & 18 deletions src/kernel/shapes/circle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,34 +6,37 @@ use crate::{
edges::{Edge, Edges},
faces::{Face, Faces},
vertices::Vertices,
Shape,
},
Shape,
},
math::{Aabb, Point, Scalar},
};

impl Shape for fj::Circle {
fn bounding_volume(&self) -> Aabb<3> {
Aabb {
min: Point::from([-self.radius, -self.radius, 0.0]),
max: Point::from([self.radius, self.radius, 0.0]),
}
}
use super::ToShape;

impl ToShape for fj::Circle {
fn to_shape(&self, _: Scalar, _: &mut DebugInfo) -> Shape {
// Circles have just a single round edge with no vertices.
let vertices = Vertices(Vec::new());

fn faces(&self, _: Scalar, _: &mut DebugInfo) -> Faces {
let edges = Edges::single_cycle([Edge::circle(self.radius)]);
Faces(vec![Face::Face {
edges,

let faces = Faces(vec![Face::Face {
edges: edges.clone(),
surface: Surface::x_y_plane(),
}])
}
}]);

fn edges(&self) -> Edges {
Edges::single_cycle([Edge::circle(self.radius)])
Shape {
vertices,
edges,
faces,
}
}

fn vertices(&self) -> Vertices {
// Circles have just a single round edge with no vertices.
Vertices(Vec::new())
fn bounding_volume(&self) -> Aabb<3> {
Aabb {
min: Point::from([-self.radius, -self.radius, 0.0]),
max: Point::from([self.radius, self.radius, 0.0]),
}
}
}
140 changes: 70 additions & 70 deletions src/kernel/shapes/difference_2d.rs
Original file line number Diff line number Diff line change
@@ -1,95 +1,95 @@
use crate::{
debug::DebugInfo,
kernel::{
topology::{
edges::Edges,
faces::{Face, Faces},
vertices::Vertices,
},
kernel::topology::{
edges::Edges,
faces::{Face, Faces},
vertices::Vertices,
Shape,
},
math::{Aabb, Scalar},
};

impl Shape for fj::Difference2d {
fn bounding_volume(&self) -> Aabb<3> {
// This is a conservative estimate of the bounding box: It's never going
// to be bigger than the bounding box of the original shape that another
// is being subtracted from.
self.a.bounding_volume()
}
use super::ToShape;

fn faces(&self, tolerance: Scalar, debug_info: &mut DebugInfo) -> Faces {
impl ToShape for fj::Difference2d {
fn to_shape(&self, tolerance: Scalar, debug_info: &mut DebugInfo) -> Shape {
// This method assumes that `b` is fully contained within `a`:
// https://github.com/hannobraun/Fornjot/issues/92

let mut a = self.a.faces(tolerance, debug_info);
let mut b = self.b.faces(tolerance, debug_info);
let mut a = self.a.to_shape(tolerance, debug_info);
let mut b = self.b.to_shape(tolerance, debug_info);

let (a, b) = if a.0.len() == 1 && b.0.len() == 1 {
// Can't panic. We just checked that length of `a` and `b` is 1.
(a.0.pop().unwrap(), b.0.pop().unwrap())
} else {
// See issue:
// https://github.com/hannobraun/Fornjot/issues/95
todo!(
"The 2-dimensional difference operation only supports one face \
in each operand."
);
};
let edges = {
let (a, b) = if a.edges.cycles.len() == 1
&& b.edges.cycles.len() == 1
{
(a.edges.cycles.pop().unwrap(), b.edges.cycles.pop().unwrap())
} else {
// See issue:
// https://github.com/hannobraun/Fornjot/issues/95
todo!(
"The 2-dimensional difference operation only supports one \
cycle in each operand."
);
};

let (a, b, surface_a, surface_b) = match (a, b) {
(
Face::Face {
edges: a,
surface: surface_a,
},
Face::Face {
edges: b,
surface: surface_b,
},
) => (a, b, surface_a, surface_b),
_ => {
// None of the 2D types still use the triangles representation.
unreachable!()
}
Edges { cycles: vec![a, b] }
};

if surface_a != surface_b {
// Panicking is not great, but as long as we don't have a real error
// handling mechanism, it will do.
panic!("Trying to subtract sketches with different surfaces.")
}
let surface = surface_a;

let mut edges = a;
edges.cycles.extend(b.cycles);
let faces = {
let (a, b) = if a.faces.0.len() == 1 && b.faces.0.len() == 1 {
// Can't panic. We just checked that length of `a` and `b` is 1.
(a.faces.0.pop().unwrap(), b.faces.0.pop().unwrap())
} else {
// See issue:
// https://github.com/hannobraun/Fornjot/issues/95
todo!(
"The 2-dimensional difference operation only supports one \
face in each operand."
);
};

Faces(vec![Face::Face { edges, surface }])
}
let (a, b, surface_a, surface_b) = match (a, b) {
(
Face::Face {
edges: a,
surface: surface_a,
},
Face::Face {
edges: b,
surface: surface_b,
},
) => (a, b, surface_a, surface_b),
_ => {
// None of the 2D types still use the triangles representation.
unreachable!()
}
};

fn edges(&self) -> Edges {
// This method assumes that `b` is fully contained within `a`:
// https://github.com/hannobraun/Fornjot/issues/92
if surface_a != surface_b {
// Panicking is not great, but as long as we don't have a real
// error handling mechanism, it will do.
panic!("Trying to subtract sketches with different surfaces.")
}
let surface = surface_a;

let mut a = self.a.edges();
let mut b = self.b.edges();
let mut edges = a;
edges.cycles.extend(b.cycles);

let (a, b) = if a.cycles.len() == 1 && b.cycles.len() == 1 {
(a.cycles.pop().unwrap(), b.cycles.pop().unwrap())
} else {
// See issue:
// https://github.com/hannobraun/Fornjot/issues/95
todo!(
"The 2-dimensional difference operation only supports one \
cycle in each operand."
);
Faces(vec![Face::Face { edges, surface }])
};

Edges { cycles: vec![a, b] }
Shape {
vertices: Vertices(Vec::new()),
edges,
faces,
}
}

fn vertices(&self) -> Vertices {
todo!()
fn bounding_volume(&self) -> Aabb<3> {
// This is a conservative estimate of the bounding box: It's never going
// to be bigger than the bounding box of the original shape that another
// is being subtracted from.
self.a.bounding_volume()
}
}
29 changes: 12 additions & 17 deletions src/kernel/shapes/difference_3d.rs
Original file line number Diff line number Diff line change
@@ -1,29 +1,24 @@
use crate::{
debug::DebugInfo,
kernel::{
topology::{edges::Edges, faces::Faces, vertices::Vertices},
Shape,
},
kernel::topology::{edges::Edges, faces::Faces, vertices::Vertices, Shape},
math::{Aabb, Scalar},
};

impl Shape for fj::Difference {
use super::ToShape;

impl ToShape for fj::Difference {
fn to_shape(&self, _: Scalar, _: &mut DebugInfo) -> Shape {
Shape {
vertices: Vertices(Vec::new()),
edges: Edges { cycles: Vec::new() },
faces: Faces(Vec::new()),
}
}

fn bounding_volume(&self) -> Aabb<3> {
// This is a conservative estimate of the bounding box: It's never going
// to be bigger than the bounding box of the original shape that another
// is being subtracted from.
self.a.bounding_volume()
}

fn faces(&self, _tolerance: Scalar, _: &mut DebugInfo) -> Faces {
todo!()
}

fn edges(&self) -> Edges {
todo!()
}

fn vertices(&self) -> Vertices {
todo!()
}
}
Loading

0 comments on commit 4e311cd

Please sign in to comment.