1use crate::render::Rect;
2
3use super::Coord;
4
5pub struct CoordPolar {
11 pub theta: String,
13 pub start: f64,
15 pub direction: f64,
17 pub inner_radius: f64,
19}
20
21impl CoordPolar {
22 pub fn new() -> Self {
23 CoordPolar {
24 theta: "x".to_string(),
25 start: 0.0,
26 direction: 1.0,
27 inner_radius: 0.0,
28 }
29 }
30
31 pub fn inner_radius(mut self, frac: f64) -> Self {
33 self.inner_radius = frac.clamp(0.0, 0.95);
34 self
35 }
36
37 pub fn theta(mut self, theta: &str) -> Self {
38 self.theta = theta.to_string();
39 self
40 }
41
42 pub fn start(mut self, start: f64) -> Self {
43 self.start = start;
44 self
45 }
46
47 pub fn direction(mut self, dir: f64) -> Self {
48 self.direction = dir;
49 self
50 }
51}
52
53impl Default for CoordPolar {
54 fn default() -> Self {
55 Self::new()
56 }
57}
58
59impl Coord for CoordPolar {
60 fn transform(&self, point: (f64, f64), plot_area: &Rect) -> (f64, f64) {
61 let (nx, ny) = point;
62
63 let (angle_norm, radius_norm) = if self.theta == "x" {
65 (nx, ny)
66 } else {
67 (ny, nx)
68 };
69
70 let angle = self.start + self.direction * angle_norm * std::f64::consts::TAU;
72
73 let max_radius = plot_area.width.min(plot_area.height) / 2.0;
75 let radius = (self.inner_radius + radius_norm * (1.0 - self.inner_radius)) * max_radius;
77
78 let cx = plot_area.x + plot_area.width / 2.0;
80 let cy = plot_area.y + plot_area.height / 2.0;
81
82 let px = cx + radius * angle.sin();
85 let py = cy - radius * angle.cos();
86
87 (px, py)
88 }
89
90 fn gridlines(&self) -> bool {
91 false
92 }
93
94 fn is_flipped(&self) -> bool {
95 false
96 }
97
98 fn is_polar(&self) -> bool {
99 true
100 }
101
102 fn polar_theta_is_x(&self) -> bool {
103 self.theta == "x"
104 }
105}