gnss_qc/report/sp3.rs
1use itertools::Itertools;
2use maud::{html, Markup, Render};
3use std::collections::HashMap;
4
5use qc_traits::{Filter, FilterItem, MaskOperand, Preprocessing};
6use sp3::prelude::{Constellation, SP3, SV};
7
8use crate::report::shared::SamplingReport;
9
10pub struct SP3Page {
11 has_clock: bool,
12 has_velocity: bool,
13 has_clock_drift: bool,
14 satellites: Vec<SV>,
15 sampling: SamplingReport,
16}
17
18impl Render for SP3Page {
19 fn render(&self) -> Markup {
20 html! {
21 div class="table-container" {
22 table class="table is-bordered" {
23 tr {
24 th class="is-info" {
25 "General"
26 }
27 }
28 tr {
29 th {
30 "Velocity"
31 }
32 td {
33 (self.has_velocity.to_string())
34 }
35 }
36 tr {
37 th {
38 "Clock offset"
39 }
40 td {
41 (self.has_clock.to_string())
42 }
43 }
44 tr {
45 th {
46 "Clock drift"
47 }
48 td {
49 (self.has_clock_drift.to_string())
50 }
51 }
52 tr {
53 th class="is-info" {
54 "Satellites"
55 }
56 td {
57 (self.satellites.iter().sorted().join(", "))
58 }
59 }
60 tr {
61 th class="is-info" {
62 "Sampling"
63 }
64 td {
65 (self.sampling.render())
66 }
67 }
68 }
69 }
70 }
71 }
72}
73
74pub struct SP3Report {
75 pub agency: String,
76 pub version: String,
77 pub coord_system: String,
78 pub orbit_fit: String,
79 pub constellation: String,
80 pub time_scale: String,
81 pub sampling: SamplingReport,
82 pub pages: HashMap<Constellation, SP3Page>,
83}
84
85impl SP3Report {
86 pub fn html_inline_menu_bar(&self) -> Markup {
87 html! {
88 a id="menu:sp3" {
89 span class="icon" {
90 i class="fa-solid fa-satellite" {}
91 }
92 "High Precision Orbit (SP3)"
93 }
94 //ul(class="menu-list", id="menu:tabs:sp3", style="display:block") {
95 // @ for page in self.pages.keys().sorted() {
96 // li {
97 // a(id=&format!("menu:sp3:{}", page), class="tab:sp3", style="margin-left:29px") {
98 // span(class="icon") {
99 // i(class="fa-solid fa-satellite");
100 // }
101 // : page.to_string()
102 // }
103 // }
104 // }
105 //}
106 }
107 }
108 pub fn new(sp3: &SP3) -> Self {
109 Self {
110 agency: sp3.header.agency.clone(),
111 version: sp3.header.version.to_string(),
112 coord_system: sp3.header.coord_system.clone(),
113 orbit_fit: sp3.header.orbit_type.to_string(),
114 time_scale: sp3.header.timescale.to_string(),
115 sampling: SamplingReport::from_sp3(sp3),
116 constellation: sp3.header.constellation.to_string(),
117 pages: {
118 let mut pages = HashMap::<Constellation, SP3Page>::new();
119 for constellation in sp3.constellations_iter() {
120 let filter = Filter::mask(
121 MaskOperand::Equals,
122 FilterItem::ConstellationItem(vec![constellation]),
123 );
124 let focused = sp3.filter(&filter);
125 //let epochs = focused.epoch().collect::<Vec<_>>();
126 let satellites = focused.satellites_iter().collect::<Vec<_>>();
127 pages.insert(
128 constellation,
129 SP3Page {
130 has_clock: focused.has_satellite_clock_offset(),
131 sampling: SamplingReport::from_sp3(&focused),
132 has_velocity: focused.has_satellite_velocity(),
133 has_clock_drift: focused.has_satellite_clock_drift(),
134 satellites,
135 },
136 );
137 }
138 pages
139 },
140 }
141 }
142}
143
144impl Render for SP3Report {
145 fn render(&self) -> Markup {
146 html! {
147 div class="table-container" {
148 table class="table is-bordered" {
149 tr {
150 th {
151 button aria-label="File revision" data-balloon-pos="right" {
152 "File revision"
153 }
154 }
155 td {
156 (self.version)
157 }
158 }
159 tr {
160 th {
161 button aria-label="Production Center" data-balloon-pos="right" {
162 "Agency"
163 }
164 }
165 td {
166 (self.agency.clone())
167 }
168 }
169 tr {
170 th {
171 button aria-label="Fitted constellations" data-balloon-pos="right" {
172 "Constellation"
173 }
174 }
175 td {
176 (self.constellation.clone())
177 }
178 }
179 tr {
180 th {
181 button aria-label="Timescale in which post-fit coordinates are expressed." data-balloon-pos="right" {
182 "Timescale"
183 }
184 }
185 td {
186 (self.time_scale.clone())
187 }
188 }
189 tr {
190 th {
191 button aria-label="Reference frame in which post-fit coordinates are expressed." data-balloon-pos="right" {
192 "Reference Frame"
193 }
194 }
195 td {
196 (self.coord_system.clone())
197 }
198 }
199 tr {
200 th {
201 button aria-label="Coordinates determination technique." data-balloon-pos="right" {
202 "Orbit FIT"
203 }
204 }
205 td {
206 (self.orbit_fit.clone())
207 }
208 }
209 tr {
210 th {
211 "Sampling"
212 }
213 td {
214 (self.sampling.render())
215 }
216 }
217 }//table
218 }//table-container
219 @for constell in self.pages.keys().sorted() {
220 @if let Some(page) = self.pages.get(constell) {
221 div class="table-container is-page" id=(format!("sp3:{}", constell)) style="display:block" {
222 table class="table is-bordered" {
223 tr {
224 th class="is-info" {
225 (constell.to_string())
226 }
227 td {
228 (page.render())
229 }
230 }
231 }
232 }
233 }
234 }
235 }
236 }
237}