From a5bcc387600cc5be431aa87b52cd3d64cc34008a Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Fri, 26 Aug 2022 11:19:03 +0200 Subject: [PATCH 1/4] Refactor --- crates/fj-kernel/src/algorithms/approx/curve.rs | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/crates/fj-kernel/src/algorithms/approx/curve.rs b/crates/fj-kernel/src/algorithms/approx/curve.rs index 25b6470a97..d9edc53df0 100644 --- a/crates/fj-kernel/src/algorithms/approx/curve.rs +++ b/crates/fj-kernel/src/algorithms/approx/curve.rs @@ -28,16 +28,10 @@ impl Approx for GlobalCurve { /// To support that, we will need additional information here, to define /// between which points the curve needs to be approximated. fn approx(&self, tolerance: Tolerance) -> Self::Approximation { - let mut points = Vec::new(); - match self.kind() { - CurveKind::Circle(curve) => { - approx_circle(curve, tolerance, &mut points) - } - CurveKind::Line(_) => {} + CurveKind::Circle(curve) => approx_circle(curve, tolerance), + CurveKind::Line(_) => Vec::new(), } - - points } } @@ -48,8 +42,9 @@ impl Approx for GlobalCurve { pub fn approx_circle( circle: &Circle<3>, tolerance: Tolerance, - out: &mut Vec>>, -) { +) -> Vec>> { + let mut out = Vec::new(); + let radius = circle.a().magnitude(); // To approximate the circle, we use a regular polygon for which @@ -65,6 +60,8 @@ pub fn approx_circle( let point = circle.point_from_circle_coords([angle]); out.push(Local::new([angle], point)); } + + out } fn number_of_vertices_for_circle(tolerance: Tolerance, radius: Scalar) -> u64 { From b7509be2ac72bec0299b7694844cad33d36e0d0a Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Fri, 26 Aug 2022 11:19:49 +0200 Subject: [PATCH 2/4] Make variable name more explicit --- crates/fj-kernel/src/algorithms/approx/curve.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/fj-kernel/src/algorithms/approx/curve.rs b/crates/fj-kernel/src/algorithms/approx/curve.rs index d9edc53df0..604fdf2628 100644 --- a/crates/fj-kernel/src/algorithms/approx/curve.rs +++ b/crates/fj-kernel/src/algorithms/approx/curve.rs @@ -43,7 +43,7 @@ pub fn approx_circle( circle: &Circle<3>, tolerance: Tolerance, ) -> Vec>> { - let mut out = Vec::new(); + let mut points = Vec::new(); let radius = circle.a().magnitude(); @@ -58,10 +58,10 @@ pub fn approx_circle( for i in 0..n { let angle = Scalar::TAU / n as f64 * i as f64; let point = circle.point_from_circle_coords([angle]); - out.push(Local::new([angle], point)); + points.push(Local::new([angle], point)); } - out + points } fn number_of_vertices_for_circle(tolerance: Tolerance, radius: Scalar) -> u64 { From 0ad3808ddd775764e57588c30fec1e65e0061003 Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Fri, 26 Aug 2022 12:09:38 +0200 Subject: [PATCH 3/4] Support arcs in `number_of_vertices_for_circle` --- .../fj-kernel/src/algorithms/approx/curve.rs | 33 ++++++++++++------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/crates/fj-kernel/src/algorithms/approx/curve.rs b/crates/fj-kernel/src/algorithms/approx/curve.rs index 604fdf2628..2b267d1d50 100644 --- a/crates/fj-kernel/src/algorithms/approx/curve.rs +++ b/crates/fj-kernel/src/algorithms/approx/curve.rs @@ -53,7 +53,7 @@ pub fn approx_circle( // and the circle. This is the same as the difference between // the circumscribed circle and the incircle. - let n = number_of_vertices_for_circle(tolerance, radius); + let n = number_of_vertices_for_circle(tolerance, radius, Scalar::TAU); for i in 0..n { let angle = Scalar::TAU / n as f64 * i as f64; @@ -64,8 +64,12 @@ pub fn approx_circle( points } -fn number_of_vertices_for_circle(tolerance: Tolerance, radius: Scalar) -> u64 { - let n = (Scalar::PI / (Scalar::ONE - (tolerance.inner() / radius)).acos()) +fn number_of_vertices_for_circle( + tolerance: Tolerance, + radius: Scalar, + range: Scalar, +) -> u64 { + let n = (range / (Scalar::ONE - (tolerance.inner() / radius)).acos() / 2.) .ceil() .into_u64(); @@ -80,31 +84,38 @@ mod tests { #[test] fn number_of_vertices_for_circle() { - verify_result(50., 100., 3); - verify_result(10., 100., 7); - verify_result(1., 100., 23); + verify_result(50., 100., Scalar::TAU, 3); + verify_result(50., 100., Scalar::PI, 3); + verify_result(10., 100., Scalar::TAU, 7); + verify_result(10., 100., Scalar::PI, 4); + verify_result(1., 100., Scalar::TAU, 23); + verify_result(1., 100., Scalar::PI, 12); fn verify_result( tolerance: impl Into, radius: impl Into, + range: impl Into, n: u64, ) { let tolerance = tolerance.into(); let radius = radius.into(); + let range = range.into(); assert_eq!( n, - super::number_of_vertices_for_circle(tolerance, radius) + super::number_of_vertices_for_circle(tolerance, radius, range) ); - assert!(calculate_error(radius, n) <= tolerance.inner()); + assert!(calculate_error(radius, range, n) <= tolerance.inner()); if n > 3 { - assert!(calculate_error(radius, n - 1) >= tolerance.inner()); + assert!( + calculate_error(radius, range, n - 1) >= tolerance.inner() + ); } } - fn calculate_error(radius: Scalar, n: u64) -> Scalar { - radius - radius * (Scalar::PI / Scalar::from_u64(n)).cos() + fn calculate_error(radius: Scalar, range: Scalar, n: u64) -> Scalar { + radius - radius * (range / Scalar::from_u64(n) / 2.).cos() } } } From a61200c241404d1131c4d3d81649f5c054dd0348 Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Fri, 26 Aug 2022 12:23:48 +0200 Subject: [PATCH 4/4] Support arcs in `approx_circle` --- crates/fj-kernel/src/algorithms/approx/curve.rs | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/crates/fj-kernel/src/algorithms/approx/curve.rs b/crates/fj-kernel/src/algorithms/approx/curve.rs index 2b267d1d50..e5bbf7954e 100644 --- a/crates/fj-kernel/src/algorithms/approx/curve.rs +++ b/crates/fj-kernel/src/algorithms/approx/curve.rs @@ -29,7 +29,9 @@ impl Approx for GlobalCurve { /// between which points the curve needs to be approximated. fn approx(&self, tolerance: Tolerance) -> Self::Approximation { match self.kind() { - CurveKind::Circle(curve) => approx_circle(curve, tolerance), + CurveKind::Circle(curve) => { + approx_circle(curve, [[Scalar::ZERO], [Scalar::TAU]], tolerance) + } CurveKind::Line(_) => Vec::new(), } } @@ -41,22 +43,27 @@ impl Approx for GlobalCurve { /// from the circle. pub fn approx_circle( circle: &Circle<3>, + between: [impl Into>; 2], tolerance: Tolerance, ) -> Vec>> { let mut points = Vec::new(); let radius = circle.a().magnitude(); + let [start, end] = between.map(Into::into); + let range = (end - start).t; + // To approximate the circle, we use a regular polygon for which // the circle is the circumscribed circle. The `tolerance` // parameter is the maximum allowed distance between the polygon // and the circle. This is the same as the difference between // the circumscribed circle and the incircle. - let n = number_of_vertices_for_circle(tolerance, radius, Scalar::TAU); + let n = number_of_vertices_for_circle(tolerance, radius, range.abs()); for i in 0..n { - let angle = Scalar::TAU / n as f64 * i as f64; + let angle = + start.t + (Scalar::TAU / n as f64 * i as f64) * range.sign(); let point = circle.point_from_circle_coords([angle]); points.push(Local::new([angle], point)); }