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
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
use crate::{transforms::Scale, Angle, Canvas, Paint, Rotate, Translate, P2, PI, V2};
use rand::{distributions::Distribution, Rng};
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct Ellipse {
pub center: P2,
pub radii: V2,
pub phase: Angle,
}
impl Ellipse {
pub fn circle(center: P2, radius: f32) -> Self {
Ellipse {
center,
radii: V2::new(radius, radius),
phase: Angle::radians(0.),
}
}
pub fn new(center: P2, radii: V2) -> Self {
Self {
center,
radii,
phase: Angle::radians(0.),
}
}
pub fn with_phase(self, phase: Angle) -> Self {
Self { phase, ..self }
}
pub fn circumphase(&self, p: &P2) -> Angle {
Angle::radians((p.y - self.center.y).atan2(p.x - self.center.x))
}
pub fn circumpoint(&self, angle: Angle) -> P2 {
P2::new(
self.center.x + angle.radians.cos() * self.radii.x,
self.center.y + angle.radians.sin() * self.radii.y,
)
}
pub fn uniform_circle_sampler(&self) -> UniformCircleSampler {
UniformCircleSampler(*self)
}
}
impl Scale for Ellipse {
fn scale(self, factor: f32) -> Self {
Self {
radii: self.radii * factor,
..self
}
}
}
impl Paint for Ellipse {
fn paint(&self, canvas: &mut Canvas) {
canvas.move_to(self.circumpoint(self.phase));
canvas.arc(self.center, self.radii, Angle::radians(PI * 2.), self.phase);
canvas.close_path();
}
}
impl Translate for Ellipse {
fn translate(self, translation: V2) -> Self {
Self {
center: self.center + translation,
..self
}
}
}
impl Rotate for Ellipse {
fn rotate(self, pivot: P2, theta: Angle) -> Self {
Self {
center: self.center.rotate(pivot, theta),
phase: self.phase + theta,
..self
}
}
}
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct UniformCircleSampler(Ellipse);
impl Distribution<P2> for UniformCircleSampler {
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> P2 {
let s = rng.gen_range(0., 1.);
let theta = rng.gen_range(0., PI * 2.);
self.0.scale(s).circumpoint(Angle::radians(theta))
}
}