INSTINCT Code Coverage Report


Directory: src/
File: internal/Node/Pin.cpp
Date: 2025-02-07 16:54:41
Exec Total Coverage
Lines: 136 229 59.4%
Functions: 27 35 77.1%
Branches: 159 345 46.1%

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 "internal/Node/Pin.hpp"
10
11 #include "internal/Node/Node.hpp"
12 #include "internal/gui/widgets/PinIcon.hpp"
13 #include "internal/gui/NodeEditorApplication.hpp"
14 #include "internal/NodeManager.hpp"
15 namespace nm = NAV::NodeManager;
16 #include "internal/FlowManager.hpp"
17
18 #include "util/Assert.h"
19
20 #include "NodeRegistry.hpp"
21
22 #include <imgui_node_editor.h>
23 #include <algorithm>
24
25 // ###########################################################################################################
26 // Pin
27 // ###########################################################################################################
28
29 273 bool NAV::Pin::canCreateLink(const OutputPin& startPin, const InputPin& endPin)
30 {
31 273 bool dataTypesMatch = true;
32
33 273 if (startPin.type == Pin::Type::Flow
34
7/8
✓ Branch 0 taken 263 times.
✓ Branch 1 taken 10 times.
✓ Branch 3 taken 263 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 2 times.
✓ Branch 6 taken 261 times.
✓ Branch 7 taken 2 times.
✓ Branch 8 taken 271 times.
273 && !NAV::NodeRegistry::NodeDataTypeAnyIsChildOf(startPin.dataIdentifier, endPin.dataIdentifier))
35 {
36 2 dataTypesMatch = false;
37 }
38
39 if (startPin.type == Pin::Type::Delegate
40
1/4
✗ Branch 1 not taken.
✓ Branch 2 taken 273 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
273 && (startPin.parentNode == nullptr
41
2/12
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✓ Branch 11 taken 273 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 273 times.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
273 || std::ranges::find(endPin.dataIdentifier, startPin.parentNode->type()) == endPin.dataIdentifier.end()))
42 {
43 dataTypesMatch = false;
44 }
45
46
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 263 times.
536 if ((startPin.type == Pin::Type::Object || startPin.type == Pin::Type::Matrix) // NOLINT(misc-redundant-expression) - false positive warning
47
5/8
✓ Branch 0 taken 263 times.
✓ Branch 1 taken 10 times.
✓ Branch 3 taken 10 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 10 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 273 times.
536 && !dataIdentifierHaveCommon(startPin.dataIdentifier, endPin.dataIdentifier))
48 {
49 dataTypesMatch = false;
50 }
51
52 273 return startPin.id != endPin.id // Different Pins
53
1/2
✓ Branch 1 taken 273 times.
✗ Branch 2 not taken.
273 && startPin.kind != endPin.kind // Input <=> Output
54
1/2
✓ Branch 1 taken 273 times.
✗ Branch 2 not taken.
273 && startPin.type == endPin.type // Same Type (Flow, Object, ...)
55
1/2
✓ Branch 0 taken 273 times.
✗ Branch 1 not taken.
273 && startPin.parentNode != endPin.parentNode // Different Nodes
56
3/4
✓ Branch 0 taken 273 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 271 times.
✓ Branch 3 taken 2 times.
546 && dataTypesMatch; // Data identifier match
57 }
58
59 10 bool NAV::Pin::dataIdentifierHaveCommon(const std::vector<std::string>& a, const std::vector<std::string>& b)
60 {
61
1/2
✓ Branch 2 taken 10 times.
✗ Branch 3 not taken.
20 return !a.empty() && !b.empty()
62
4/8
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
✓ Branch 4 taken 10 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 10 times.
✗ Branch 8 not taken.
✓ Branch 11 taken 10 times.
✗ Branch 12 not taken.
30 && std::ranges::find_if(a, [&b](const std::string& str) { return std::ranges::find(b, str) != b.end(); }) != a.end();
63 }
64
65 ImColor NAV::Pin::getIconColor() const
66 {
67 switch (Type::Value(type))
68 {
69 case Type::None:
70 return { 0, 0, 0 };
71 case Type::Flow:
72 if (ax::NodeEditor::GetStyle().Colors[ax::NodeEditor::StyleColor_NodeBg].x
73 + ax::NodeEditor::GetStyle().Colors[ax::NodeEditor::StyleColor_NodeBg].y
74 + ax::NodeEditor::GetStyle().Colors[ax::NodeEditor::StyleColor_NodeBg].z
75 > 2.0F)
76 {
77 return { 0, 0, 0 };
78 }
79 return { 255, 255, 255 };
80 case Type::Bool:
81 return { 220, 48, 48 };
82 case Type::Int:
83 return { 68, 201, 156 };
84 case Type::Float:
85 return { 147, 226, 74 };
86 case Type::String:
87 return { 124, 21, 153 };
88 case Type::Object:
89 return { 51, 150, 215 };
90 case Type::Matrix:
91 return { 255, 165, 0 };
92 case Type::Delegate:
93 return { 255, 48, 48 };
94 }
95 return { 0, 0, 0 };
96 }
97
98 void NAV::Pin::drawPinIcon(bool connected, int alpha) const
99 {
100 namespace PinIcon = gui::widgets::PinIcon;
101
102 PinIcon::Type iconType = PinIcon::Type::Flow;
103 ImColor color = getIconColor();
104 color.Value.w = static_cast<float>(alpha) / 255.0F;
105 switch (Type::Value(type))
106 {
107 case Type::None:
108 iconType = PinIcon::Type::Grid;
109 break;
110 case Type::Flow:
111 iconType = PinIcon::Type::Flow;
112 break;
113 case Type::Bool:
114 // iconType = PinIcon::Type::Circle;
115 // break;
116 case Type::Int:
117 // iconType = PinIcon::Type::Circle;
118 // break;
119 case Type::Float:
120 iconType = PinIcon::Type::Circle;
121 break;
122 case Type::String:
123 iconType = PinIcon::Type::RoundSquare;
124 break;
125 case Type::Object:
126 // iconType = PinIcon::Type::Diamond;
127 // break;
128 case Type::Matrix:
129 iconType = PinIcon::Type::Diamond;
130 break;
131 case Type::Delegate:
132 iconType = PinIcon::Type::Square;
133 break;
134 default:
135 return;
136 }
137
138 gui::widgets::PinIcon::Draw(ImVec2(static_cast<float>(m_PinIconSize) * gui::NodeEditorApplication::defaultFontRatio(),
139 static_cast<float>(m_PinIconSize) * gui::NodeEditorApplication::defaultFontRatio()),
140 iconType, connected, color, ImColor(32, 32, 32, alpha));
141 }
142
143 539 bool NAV::Pin::createLink(OutputPin& startPin, InputPin& endPin, ax::NodeEditor::LinkId linkId)
144 {
145
2/2
✓ Branch 1 taken 267 times.
✓ Branch 2 taken 272 times.
539 if (startPin.isPinLinked(endPin)) { return true; } // Pins are already linked
146
147
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 270 times.
272 if (!startPin.canCreateLink(endPin)) { return false; } // Types do not match
148
149
2/4
✓ Branch 0 taken 270 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 270 times.
270 if (!startPin.parentNode || !endPin.parentNode) { return false; }
150 LOG_TRACE("called: {} of [{}] ==> {} of [{}]", size_t(startPin.id), startPin.parentNode->nameId(), size_t(endPin.id), endPin.parentNode->nameId());
151
152
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 270 times.
270 if (!startPin.parentNode->onCreateLink(startPin, endPin))
153 {
154 LOG_ERROR("The new Link between node '{}' and '{}' was refused by its start node.",
155 startPin.parentNode->nameId(), endPin.parentNode->nameId());
156 return false;
157 }
158
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 270 times.
270 if (!endPin.parentNode->onCreateLink(startPin, endPin))
159 {
160 LOG_ERROR("The new Link between node '{}' and '{}' was refused by its end node.",
161 startPin.parentNode->nameId(), endPin.parentNode->nameId());
162 return false;
163 }
164
165
5/10
✓ Branch 2 taken 270 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 270 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 270 times.
✗ Branch 9 not taken.
✓ Branch 11 taken 270 times.
✗ Branch 12 not taken.
✓ Branch 15 taken 270 times.
✗ Branch 16 not taken.
270 LOG_DEBUG("Creating link from pin {} of [{}] ==> {} of [{}]",
166 size_t(startPin.id), startPin.parentNode->nameId(),
167 size_t(endPin.id), endPin.parentNode->nameId());
168
169 270 startPin.connect(endPin, linkId);
170 270 endPin.connect(startPin, linkId);
171
172 270 nm::AddLink(linkId);
173
174
2/2
✓ Branch 1 taken 10 times.
✓ Branch 2 taken 260 times.
270 if (endPin.type != Pin::Type::Flow)
175 {
176
4/8
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 10 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 10 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 10 times.
✗ Branch 8 not taken.
10 if (startPin.parentNode && endPin.parentNode && !startPin.parentNode->isInitialized())
177 {
178
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 10 times.
10 if (endPin.parentNode->isInitialized())
179 {
180 endPin.parentNode->doDeinitialize(true);
181 }
182 }
183 }
184
185
2/4
✓ Branch 0 taken 270 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 270 times.
✗ Branch 3 not taken.
270 if (startPin.parentNode && endPin.parentNode)
186 {
187 270 startPin.parentNode->afterCreateLink(startPin, endPin);
188 270 endPin.parentNode->afterCreateLink(startPin, endPin);
189 }
190
191 270 flow::ApplyChanges();
192
193 270 return true;
194 }
195
196 1 bool NAV::Pin::recreateLink(OutputPin& startPin, InputPin& endPin)
197 {
198
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 if (startPin.isPinLinked(endPin))
199 {
200 1 deleteLink(startPin, endPin);
201
2/4
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
1 return createLink(startPin, endPin);
202 }
203 return false;
204 }
205
206 269 void NAV::Pin::deleteLink(OutputPin& startPin, InputPin& endPin)
207 {
208
2/4
✓ Branch 0 taken 269 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 269 times.
269 if (!startPin.parentNode || !endPin.parentNode) { return; }
209
210
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 269 times.
269 if (!startPin.isPinLinked(endPin))
211 {
212 LOG_ERROR("Cannot delete the link, because the nodes '{}' and '{}' are not linked over pins '{}' => '{}'.",
213 startPin.parentNode->nameId(), endPin.parentNode->nameId(),
214 size_t(startPin.id), size_t(endPin.id));
215 return;
216 }
217
218
6/12
✓ Branch 2 taken 269 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 269 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 269 times.
✗ Branch 9 not taken.
✓ Branch 11 taken 269 times.
✗ Branch 12 not taken.
✓ Branch 14 taken 269 times.
✗ Branch 15 not taken.
✓ Branch 18 taken 269 times.
✗ Branch 19 not taken.
269 LOG_DEBUG("Deleting link {} from pin {} of [{}] ==> pin {} of [{}]", size_t(endPin.link.linkId),
219 size_t(startPin.id), startPin.parentNode->nameId(), size_t(endPin.id), endPin.parentNode->nameId());
220
221 269 startPin.parentNode->onDeleteLink(startPin, endPin);
222 269 endPin.parentNode->onDeleteLink(startPin, endPin);
223
224
2/2
✓ Branch 1 taken 10 times.
✓ Branch 2 taken 259 times.
269 if (endPin.type != Pin::Type::Flow) { endPin.parentNode->doDeinitialize(true); }
225
226 269 startPin.disconnect(endPin);
227 269 endPin.disconnect();
228
229 269 startPin.parentNode->afterDeleteLink(startPin, endPin);
230 269 endPin.parentNode->afterDeleteLink(startPin, endPin);
231
232 269 flow::ApplyChanges();
233 }
234
235 // ###########################################################################################################
236 // OutputPin
237 // ###########################################################################################################
238
239 273 bool NAV::OutputPin::canCreateLink(const NAV::InputPin& other) const
240 {
241 273 return Pin::canCreateLink(*this, other);
242 }
243
244 494 bool NAV::OutputPin::isPinLinked() const
245 {
246 494 return !links.empty();
247 }
248
249 809 bool NAV::OutputPin::isPinLinked(const NAV::InputPin& endPin) const
250 {
251
1/2
✓ Branch 1 taken 809 times.
✗ Branch 2 not taken.
809 auto iter = std::ranges::find_if(links, [&endPin](const OutgoingLink& link) {
252
4/4
✓ Branch 0 taken 588 times.
✓ Branch 1 taken 146 times.
✓ Branch 3 taken 537 times.
✓ Branch 4 taken 51 times.
734 return link.connectedNode == endPin.parentNode && link.connectedPinId == endPin.id;
253 });
254 809 return iter != links.cend();
255 }
256
257 538 bool NAV::OutputPin::createLink(InputPin& endPin, ax::NodeEditor::LinkId linkId)
258 {
259 538 return Pin::createLink(*this, endPin, linkId);
260 }
261
262 1 bool NAV::OutputPin::recreateLink(InputPin& endPin)
263 {
264 1 return Pin::recreateLink(*this, endPin);
265 }
266
267 void NAV::OutputPin::deleteLink(InputPin& endPin)
268 {
269 Pin::deleteLink(*this, endPin);
270 }
271
272 73 void NAV::OutputPin::deleteLinks()
273 {
274
2/2
✓ Branch 1 taken 96 times.
✓ Branch 2 taken 73 times.
169 while (!links.empty())
275 {
276
1/2
✓ Branch 2 taken 96 times.
✗ Branch 3 not taken.
96 if (auto* endPin = links.back().getConnectedPin())
277 {
278 96 Pin::deleteLink(*this, *endPin);
279 }
280 else
281 {
282 links.pop_back();
283 }
284 }
285 73 }
286
287 270 void NAV::OutputPin::connect(NAV::InputPin& endPin, ax::NodeEditor::LinkId linkId)
288 {
289
1/2
✓ Branch 1 taken 270 times.
✗ Branch 2 not taken.
270 auto iter = std::ranges::find_if(links, [&endPin](const OutgoingLink& link) {
290
3/4
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 49 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 17 times.
66 return link.connectedNode == endPin.parentNode && link.connectedPinId == endPin.id;
291 });
292
1/2
✓ Branch 2 taken 270 times.
✗ Branch 3 not taken.
270 if (iter == links.end()) // Link does not yet exist
293 {
294
3/4
✓ Branch 1 taken 270 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 269 times.
✓ Branch 4 taken 1 times.
270 if (linkId)
295 {
296 // LinkId is given
297
1/2
✓ Branch 1 taken 269 times.
✗ Branch 2 not taken.
269 links.emplace_back(linkId, endPin.parentNode, endPin.id);
298
2/4
✓ Branch 1 taken 269 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 269 times.
✗ Branch 4 not taken.
269 if (endPin.link.linkId != linkId)
299 {
300
1/2
✓ Branch 1 taken 269 times.
✗ Branch 2 not taken.
269 endPin.disconnect();
301
1/2
✓ Branch 1 taken 269 times.
✗ Branch 2 not taken.
269 endPin.connect(*this, linkId);
302 }
303 }
304
2/8
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 1 times.
1 else if (endPin.link.connectedNode == parentNode && endPin.link.connectedPinId == id)
305 {
306 // Connected pin is already linked, so get linkId from the connected pin
307 links.emplace_back(endPin.link.linkId, endPin.parentNode, endPin.id);
308 }
309 else
310 {
311 // Connected pin is not linked, so get new linkId
312
2/4
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
1 links.emplace_back(nm::GetNextLinkId(), endPin.parentNode, endPin.id);
313 // Also connect the endPin to this one
314
2/4
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
1 endPin.connect(*this);
315 }
316 }
317 270 }
318
319 269 void NAV::OutputPin::disconnect(InputPin& endPin)
320 {
321
1/2
✓ Branch 1 taken 269 times.
✗ Branch 2 not taken.
269 auto iter = std::ranges::find_if(links, [&endPin](const OutgoingLink& link) {
322
4/4
✓ Branch 0 taken 286 times.
✓ Branch 1 taken 48 times.
✓ Branch 3 taken 269 times.
✓ Branch 4 taken 17 times.
334 return link.connectedNode == endPin.parentNode && link.connectedPinId == endPin.id;
323 });
324
1/2
✓ Branch 2 taken 269 times.
✗ Branch 3 not taken.
269 if (iter != links.end())
325 {
326
1/2
✓ Branch 2 taken 269 times.
✗ Branch 3 not taken.
269 links.erase(iter);
327
4/8
✓ Branch 0 taken 269 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 269 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 269 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 269 times.
✗ Branch 8 not taken.
269 if (endPin.link.connectedNode == parentNode && endPin.link.connectedPinId == id)
328 {
329
1/2
✓ Branch 1 taken 269 times.
✗ Branch 2 not taken.
269 endPin.disconnect();
330 }
331 }
332 269 }
333
334 543491 NAV::InputPin* NAV::OutputPin::OutgoingLink::getConnectedPin() const
335 {
336
2/2
✓ Branch 0 taken 543293 times.
✓ Branch 1 taken 198 times.
543491 if (connectedNode)
337 {
338
1/2
✓ Branch 5 taken 1047172 times.
✗ Branch 6 not taken.
1047405 for (auto& inputPin : connectedNode->inputPins)
339 {
340
3/4
✓ Branch 1 taken 1047634 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 543522 times.
✓ Branch 4 taken 504112 times.
1047143 if (inputPin.id == connectedPinId) { return &inputPin; }
341 }
342 }
343 198 return nullptr;
344 }
345
346 // ###########################################################################################################
347 // InputPin
348 // ###########################################################################################################
349
350 bool NAV::InputPin::canCreateLink(const OutputPin& other) const
351 {
352 return Pin::canCreateLink(other, *this);
353 }
354
355 656138 bool NAV::InputPin::isPinLinked() const
356 {
357
4/6
✓ Branch 1 taken 655730 times.
✓ Branch 2 taken 236 times.
✓ Branch 3 taken 655764 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 654810 times.
✗ Branch 7 not taken.
656138 return link.linkId && link.connectedNode && link.connectedPinId;
358 }
359
360 bool NAV::InputPin::createLink(OutputPin& startPin, ax::NodeEditor::LinkId linkId)
361 {
362 return Pin::createLink(startPin, *this, linkId);
363 }
364
365 bool NAV::InputPin::recreateLink(OutputPin& startPin)
366 {
367 return Pin::recreateLink(startPin, *this);
368 }
369
370 172 void NAV::InputPin::deleteLink()
371 {
372
1/2
✓ Branch 1 taken 172 times.
✗ Branch 2 not taken.
172 if (auto* startPin = link.getConnectedPin())
373 {
374 172 Pin::deleteLink(*startPin, *this);
375 }
376 172 }
377
378 540 void NAV::InputPin::connect(NAV::OutputPin& startPin, ax::NodeEditor::LinkId linkId)
379 {
380
5/6
✓ Branch 0 taken 270 times.
✓ Branch 1 taken 270 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 270 times.
✓ Branch 5 taken 270 times.
✓ Branch 6 taken 270 times.
540 if (link.connectedNode != startPin.parentNode || link.connectedPinId != startPin.id) // Link does not yet exist
381 {
382 270 link.connectedNode = startPin.parentNode;
383 270 link.connectedPinId = startPin.id;
384
385
1/2
✓ Branch 1 taken 270 times.
✗ Branch 2 not taken.
270 auto iter = std::ranges::find_if(startPin.links, [&, this](const OutputPin::OutgoingLink& link) {
386
4/4
✓ Branch 0 taken 287 times.
✓ Branch 1 taken 49 times.
✓ Branch 3 taken 270 times.
✓ Branch 4 taken 17 times.
336 return link.connectedNode == parentNode && link.connectedPinId == id;
387 });
388
389
3/4
✓ Branch 1 taken 270 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 269 times.
✓ Branch 4 taken 1 times.
270 if (linkId)
390 {
391 // LinkId is given
392 269 link.linkId = linkId;
393
4/8
✓ Branch 2 taken 269 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 269 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 269 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 269 times.
269 if (iter != startPin.links.end() && iter->linkId != linkId)
394 {
395 startPin.disconnect(*this);
396 startPin.connect(*this, linkId);
397 }
398 }
399
1/2
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
1 else if (iter != startPin.links.end())
400 {
401 // Connected pin is already linked, so get linkId from the connected pin
402 1 link.linkId = iter->linkId;
403 }
404 else
405 {
406 // Connected pin is not linked, so get new linkId
407 link.linkId = nm::GetNextLinkId();
408 // Also connect the startPin to this one
409 startPin.connect(*this);
410 }
411 }
412 540 }
413
414 807 void NAV::InputPin::disconnect()
415 {
416
6/8
✓ Branch 0 taken 538 times.
✓ Branch 1 taken 269 times.
✓ Branch 3 taken 538 times.
✗ Branch 4 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 538 times.
✓ Branch 8 taken 269 times.
✓ Branch 9 taken 538 times.
807 if (link.connectedNode || link.connectedPinId || link.linkId)
417 {
418 269 auto* startPin = link.getConnectedPin();
419
420
1/2
✓ Branch 1 taken 269 times.
✗ Branch 2 not taken.
269 link.linkId = 0;
421 269 link.connectedNode = nullptr;
422
1/2
✓ Branch 1 taken 269 times.
✗ Branch 2 not taken.
269 link.connectedPinId = 0;
423
424
1/2
✓ Branch 0 taken 269 times.
✗ Branch 1 not taken.
269 if (startPin)
425 {
426
1/2
✓ Branch 1 taken 269 times.
✗ Branch 2 not taken.
269 auto iter = std::ranges::find_if(startPin->links, [&, this](const OutputPin::OutgoingLink& link) {
427
3/4
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 49 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 17 times.
66 return link.connectedNode == parentNode && link.connectedPinId == id;
428 });
429
430
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 269 times.
269 if (iter != startPin->links.end())
431 {
432 startPin->disconnect(*this);
433 }
434 }
435 }
436 807 }
437
438 1571889 NAV::OutputPin* NAV::InputPin::IncomingLink::getConnectedPin() const
439 {
440
2/2
✓ Branch 0 taken 1571598 times.
✓ Branch 1 taken 291 times.
1571889 if (connectedNode)
441 {
442
1/2
✓ Branch 5 taken 2140431 times.
✗ Branch 6 not taken.
2140854 for (auto& outputPin : connectedNode->outputPins)
443 {
444
3/4
✓ Branch 1 taken 2140699 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1571443 times.
✓ Branch 4 taken 569256 times.
2140406 if (outputPin.id == connectedPinId) { return &outputPin; }
445 }
446 }
447 291 return nullptr;
448 }
449
450 // ###########################################################################################################
451
452 void NAV::to_json(json& j, const OutputPin& pin)
453 {
454 j = json{
455 { "id", size_t(pin.id) },
456 { "name", pin.name },
457 };
458 }
459 1067 void NAV::from_json(const json& j, OutputPin& pin)
460 {
461
3/6
✓ Branch 1 taken 1067 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1067 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1067 times.
✗ Branch 8 not taken.
1067 pin.id = j.at("id").get<size_t>();
462
1/2
✓ Branch 1 taken 1067 times.
✗ Branch 2 not taken.
1067 if (j.contains("name")) { j.at("name").get_to(pin.name); }
463 1067 }
464
465 void NAV::to_json(json& j, const InputPin& pin)
466 {
467 j = json{
468 { "id", size_t(pin.id) },
469 { "name", pin.name },
470 };
471 }
472 1022 void NAV::from_json(const json& j, InputPin& pin)
473 {
474
3/6
✓ Branch 1 taken 1022 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1022 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1022 times.
✗ Branch 8 not taken.
1022 pin.id = j.at("id").get<size_t>();
475
1/2
✓ Branch 1 taken 1022 times.
✗ Branch 2 not taken.
1022 if (j.contains("name")) { j.at("name").get_to(pin.name); }
476 1022 }
477