mirror of https://github.com/hannobraun/Fornjot
Merge pull request #733 from hannobraun/transform
Decouple transform algorithm from `Shape`
This commit is contained in:
commit
79ccdefbd8
|
@ -13,6 +13,6 @@ pub mod intersection;
|
|||
pub use self::{
|
||||
approx::{CycleApprox, FaceApprox, InvalidTolerance, Tolerance},
|
||||
sweep::sweep,
|
||||
transform::transform_shape,
|
||||
transform::transform,
|
||||
triangulation::triangulate,
|
||||
};
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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())
|
||||
|
|
Loading…
Reference in New Issue