Skip to content

Commit

Permalink
Merge pull request #824 from hannobraun/shape
Browse files Browse the repository at this point in the history
Make use of `Sketch` and `Solid` in `fj-operations`
  • Loading branch information
hannobraun authored Jul 15, 2022
2 parents f1f0742 + ee6b24a commit a1c6e4c
Show file tree
Hide file tree
Showing 6 changed files with 124 additions and 74 deletions.
16 changes: 7 additions & 9 deletions crates/fj-operations/src/difference_2d.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,24 +3,26 @@ use fj_kernel::{
algorithms::Tolerance,
iter::ObjectIters,
local::Local,
objects::{Cycle, Edge, Face},
objects::{Cycle, Edge, Face, Sketch},
validation::{validate, Validated, ValidationConfig, ValidationError},
};
use fj_math::Aabb;

use super::Shape;

impl Shape for fj::Difference2d {
type Brep = Sketch;

fn compute_brep(
&self,
config: &ValidationConfig,
tolerance: Tolerance,
debug_info: &mut DebugInfo,
) -> Result<Validated<Vec<Face>>, ValidationError> {
) -> Result<Validated<Self::Brep>, ValidationError> {
// This method assumes that `b` is fully contained within `a`:
// https://github.com/hannobraun/Fornjot/issues/92

let mut difference = Vec::new();
let mut faces = Vec::new();

let mut exteriors = Vec::new();
let mut interiors = Vec::new();
Expand Down Expand Up @@ -72,14 +74,10 @@ impl Shape for fj::Difference2d {
}
}

difference.push(Face::new(
surface,
exteriors,
interiors,
self.color(),
));
faces.push(Face::new(surface, exteriors, interiors, self.color()));
}

let difference = Sketch::from_faces(faces);
validate(difference, config)
}

Expand Down
15 changes: 9 additions & 6 deletions crates/fj-operations/src/group.rs
Original file line number Diff line number Diff line change
@@ -1,29 +1,32 @@
use fj_interop::debug::DebugInfo;
use fj_kernel::{
algorithms::Tolerance,
objects::Face,
objects::Solid,
validation::{validate, Validated, ValidationConfig, ValidationError},
};
use fj_math::Aabb;

use super::Shape;

impl Shape for fj::Group {
type Brep = Solid;

fn compute_brep(
&self,
config: &ValidationConfig,
tolerance: Tolerance,
debug_info: &mut DebugInfo,
) -> Result<Validated<Vec<Face>>, ValidationError> {
let mut shape = Vec::new();
) -> Result<Validated<Self::Brep>, ValidationError> {
let mut faces = Vec::new();

let a = self.a.compute_brep(config, tolerance, debug_info)?;
let b = self.b.compute_brep(config, tolerance, debug_info)?;

shape.extend(a.into_inner());
shape.extend(b.into_inner());
faces.extend(a.into_inner().into_faces());
faces.extend(b.into_inner().into_faces());

validate(shape, config)
let group = Solid::from_faces(faces);
validate(group, config)
}

fn bounding_volume(&self) -> Aabb<3> {
Expand Down
125 changes: 87 additions & 38 deletions crates/fj-operations/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,20 +27,23 @@ mod transform;
use fj_interop::debug::DebugInfo;
use fj_kernel::{
algorithms::Tolerance,
objects::Face,
validation::{Validated, ValidationConfig, ValidationError},
objects::{Face, Sketch, Solid},
validation::{validate, Validated, ValidationConfig, ValidationError},
};
use fj_math::Aabb;

/// Implemented for all operations from the [`fj`] crate
pub trait Shape {
/// The type that is used for the shape's boundary representation
type Brep;

/// Compute the boundary representation of the shape
fn compute_brep(
&self,
config: &ValidationConfig,
tolerance: Tolerance,
debug_info: &mut DebugInfo,
) -> Result<Validated<Vec<Face>>, ValidationError>;
) -> Result<Validated<Self::Brep>, ValidationError>;

/// Access the axis-aligned bounding box of a shape
///
Expand All @@ -49,49 +52,95 @@ pub trait Shape {
fn bounding_volume(&self) -> Aabb<3>;
}

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::Shape {
type Brep = Vec<Face>;

fn compute_brep(
&self,
config: &ValidationConfig,
tolerance: Tolerance,
debug_info: &mut DebugInfo,
) -> Result<Validated<Self::Brep>, ValidationError> {
match self {
Self::Shape2d(shape) => validate(
shape
.compute_brep(config, tolerance, debug_info)?
.into_inner()
.into_faces(),
config,
),
Self::Shape3d(shape) => validate(
shape
.compute_brep(config, tolerance, debug_info)?
.into_inner()
.into_faces(),
config,
),
}
}

fn bounding_volume(&self) -> Aabb<3> {
match self {
Self::Shape2d(shape) => shape.bounding_volume(),
Self::Shape3d(shape) => shape.bounding_volume(),
}
}
}

impl Shape for fj::Shape2d {
type Brep = Sketch;

impl Shape for fj::Shape2d {
$(
fn $method(&self, $($arg_name: $arg_ty,)*) -> $ret {
match self {
Self::Difference(shape) => shape.$method($($arg_name,)*),
Self::Sketch(shape) => shape.$method($($arg_name,)*),
}
}
)*
fn compute_brep(
&self,
config: &ValidationConfig,
tolerance: Tolerance,
debug_info: &mut DebugInfo,
) -> Result<Validated<Self::Brep>, ValidationError> {
match self {
Self::Difference(shape) => {
shape.compute_brep(config, tolerance, debug_info)
}
Self::Sketch(shape) => {
shape.compute_brep(config, tolerance, debug_info)
}
}
}

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

dispatch! {
compute_brep(
impl Shape for fj::Shape3d {
type Brep = Solid;

fn compute_brep(
&self,
config: &ValidationConfig,
tolerance: Tolerance,
debug_info: &mut DebugInfo,
) -> Result<Validated<Vec<Face>>, ValidationError>;
bounding_volume() -> Aabb<3>;
) -> Result<Validated<Self::Brep>, ValidationError> {
match self {
Self::Group(shape) => {
shape.compute_brep(config, tolerance, debug_info)
}
Self::Sweep(shape) => {
shape.compute_brep(config, tolerance, debug_info)
}
Self::Transform(shape) => {
shape.compute_brep(config, tolerance, debug_info)
}
}
}

fn bounding_volume(&self) -> Aabb<3> {
match self {
Self::Group(shape) => shape.bounding_volume(),
Self::Sweep(shape) => shape.bounding_volume(),
Self::Transform(shape) => shape.bounding_volume(),
}
}
}
11 changes: 7 additions & 4 deletions crates/fj-operations/src/sketch.rs
Original file line number Diff line number Diff line change
@@ -1,23 +1,25 @@
use fj_interop::debug::DebugInfo;
use fj_kernel::{
algorithms::Tolerance,
objects::{Cycle, Edge, Face, Surface},
objects::{Cycle, Edge, Face, Sketch, Surface},
validation::{validate, Validated, ValidationConfig, ValidationError},
};
use fj_math::{Aabb, Point, Scalar};

use super::Shape;

impl Shape for fj::Sketch {
type Brep = Sketch;

fn compute_brep(
&self,
config: &ValidationConfig,
_: Tolerance,
_: &mut DebugInfo,
) -> Result<Validated<Vec<Face>>, ValidationError> {
) -> Result<Validated<Self::Brep>, ValidationError> {
let surface = Surface::xy_plane();

let sketch = match self.chain() {
let face = match self.chain() {
fj::Chain::Circle(circle) => {
// Circles have just a single round edge with no vertices. So
// none need to be added here.
Expand All @@ -39,7 +41,8 @@ impl Shape for fj::Sketch {
}
};

validate(vec![sketch], config)
let sketch = Sketch::from_faces([face]);
validate(sketch, config)
}

fn bounding_volume(&self) -> Aabb<3> {
Expand Down
16 changes: 6 additions & 10 deletions crates/fj-operations/src/sweep.rs
Original file line number Diff line number Diff line change
@@ -1,33 +1,29 @@
use fj_interop::debug::DebugInfo;
use fj_kernel::{
algorithms::{sweep, Tolerance},
objects::{Face, Sketch},
objects::Solid,
validation::{validate, Validated, ValidationConfig, ValidationError},
};
use fj_math::{Aabb, Vector};

use super::Shape;

impl Shape for fj::Sweep {
type Brep = Solid;

fn compute_brep(
&self,
config: &ValidationConfig,
tolerance: Tolerance,
debug_info: &mut DebugInfo,
) -> Result<Validated<Vec<Face>>, ValidationError> {
) -> Result<Validated<Self::Brep>, ValidationError> {
let sketch =
self.shape().compute_brep(config, tolerance, debug_info)?;
let path = Vector::from(self.path());
let color = self.shape().color();

let solid = sweep(
Sketch::from_faces(sketch.into_inner()),
path,
tolerance,
color,
);

validate(solid.into_faces(), config)
let solid = sweep(sketch.into_inner(), path, tolerance, color);
validate(solid, config)
}

fn bounding_volume(&self) -> Aabb<3> {
Expand Down
15 changes: 8 additions & 7 deletions crates/fj-operations/src/transform.rs
Original file line number Diff line number Diff line change
@@ -1,28 +1,29 @@
use fj_interop::debug::DebugInfo;
use fj_kernel::{
algorithms::{transform_faces, Tolerance},
objects::Face,
algorithms::{Tolerance, TransformObject},
objects::Solid,
validation::{validate, Validated, ValidationConfig, ValidationError},
};
use fj_math::{Aabb, Transform, Vector};

use super::Shape;

impl Shape for fj::Transform {
type Brep = Solid;

fn compute_brep(
&self,
config: &ValidationConfig,
tolerance: Tolerance,
debug_info: &mut DebugInfo,
) -> Result<Validated<Vec<Face>>, ValidationError> {
let mut shape = self
) -> Result<Validated<Self::Brep>, ValidationError> {
let original = self
.shape
.compute_brep(config, tolerance, debug_info)?
.into_inner();

transform_faces(&mut shape, &make_transform(self));

validate(shape, config)
let transformed = original.transform(&make_transform(self));
validate(transformed, config)
}

fn bounding_volume(&self) -> Aabb<3> {
Expand Down

0 comments on commit a1c6e4c

Please sign in to comment.