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::{ pub use self::{
approx::{CycleApprox, FaceApprox, InvalidTolerance, Tolerance}, approx::{CycleApprox, FaceApprox, InvalidTolerance, Tolerance},
sweep::sweep, sweep::sweep,
transform::transform_shape, transform::transform,
triangulation::triangulate, triangulation::triangulate,
}; };

View File

@ -8,7 +8,7 @@ use crate::{
shape::{LocalForm, Shape}, shape::{LocalForm, Shape},
}; };
use super::{CycleApprox, Tolerance}; use super::{transform::transform_cycles, CycleApprox, Tolerance};
/// Create a solid by sweeping a sketch /// Create a solid by sweeping a sketch
pub fn sweep( pub fn sweep(
@ -101,9 +101,8 @@ fn create_top_face(
surface = surface.transform(&translation); surface = surface.transform(&translation);
let mut tmp = Shape::new(); exteriors = transform_cycles(&exteriors, &translation);
exteriors = transform_cycle(&exteriors, &translation, &mut tmp); interiors = transform_cycles(&interiors, &translation);
interiors = transform_cycle(&interiors, &translation, &mut tmp);
if is_sweep_along_negative_direction { if is_sweep_along_negative_direction {
surface = surface.reverse(); surface = surface.reverse();
@ -112,6 +111,7 @@ fn create_top_face(
interiors = reverse_local_coordinates_in_cycle(&interiors); interiors = reverse_local_coordinates_in_cycle(&interiors);
}; };
let mut tmp = Shape::new();
let surface = tmp.insert(surface); let surface = tmp.insert(surface);
let face = Face::new( let face = Face::new(
@ -149,84 +149,6 @@ fn reverse_local_coordinates_in_cycle(cycles: &CyclesInFace) -> CyclesInFace {
CyclesInFace::new(cycles) 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( fn create_non_continuous_side_face(
path: Vector<3>, path: Vector<3>,
is_sweep_along_negative_direction: bool, is_sweep_along_negative_direction: bool,

View File

@ -1,30 +1,125 @@
use fj_math::Transform; use fj_math::Transform;
use crate::{ use crate::{
objects::{Curve, Face, Surface, Vertex}, objects::{Cycle, CyclesInFace, Edge, Face, FaceBRep, Vertex},
shape::Shape, shape::{LocalForm, Shape},
}; };
/// Transform the geometry of the shape /// Transform a shape
/// pub fn transform(faces: &[Face], transform: &Transform) -> Vec<Face> {
/// Since the topological types refer to geometry, and don't contain any let mut target = Vec::new();
/// geometry themselves, this transforms the whole shape.
pub fn transform_shape(shape: &mut Shape, transform: &Transform) { for face in faces {
shape let face = match face {
.update() Face::Face(face) => {
.update_all(|vertex: &mut Vertex| { let mut tmp = Shape::new();
vertex.point = transform.transform_point(&vertex.point) 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,
}) })
.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);
} }
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_interop::debug::DebugInfo;
use fj_kernel::{ use fj_kernel::{
algorithms::{transform_shape, Tolerance}, algorithms::{transform, Tolerance},
iter::ObjectIters,
shape::Shape, shape::Shape,
validation::{validate, Validated, ValidationConfig, ValidationError}, validation::{validate, Validated, ValidationConfig, ValidationError},
}; };
@ -16,22 +17,27 @@ impl ToShape for fj::Transform {
debug_info: &mut DebugInfo, debug_info: &mut DebugInfo,
) -> Result<Validated<Shape>, ValidationError> { ) -> Result<Validated<Shape>, ValidationError> {
let shape = self.shape.to_shape(config, tolerance, debug_info)?; 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 mut target = Shape::new();
let shape = validate(shape, config)?; for face in faces {
target.merge(face);
}
let shape = validate(target, config)?;
Ok(shape) Ok(shape)
} }
fn bounding_volume(&self) -> Aabb<3> { 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(); let axis = Vector::from(transform.axis).normalize();
Transform::translation(transform.offset) Transform::translation(transform.offset)
* Transform::rotation(axis * transform.angle.rad()) * Transform::rotation(axis * transform.angle.rad())