INSTINCT Code Coverage Report


Directory: src/
File: internal/gui/widgets/PositionInput.cpp
Date: 2025-02-07 16:54:41
Exec Total Coverage
Lines: 14 94 14.9%
Functions: 2 7 28.6%
Branches: 16 220 7.3%

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 PositionInput.hpp
10 /// @brief Position Input GUI widgets
11 /// @author T. Topp (topp@ins.uni-stuttgart.de)
12 /// @date 2023-08-14
13
14 #include "PositionInput.hpp"
15
16 #include <imgui.h>
17 #include <fmt/core.h>
18
19 #include "internal/gui/widgets/imgui_ex.hpp"
20 #include "internal/gui/widgets/EnumCombo.hpp"
21
22 namespace NAV
23 {
24
25 const char* to_string(gui::widgets::PositionWithFrame::ReferenceFrame refFrame)
26 {
27 switch (refFrame)
28 {
29 case gui::widgets::PositionWithFrame::ReferenceFrame::ECEF:
30 return "ECEF";
31 case gui::widgets::PositionWithFrame::ReferenceFrame::LLA:
32 return "LLA";
33 case gui::widgets::PositionWithFrame::ReferenceFrame::COUNT:
34 break;
35 }
36 return "";
37 }
38
39 namespace gui::widgets
40 {
41 namespace
42 {
43 /// @brief Shows a ComboBox to select the position input reference frame
44 /// @param[in] label Label to show beside the combo box. This has to be a unique id for ImGui.
45 /// @param[in] refFrame Reference to the frame to select
46 bool ComboPositionInputReferenceFrame(const char* label, PositionWithFrame::ReferenceFrame& refFrame)
47 {
48 return gui::widgets::EnumCombo(label, refFrame);
49 }
50 } // namespace
51 } // namespace gui::widgets
52
53 } // namespace NAV
54
55 bool NAV::gui::widgets::PositionInput(const char* str, PositionWithFrame& position, PositionInputLayout layout, float itemWidth)
56 {
57 bool changes = false;
58 bool edited = false;
59
60 ImGui::BeginGroup();
61
62 if (layout == PositionInputLayout::SINGLE_ROW)
63 {
64 std::string txt = str;
65 txt = txt.substr(0, txt.find_first_of('#'));
66 ImGui::TextUnformatted(txt.c_str());
67 ImGui::SameLine();
68 }
69
70 if (layout == PositionInputLayout::SINGLE_ROW) { ImGui::SetNextItemWidth(80.0F); }
71 else { ImGui::SetNextItemWidth(itemWidth); }
72 if (ComboPositionInputReferenceFrame(fmt::format("{}##ComboPositionInputReferenceFrame {}", layout != PositionInputLayout::SINGLE_ROW ? str : "", str).c_str(), position.frame))
73 {
74 changes = true;
75 }
76 if (layout == PositionInputLayout::SINGLE_ROW) { ImGui::SameLine(); }
77
78 if (position.frame == PositionWithFrame::ReferenceFrame::ECEF)
79 {
80 ImGui::SetNextItemWidth(itemWidth);
81 if (ImGui::InputDouble(fmt::format("{}##X {}", layout != PositionInputLayout::TWO_ROWS ? "X" : "", str).c_str(), &position.e_position(0), 0.0, 0.0, "%.4fm")) { changes = true; }
82
83 if (layout == PositionInputLayout::SINGLE_ROW || layout == PositionInputLayout::TWO_ROWS) { ImGui::SameLine(); }
84 ImGui::SetNextItemWidth(itemWidth);
85 if (ImGui::InputDouble(fmt::format("{}##Y {}", layout != PositionInputLayout::TWO_ROWS ? "Y" : "", str).c_str(), &position.e_position(1), 0.0, 0.0, "%.4fm")) { changes = true; }
86
87 if (layout == PositionInputLayout::SINGLE_ROW || layout == PositionInputLayout::TWO_ROWS) { ImGui::SameLine(); }
88 ImGui::SetNextItemWidth(itemWidth);
89 if (ImGui::InputDouble(fmt::format("{}##Z {}", layout != PositionInputLayout::TWO_ROWS ? "Z" : "", str).c_str(), &position.e_position(2), 0.0, 0.0, "%.4fm")) { changes = true; }
90
91 if (layout == PositionInputLayout::TWO_ROWS)
92 {
93 ImGui::SameLine();
94 ImGui::SetCursorPosX(ImGui::GetCursorPosX() - ImGui::GetStyle().ItemSpacing.x + ImGui::GetStyle().ItemInnerSpacing.x);
95 ImGui::TextUnformatted("XYZ");
96 }
97 }
98 else if (position.frame == PositionWithFrame::ReferenceFrame::LLA)
99 {
100 auto lla_position = trafo::ecef2lla_WGS84(position.e_position);
101 lla_position(0) = rad2deg(lla_position(0));
102 lla_position(1) = rad2deg(lla_position(1));
103 if (lla_position.hasNaN())
104 {
105 lla_position = Eigen::Vector3d(0, 0, 0);
106 position.e_position = trafo::lla2ecef_WGS84(lla_position);
107 }
108
109 ImGui::SetNextItemWidth(itemWidth);
110 if (ImGui::InputDoubleL(fmt::format("{}##Lat {}", layout != PositionInputLayout::TWO_ROWS ? "Latitude" : "", str).c_str(), &lla_position(0), -90.0, 90.0, 0.0, 0.0, "%.9f°")) { edited = true; }
111 if (ImGui::IsItemDeactivatedAfterEdit()) { changes = true; }
112
113 if (layout == PositionInputLayout::SINGLE_ROW || layout == PositionInputLayout::TWO_ROWS) { ImGui::SameLine(); }
114 ImGui::SetNextItemWidth(itemWidth);
115 if (ImGui::InputDoubleL(fmt::format("{}##Lon {}", layout != PositionInputLayout::TWO_ROWS ? "Longitude" : "", str).c_str(), &lla_position(1), -180.0, 180.0, 0.0, 0.0, "%.9f°")) { edited = true; }
116 if (ImGui::IsItemDeactivatedAfterEdit()) { changes = true; }
117
118 if (layout == PositionInputLayout::SINGLE_ROW || layout == PositionInputLayout::TWO_ROWS) { ImGui::SameLine(); }
119 ImGui::SetNextItemWidth(itemWidth);
120 if (ImGui::InputDouble(fmt::format("{}##Alt {}", layout != PositionInputLayout::TWO_ROWS ? "Altitude" : "", str).c_str(), &lla_position(2), 0.0, 0.0, "%.4fm")) { edited = true; }
121 if (ImGui::IsItemDeactivatedAfterEdit()) { changes = true; }
122
123 if (layout == PositionInputLayout::TWO_ROWS)
124 {
125 ImGui::SameLine();
126 ImGui::SetCursorPosX(ImGui::GetCursorPosX() - ImGui::GetStyle().ItemSpacing.x + ImGui::GetStyle().ItemInnerSpacing.x);
127 ImGui::TextUnformatted("Lat, Lon, Alt");
128 }
129
130 if (changes || edited)
131 {
132 lla_position(0) = deg2rad(lla_position(0));
133 lla_position(1) = deg2rad(lla_position(1));
134 if (!lla_position.hasNaN())
135 {
136 position.e_position = trafo::lla2ecef_WGS84(lla_position);
137 }
138 }
139 }
140
141 ImGui::EndGroup();
142
143 return changes;
144 }
145
146 void NAV::gui::widgets::to_json(json& j, const PositionWithFrame::ReferenceFrame& refFrame)
147 {
148 j = to_string(refFrame);
149 }
150
151 9 void NAV::gui::widgets::from_json(const json& j, PositionWithFrame::ReferenceFrame& refFrame)
152 {
153
1/2
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
9 auto text = j.get<std::string>();
154
2/4
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 9 times.
9 if (text == "ECEF") { refFrame = PositionWithFrame::ReferenceFrame::ECEF; }
155
2/4
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 9 times.
✗ Branch 4 not taken.
9 else if (text == "LLA") { refFrame = PositionWithFrame::ReferenceFrame::LLA; }
156 9 }
157 void NAV::gui::widgets::to_json(json& j, const PositionWithFrame& position)
158 {
159 j["frame"] = position.frame;
160 if (position.frame == PositionWithFrame::ReferenceFrame::ECEF)
161 {
162 j["position"] = position.e_position;
163 }
164 else if (position.frame == PositionWithFrame::ReferenceFrame::LLA)
165 {
166 auto lla = trafo::ecef2lla_WGS84(position.e_position);
167 j["position"] = Eigen::Vector3d(rad2deg(lla(0)), rad2deg(lla(1)), lla(2));
168 }
169 }
170
171 9 void NAV::gui::widgets::from_json(const json& j, PositionWithFrame& position)
172 {
173
1/2
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
9 if (j.contains("frame"))
174 {
175 9 j.at("frame").get_to(position.frame);
176 }
177
1/2
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
9 if (j.contains("position"))
178 {
179
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
9 if (position.frame == PositionWithFrame::ReferenceFrame::ECEF)
180 {
181 j.at("position").get_to(position.e_position);
182 }
183
1/2
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
9 else if (position.frame == PositionWithFrame::ReferenceFrame::LLA)
184 {
185
2/4
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 9 times.
✗ Branch 5 not taken.
9 auto lla = j.at("position").get<Eigen::Vector3d>();
186
5/10
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 9 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 9 times.
✗ Branch 9 not taken.
✓ Branch 12 taken 9 times.
✗ Branch 13 not taken.
✓ Branch 15 taken 9 times.
✗ Branch 16 not taken.
9 position.e_position = trafo::lla2ecef_WGS84(Eigen::Vector3d(deg2rad(lla(0)), deg2rad(lla(1)), lla(2)));
187 }
188 }
189 9 }
190