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: String,
28
29}
30
31impl GRID1D {
32 pub 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:"".to_string(),
48 }
49 }
50
51
52 pub fn new_from_points(points:Vec<f64>,snap_precision:f64,label:String)-> GRID1D{
53 let num = points.len();
55 assert!(num>=2, "Need at least 2 points to make a grid");
56 let high = points[num-1];
57 let low = points[0];
58 assert!(low < high, "First point is not lower than last point");
59 let expected_interval = (high-low)/(num as f64 -1.0);
60 (0..num-1).for_each(|i|{
61 assert!(points[i+1]>points[i],
62 "Failed to make grid because points must monotonically increase");
63 assert!(((points[i+1]-points[i]) - expected_interval).abs() < snap_precision*expected_interval,
64 " Failed to make grid because points must be evenly spaced")
65 });
66 GRID1D{
67 scale: 1.0,
68 step_size: expected_interval,
69 minimum_value: low,
70 maximum_value: high,
71 snap_precision,
72 label,
73 }
74 }
75
76 pub fn pretty_print(&self){
77 println!("1D grid {:?} \n\
78 min: {} \n\
79 max: {} \n\
80 step size: {} \n\
81 snap precision: {} \n",
82 self.label,
83 self.minimum_value,
84 self.maximum_value,
85 self.step_size,
86 self.snap_precision)
87 }
88 pub fn num(&self)-> usize{
89 ( (self.maximum_value-self.minimum_value)/self.step_size ) as usize + 1
91 }
92
93
94 pub fn location(&self, grid_number:usize) -> f64 {
95 assert!((grid_number <= self.num()-1)&&(grid_number >= 0));
96 self.minimum_value + self.step_size*grid_number as f64
97 }
98
99 pub fn size(&self)-> f64{
100 self.step_size*(self.num()-1)as f64
101 }
102
103 pub fn random(&self)-> f64{
104 let mut rng = rand::rng();
105 let scale: f64 = rng.random();
106 self.minimum_value + self.size()*scale
107
108 }
109 pub fn inside_or_outside(&self, point:f64) -> Location1D{
110 let epsilon = self.snap_precision;
111 let max = self.minimum_value + self.size();
112 if (point < self.minimum_value - epsilon) {
113 return Location1D::TooLow
114 };
115 if (point > max + epsilon){
116 return Location1D::TooHigh
117 }
118 Location1D::JustRight
119 }
120
121 pub fn fit_grid(&self, point:f64)->(usize,f64){
122 match self.inside_or_outside(point) {
124 Location1D::TooHigh => {panic!("too big to fit")}
125 Location1D::TooLow => {panic!("too small to fit")}
126 Location1D::JustRight => {}
127 }
128 let delta = point - self.minimum_value;
130 let scaled_residual = delta/self.step_size - (delta/self.step_size).floor();
131
132
133 let (modulus, residual) = if scaled_residual <= 0.5{
134 let modulus = (delta/self.step_size).floor() as usize;
135 let residual = scaled_residual*self.step_size;
136 (modulus,residual)
137
138 }else{
139 let modulus = (delta/self.step_size).floor() as usize + 1;
140 let residual = (scaled_residual-1.0)*self.step_size;
141 (modulus,residual)
142 };
143
144 (modulus, residual)
145 }
146 pub fn snap(&self,point:f64)-> usize{
149 let (modulus,residual) = self.fit_grid(point);
150 if (residual.abs() >= self.snap_precision){
151 panic!("Couldn't snap point")
152 };
153 modulus
154 }
155
156
157 pub fn find_neighbors(&self, point:f64) -> Neighbors{
158 let epsilon = self.snap_precision;
159 let (modulus,residual) = self.fit_grid(point);
160 if (residual.abs() <= epsilon){
161 return Neighbors::One(self.snap(point))
162 };
163 let (upper,lower) = if residual < 0.0{ (modulus,modulus-1) }else{ (modulus+1, modulus)};
165 Neighbors::Two(upper,lower)
166 }
167
168 pub fn plot_points(&self, plot:&mut Plot, add_point:PlotPoint){
169
170 let mut frame = Curve::new();
171 frame.set_marker_color("pink")
172 .set_marker_every(1)
173 .set_marker_style(".");
174
175 let mut grid_points = Curve::new();
176 grid_points.set_line_style("none")
177 .set_label(format!("Grid points: {:?}",self.label).as_str())
178 .set_marker_color("blue")
179 .set_marker_every(1)
180 .set_marker_size(7.0)
181 .set_marker_style(".");
182
183 let mut corner = Curve::new();
184 corner
185 .set_label("Corner")
186 .set_line_style("none")
187 .set_marker_color("#eeea83")
188 .set_marker_every(1)
189 .set_marker_size(10.0)
190 .set_marker_style(".");
191
192
193 let mut extra_point = Curve::new();
194 extra_point.set_marker_color("#eeea83")
195 .set_marker_every(1)
196 .set_marker_size(10.0)
197 .set_line_style("none")
198 .set_marker_style("*");
199
200
201
202 let mut grid_numbers = Text::new();
203 grid_numbers.set_color("purple")
204 .set_fontsize(5.0);
205
206
207 grid_points.points_begin();
208 for point in 0..self.num(){
209 let point_location = self.location(point);
210 grid_points.points_add(point_location, 0.0);
211 let label = format!("{}",point);
212 grid_numbers.draw(point_location, 0.0, label.as_str());
213 }
214 grid_points.points_end();
215
216 corner.points_begin();
217 let corner_location = self.minimum_value;
218 let corner_label = format!("Corner: ({:.3},{:.3})",corner_location,0.0);
219 corner.points_add(corner_location,0.0).set_label(corner_label.as_str());
220 corner.points_end();
221
222 let mut example_point = Vec::new();
223
224 match add_point {
225 PlotPoint::No => {}
226 PlotPoint::Given(point) => { example_point.push(point.x)}
227 PlotPoint::Random => {
228 let random = self.random();
229 example_point.push((random)); }
230 };
231
232 for point in example_point{
233 let (_,res) = self.fit_grid(point);
234 extra_point.points_begin();
235 extra_point.points_add(point,0.0).set_label(format!("x, y residuals: {:.3}", res).as_str());
236 extra_point.points_end();
237
238 let corners = self.find_neighbors(point);
239 let mut frame_points = Vec::new();
240 match corners{
241
242 Neighbors::Two(a,b) => {
243 frame_points.push(a);
244 frame_points.push(b);
245 println!("{:?}",(a,b));}
246
247 Neighbors::One(a) => { frame_points.push(a); }
248 }
249 frame.points_begin();
250 for point in frame_points{
251 println!("point {point}");
252 let point = self.location(point);
253 frame.points_add(point,0.0);
254 }
255
256 frame.points_end();
257 }
258
259
260
261 plot.add(&grid_numbers);
262 plot.add(&grid_points);
263 plot.add(&extra_point);
264 plot.add(&corner);
265 plot.add(&frame)
266 .set_figure_size_inches(10.0,10.0)
267 .grid_labels_legend("x", "y");
268
269
270 }
271
272}
273
274
275