INSTINCT Code Coverage Report


Directory: src/
File: Navigation/GNSS/SNRMask.cpp
Date: 2025-02-07 16:54:41
Exec Total Coverage
Lines: 16 101 15.8%
Functions: 3 9 33.3%
Branches: 13 162 8.0%

Line Branch Exec Source
1 // This file is part of INSTINCT, the INS Toolkit for Integrated
2 // Navigation Concepts and Training by the Institute of Navigation of
3 // the University of Stuttgart, Germany.
4 //
5 // This Source Code Form is subject to the terms of the Mozilla Public
6 // License, v. 2.0. If a copy of the MPL was not distributed with this
7 // file, You can obtain one at https://mozilla.org/MPL/2.0/.
8
9 /// @file SNRMask.cpp
10 /// @brief Signal to Noise Ratio Mask
11 /// @author T. Topp (topp@ins.uni-stuttgart.de)
12 /// @date 2023-12-17
13
14 #include "SNRMask.hpp"
15
16 #include <imgui.h>
17 #include <fmt/format.h>
18
19 #include "internal/gui/widgets/imgui_ex.hpp"
20 #include "internal/gui/widgets/HelpMarker.hpp"
21
22 namespace NAV
23 {
24
25 128 SNRMask::SNRMask()
26 {
27 128 const auto frequencies = Frequency::GetAll();
28
2/2
✓ Branch 0 taken 3456 times.
✓ Branch 1 taken 128 times.
3712 for (size_t i = 0; i < frequencies.size(); i++)
29 {
30
2/4
✓ Branch 1 taken 3456 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 3456 times.
✗ Branch 5 not taken.
3456 mask.at(i).first = frequencies.at(i);
31
1/2
✓ Branch 1 taken 3456 times.
✗ Branch 2 not taken.
3456 mask.at(i).second.second = true;
32 }
33 128 }
34
35 bool SNRMask::ShowGuiWidgets(const char* label)
36 {
37 bool changed = false;
38 if (!label) { label = "SNR Mask"; }
39
40 if (isInactive()) { ImGui::PushStyleColor(ImGuiCol_Button, ImGui::GetStyle().Colors[ImGuiCol_TextDisabled]); }
41 if (ImGui::Button(fmt::format("{}", label).c_str()))
42 {
43 ImGui::OpenPopup(fmt::format("SNR Mask##Popup - {}", label).c_str());
44 }
45 if (isInactive())
46 {
47 ImGui::PopStyleColor();
48 if (ImGui::IsItemHovered())
49 {
50 ImGui::SetTooltip("Inactive due to all values being 0");
51 }
52 }
53
54 constexpr float INPUT_WIDTH = 40.0F;
55
56 if (ImGui::BeginPopup(fmt::format("SNR Mask##Popup - {}", label).c_str()))
57 {
58 if (ImGui::BeginTable(fmt::format("").c_str(), elevations.size() + 2, ImGuiTableFlags_Borders))
59 {
60 ImGui::TableSetupColumn("Elevation:");
61 for (const auto& elevation : elevations)
62 {
63 ImGui::TableSetupColumn(fmt::format("< {:.0f}", rad2deg(elevation)).c_str());
64 }
65 ImGui::TableSetupColumn("");
66 ImGui::TableHeadersRow();
67
68 ImGui::TableNextColumn();
69 ImGui::TextUnformatted("All");
70 ImGui::SameLine();
71 gui::widgets::HelpMarker("- The values for each frequency are used for the calculation,\n"
72 " this row is only used to change all frequencies at the same time.\n"
73 "- Grayed out when not all frequencies below have the same value.");
74 for (size_t i = 0; i < allOverride.first.size(); ++i)
75 {
76 ImGui::TableNextColumn();
77 ImGui::SetNextItemWidth(INPUT_WIDTH);
78 if (allOverride.second && i != 0) { ImGui::BeginDisabled(); }
79 bool anyValueDiffers = std::ranges::any_of(mask, [&](const auto& freqMask) {
80 return allOverride.first.at(i) != freqMask.second.first.at(i);
81 });
82 if (anyValueDiffers) { ImGui::PushStyleColor(ImGuiCol_FrameBg, ImGui::GetStyle().Colors[ImGuiCol_TextDisabled]); }
83 if (ImGui::DragDouble(fmt::format("##all {} {}", label, i).c_str(), &allOverride.first.at(i), 1.0, 0.0, 100.0, "%.1f"))
84 {
85 changed = true;
86 if (!allOverride.second)
87 {
88 for (auto& freqSNRs : mask)
89 {
90 freqSNRs.second.first.at(i) = allOverride.first.at(i);
91 }
92 }
93 else
94 {
95 for (size_t i = 0; i < allOverride.first.size(); ++i)
96 {
97 allOverride.first.at(i) = allOverride.first[0];
98 for (auto& freqSNRs : mask)
99 {
100 freqSNRs.second.first.at(i) = allOverride.first.at(i);
101 }
102 }
103 }
104 }
105 if (anyValueDiffers) { ImGui::PopStyleColor(); }
106 if (allOverride.second && i != 0) { ImGui::EndDisabled(); }
107 }
108 ImGui::TableNextColumn();
109 if (ImGui::Checkbox(fmt::format("##lock together - all {}", label).c_str(), &allOverride.second))
110 {
111 changed = true;
112 if (allOverride.second)
113 {
114 for (size_t i = 0; i < allOverride.first.size(); ++i)
115 {
116 allOverride.first.at(i) = allOverride.first[0];
117 for (auto& freqSNRs : mask)
118 {
119 freqSNRs.second.first.at(i) = allOverride.first.at(i);
120 }
121 }
122 }
123 }
124 if (ImGui::IsItemHovered()) { ImGui::SetTooltip("Lock all values together"); }
125
126 for (auto& [freq, SNRs] : mask)
127 {
128 ImGui::TableNextColumn();
129 ImGui::TextUnformatted(fmt::format("{}", freq).c_str());
130 for (size_t i = 0; i < SNRs.first.size(); ++i)
131 {
132 ImGui::TableNextColumn();
133 ImGui::SetNextItemWidth(INPUT_WIDTH);
134 if (SNRs.second && i != 0) { ImGui::BeginDisabled(); }
135 if (ImGui::DragDouble(fmt::format("##{} {} {}", freq, label, i).c_str(), &SNRs.first.at(i), 1.0, 0.0, 100.0, "%.1f"))
136 {
137 changed = true;
138 if (SNRs.second)
139 {
140 for (size_t j = 1; j < SNRs.first.size(); ++j)
141 {
142 SNRs.first.at(j) = SNRs.first.at(i);
143 }
144 }
145 }
146 if (SNRs.second && i != 0) { ImGui::EndDisabled(); }
147 }
148 ImGui::TableNextColumn();
149 if (ImGui::Checkbox(fmt::format("##lock together - all {} {}", freq, label).c_str(), &SNRs.second))
150 {
151 changed = true;
152 if (SNRs.second)
153 {
154 for (size_t i = 1; i < SNRs.first.size(); ++i)
155 {
156 SNRs.first.at(i) = SNRs.first[0];
157 }
158 }
159 }
160 if (ImGui::IsItemHovered()) { ImGui::SetTooltip("Lock all values together"); }
161 }
162
163 ImGui::EndTable();
164 }
165
166 ImGui::EndPopup();
167 }
168
169 return changed;
170 }
171
172 bool SNRMask::isInactive() const
173 {
174 return std::ranges::all_of(mask, [](const auto& freqMask) {
175 return std::ranges::all_of(freqMask.second.first, [](const auto& SNR) {
176 return SNR < 1e-7;
177 });
178 });
179 }
180
181 40003 bool SNRMask::checkSNRMask(Frequency freq, double elevation, double SNR) const
182 {
183
1/2
✓ Branch 4 taken 66475 times.
✗ Branch 5 not taken.
66475 for (const auto& [maskFreq, SNRs] : mask)
184 {
185
2/2
✓ Branch 1 taken 40003 times.
✓ Branch 2 taken 26472 times.
66475 if (maskFreq == freq)
186 {
187
1/2
✓ Branch 0 taken 197239 times.
✗ Branch 1 not taken.
394478 for (size_t i = 0; i < elevations.size(); i++)
188 {
189
2/2
✓ Branch 1 taken 40003 times.
✓ Branch 2 taken 157236 times.
197239 if (elevation <= elevations.at(i))
190 {
191 40003 return SNR > SNRs.first.at(i);
192 }
193 }
194 }
195 }
196
197 return false;
198 }
199
200 void to_json(json& j, const SNRMask& obj)
201 {
202 j = json{
203 { "allOverride", obj.allOverride },
204 { "mask", obj.mask },
205 };
206 }
207
208 8 void from_json(const json& j, SNRMask& obj)
209 {
210
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 if (j.contains("allOverride")) { j.at("allOverride").get_to(obj.allOverride); }
211
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 if (j.contains("mask")) { j.at("mask").get_to(obj.mask); }
212 8 }
213
214 } // namespace NAV
215