1use plotpy::{Curve, Plot, Text};
2use crate::coordinate_system::{CoordinateSystem, Coordinates};
3use rand::RngExt;
4use crate::points::{Point};
5
6
7pub enum Corners{
8 Four(usize,usize,usize,usize),
9 Two(usize,usize),
10 One(usize),
11}
12#[derive(Debug)]
13pub enum Location{
14 Outside,
15 Inside,
16}
17pub enum Bin{
18 Binned(usize,usize),
19 Outside,
20}
21
22
23#[derive(Debug,Clone)]
24pub struct GRID2D {
25 pub coordinates: Coordinates,
26
27 pub x_num: usize,
28 pub y_num: usize,
29
30 pub x_step_size: f64, pub y_step_size: f64, pub x_size: f64,
34 pub y_size: f64,
35
36 pub num_points: usize,
37
38 pub center: (f64,f64),
39 pub corner: (f64,f64),
40
41 pub snap_precision: f64, pub label: String,
44
45}
46
47impl GRID2D {
48 pub fn new_empty((x_num,y_num): (usize,usize),
49 (x_step_size,y_step_size): (f64,f64), center: (f64,f64),
51 snap_precision: f64,
52 coordinates: Coordinates,
53 ) -> GRID2D {
54 let x_size = x_step_size*(x_num-1)as f64;
55 let y_size = y_step_size*(y_num-1)as f64;
56 let num_points = x_num*y_num;
57 let (x_0,y_0) = center;
58 let corner = (x_0 - x_size/2.0,y_0 - y_size/2.0);
59 assert!(snap_precision<0.5);
63 GRID2D {
64 coordinates,
65 x_num,
66 x_step_size,
67 x_size,
68 y_num,
69 y_step_size,
70 y_size,
71 num_points,
72 center,
73 corner,
74 snap_precision:snap_precision*f64::min(y_step_size,x_step_size),
75 label: "".to_string(),
76 }
77 }
78
79
80 pub fn new_from_width((x_num,y_num): (usize,usize),
81 (x_width,y_width): (f64,f64), center: (f64,f64),
83 snap_precision: f64,
84 coordinates: Coordinates,
85 ) -> GRID2D {
86 let x_step_size = x_width/(x_num-1)as f64;
87 let y_step_size = y_width/(y_num-1)as f64;
88 let num_points = x_num*y_num;
89 let (x_0,y_0) = center;
90 let corner = (x_0 - x_width/2.0,y_0 - y_width/2.0);
91 assert!(snap_precision<0.5);
95 GRID2D {
96 coordinates,
97 x_num,
98 x_step_size,
99 x_size:x_width,
100 y_num,
101 y_step_size,
102 y_size:y_width,
103 num_points,
104 center,
105 corner,
106 snap_precision:snap_precision*f64::min(y_step_size,x_step_size),
107 label: "".to_string(),
108 }
109 }
110
111
112
113
114 pub fn xy_indices(&self, grid_number:usize) -> (usize,usize){
115 assert!((grid_number <= self.num_points - 1)&&(grid_number >= 0));
116 let x_index = grid_number % self.x_num;
117 let y_index = (grid_number - x_index)/self.y_num;
118 (x_index,y_index)
119 }
120
121 pub fn grid_number(&self, x_index:usize,y_index:usize) -> usize{
122 assert!(x_index <= self.x_num-1);
123 assert!(y_index <= self.y_num-1);
124 y_index*self.x_num + x_index
125 }
126
127 pub fn locate(&self, grid_number:usize) -> Point {
128
129 assert!((grid_number <= self.x_num*self.y_num-1)&&(grid_number >= 0));
130 let (x_corner,y_corner) = self.corner;
131 let (x_index,y_index) = self.xy_indices(grid_number);
132 let (x,y) = (x_corner + x_index as f64 *self.x_step_size, y_corner + y_index as f64 *self.y_step_size);
133 Point::new(x,y,self.coordinates.clone())
135 }
136
137
138
139 pub fn snap(&self,point:Point)-> usize{
140 let (x_mod,y_mod,x_residual,y_residual) = self.fit_grid(&point);
141 if (x_residual.abs() >= self.snap_precision) | (y_residual.abs() >= self.snap_precision){
142 panic!("Couldn't snap point")
143 };
144 self.grid_number(x_mod,y_mod)
145 }
146
147 pub fn random(&self)-> Point{
148 let mut rng = rand::rng();
149 let x_scale: f64 = rng.random();
150 let y_scale: f64 = rng.random();
151 let (x,y) = (self.corner.0 + self.x_size*x_scale, self.corner.1 + self.y_size*y_scale);
152 let point = Point::new(x,y,self.coordinates.clone());
154 point
156 }
157
158 pub fn fit_grid(&self, point:&Point)->(usize,usize,f64,f64){
159 match self.inside_or_outside(&point) {
161 Location::Outside => {
162 println!("Tried to grid point {:?}",point);
163 panic!("Tried to grid a point that was outside of the grid")}
164 Location::Inside => {}
165 }
166 let (x,y) = point.convert(&self.coordinates).values();
169 let (corner_x,corner_y) = self.corner;
172
173 let delta_x = x - corner_x;
174 let delta_y = y - corner_y;
175 let x_scaled_residual = delta_x/self.x_step_size - (delta_x/self.x_step_size).floor();
177 let y_scaled_residual = delta_y/self.y_step_size - (delta_y/self.y_step_size).floor();
178
179 let (x_mod, x_residual) = if x_scaled_residual <= 0.5{
182 let x_mod = (delta_x/self.x_step_size).floor() as usize;
183 let x_residual = x_scaled_residual*self.x_step_size;
184
185 (x_mod,x_residual)
186
187 }else{
188 let x_mod = (delta_x/self.x_step_size).floor() as usize + 1;
189 let x_residual = (x_scaled_residual-1.0)*self.x_step_size;
190 (x_mod,x_residual)
191 };
192
193 let (y_mod,y_residual) = if y_scaled_residual <=0.5{
194 let y_mod = (delta_y/self.y_step_size).floor() as usize;
195 let y_residual = y_scaled_residual*self.y_step_size;
196 (y_mod,y_residual)
197 }else{
198 let y_mod = (delta_y/self.y_step_size).floor() as usize + 1;
199 let y_residual = (y_scaled_residual-1.0)*self.y_step_size;
200 (y_mod,y_residual)
201 };
202
203 (x_mod,y_mod,x_residual,y_residual)
207 }
208 pub fn fit_grid_unscaled(&self, point:Point)->(usize,usize,f64,f64){
210 match self.inside_or_outside(&point) {
212 Location::Outside => {
213 println!("Tried to grid point {:?}",point);
214 panic!("Tried to grid a point that was outside of the grid")}
215 Location::Inside => {}
216 }
217 let (x,y) = point.convert(&self.coordinates).values();
220 let (corner_x,corner_y) = self.corner;
222
223 let delta_x = x - corner_x;
224 let delta_y = y - corner_y;
225 let x_scaled_residual = delta_x/self.x_step_size - (delta_x/self.x_step_size).floor();
228 let y_scaled_residual = delta_y/self.y_step_size - (delta_y/self.y_step_size).floor();
229
230 let (x_mod, x_residual) = if x_scaled_residual <= 0.5{
233 let x_mod = (delta_x/self.x_step_size).floor() as usize;
234 let x_residual = x_scaled_residual;
235
236 (x_mod,x_residual)
237
238 }else{
239 let x_mod = (delta_x/self.x_step_size).floor() as usize + 1;
240 let x_residual = (x_scaled_residual-1.0);
241 (x_mod,x_residual)
242 };
243
244 let (y_mod,y_residual) = if y_scaled_residual <=0.5{
245 let y_mod = (delta_y/self.y_step_size).floor() as usize;
246 let y_residual = y_scaled_residual;
247 (y_mod,y_residual)
248 }else{
249 let y_mod = (delta_y/self.y_step_size).floor() as usize + 1;
250 let y_residual = (y_scaled_residual-1.0);
251 (y_mod,y_residual)
252 };
253
254 (x_mod,y_mod,x_residual,y_residual)
258 }
259
260 pub fn bin_up_patch(&self, center_of_the_corner_pixel:Point,psf:&Vec<Vec<f64>>,scale:usize)-> ((usize,usize),Vec<Vec<f64>>){ let (x_mod,y_mod,x_residual,y_residual) = self.fit_grid_unscaled(center_of_the_corner_pixel);
265 let x_pixels = 64; let y_pixels = 64;
272 let scale = scale as f64;
273 let x_tail_end_in_pixels = x_residual*scale + scale/2.0 - 1.0;
274 let y_tail_end_in_pixels = y_residual*scale + scale/2.0 - 1.0;
275 let x_offset = if x_tail_end_in_pixels < 0.0{ 0 }else{
276 x_tail_end_in_pixels.ceil() as usize
277 };
278 let y_offset = if y_tail_end_in_pixels < 0.0{ 0 }else{
279 y_tail_end_in_pixels.ceil() as usize
280 };
281
282 let binned_x_size = if x_offset > 0{
283 (x_pixels as f64/scale + 1.0) as usize
284 }else{
285 (x_pixels as f64/scale) as usize
286 };
287
288 let binned_y_size = if y_offset > 0{
289 (y_pixels as f64/scale + 1.0) as usize
290 }else{
291 (y_pixels as f64/scale) as usize
292 };
293 let mut binned_psf = vec![vec![0.0;(x_pixels as f64/scale).ceil() as usize + 1];(y_pixels as f64/scale).ceil() as usize + 1];
296 for y in 0..y_pixels{
297 for x in 0..x_pixels{
298 let binned_x_index:usize = ((x + x_offset) as f64/scale).floor() as usize;
299 let binned_y_index:usize = ((y + y_offset) as f64/scale).floor() as usize;
300 binned_psf[binned_y_index][binned_x_index] += psf[y][x];
301 }
302 }
303 ((x_mod,y_mod),binned_psf)
305
306 }
307
308
309
310
311
312 pub fn inside_or_outside(&self, point:&Point) -> Location{
313 let (x,y) = point.convert(&self.coordinates).values();
314 let epsilon = self.snap_precision;
316 let (corner_x,corner_y) = self.corner;
317 let (grid_x_min, grid_x_max) = (corner_x, corner_x + self.x_size);
318 let (grid_y_min, grid_y_max) = (corner_y, corner_y + self.y_size);
319
320 if (x < grid_x_min - epsilon) | (x > grid_x_max + epsilon) | (y < grid_y_min - epsilon) | (y > grid_y_max + epsilon){
321 return Location::Outside
323 };
324 Location::Inside
325 }
326
327 pub fn project(&self, point:&Point) -> Point{
328 let (x,y) = point.convert(&self.coordinates).values();
337 let (corner_x,corner_y) = self.corner;
338 let (grid_x_min, grid_x_max) = (corner_x, corner_x + self.x_size);
339 let (grid_y_min, grid_y_max) = (corner_y, corner_y + self.y_size);
340
341 let new_x = if x < grid_x_min{
342 grid_x_min
343 } else if x > grid_x_max{
344 grid_x_max
345 } else {
346 x
347 };
348 let new_y = if y < grid_y_min{
349 grid_y_min
350 } else if y > grid_y_max{
351 grid_y_max
352 } else {
353 y
354 };
355 Point::new(new_x,new_y,self.coordinates.clone())
356
357
358 }
359
360
361
362 pub fn find_corners(&self,point:Point) -> Corners{
363 let epsilon = self.snap_precision;
364
365
366 let (x_mod,y_mod,x_residual,y_residual) = self.fit_grid(&point);
367
368 if (x_residual.abs() <= epsilon) && (y_residual.abs() <= epsilon) {
370 return Corners::One(self.grid_number(x_mod,y_mod))
372 };
373 if (x_residual.abs() <= epsilon) {
375 if y_residual < 0.0{
377 return Corners::Two(self.grid_number(x_mod,y_mod),self.grid_number(x_mod,y_mod-1));
378 }else{
379 return Corners::Two(self.grid_number(x_mod,y_mod+1),self.grid_number(x_mod,y_mod));
380 }
381 };
382 if (y_residual.abs() <= epsilon) {
384 if x_residual < 0.0{
386 return Corners::Two(self.grid_number(x_mod,y_mod),self.grid_number(x_mod-1,y_mod));
387 }else{
388 return Corners::Two(self.grid_number(x_mod+1,y_mod),self.grid_number(x_mod,y_mod));
389 }
390 };
391 let (upper_x,lower_x) = if x_residual < 0.0{ (x_mod,x_mod-1) }else{ (x_mod+1, x_mod)};
394 let (upper_y,lower_y) = if y_residual < 0.0{ (y_mod,y_mod-1) }else{ (y_mod+1, y_mod)};
395
396 Corners::Four(self.grid_number(lower_x,upper_y),
398 self.grid_number(upper_x,upper_y),
399 self.grid_number(upper_x,lower_y),
400 self.grid_number(lower_x,lower_y))
401
402 }
403
404 pub fn plot_points(&self, plot:&mut Plot, add_point:PlotPoint){
405 let mut grid_points = Curve::new();
408 grid_points.set_line_style("none")
409 .set_label(format!("Grid points: {:?}",self.label).as_str())
410 .set_marker_color("blue")
411 .set_marker_every(1)
412 .set_marker_size(7.0)
413 .set_marker_style(".");
414
415 let mut corner = Curve::new();
416 corner
417 .set_label("Corner")
418 .set_line_style("none")
419 .set_marker_color("#eeea83")
420 .set_marker_every(1)
421 .set_marker_size(10.0)
422 .set_marker_style(".");
423
424 let mut frame = Curve::new();
425 frame.set_line_width(1.0)
426 .set_label("Frame")
427 .set_line_style("solid")
428 .set_line_width(1.0)
429 .set_marker_color("purple")
430 .set_marker_every(1)
431 .set_marker_size(10.0)
432 .set_marker_style(".");
433
434 let mut extra_point = Curve::new();
435 extra_point.set_marker_color("#eeea83")
436 .set_marker_every(1)
437 .set_marker_size(10.0)
438 .set_line_style("none")
439 .set_marker_style("*");
440
441
442
443 let mut grid_numbers = Text::new();
444 grid_numbers.set_color("purple")
445 .set_fontsize(5.0);
446
447
448 grid_points.points_begin();
449 for point in 0..self.num_points{
450 let point_location = self.locate(point).to_absolute();
451 grid_points.points_add(point_location.x, point_location.y);
452 let label = format!("{}",point);
453 grid_numbers.draw(point_location.x, point_location.y, label.as_str());
454 }
455 grid_points.points_end();
456
457
458
459 corner.points_begin();
460 let corner_location = self.locate(0).to_absolute().values();
461 let corner_label = format!("Corner: ({:.3},{:.3})",corner_location.0,corner_location.1);
462 corner.points_add(corner_location.0,corner_location.1).set_label(corner_label.as_str());
463 corner.points_end();
464
465 let mut example_point = Vec::new();
466
467 match add_point {
468 PlotPoint::No => {}
469 PlotPoint::Given(point) => { example_point.push(point)}
470 PlotPoint::Random => {
471 let random = self.random();
472 example_point.push(random); }
473 };
474
475 for point in example_point{
476 let (_,_, x_res, y_res) = self.fit_grid(&point);
477 extra_point.points_begin();
478 extra_point.points_add(point.to_absolute().values().0,point.to_absolute().clone().values().1).set_label(format!("x, y residuals: {:.3}, {:.3}", x_res, y_res).as_str());
479 extra_point.points_end();
480
481 let corners = self.find_corners(point);
482 let mut frame_points = Vec::new();
483 match corners{
484 Corners::Four(a, b, c, d) => {
485 frame_points.push(a);
486 frame_points.push(b);
487 frame_points.push(c);
488 frame_points.push(d);
489 frame_points.push(a);
490 }
491 Corners::Two(a,b) => {
492 frame_points.push(a);
493 frame_points.push(b);}
494 Corners::One(a) => { frame_points.push(a); }
495 }
496 frame.points_begin();
497 for point in frame_points{
498 let point = self.locate(point).to_absolute();
500 frame.points_add(point.x,point.y);
501 }
502
503 frame.points_end();
504 }
505
506 plot.add(&frame);
507 plot.add(&grid_numbers);
508 plot.add(&grid_points);
509 plot.add(&extra_point);
510 plot.add(&corner)
511 .set_figure_size_inches(10.0,10.0)
512 .set_num_ticks_y(self.y_num+1)
513 .set_num_ticks_x(self.x_num+1)
514 .grid_labels_legend("x", "y");
515
516
517 }
518
519 pub fn outer_boarder(&self) -> (Point,Point, Point, Point){
520 let (c1x,c1y) = (self.corner.0 -self.x_step_size/2.0, self.corner.1-self.y_step_size/2.0);
521
522 let (c2x,c2y) = (c1x + self.x_size + self.x_step_size, c1y);
523 let (c3x,c3y) = (c1x + self.x_size + self.x_step_size, c1y + self.y_size + self.y_step_size);
524 let (c4x,c4y) = (c1x , c1y + self.y_size + self.y_step_size);
525
526 let point = Point::new(c1x,c1y,self.coordinates.clone());
527 (Point::new(c1x,c1y,self.coordinates.clone()),
529 Point::new(c2x,c2y,self.coordinates.clone()),
530 Point::new(c3x,c3y,self.coordinates.clone()),
531 Point::new(c4x,c4y,self.coordinates.clone()))
532
533 }
534
535 pub fn plot_outline(&self, plot:&mut Plot, color: &str){
536 self.coordinates.plot(plot,color);
537
538 let mut outline = Curve::new();
542 outline.set_line_width(1.0)
543 .set_label(format!("Frame of {:?}",self.label).as_str())
544 .set_line_style("solid")
545 .set_line_width(1.0)
546 .set_marker_color(color)
547 .set_line_color(color)
548 .set_marker_every(1)
549 .set_marker_size(10.0)
550 .set_marker_style(".");
551
552
553
554
555 outline.points_begin();
556
557 let (p0,p1,p2,p3) = self.outer_boarder();
558 let p0 = p0.to_absolute();
559 let p1 = p1.to_absolute();
560 let p2 = p2.to_absolute();
561 let p3 = p3.to_absolute();
562 outline.points_add(p0.x,p0.y);
563 outline.points_add(p1.x,p1.y);
564 outline.points_add(p2.x,p2.y);
565 outline.points_add(p3.x,p3.y);
566 outline.points_add(p0.x,p0.y);
567
568 outline.points_end();
569
570
571 plot.add(&outline);
572
573
574 }
575
576 pub fn projected_interpolation_coefficients(&self, point:&Point)-> InterpolationData{
577 self.interpolation_coefficients(&self.project(point))
578 }
579
580
581 pub fn interpolation_coefficients(&self, point:&Point) -> InterpolationData{
582
583 match self.find_corners(point.clone()){
584 Corners::Four(Q12, Q22, Q21, Q11) => { let Q11point = self.locate(Q11);
587 let Q22point = self.locate(Q22);
588
589 let (x1,y1) = (Q11point.x,Q11point.y);
590 let (x2,y2) = (Q22point.x,Q22point.y);
591 let (x,y) = point.convert(&self.coordinates).values();
592 let c11 = (x2-x)*(y2-y);
593 let c12 = (x2-x)*(y-y1);
594 let c21 = (x-x1)*(y2-y);
595 let c22 = (x-x1)*(y-y1);
596 let normalization = (x2-x1)*(y2-y1);
598 InterpolationData{
599 corners: Corners::Four(Q12, Q22, Q21, Q11) ,
600 coefficients:vec![c11,c12,c21,c22],
601 normalization
602 }
603 }
604 Corners::Two(Q1, Q2) => {
605
606 let Q1point = self.locate(Q1);
607 let Q2point = self.locate(Q2);
608
609 let (x1,y1) = (Q1point.x,Q1point.y);
610 let (x2,y2) = (Q2point.x,Q2point.y);
611 let (x,y) = point.convert(&self.coordinates).values();
612
613 if ((x1-x2) < 2.0*self.snap_precision) && ((y1-y2) > 2.0*self.snap_precision){
614 let c1 = (y1-y).abs();
616 let c2 = (y2-y).abs();
617 let normalization = self.y_step_size;
618 return InterpolationData{
619 corners: Corners::Two(Q1, Q2),
620 coefficients:vec![c1,c2],
621 normalization
622 }
623 }else if ((x1-x2) > 2.0*self.snap_precision) && ((y1-y2) < 2.0*self.snap_precision){
624 let c1 = (x1-x).abs();
626 let c2 = (x2-x).abs();
627 let normalization = self.x_step_size;
628 return InterpolationData{
629 corners: Corners::Two(Q1, Q2),
630 coefficients:vec![c1,c2],
631 normalization
632 }
633 }else{
634 panic!("Unreachable")
635 }
636
637 }
638 Corners::One(Q1) => {
639 InterpolationData{
640 corners: Corners::One(Q1),
641 coefficients:vec![1.0],
642 normalization:1.0,
643 }
644 }
645 }
646
647 }
648
649
650}
651
652pub struct InterpolationData{
653 pub corners: Corners,
654 pub coefficients: Vec<f64>,
655 pub normalization:f64,
656}
657
658
659pub enum PlotPoint{
660 No,
661 Given(Point),
662 Random,
663}
664
665
666