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::{
|
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,
|
||||||
};
|
};
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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())
|
||||||
|
|
Loading…
Reference in New Issue