citra_solve/solver/
solution.rs1use crate::core::types::{CatalogStar, RaDec};
4use crate::wcs::Wcs;
5
6#[derive(Debug, Clone)]
8pub struct Solution {
9 pub wcs: Wcs,
11 pub center: RaDec,
13 pub fov_width_deg: f64,
15 pub fov_height_deg: f64,
17 pub rotation_deg: f64,
19 pub pixel_scale_arcsec: f64,
21 pub rms_arcsec: f64,
23 pub num_matched_stars: usize,
25 pub log_odds: f64,
27 pub matched_stars: Vec<(usize, CatalogStar)>,
29}
30
31impl Solution {
32 pub fn new(
34 wcs: Wcs,
35 image_width: u32,
36 image_height: u32,
37 rms_arcsec: f64,
38 log_odds: f64,
39 matched_stars: Vec<(usize, CatalogStar)>,
40 ) -> Self {
41 let center = wcs.pixel_to_sky(image_width as f64 / 2.0, image_height as f64 / 2.0);
42 let pixel_scale = wcs.pixel_scale_arcsec();
43 let fov_width_deg = image_width as f64 * pixel_scale / 3600.0;
44 let fov_height_deg = image_height as f64 * pixel_scale / 3600.0;
45 let rotation_deg = wcs.rotation_deg();
46
47 Self {
48 wcs,
49 center,
50 fov_width_deg,
51 fov_height_deg,
52 rotation_deg,
53 pixel_scale_arcsec: pixel_scale,
54 rms_arcsec,
55 num_matched_stars: matched_stars.len(),
56 log_odds,
57 matched_stars,
58 }
59 }
60
61 pub fn pixel_to_sky(&self, x: f64, y: f64) -> RaDec {
63 self.wcs.pixel_to_sky(x, y)
64 }
65
66 pub fn sky_to_pixel(&self, radec: &RaDec) -> (f64, f64) {
68 self.wcs.sky_to_pixel(radec)
69 }
70
71 pub fn to_fits_header(&self) -> String {
73 self.wcs.to_fits_header()
74 }
75
76 pub fn corners(&self, image_width: u32, image_height: u32) -> [RaDec; 4] {
78 [
79 self.wcs.pixel_to_sky(0.0, 0.0),
80 self.wcs.pixel_to_sky(image_width as f64, 0.0),
81 self.wcs
82 .pixel_to_sky(image_width as f64, image_height as f64),
83 self.wcs.pixel_to_sky(0.0, image_height as f64),
84 ]
85 }
86}
87
88impl std::fmt::Display for Solution {
89 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
90 writeln!(f, "Plate Solve Solution:")?;
91 writeln!(
92 f,
93 " Center: RA={:.6}° Dec={:.6}°",
94 self.center.ra_deg(),
95 self.center.dec_deg()
96 )?;
97 writeln!(
98 f,
99 " FOV: {:.3}° x {:.3}°",
100 self.fov_width_deg, self.fov_height_deg
101 )?;
102 writeln!(f, " Rotation: {:.2}°", self.rotation_deg)?;
103 writeln!(f, " Scale: {:.4}\"/pixel", self.pixel_scale_arcsec)?;
104 writeln!(f, " RMS: {:.2}\"", self.rms_arcsec)?;
105 writeln!(f, " Matched stars: {}", self.num_matched_stars)?;
106 writeln!(f, " Log-odds: {:.1}", self.log_odds)?;
107 Ok(())
108 }
109}
110
111#[cfg(test)]
112mod tests {
113 use super::*;
114
115 #[test]
116 fn test_solution_display() {
117 let wcs = Wcs::new(
118 (512.0, 384.0),
119 RaDec::from_degrees(180.0, 45.0),
120 [[-0.001, 0.0], [0.0, 0.001]],
121 );
122 let solution = Solution::new(wcs, 1024, 768, 1.5, 25.0, vec![]);
123 let display = format!("{}", solution);
124 assert!(display.contains("Plate Solve Solution"));
125 assert!(display.contains("Center"));
126 }
127}