Merge pull request #733 from hannobraun/transform

Decouple transform algorithm from `Shape`
This commit is contained in:
Hanno Braun 2022-06-28 16:50:18 +02:00 committed by GitHub
commit 79ccdefbd8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 136 additions and 113 deletions

View File

@ -13,6 +13,6 @@ pub mod intersection;
pub use self::{
approx::{CycleApprox, FaceApprox, InvalidTolerance, Tolerance},
sweep::sweep,
transform::transform_shape,
transform::transform,
triangulation::triangulate,
};

View File

@ -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(
@ -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();
@ -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(
@ -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,

View File

@ -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)
}

View File

@ -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},
};
@ -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())