INSTINCT Code Coverage Report


Directory: src/
File: internal/Node/Pin.cpp
Date: 2025-07-19 10:51:51
Exec Total Coverage
Lines: 136 229 59.4%
Functions: 27 35 77.1%
Branches: 167 345 48.4%

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 296 bool NAV::Pin::canCreateLink(const OutputPin& startPin, const InputPin& endPin)
30 {
31 296 bool dataTypesMatch = true;
32
33 296 if (startPin.type == Pin::Type::Flow
34
7/8
✓ Branch 0 taken 274 times.
✓ Branch 1 taken 22 times.
✓ Branch 3 taken 274 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 2 times.
✓ Branch 6 taken 272 times.
✓ Branch 7 taken 2 times.
✓ Branch 8 taken 294 times.
296 && !NAV::NodeRegistry::NodeDataTypeAnyIsChildOf(startPin.dataIdentifier, endPin.dataIdentifier))
35 {
36 2 dataTypesMatch = false;
37 }
38
39 if (startPin.type == Pin::Type::Delegate
40
3/4
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 295 times.
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
297 && (startPin.parentNode == nullptr
41
6/12
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 1 times.
✓ Branch 10 taken 1 times.
✓ Branch 11 taken 295 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 296 times.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
297 || std::ranges::find(endPin.dataIdentifier, startPin.parentNode->type()) == endPin.dataIdentifier.end()))
42 {
43 dataTypesMatch = false;
44 }
45
46
2/2
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 281 times.
578 if ((startPin.type == Pin::Type::Object || startPin.type == Pin::Type::Matrix) // NOLINT(misc-redundant-expression) - false positive warning
47
5/8
✓ Branch 0 taken 282 times.
✓ Branch 1 taken 14 times.
✓ Branch 3 taken 15 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 15 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 296 times.
578 && !dataIdentifierHaveCommon(startPin.dataIdentifier, endPin.dataIdentifier))
48 {
49 dataTypesMatch = false;
50 }
51
52 296 return startPin.id != endPin.id // Different Pins
53
1/2
✓ Branch 1 taken 296 times.
✗ Branch 2 not taken.
296 && startPin.kind != endPin.kind // Input <=> Output
54
1/2
✓ Branch 1 taken 296 times.
✗ Branch 2 not taken.
296 && startPin.type == endPin.type // Same Type (Flow, Object, ...)
55
1/2
✓ Branch 0 taken 296 times.
✗ Branch 1 not taken.
296 && startPin.parentNode != endPin.parentNode // Different Nodes
56
3/4
✓ Branch 0 taken 296 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 294 times.
✓ Branch 3 taken 2 times.
592 && dataTypesMatch; // Data identifier match
57 }
58
59 15 bool NAV::Pin::dataIdentifierHaveCommon(const std::vector<std::string>& a, const std::vector<std::string>& b)
60 {
61
1/2
✓ Branch 2 taken 15 times.
✗ Branch 3 not taken.
30 return !a.empty() && !b.empty()
62
4/8
✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
✓ Branch 4 taken 15 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 15 times.
✗ Branch 8 not taken.
✓ Branch 11 taken 15 times.
✗ Branch 12 not taken.
45 && 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 583 bool NAV::Pin::createLink(OutputPin& startPin, InputPin& endPin, ax::NodeEditor::LinkId linkId)
144 {
145
2/2
✓ Branch 1 taken 288 times.
✓ Branch 2 taken 295 times.
583 if (startPin.isPinLinked(endPin)) { return true; } // Pins are already linked
146
147
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 293 times.
295 if (!startPin.canCreateLink(endPin)) { return false; } // Types do not match
148
149
2/4
✓ Branch 0 taken 293 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 293 times.
293 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 293 times.
293 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 293 times.
293 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 293 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 293 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 293 times.
✗ Branch 9 not taken.
✓ Branch 11 taken 293 times.
✗ Branch 12 not taken.
✓ Branch 15 taken 293 times.
✗ Branch 16 not taken.
293 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 293 startPin.connect(endPin, linkId);
170 293 endPin.connect(startPin, linkId);
171
172 293 nm::AddLink(linkId);
173
174
2/2
✓ Branch 1 taken 22 times.
✓ Branch 2 taken 271 times.
293 if (endPin.type != Pin::Type::Flow)
175 {
176
4/8
✓ Branch 0 taken 22 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 22 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 22 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 22 times.
✗ Branch 8 not taken.
22 if (startPin.parentNode && endPin.parentNode && !startPin.parentNode->isInitialized())
177 {
178
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 22 times.
22 if (endPin.parentNode->isInitialized())
179 {
180 endPin.parentNode->doDeinitialize(true);
181 }
182 }
183 }
184
185
2/4
✓ Branch 0 taken 293 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 293 times.
✗ Branch 3 not taken.
293 if (startPin.parentNode && endPin.parentNode)
186 {
187 293 startPin.parentNode->afterCreateLink(startPin, endPin);
188 293 endPin.parentNode->afterCreateLink(startPin, endPin);
189 }
190
191 293 flow::ApplyChanges();
192
193 293 return true;
194 }
195
196 3 bool NAV::Pin::recreateLink(OutputPin& startPin, InputPin& endPin)
197 {
198
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
3 if (startPin.isPinLinked(endPin))
199 {
200 3 deleteLink(startPin, endPin);
201
2/4
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
3 return createLink(startPin, endPin);
202 }
203 return false;
204 }
205
206 292 void NAV::Pin::deleteLink(OutputPin& startPin, InputPin& endPin)
207 {
208
2/4
✓ Branch 0 taken 292 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 292 times.
292 if (!startPin.parentNode || !endPin.parentNode) { return; }
209
210
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 292 times.
292 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 292 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 292 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 292 times.
✗ Branch 9 not taken.
✓ Branch 11 taken 292 times.
✗ Branch 12 not taken.
✓ Branch 14 taken 292 times.
✗ Branch 15 not taken.
✓ Branch 18 taken 292 times.
✗ Branch 19 not taken.
292 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 292 startPin.parentNode->onDeleteLink(startPin, endPin);
222 292 endPin.parentNode->onDeleteLink(startPin, endPin);
223
224
2/2
✓ Branch 1 taken 22 times.
✓ Branch 2 taken 270 times.
292 if (endPin.type != Pin::Type::Flow) { endPin.parentNode->doDeinitialize(true); }
225
226 292 startPin.disconnect(endPin);
227 292 endPin.disconnect();
228
229 292 startPin.parentNode->afterDeleteLink(startPin, endPin);
230 292 endPin.parentNode->afterDeleteLink(startPin, endPin);
231
232 292 flow::ApplyChanges();
233 }
234
235 // ###########################################################################################################
236 // OutputPin
237 // ###########################################################################################################
238
239 296 bool NAV::OutputPin::canCreateLink(const NAV::InputPin& other) const
240 {
241 296 return Pin::canCreateLink(*this, other);
242 }
243
244 615 bool NAV::OutputPin::isPinLinked() const
245 {
246 615 return !links.empty();
247 }
248
249 878 bool NAV::OutputPin::isPinLinked(const NAV::InputPin& endPin) const
250 {
251
1/2
✓ Branch 1 taken 878 times.
✗ Branch 2 not taken.
878 auto iter = std::ranges::find_if(links, [&endPin](const OutgoingLink& link) {
252
4/4
✓ Branch 0 taken 631 times.
✓ Branch 1 taken 150 times.
✓ Branch 3 taken 583 times.
✓ Branch 4 taken 48 times.
781 return link.connectedNode == endPin.parentNode && link.connectedPinId == endPin.id;
253 });
254 878 return iter != links.cend();
255 }
256
257 580 bool NAV::OutputPin::createLink(InputPin& endPin, ax::NodeEditor::LinkId linkId)
258 {
259 580 return Pin::createLink(*this, endPin, linkId);
260 }
261
262 3 bool NAV::OutputPin::recreateLink(InputPin& endPin)
263 {
264 3 return Pin::recreateLink(*this, endPin);
265 }
266
267 void NAV::OutputPin::deleteLink(InputPin& endPin)
268 {
269 Pin::deleteLink(*this, endPin);
270 }
271
272 82 void NAV::OutputPin::deleteLinks()
273 {
274
2/2
✓ Branch 1 taken 101 times.
✓ Branch 2 taken 82 times.
183 while (!links.empty())
275 {
276
1/2
✓ Branch 2 taken 101 times.
✗ Branch 3 not taken.
101 if (auto* endPin = links.back().getConnectedPin())
277 {
278 101 Pin::deleteLink(*this, *endPin);
279 }
280 else
281 {
282 links.pop_back();
283 }
284 }
285 82 }
286
287 293 void NAV::OutputPin::connect(NAV::InputPin& endPin, ax::NodeEditor::LinkId linkId)
288 {
289
1/2
✓ Branch 1 taken 293 times.
✗ Branch 2 not taken.
293 auto iter = std::ranges::find_if(links, [&endPin](const OutgoingLink& link) {
290
3/4
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 63 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 16 times.
79 return link.connectedNode == endPin.parentNode && link.connectedPinId == endPin.id;
291 });
292
1/2
✓ Branch 2 taken 293 times.
✗ Branch 3 not taken.
293 if (iter == links.end()) // Link does not yet exist
293 {
294
3/4
✓ Branch 1 taken 293 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 290 times.
✓ Branch 4 taken 3 times.
293 if (linkId)
295 {
296 // LinkId is given
297
1/2
✓ Branch 1 taken 290 times.
✗ Branch 2 not taken.
290 links.emplace_back(linkId, endPin.parentNode, endPin.id);
298
2/4
✓ Branch 1 taken 290 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 290 times.
✗ Branch 4 not taken.
290 if (endPin.link.linkId != linkId)
299 {
300
1/2
✓ Branch 1 taken 290 times.
✗ Branch 2 not taken.
290 endPin.disconnect();
301
1/2
✓ Branch 1 taken 290 times.
✗ Branch 2 not taken.
290 endPin.connect(*this, linkId);
302 }
303 }
304
2/8
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 3 times.
3 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 3 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
3 links.emplace_back(nm::GetNextLinkId(), endPin.parentNode, endPin.id);
313 // Also connect the endPin to this one
314
2/4
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
3 endPin.connect(*this);
315 }
316 }
317 293 }
318
319 292 void NAV::OutputPin::disconnect(InputPin& endPin)
320 {
321
1/2
✓ Branch 1 taken 292 times.
✗ Branch 2 not taken.
292 auto iter = std::ranges::find_if(links, [&endPin](const OutgoingLink& link) {
322
4/4
✓ Branch 0 taken 308 times.
✓ Branch 1 taken 25 times.
✓ Branch 3 taken 292 times.
✓ Branch 4 taken 16 times.
333 return link.connectedNode == endPin.parentNode && link.connectedPinId == endPin.id;
323 });
324
1/2
✓ Branch 2 taken 292 times.
✗ Branch 3 not taken.
292 if (iter != links.end())
325 {
326
1/2
✓ Branch 2 taken 292 times.
✗ Branch 3 not taken.
292 links.erase(iter);
327
4/8
✓ Branch 0 taken 292 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 292 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 292 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 292 times.
✗ Branch 8 not taken.
292 if (endPin.link.connectedNode == parentNode && endPin.link.connectedPinId == id)
328 {
329
1/2
✓ Branch 1 taken 292 times.
✗ Branch 2 not taken.
292 endPin.disconnect();
330 }
331 }
332 292 }
333
334 556388 NAV::InputPin* NAV::OutputPin::OutgoingLink::getConnectedPin() const
335 {
336
2/2
✓ Branch 0 taken 556322 times.
✓ Branch 1 taken 66 times.
556388 if (connectedNode)
337 {
338
1/2
✓ Branch 5 taken 1098662 times.
✗ Branch 6 not taken.
1098955 for (auto& inputPin : connectedNode->inputPins)
339 {
340
3/4
✓ Branch 1 taken 1099200 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 556567 times.
✓ Branch 4 taken 542633 times.
1098580 if (inputPin.id == connectedPinId) { return &inputPin; }
341 }
342 }
343 66 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 708757 bool NAV::InputPin::isPinLinked() const
356 {
357
4/6
✓ Branch 1 taken 708013 times.
✓ Branch 2 taken 120 times.
✓ Branch 3 taken 708055 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 707770 times.
✗ Branch 7 not taken.
708757 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 191 void NAV::InputPin::deleteLink()
371 {
372
2/2
✓ Branch 1 taken 188 times.
✓ Branch 2 taken 3 times.
191 if (auto* startPin = link.getConnectedPin())
373 {
374 188 Pin::deleteLink(*startPin, *this);
375 }
376 191 }
377
378 586 void NAV::InputPin::connect(NAV::OutputPin& startPin, ax::NodeEditor::LinkId linkId)
379 {
380
5/6
✓ Branch 0 taken 293 times.
✓ Branch 1 taken 293 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 293 times.
✓ Branch 5 taken 293 times.
✓ Branch 6 taken 293 times.
586 if (link.connectedNode != startPin.parentNode || link.connectedPinId != startPin.id) // Link does not yet exist
381 {
382 293 link.connectedNode = startPin.parentNode;
383 293 link.connectedPinId = startPin.id;
384
385
1/2
✓ Branch 1 taken 293 times.
✗ Branch 2 not taken.
293 auto iter = std::ranges::find_if(startPin.links, [&, this](const OutputPin::OutgoingLink& link) {
386
4/4
✓ Branch 0 taken 309 times.
✓ Branch 1 taken 63 times.
✓ Branch 3 taken 293 times.
✓ Branch 4 taken 16 times.
372 return link.connectedNode == parentNode && link.connectedPinId == id;
387 });
388
389
3/4
✓ Branch 1 taken 293 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 290 times.
✓ Branch 4 taken 3 times.
293 if (linkId)
390 {
391 // LinkId is given
392 290 link.linkId = linkId;
393
4/8
✓ Branch 2 taken 290 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 290 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 290 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 290 times.
290 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 3 times.
✗ Branch 3 not taken.
3 else if (iter != startPin.links.end())
400 {
401 // Connected pin is already linked, so get linkId from the connected pin
402 3 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 586 }
413
414 874 void NAV::InputPin::disconnect()
415 {
416
6/8
✓ Branch 0 taken 582 times.
✓ Branch 1 taken 292 times.
✓ Branch 3 taken 582 times.
✗ Branch 4 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 582 times.
✓ Branch 8 taken 292 times.
✓ Branch 9 taken 582 times.
874 if (link.connectedNode || link.connectedPinId || link.linkId)
417 {
418 292 auto* startPin = link.getConnectedPin();
419
420
1/2
✓ Branch 1 taken 292 times.
✗ Branch 2 not taken.
292 link.linkId = 0;
421 292 link.connectedNode = nullptr;
422
1/2
✓ Branch 1 taken 292 times.
✗ Branch 2 not taken.
292 link.connectedPinId = 0;
423
424
1/2
✓ Branch 0 taken 292 times.
✗ Branch 1 not taken.
292 if (startPin)
425 {
426
1/2
✓ Branch 1 taken 292 times.
✗ Branch 2 not taken.
292 auto iter = std::ranges::find_if(startPin->links, [&, this](const OutputPin::OutgoingLink& link) {
427
3/4
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 63 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 16 times.
79 return link.connectedNode == parentNode && link.connectedPinId == id;
428 });
429
430
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 292 times.
292 if (iter != startPin->links.end())
431 {
432 startPin->disconnect(*this);
433 }
434 }
435 }
436 874 }
437
438 1702486 NAV::OutputPin* NAV::InputPin::IncomingLink::getConnectedPin() const
439 {
440
2/2
✓ Branch 0 taken 1702284 times.
✓ Branch 1 taken 202 times.
1702486 if (connectedNode)
441 {
442
1/2
✓ Branch 5 taken 2282061 times.
✗ Branch 6 not taken.
2282402 for (auto& outputPin : connectedNode->outputPins)
443 {
444
3/4
✓ Branch 1 taken 2282269 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1702151 times.
✓ Branch 4 taken 580118 times.
2282007 if (outputPin.id == connectedPinId) { return &outputPin; }
445 }
446 }
447 202 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 1155 void NAV::from_json(const json& j, OutputPin& pin)
460 {
461
3/6
✓ Branch 1 taken 1155 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1155 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1155 times.
✗ Branch 8 not taken.
1155 pin.id = j.at("id").get<size_t>();
462
1/2
✓ Branch 1 taken 1155 times.
✗ Branch 2 not taken.
1155 if (j.contains("name")) { j.at("name").get_to(pin.name); }
463 1155 }
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 1120 void NAV::from_json(const json& j, InputPin& pin)
473 {
474
3/6
✓ Branch 1 taken 1120 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1120 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1120 times.
✗ Branch 8 not taken.
1120 pin.id = j.at("id").get<size_t>();
475
1/2
✓ Branch 1 taken 1120 times.
✗ Branch 2 not taken.
1120 if (j.contains("name")) { j.at("name").get_to(pin.name); }
476 1120 }
477