astroimsim_geometry/
grid1d.rs1use plotpy::{Curve, Plot, Text};
2use crate::coordinate_system::{CoordinateSystem, Coordinates};
3use rand::RngExt;
4use crate::grid2d::PlotPoint;
5use crate::points::Point;
6
7
8
9pub enum Location1D{
10 TooHigh,
11 TooLow,
12 JustRight,
13}
14
15pub enum Neighbors {
16 Two(usize,usize),
17 One(usize),
18}
19
20#[derive(Debug,Clone)]
21pub struct GRID1D {
22 pub scale: f64,
23 pub step_size: f64,
24 pub minimum_value: f64,
25 pub maximum_value: f64,
26 pub snap_precision: f64,
27 pub label: &'static str,
28
29}
30
31impl GRID1D {
32 pub const fn new_empty(
33 step_size: f64, minimum_value: f64,
35 maximum_value: f64,
36 snap_precision: f64,
37 scale:f64,
38
39 ) -> GRID1D {
40 assert!(snap_precision<0.5);
41 GRID1D {
42 scale,
43 step_size,
44 minimum_value,
45 maximum_value,
46 snap_precision,
47 label:"",
48 }
49 }
50 pub fn num(&self)-> usize{
51 ( (self.maximum_value-self.minimum_value)/self.step_size ) as usize + 1
53 }
54
55
56 pub fn location(&self, grid_number:usize) -> f64 {
57 assert!((grid_number <= self.num()-1)&&(grid_number >= 0));
58 self.minimum_value + self.step_size*grid_number as f64
59 }
60
61 pub fn size(&self)-> f64{
62 self.step_size*(self.num()-1)as f64
63 }
64
65 pub fn random(&self)-> f64{
66 let mut rng = rand::rng();
67 let scale: f64 = rng.random();
68 self.minimum_value + self.size()*scale
69
70 }
71 pub fn inside_or_outside(&self, point:f64) -> Location1D{
72 let epsilon = self.snap_precision;
73 let max = self.minimum_value + self.size();
74 if (point < self.minimum_value - epsilon) {
75 return Location1D::TooLow
76 };
77 if (point > max + epsilon){
78 return Location1D::TooHigh
79 }
80 Location1D::JustRight
81 }
82
83 pub fn fit_grid(&self, point:f64)->(usize,f64){
84 match self.inside_or_outside(point) {
86 Location1D::TooHigh => {panic!("too big to fit")}
87 Location1D::TooLow => {panic!("too small to fit")}
88 Location1D::JustRight => {}
89 }
90 let delta = point - self.minimum_value;
92 let scaled_residual = delta/self.step_size - (delta/self.step_size).floor();
93
94
95 let (modulus, residual) = if scaled_residual <= 0.5{
96 let modulus = (delta/self.step_size).floor() as usize;
97 let residual = scaled_residual*self.step_size;
98 (modulus,residual)
99
100 }else{
101 let modulus = (delta/self.step_size).floor() as usize + 1;
102 let residual = (scaled_residual-1.0)*self.step_size;
103 (modulus,residual)
104 };
105
106 (modulus, residual)
107 }
108 pub fn snap(&self,point:f64)-> usize{
111 let (modulus,residual) = self.fit_grid(point);
112 if (residual.abs() >= self.snap_precision){
113 panic!("Couldn't snap point")
114 };
115 modulus
116 }
117
118
119 pub fn find_neighbors(&self, point:f64) -> Neighbors{
120 let epsilon = self.snap_precision;
121 let (modulus,residual) = self.fit_grid(point);
122 if (residual.abs() <= epsilon){
123 return Neighbors::One(self.snap(point))
124 };
125 let (upper,lower) = if residual < 0.0{ (modulus,modulus-1) }else{ (modulus+1, modulus)};
127 Neighbors::Two(upper,lower)
128 }
129
130 pub fn plot_points(&self, plot:&mut Plot, add_point:PlotPoint){
131
132 let mut frame = Curve::new();
133 frame.set_marker_color("pink")
134 .set_marker_every(1)
135 .set_marker_style(".");
136
137 let mut grid_points = Curve::new();
138 grid_points.set_line_style("none")
139 .set_label(format!("Grid points: {:?}",self.label).as_str())
140 .set_marker_color("blue")
141 .set_marker_every(1)
142 .set_marker_size(7.0)
143 .set_marker_style(".");
144
145 let mut corner = Curve::new();
146 corner
147 .set_label("Corner")
148 .set_line_style("none")
149 .set_marker_color("#eeea83")
150 .set_marker_every(1)
151 .set_marker_size(10.0)
152 .set_marker_style(".");
153
154
155 let mut extra_point = Curve::new();
156 extra_point.set_marker_color("#eeea83")
157 .set_marker_every(1)
158 .set_marker_size(10.0)
159 .set_line_style("none")
160 .set_marker_style("*");
161
162
163
164 let mut grid_numbers = Text::new();
165 grid_numbers.set_color("purple")
166 .set_fontsize(5.0);
167
168
169 grid_points.points_begin();
170 for point in 0..self.num(){
171 let point_location = self.location(point);
172 grid_points.points_add(point_location, 0.0);
173 let label = format!("{}",point);
174 grid_numbers.draw(point_location, 0.0, label.as_str());
175 }
176 grid_points.points_end();
177
178 corner.points_begin();
179 let corner_location = self.minimum_value;
180 let corner_label = format!("Corner: ({:.3},{:.3})",corner_location,0.0);
181 corner.points_add(corner_location,0.0).set_label(corner_label.as_str());
182 corner.points_end();
183
184 let mut example_point = Vec::new();
185
186 match add_point {
187 PlotPoint::No => {}
188 PlotPoint::Given(point) => { example_point.push(point.x)}
189 PlotPoint::Random => {
190 let random = self.random();
191 example_point.push((random)); }
192 };
193
194 for point in example_point{
195 let (_,res) = self.fit_grid(point);
196 extra_point.points_begin();
197 extra_point.points_add(point,0.0).set_label(format!("x, y residuals: {:.3}", res).as_str());
198 extra_point.points_end();
199
200 let corners = self.find_neighbors(point);
201 let mut frame_points = Vec::new();
202 match corners{
203
204 Neighbors::Two(a,b) => {
205 frame_points.push(a);
206 frame_points.push(b);
207 println!("{:?}",(a,b));}
208
209 Neighbors::One(a) => { frame_points.push(a); }
210 }
211 frame.points_begin();
212 for point in frame_points{
213 println!("point {point}");
214 let point = self.location(point);
215 frame.points_add(point,0.0);
216 }
217
218 frame.points_end();
219 }
220
221
222
223 plot.add(&grid_numbers);
224 plot.add(&grid_points);
225 plot.add(&extra_point);
226 plot.add(&corner);
227 plot.add(&frame)
228 .set_figure_size_inches(10.0,10.0)
229 .grid_labels_legend("x", "y");
230
231
232 }
233
234}
235
236
237