Skip to content

Commit

Permalink
Merge pull request #733 from hannobraun/transform
Browse files Browse the repository at this point in the history
Decouple transform algorithm from `Shape`
  • Loading branch information
hannobraun authored Jun 28, 2022
2 parents e8c79ab + 5e29f60 commit 79ccdef
Show file tree
Hide file tree
Showing 4 changed files with 134 additions and 111 deletions.
2 changes: 1 addition & 1 deletion crates/fj-kernel/src/algorithms/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,6 @@ pub mod intersection;
pub use self::{
approx::{CycleApprox, FaceApprox, InvalidTolerance, Tolerance},
sweep::sweep,
transform::transform_shape,
transform::transform,
triangulation::triangulate,
};
86 changes: 4 additions & 82 deletions crates/fj-kernel/src/algorithms/sweep.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use crate::{
shape::{LocalForm, Shape},
};

use super::{CycleApprox, Tolerance};
use super::{transform::transform_cycles, CycleApprox, Tolerance};

/// Create a solid by sweeping a sketch
pub fn sweep(
Expand Down Expand Up @@ -101,9 +101,8 @@ fn create_top_face(

surface = surface.transform(&translation);

let mut tmp = Shape::new();
exteriors = transform_cycle(&exteriors, &translation, &mut tmp);
interiors = transform_cycle(&interiors, &translation, &mut tmp);
exteriors = transform_cycles(&exteriors, &translation);
interiors = transform_cycles(&interiors, &translation);

if is_sweep_along_negative_direction {
surface = surface.reverse();
Expand All @@ -112,6 +111,7 @@ fn create_top_face(
interiors = reverse_local_coordinates_in_cycle(&interiors);
};

let mut tmp = Shape::new();
let surface = tmp.insert(surface);

let face = Face::new(
Expand Down Expand Up @@ -149,84 +149,6 @@ fn reverse_local_coordinates_in_cycle(cycles: &CyclesInFace) -> CyclesInFace {
CyclesInFace::new(cycles)
}

fn transform_cycle(
cycles: &CyclesInFace,
transform: &Transform,
target: &mut Shape,
) -> CyclesInFace {
let cycles = cycles.as_local_form().map(|cycle| {
let edges_local = cycle
.local()
.edges
.iter()
.map(|edge| {
let curve_local = *edge.local().curve.local();
let curve_canonical = target
.merge(edge.canonical().get().curve().transform(transform));

let vertices = edge.canonical().get().vertices.map(|vertex| {
let point = vertex.canonical().get().point;
let point = transform.transform_point(&point);

let local = *vertex.local();
let canonical = target.merge(Vertex { point });

LocalForm::new(local, canonical)
});

let edge_local = Edge {
curve: LocalForm::new(curve_local, curve_canonical.clone()),
vertices: vertices.clone(),
};
let edge_canonical = target.merge(Edge {
curve: LocalForm::canonical_only(curve_canonical),
vertices,
});

LocalForm::new(edge_local, edge_canonical)
})
.collect();
let edges_canonical = cycle
.canonical()
.get()
.edges
.iter()
.map(|edge| {
let edge = edge.canonical().get();

let curve = {
let curve = edge.curve().transform(transform);

let curve = target.merge(curve);
LocalForm::canonical_only(curve)
};
let vertices = edge.vertices.map(|vertex| {
let point = vertex.canonical().get().point;
let point = transform.transform_point(&point);

let local = *vertex.local();
let canonical = target.merge(Vertex { point });

LocalForm::new(local, canonical)
});

let edge = target.merge(Edge { curve, vertices });
LocalForm::canonical_only(edge)
})
.collect();

let cycle_local = Cycle { edges: edges_local };

let cycle_canonical = target.merge(Cycle {
edges: edges_canonical,
});

LocalForm::new(cycle_local, cycle_canonical)
});

CyclesInFace::new(cycles)
}

fn create_non_continuous_side_face(
path: Vector<3>,
is_sweep_along_negative_direction: bool,
Expand Down
137 changes: 116 additions & 21 deletions crates/fj-kernel/src/algorithms/transform.rs
Original file line number Diff line number Diff line change
@@ -1,30 +1,125 @@
use fj_math::Transform;

use crate::{
objects::{Curve, Face, Surface, Vertex},
shape::Shape,
objects::{Cycle, CyclesInFace, Edge, Face, FaceBRep, Vertex},
shape::{LocalForm, Shape},
};

/// Transform the geometry of the shape
///
/// Since the topological types refer to geometry, and don't contain any
/// geometry themselves, this transforms the whole shape.
pub fn transform_shape(shape: &mut Shape, transform: &Transform) {
shape
.update()
.update_all(|vertex: &mut Vertex| {
vertex.point = transform.transform_point(&vertex.point)
})
.update_all(|curve: &mut Curve<3>| *curve = curve.transform(transform))
.update_all(|surface: &mut Surface| {
*surface = surface.transform(transform)
})
.update_all(|mut face: &mut Face| {
use std::ops::DerefMut as _;
if let Face::Triangles(triangles) = face.deref_mut() {
for (triangle, _) in triangles {
*triangle = transform.transform_triangle(triangle);
/// Transform a shape
pub fn transform(faces: &[Face], transform: &Transform) -> Vec<Face> {
let mut target = Vec::new();

for face in faces {
let face = match face {
Face::Face(face) => {
let mut tmp = Shape::new();
let surface = face.surface.get().transform(transform);
let surface = tmp.insert(surface);

let exteriors = transform_cycles(&face.exteriors, transform);
let interiors = transform_cycles(&face.interiors, transform);

let color = face.color;

Face::Face(FaceBRep {
surface,
exteriors,
interiors,
color,
})
}
Face::Triangles(triangles) => {
let mut target = Vec::new();

for &(triangle, color) in triangles {
let triangle = transform.transform_triangle(&triangle);
target.push((triangle, color));
}

Face::Triangles(target)
}
};
target.push(face);
}

target
}

pub fn transform_cycles(
cycles: &CyclesInFace,
transform: &Transform,
) -> CyclesInFace {
let mut tmp = Shape::new();

let cycles = cycles.as_local_form().map(|cycle| {
let edges_local = cycle
.local()
.edges
.iter()
.map(|edge| {
let curve_local = *edge.local().curve.local();
let curve_canonical = tmp
.merge(edge.canonical().get().curve().transform(transform));

let vertices = edge.canonical().get().vertices.map(|vertex| {
let point = vertex.canonical().get().point;
let point = transform.transform_point(&point);

let local = *vertex.local();
let canonical = tmp.merge(Vertex { point });

LocalForm::new(local, canonical)
});

let edge_local = Edge {
curve: LocalForm::new(curve_local, curve_canonical.clone()),
vertices: vertices.clone(),
};
let edge_canonical = tmp.merge(Edge {
curve: LocalForm::canonical_only(curve_canonical),
vertices,
});

LocalForm::new(edge_local, edge_canonical)
})
.collect();
let edges_canonical = cycle
.canonical()
.get()
.edges
.iter()
.map(|edge| {
let edge = edge.canonical().get();

let curve = {
let curve = edge.curve().transform(transform);

let curve = tmp.merge(curve);
LocalForm::canonical_only(curve)
};
let vertices = edge.vertices.map(|vertex| {
let point = vertex.canonical().get().point;
let point = transform.transform_point(&point);

let local = *vertex.local();
let canonical = tmp.merge(Vertex { point });

LocalForm::new(local, canonical)
});

let edge = tmp.merge(Edge { curve, vertices });
LocalForm::canonical_only(edge)
})
.collect();

let cycle_local = Cycle { edges: edges_local };

let cycle_canonical = tmp.merge(Cycle {
edges: edges_canonical,
});

LocalForm::new(cycle_local, cycle_canonical)
});

CyclesInFace::new(cycles)
}
20 changes: 13 additions & 7 deletions crates/fj-operations/src/transform.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use fj_interop::debug::DebugInfo;
use fj_kernel::{
algorithms::{transform_shape, Tolerance},
algorithms::{transform, Tolerance},
iter::ObjectIters,
shape::Shape,
validation::{validate, Validated, ValidationConfig, ValidationError},
};
Expand All @@ -16,22 +17,27 @@ impl ToShape for fj::Transform {
debug_info: &mut DebugInfo,
) -> Result<Validated<Shape>, ValidationError> {
let shape = self.shape.to_shape(config, tolerance, debug_info)?;
let mut shape = shape.into_inner();
let shape = shape.into_inner();

let transform = transform(self);
let shape = shape.face_iter().collect::<Vec<_>>();
let faces = transform(&shape, &make_transform(self));

transform_shape(&mut shape, &transform);
let shape = validate(shape, config)?;
let mut target = Shape::new();
for face in faces {
target.merge(face);
}

let shape = validate(target, config)?;

Ok(shape)
}

fn bounding_volume(&self) -> Aabb<3> {
transform(self).transform_aabb(&self.shape.bounding_volume())
make_transform(self).transform_aabb(&self.shape.bounding_volume())
}
}

fn transform(transform: &fj::Transform) -> Transform {
fn make_transform(transform: &fj::Transform) -> Transform {
let axis = Vector::from(transform.axis).normalize();
Transform::translation(transform.offset)
* Transform::rotation(axis * transform.angle.rad())
Expand Down

0 comments on commit 79ccdef

Please sign in to comment.