-
-
Notifications
You must be signed in to change notification settings - Fork 119
/
Copy pathcircle.rs
76 lines (61 loc) · 2.46 KB
/
circle.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
use std::f64::consts::PI;
use nalgebra::vector;
use parry3d_f64::math::Isometry;
use crate::math::{Point, Vector};
/// A circle
#[derive(Clone, Debug)]
pub struct Circle {
/// The center point of the circle
pub center: Point<3>,
/// The radius of the circle
///
/// The radius is represented by a vector that points from the center to the
/// circumference. The point on the circumference that it points to defines
/// the origin of the circle's 1-dimensional curve coordinate system.
pub radius: Vector<3>,
}
impl Circle {
pub fn transform(&mut self, transform: &Isometry<f64>) {
self.center = transform.transform_point(&self.center);
self.radius = transform.transform_vector(&self.radius);
}
pub fn approx_vertices(&self, tolerance: f64, out: &mut Vec<Point<3>>) {
let radius = self.radius.magnitude();
// 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's figure which regular polygon we need to use, by just
// trying out some of them until we find one whose maximum error
// is less than or equal to the tolerance.
let mut n = 3;
loop {
let incircle_radius = radius * (PI / n as f64).cos();
let maximum_error = radius - incircle_radius;
if maximum_error <= tolerance {
break;
}
n += 1;
// If `n` is too large, due to an unreasonably low `tolerance`
// value, this loop might take a long time, and the program will
// just hang.
//
// Logging a warning or adding an `assert!` isn't really a solution,
// since we can only speculate what is reasonable for a specific use
// case.
//
// We can probably do away with this loop completely:
// https://github.com/hannobraun/Fornjot/issues/91
}
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.];
out.push(point);
}
}
}