INSTINCT Code Coverage Report


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