Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Approximate faces in surface coordinates #762

Merged
merged 3 commits into from
Jul 1, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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