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

Clean up curves #189

Merged
merged 7 commits into from
Feb 15, 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
43 changes: 27 additions & 16 deletions src/kernel/geometry/curves/circle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,20 +35,38 @@ impl Circle {
/// Converts the provided point into curve coordinates between `0.`
/// (inclusive) and `PI * 2.` (exclusive).
///
/// Ignores the radius, meaning points that are not on the circle will be
/// converted to the curve coordinate of their projection on the circle.
/// Projects the point onto the circle before computing curve coordinate,
/// ignoring the radius. This is done to make this method robust against
/// floating point accuracy issues.
///
/// 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 circle, intended or not, will not result in
/// an error.
/// Callers are advised to be careful about the points they pass, as the
/// point not being on the curve, intentional or not, will not result in an
/// error.
pub fn point_model_to_curve(&self, point: &Point<3>) -> Point<1> {
let v = point - self.center;
let atan = f64::atan2(v.y, v.x);
let coord = if atan >= 0. { atan } else { atan + PI * 2. };
point![coord]
}

/// Convert a point on the curve into model coordinates
pub fn point_curve_to_model(&self, point: &Point<1>) -> Point<3> {
self.center + self.vector_curve_to_model(&point.coords)
}

/// Convert a vector on the curve into model coordinates
pub fn vector_curve_to_model(&self, point: &Vector<1>) -> Vector<3> {
let radius = self.radius.magnitude();
let angle = point.x;

let (sin, cos) = angle.sin_cos();

let x = cos * radius;
let y = sin * radius;

vector![x, y, 0.]
}

pub fn approx(&self, tolerance: f64, out: &mut Vec<Point<3>>) {
let radius = self.radius.magnitude();

Expand All @@ -62,14 +80,7 @@ impl Circle {

for i in 0..n {
let angle = 2. * PI / n as f64 * i as f64;

let (sin, cos) = angle.sin_cos();

let x = cos * radius;
let y = sin * radius;

let point = self.center + vector![x, y, 0.];

let point = self.point_curve_to_model(&point![angle]);
out.push(point);
}
}
Expand All @@ -93,7 +104,7 @@ mod tests {
use super::Circle;

#[test]
fn test_point_model_to_curve() {
fn point_model_to_curve() {
let circle = Circle {
center: point![1., 2., 3.],
radius: vector![1., 0.],
Expand All @@ -118,7 +129,7 @@ mod tests {
}

#[test]
fn test_number_of_vertices() {
fn number_of_vertices() {
verify_result(50., 100., 3);
verify_result(10., 100., 7);
verify_result(1., 100., 23);
Expand Down
30 changes: 21 additions & 9 deletions src/kernel/geometry/curves/line.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,12 @@ impl Line {

/// Convert a point in model coordinates to curve coordinates
///
/// Ignores the distance of the point to the line, meaning points on the
/// line will be converted to the curve coordinates of their projection on
/// the line.
/// Projects the point onto the line before computing curve coordinate. This
/// is done to make this method robust against floating point accuracy
/// issues.
///
/// 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 line, intended or not, will not result in an
/// Callers are advised to be careful about the points they pass, as the
/// point not being on the line, intentional or not, will never result in an
/// error.
pub fn point_model_to_curve(&self, point: &Point<3>) -> Point<1> {
let p = point - self.origin;
Expand All @@ -46,6 +45,19 @@ impl Line {

point![t]
}

/// Convert a point on the curve into model coordinates
#[cfg(test)]
pub fn point_curve_to_model(&self, point: &Point<1>) -> Point<3> {
self.origin + self.vector_curve_to_model(&point.coords)
}

/// Convert a vector on the curve into model coordinates
#[cfg(test)]
pub fn vector_curve_to_model(&self, point: &Vector<1>) -> Vector<3> {
let t = point.x;
self.direction * t
}
}

impl AbsDiffEq for Line {
Expand Down Expand Up @@ -74,7 +86,7 @@ mod tests {
use super::Line;

#[test]
fn test_transform() {
fn transform() {
let line = Line {
origin: point![1., 0., 0.],
direction: vector![0., 1., 0.],
Expand All @@ -96,7 +108,7 @@ mod tests {
}

#[test]
fn test_point_model_to_curve() {
fn point_model_to_curve() {
let line = Line {
origin: point![1., 0., 0.],
direction: vector![2., 0., 0.],
Expand All @@ -108,7 +120,7 @@ mod tests {
verify(line, 2.);

fn verify(line: Line, t: f64) {
let point = line.origin + line.direction * t;
let point = line.point_curve_to_model(&point![t]);
let t_result = line.point_model_to_curve(&point);

assert_eq!(point![t], t_result);
Expand Down
21 changes: 10 additions & 11 deletions src/kernel/geometry/curves/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@ impl Curve {
#[must_use]
pub fn transform(self, transform: &Isometry<f64>) -> Self {
match self {
Self::Circle(circle) => Self::Circle(circle.transform(transform)),
Self::Line(line) => Self::Line(line.transform(transform)),
Self::Circle(curve) => Self::Circle(curve.transform(transform)),
Self::Line(curve) => Self::Line(curve.transform(transform)),

#[cfg(test)]
Self::Mock { .. } => todo!(),
Expand All @@ -46,18 +46,17 @@ impl Curve {

/// Convert a point in model coordinates to curve coordinates
///
/// Whether the point is actually on the curve or not will be ignored. The
/// curve coordinates of the projection of the point on the curve will be
/// returned.
///
/// 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, intended or not, will not result in an
/// error.
/// 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_model_to_curve(&self, point: &Point<3>) -> Point<1> {
match self {
Self::Circle(circle) => circle.point_model_to_curve(point),
Self::Line(line) => line.point_model_to_curve(point),
Self::Circle(curve) => curve.point_model_to_curve(point),
Self::Line(curve) => curve.point_model_to_curve(point),

#[cfg(test)]
Self::Mock { coords, .. } => coords.borrow_mut().remove(0),
Expand Down