INSTINCT Code Coverage Report


Directory: src/
File: Nodes/Utility/TimeWindow.cpp
Date: 2025-02-07 16:54:41
Exec Total Coverage
Lines: 52 85 61.2%
Functions: 9 12 75.0%
Branches: 69 196 35.2%

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 #include "TimeWindow.hpp"
10
11 #include "internal/NodeManager.hpp"
12 namespace nm = NAV::NodeManager;
13 #include "internal/FlowManager.hpp"
14
15 #include "internal/gui/widgets/imgui_ex.hpp"
16 #include "internal/gui/widgets/HelpMarker.hpp"
17 #include "internal/gui/NodeEditorApplication.hpp"
18
19 // ---------------------------------------------------------- Member functions -------------------------------------------------------------
20
21
2/4
✓ Branch 1 taken 114 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 114 times.
✗ Branch 5 not taken.
114 NAV::TimeWindow::TimeWindow() : Node(typeStatic())
22 {
23 LOG_TRACE("{}: called", name);
24 114 _hasConfig = true;
25 114 _guiConfigDefaultWindowSize = { 500, 290 };
26
27
4/8
✓ Branch 1 taken 114 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 114 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 114 times.
✓ Branch 9 taken 114 times.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
342 nm::CreateInputPin(this, "Input", Pin::Type::Flow, { NodeData::type() }, &TimeWindow::receiveObs);
28
29
4/8
✓ Branch 2 taken 114 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 114 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 114 times.
✓ Branch 10 taken 114 times.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
456 nm::CreateOutputPin(this, "Output", Pin::Type::Flow, { NodeData::type() });
30 342 }
31
32 232 NAV::TimeWindow::~TimeWindow()
33 {
34 LOG_TRACE("{}: called", nameId());
35 232 }
36
37 226 std::string NAV::TimeWindow::typeStatic()
38 {
39
1/2
✓ Branch 1 taken 226 times.
✗ Branch 2 not taken.
452 return "TimeWindow";
40 }
41
42 std::string NAV::TimeWindow::type() const
43 {
44 return typeStatic();
45 }
46
47 112 std::string NAV::TimeWindow::category()
48 {
49
1/2
✓ Branch 1 taken 112 times.
✗ Branch 2 not taken.
224 return "Utility";
50 }
51
52 void NAV::TimeWindow::guiConfig()
53 {
54 if (ImGui::Checkbox(fmt::format("Inverse Window##{}", size_t(id)).c_str(), &_inverseWindow))
55 {
56 flow::ApplyChanges();
57 }
58 ImGui::SameLine();
59 gui::widgets::HelpMarker("Normal: [startTime, endTime]\n"
60 "Inverse: (-∞, startTime), (endTime, ∞)");
61
62 if (ImGui::BeginTable(fmt::format("Time Window##{}", size_t(id)).c_str(), 2, ImGuiTableFlags_Borders | ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_NoHostExtendX, ImVec2(0.0F, 0.0F)))
63 {
64 ImGui::TableSetupColumn("Beginning");
65 ImGui::TableSetupColumn("End");
66 ImGui::TableHeadersRow();
67
68 for (size_t i = 0; i < _startEndTime.size(); i++)
69 {
70 ImGui::TableNextColumn();
71 if (gui::widgets::TimeEdit(fmt::format("Time edit##{} {}", i, size_t(id)).c_str(), _startEndTime.at(i), _timeEditFormat.at(i)))
72 {
73 LOG_DEBUG("{}: {}Time = {}", nameId(), i == 0 ? "start" : "end", _startEndTime.at(i));
74 flow::ApplyChanges();
75 if (_startEndTime[0] >= _startEndTime[1]) { doDeinitialize(); }
76 }
77 }
78
79 ImGui::EndTable();
80 }
81 }
82
83 json NAV::TimeWindow::save() const
84 {
85 LOG_TRACE("{}: called", nameId());
86
87 json j;
88
89 j["startEndTime"] = _startEndTime;
90 j["timeEditFormat"] = _timeEditFormat;
91 j["inverseWindow"] = _inverseWindow;
92
93 return j;
94 }
95
96 2 void NAV::TimeWindow::restore(json const& j)
97 {
98 LOG_TRACE("{}: called", nameId());
99
100
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 if (j.contains("startEndTime"))
101 {
102 2 j.at("startEndTime").get_to(_startEndTime);
103 }
104
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 if (j.contains("timeEditFormat"))
105 {
106 2 j.at("timeEditFormat").get_to(_timeEditFormat);
107 }
108
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 if (j.contains("inverseWindow"))
109 {
110 2 j.at("inverseWindow").get_to(_inverseWindow);
111 }
112 2 }
113
114 6 bool NAV::TimeWindow::initialize()
115 {
116 LOG_TRACE("{}: called", nameId());
117
118
1/2
✗ Branch 3 not taken.
✓ Branch 4 taken 6 times.
6 if (_startEndTime[0] >= _startEndTime[1])
119 {
120 LOG_ERROR("{}: startTime >= endTime is not allowed. Please reconfigure the node.", nameId());
121 return false;
122 }
123
124 6 return true;
125 }
126
127 4 void NAV::TimeWindow::afterCreateLink(OutputPin& startPin, InputPin& endPin)
128 {
129 LOG_TRACE("{}: called for {} ==> {}", nameId(), size_t(startPin.id), size_t(endPin.id));
130
131
3/4
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 2 times.
4 if (endPin.parentNode->id != id)
132 {
133 2 return; // Link on Output Port
134 }
135
136 // Store previous output pin identifier
137
2/4
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
2 auto previousOutputPinDataIdentifier = outputPins.at(OUTPUT_PORT_INDEX_FLOW).dataIdentifier;
138 // Overwrite output pin identifier with input pin identifier
139
2/4
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
2 outputPins.at(OUTPUT_PORT_INDEX_FLOW).dataIdentifier = startPin.dataIdentifier;
140
141
3/6
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 2 times.
✗ Branch 7 not taken.
2 if (previousOutputPinDataIdentifier != outputPins.at(OUTPUT_PORT_INDEX_FLOW).dataIdentifier) // If the identifier changed
142 {
143 // Check if connected links on output port are still valid
144
2/4
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 2 times.
2 for (auto& link : outputPins.at(OUTPUT_PORT_INDEX_FLOW).links)
145 {
146 if (auto* endPin = link.getConnectedPin())
147 {
148 if (!outputPins.at(OUTPUT_PORT_INDEX_FLOW).canCreateLink(*endPin))
149 {
150 // If the link is not valid anymore, delete it
151 outputPins.at(OUTPUT_PORT_INDEX_FLOW).deleteLink(*endPin);
152 }
153 }
154 }
155
156 // Refresh all links connected to the output pin if the type changed
157
3/6
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 2 times.
✗ Branch 7 not taken.
2 if (outputPins.at(OUTPUT_PORT_INDEX_FLOW).dataIdentifier != previousOutputPinDataIdentifier)
158 {
159
2/4
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 2 times.
2 for (auto& link : outputPins.at(OUTPUT_PORT_INDEX_FLOW).links)
160 {
161 if (auto* connectedPin = link.getConnectedPin())
162 {
163 outputPins.at(OUTPUT_PORT_INDEX_FLOW).recreateLink(*connectedPin);
164 }
165 }
166 }
167 }
168 2 }
169
170 4 void NAV::TimeWindow::afterDeleteLink(OutputPin& startPin, InputPin& endPin)
171 {
172 LOG_TRACE("{}: called for {} ==> {}", nameId(), size_t(startPin.id), size_t(endPin.id));
173
174 4 if ((endPin.parentNode->id != id // Link on Output port is removed
175
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
2 && !inputPins.at(INPUT_PORT_INDEX_FLOW).isPinLinked()) // and the Input port is not linked
176
5/6
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
✓ Branch 3 taken 2 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 2 times.
✓ Branch 6 taken 2 times.
8 || (startPin.parentNode->id != id // Link on Input port is removed
177
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
2 && !outputPins.at(OUTPUT_PORT_INDEX_FLOW).isPinLinked())) // and the Output port is not linked
178 {
179
3/6
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 2 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
4 outputPins.at(OUTPUT_PORT_INDEX_FLOW).dataIdentifier = { NodeData::type() };
180 }
181 6 }
182
183 188 void NAV::TimeWindow::receiveObs(NAV::InputPin::NodeDataQueue& queue, size_t /* pinIdx */)
184 {
185 // Check whether timestamp is within the time window
186
1/2
✓ Branch 1 taken 188 times.
✗ Branch 2 not taken.
188 auto obs = queue.extract_front();
187
2/2
✓ Branch 0 taken 101 times.
✓ Branch 1 taken 87 times.
188 if (_inverseWindow)
188 {
189
7/8
✓ Branch 3 taken 86 times.
✓ Branch 4 taken 15 times.
✓ Branch 8 taken 86 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 15 times.
✓ Branch 11 taken 71 times.
✓ Branch 12 taken 30 times.
✓ Branch 13 taken 71 times.
101 if (obs->insTime < _startEndTime[0] || obs->insTime > _startEndTime[1])
190 {
191
1/2
✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
30 invokeCallbacks(OUTPUT_PORT_INDEX_FLOW, obs);
192 }
193 }
194 else
195 {
196
8/10
✓ Branch 3 taken 87 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 72 times.
✓ Branch 6 taken 15 times.
✓ Branch 10 taken 72 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 71 times.
✓ Branch 13 taken 1 times.
✓ Branch 14 taken 71 times.
✓ Branch 15 taken 16 times.
87 if (obs->insTime >= _startEndTime[0] && obs->insTime <= _startEndTime[1])
197 {
198
1/2
✓ Branch 1 taken 71 times.
✗ Branch 2 not taken.
71 invokeCallbacks(OUTPUT_PORT_INDEX_FLOW, obs);
199 }
200
3/4
✓ Branch 3 taken 16 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 1 times.
✓ Branch 6 taken 15 times.
16 else if (obs->insTime > _startEndTime[1])
201 {
202
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 inputPins.at(INPUT_PORT_INDEX_FLOW).queueBlocked = true;
203
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 inputPins.at(INPUT_PORT_INDEX_FLOW).queue.clear();
204
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 outputPins.at(OUTPUT_PORT_INDEX_FLOW).noMoreDataAvailable = true;
205 }
206 }
207 188 }
208