Skip to content

Commit

Permalink
Merge pull request #762 from hannobraun/approx
Browse files Browse the repository at this point in the history
Approximate faces in surface coordinates
  • Loading branch information
hannobraun authored Jul 1, 2022
2 parents 4415967 + 1ef9290 commit 5c531ce
Show file tree
Hide file tree
Showing 5 changed files with 37 additions and 116 deletions.
19 changes: 11 additions & 8 deletions crates/fj-kernel/src/algorithms/approx/cycles.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
use fj_math::{Point, Segment};

use crate::objects::Cycle;
use crate::{local::Local, objects::Cycle};

use super::{curves::approx_curve, edges::approx_edge, Tolerance};

/// An approximation of a [`Cycle`]
#[derive(Debug, Eq, PartialEq, Hash)]
pub struct CycleApprox {
/// The points that approximate the cycle
pub points: Vec<Point<3>>,
pub points: Vec<Local<Point<2>>>,
}

impl CycleApprox {
Expand All @@ -24,13 +24,16 @@ impl CycleApprox {
approx_curve(&edge.curve(), tolerance, &mut edge_points);
approx_edge(edge.vertices.clone(), &mut edge_points);

points.extend(edge_points);
points.extend(edge_points.into_iter().map(|point| {
let local =
edge.curve.local().point_from_curve_coords(point.local());
Local::new(local, point.global())
}));
}

let mut points: Vec<_> =
points.into_iter().map(|point| point.global()).collect();

points.dedup();
// Can't just rely on `dedup`, as the conversion from curve coordinates
// could lead to subtly different surface coordinates.
points.dedup_by(|a, b| a.global() == b.global());

Self { points }
}
Expand All @@ -44,7 +47,7 @@ impl CycleApprox {
// up, once `array_windows` is stable.
let segment = [segment[0], segment[1]];

segments.push(Segment::from(segment));
segments.push(Segment::from(segment.map(|point| point.global())));
}

segments
Expand Down
25 changes: 14 additions & 11 deletions crates/fj-kernel/src/algorithms/approx/faces.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use std::collections::HashSet;

use fj_math::Point;

use crate::objects::Face;
use crate::{local::Local, objects::Face};

use super::{CycleApprox, Tolerance};

Expand All @@ -13,7 +13,7 @@ pub struct FaceApprox {
///
/// These could be actual vertices from the model, points that approximate
/// an edge, or points that approximate a face.
pub points: HashSet<Point<3>>,
pub points: HashSet<Local<Point<2>>>,

/// Approximation of the exterior cycle
pub exterior: CycleApprox,
Expand Down Expand Up @@ -83,7 +83,10 @@ mod tests {
use fj_math::{Point, Scalar};
use map_macro::set;

use crate::objects::{Face, Surface};
use crate::{
local::Local,
objects::{Face, Surface},
};

use super::{CycleApprox, FaceApprox, Tolerance};

Expand All @@ -108,14 +111,14 @@ mod tests {
.with_interior_polygon([e, f, g, h])
.build();

let a = a.to_xyz();
let b = b.to_xyz();
let c = c.to_xyz();
let d = d.to_xyz();
let e = e.to_xyz();
let f = f.to_xyz();
let g = g.to_xyz();
let h = h.to_xyz();
let a = Local::new(a, a.to_xyz());
let b = Local::new(b, b.to_xyz());
let c = Local::new(c, c.to_xyz());
let d = Local::new(d, d.to_xyz());
let e = Local::new(e, e.to_xyz());
let f = Local::new(f, f.to_xyz());
let g = Local::new(g, g.to_xyz());
let h = Local::new(h, h.to_xyz());

let approx = FaceApprox::new(&face, tolerance);
let expected = FaceApprox {
Expand Down
34 changes: 12 additions & 22 deletions crates/fj-kernel/src/algorithms/triangulate/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,31 +25,21 @@ pub fn triangulate(
let surface = brep.surface;
let approx = FaceApprox::new(&face, tolerance);

let points: Vec<_> = approx
.points
.into_iter()
.map(|vertex| {
// Can't panic, unless the approximation wrongfully
// generates points that are not in the surface.
surface.point_to_surface_coords(vertex)
})
.collect();
let points: Vec<_> = approx.points.into_iter().collect();
let face_as_polygon = Polygon::new(surface)
.with_exterior(approx.exterior.points.into_iter().map(
|point| {
// Can't panic, unless the approximation wrongfully
// generates points that are not in the surface.
surface.point_to_surface_coords(point).local()
},
))
.with_exterior(
approx
.exterior
.points
.into_iter()
.map(|point| point.local()),
)
.with_interiors(approx.interiors.into_iter().map(
|interior| {
interior.points.into_iter().map(|point| {
// Can't panic, unless the approximation
// wrongfully generates points that are not in
// the surface.
surface.point_to_surface_coords(point).local()
})
interior
.points
.into_iter()
.map(|point| point.local())
},
));

Expand Down
21 changes: 0 additions & 21 deletions crates/fj-kernel/src/objects/curve.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,27 +47,6 @@ impl<const D: usize> Curve<D> {
}
}

/// Convert a point in model coordinates to curve coordinates
///
/// Projects the point onto the curve before computing curve coordinate.
/// This is done to make this method robust against floating point accuracy
/// issues.
///
/// Callers are advised to be careful about the points they pass, as the
/// point not being on the curve, intentional or not, will never result in
/// an error.
pub fn point_to_curve_coords(
&self,
point: impl Into<Point<D>>,
) -> Point<1> {
let point = point.into();

match self {
Self::Circle(curve) => curve.point_to_circle_coords(point),
Self::Line(curve) => curve.point_to_line_coords(point),
}
}

/// Convert a point on the curve into model coordinates
pub fn point_from_curve_coords(
&self,
Expand Down
54 changes: 0 additions & 54 deletions crates/fj-kernel/src/objects/surface.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
use fj_math::{Line, Point, Transform, Vector};

use crate::local::Local;

use super::Curve;

/// A two-dimensional shape
Expand Down Expand Up @@ -64,22 +62,6 @@ impl Surface {
}
}

/// Convert a point in model coordinates to surface coordinates
pub fn point_to_surface_coords(
&self,
point_3d: impl Into<Point<3>>,
) -> Local<Point<2>> {
let point_3d = point_3d.into();

let point_2d = match self {
Self::SweptCurve(surface) => {
surface.point_to_surface_coords(point_3d)
}
};

Local::new(point_2d, point_3d)
}

/// Convert a point in surface coordinates to model coordinates
pub fn point_from_surface_coords(
&self,
Expand Down Expand Up @@ -131,19 +113,6 @@ impl SweptCurve {
self
}

/// Convert a point in model coordinates to surface coordinates
pub fn point_to_surface_coords(
&self,
point: impl Into<Point<3>>,
) -> Point<2> {
let point = point.into();

let u = self.curve.point_to_curve_coords(point).t;
let v = self.path_to_line().point_to_line_coords(point).t;

Point::from([u, v])
}

/// Convert a point in surface coordinates to model coordinates
pub fn point_from_surface_coords(
&self,
Expand Down Expand Up @@ -203,29 +172,6 @@ mod tests {
assert_eq!(expected, reversed);
}

#[test]
fn point_to_surface_coords() {
let plane = SweptCurve {
curve: Curve::Line(Line {
origin: Point::from([1., 0., 0.]),
direction: Vector::from([0., 2., 0.]),
}),
path: Vector::from([0., 0., 3.]),
};

verify(&plane, Point::from([-1., -1.]));
verify(&plane, Point::from([0., 0.]));
verify(&plane, Point::from([1., 1.]));
verify(&plane, Point::from([2., 3.]));

fn verify(swept: &SweptCurve, surface_point: Point<2>) {
let point = swept.point_from_surface_coords(surface_point);
let result = swept.point_to_surface_coords(point);

assert_eq!(result, surface_point);
}
}

#[test]
fn point_from_surface_coords() {
let swept = SweptCurve {
Expand Down

0 comments on commit 5c531ce

Please sign in to comment.