0.3.0
Loading...
Searching...
No Matches
Pin.cpp
Go to the documentation of this file.
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
10
15namespace nm = NAV::NodeManager;
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
29bool NAV::Pin::canCreateLink(const OutputPin& startPin, const InputPin& endPin)
30{
31 bool dataTypesMatch = true;
32
33 if (startPin.type == Pin::Type::Flow
35 {
36 dataTypesMatch = false;
37 }
38
39 if (startPin.type == Pin::Type::Delegate
40 && (startPin.parentNode == nullptr
41 || std::ranges::find(endPin.dataIdentifier, startPin.parentNode->type()) == endPin.dataIdentifier.end()))
42 {
43 dataTypesMatch = false;
44 }
45
46 if ((startPin.type == Pin::Type::Object || startPin.type == Pin::Type::Matrix) // NOLINT(misc-redundant-expression) - false positive warning
48 {
49 dataTypesMatch = false;
50 }
51
52 return startPin.id != endPin.id // Different Pins
53 && startPin.kind != endPin.kind // Input <=> Output
54 && startPin.type == endPin.type // Same Type (Flow, Object, ...)
55 && startPin.parentNode != endPin.parentNode // Different Nodes
56 && dataTypesMatch; // Data identifier match
57}
58
59bool NAV::Pin::dataIdentifierHaveCommon(const std::vector<std::string>& a, const std::vector<std::string>& b)
60{
61 return !a.empty() && !b.empty()
62 && std::ranges::find_if(a, [&b](const std::string& str) { return std::ranges::find(b, str) != b.end(); }) != a.end();
63}
64
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
98void 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
140 iconType, connected, color, ImColor(32, 32, 32, alpha));
141}
142
143bool NAV::Pin::createLink(OutputPin& startPin, InputPin& endPin, ax::NodeEditor::LinkId linkId)
144{
145 if (startPin.isPinLinked(endPin)) { return true; } // Pins are already linked
146
147 if (!startPin.canCreateLink(endPin)) { return false; } // Types do not match
148
149 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 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 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 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 startPin.connect(endPin, linkId);
170 endPin.connect(startPin, linkId);
171
172 nm::AddLink(linkId);
173
174 if (endPin.type != Pin::Type::Flow)
175 {
176 if (startPin.parentNode && endPin.parentNode && !startPin.parentNode->isInitialized())
177 {
178 if (endPin.parentNode->isInitialized())
179 {
180 endPin.parentNode->doDeinitialize(true);
181 }
182 }
183 }
184
185 if (startPin.parentNode && endPin.parentNode)
186 {
187 startPin.parentNode->afterCreateLink(startPin, endPin);
188 endPin.parentNode->afterCreateLink(startPin, endPin);
189 }
190
192
193 return true;
194}
195
197{
198 if (startPin.isPinLinked(endPin))
199 {
200 deleteLink(startPin, endPin);
201 return createLink(startPin, endPin);
202 }
203 return false;
204}
205
207{
208 if (!startPin.parentNode || !endPin.parentNode) { return; }
209
210 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 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 startPin.parentNode->onDeleteLink(startPin, endPin);
222 endPin.parentNode->onDeleteLink(startPin, endPin);
223
224 if (endPin.type != Pin::Type::Flow) { endPin.parentNode->doDeinitialize(true); }
225
226 startPin.disconnect(endPin);
227 endPin.disconnect();
228
229 startPin.parentNode->afterDeleteLink(startPin, endPin);
230 endPin.parentNode->afterDeleteLink(startPin, endPin);
231
233}
234
235// ###########################################################################################################
236// OutputPin
237// ###########################################################################################################
238
240{
241 return Pin::canCreateLink(*this, other);
242}
243
245{
246 return !links.empty();
247}
248
250{
251 auto iter = std::ranges::find_if(links, [&endPin](const OutgoingLink& link) {
252 return link.connectedNode == endPin.parentNode && link.connectedPinId == endPin.id;
253 });
254 return iter != links.cend();
255}
256
257bool NAV::OutputPin::createLink(InputPin& endPin, ax::NodeEditor::LinkId linkId)
258{
259 return Pin::createLink(*this, endPin, linkId);
260}
261
263{
264 return Pin::recreateLink(*this, endPin);
265}
266
268{
269 Pin::deleteLink(*this, endPin);
270}
271
273{
274 while (!links.empty())
275 {
276 if (auto* endPin = links.back().getConnectedPin())
277 {
278 Pin::deleteLink(*this, *endPin);
279 }
280 else
281 {
282 links.pop_back();
283 }
284 }
285}
286
287void NAV::OutputPin::connect(NAV::InputPin& endPin, ax::NodeEditor::LinkId linkId)
288{
289 auto iter = std::ranges::find_if(links, [&endPin](const OutgoingLink& link) {
290 return link.connectedNode == endPin.parentNode && link.connectedPinId == endPin.id;
291 });
292 if (iter == links.end()) // Link does not yet exist
293 {
294 if (linkId)
295 {
296 // LinkId is given
297 links.emplace_back(linkId, endPin.parentNode, endPin.id);
298 if (endPin.link.linkId != linkId)
299 {
300 endPin.disconnect();
301 endPin.connect(*this, linkId);
302 }
303 }
304 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 links.emplace_back(nm::GetNextLinkId(), endPin.parentNode, endPin.id);
313 // Also connect the endPin to this one
314 endPin.connect(*this);
315 }
316 }
317}
318
320{
321 auto iter = std::ranges::find_if(links, [&endPin](const OutgoingLink& link) {
322 return link.connectedNode == endPin.parentNode && link.connectedPinId == endPin.id;
323 });
324 if (iter != links.end())
325 {
326 links.erase(iter);
327 if (endPin.link.connectedNode == parentNode && endPin.link.connectedPinId == id)
328 {
329 endPin.disconnect();
330 }
331 }
332}
333
335{
336 if (connectedNode)
337 {
338 for (auto& inputPin : connectedNode->inputPins)
339 {
340 if (inputPin.id == connectedPinId) { return &inputPin; }
341 }
342 }
343 return nullptr;
344}
345
346// ###########################################################################################################
347// InputPin
348// ###########################################################################################################
349
351{
352 return Pin::canCreateLink(other, *this);
353}
354
356{
357 return link.linkId && link.connectedNode && link.connectedPinId;
358}
359
360bool NAV::InputPin::createLink(OutputPin& startPin, ax::NodeEditor::LinkId linkId)
361{
362 return Pin::createLink(startPin, *this, linkId);
363}
364
366{
367 return Pin::recreateLink(startPin, *this);
368}
369
371{
372 if (auto* startPin = link.getConnectedPin())
373 {
374 Pin::deleteLink(*startPin, *this);
375 }
376}
377
378void NAV::InputPin::connect(NAV::OutputPin& startPin, ax::NodeEditor::LinkId linkId)
379{
380 if (link.connectedNode != startPin.parentNode || link.connectedPinId != startPin.id) // Link does not yet exist
381 {
382 link.connectedNode = startPin.parentNode;
383 link.connectedPinId = startPin.id;
384
385 auto iter = std::ranges::find_if(startPin.links, [&, this](const OutputPin::OutgoingLink& link) {
386 return link.connectedNode == parentNode && link.connectedPinId == id;
387 });
388
389 if (linkId)
390 {
391 // LinkId is given
392 link.linkId = linkId;
393 if (iter != startPin.links.end() && iter->linkId != linkId)
394 {
395 startPin.disconnect(*this);
396 startPin.connect(*this, linkId);
397 }
398 }
399 else if (iter != startPin.links.end())
400 {
401 // Connected pin is already linked, so get linkId from the connected pin
402 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}
413
415{
416 if (link.connectedNode || link.connectedPinId || link.linkId)
417 {
418 auto* startPin = link.getConnectedPin();
419
420 link.linkId = 0;
421 link.connectedNode = nullptr;
422 link.connectedPinId = 0;
423
424 if (startPin)
425 {
426 auto iter = std::ranges::find_if(startPin->links, [&, this](const OutputPin::OutgoingLink& link) {
427 return link.connectedNode == parentNode && link.connectedPinId == id;
428 });
429
430 if (iter != startPin->links.end())
431 {
432 startPin->disconnect(*this);
433 }
434 }
435 }
436}
437
439{
440 if (connectedNode)
441 {
442 for (auto& outputPin : connectedNode->outputPins)
443 {
444 if (outputPin.id == connectedPinId) { return &outputPin; }
445 }
446 }
447 return nullptr;
448}
449
450// ###########################################################################################################
451
452void NAV::to_json(json& j, const OutputPin& pin)
453{
454 j = json{
455 { "id", size_t(pin.id) },
456 { "name", pin.name },
457 };
458}
459void NAV::from_json(const json& j, OutputPin& pin)
460{
461 pin.id = j.at("id").get<size_t>();
462 if (j.contains("name")) { j.at("name").get_to(pin.name); }
463}
464
465void NAV::to_json(json& j, const InputPin& pin)
466{
467 j = json{
468 { "id", size_t(pin.id) },
469 { "name", pin.name },
470 };
471}
472void NAV::from_json(const json& j, InputPin& pin)
473{
474 pin.id = j.at("id").get<size_t>();
475 if (j.contains("name")) { j.at("name").get_to(pin.name); }
476}
Assertion helpers.
Save/Load the Nodes.
nlohmann::json json
json namespace
#define LOG_DEBUG
Debug information. Should not be called on functions which receive observations (spamming)
Definition Logger.hpp:67
#define LOG_ERROR
Error occurred, which stops part of the program to work, but not everything.
Definition Logger.hpp:73
#define LOG_TRACE
Detailled info to trace the execution of the program. Should not be called on functions which receive...
Definition Logger.hpp:65
Manages all Nodes.
Utility class which specifies available nodes.
Node Class.
Pin class.
Input pins of nodes.
Definition Pin.hpp:491
void connect(OutputPin &startPin, ax::NodeEditor::LinkId linkId=0)
Connects this pin to another.
Definition Pin.cpp:378
IncomingLink link
Info to identify the linked pin.
Definition Pin.hpp:704
friend class OutputPin
Definition Pin.hpp:764
bool createLink(OutputPin &startPin, ax::NodeEditor::LinkId linkId=0)
Creates a link from this pin to another, calling all node specific callbacks.
Definition Pin.cpp:360
bool isPinLinked() const
Checks if the pin is linked.
Definition Pin.cpp:355
bool recreateLink(OutputPin &startPin)
Destroys and recreates a link from this pin to another.
Definition Pin.cpp:365
void disconnect()
Disconnects the link.
Definition Pin.cpp:414
void deleteLink()
Disconnects the link.
Definition Pin.cpp:370
bool canCreateLink(const OutputPin &other) const
Checks if this pin can connect to the provided pin.
Definition Pin.cpp:350
bool isInitialized() const
Checks if the node is initialized.
Definition Node.cpp:504
bool doDeinitialize(bool wait=false)
Asks the node worker to deinitialize the node.
Definition Node.cpp:395
std::string nameId() const
Node name and id.
Definition Node.cpp:253
virtual void afterCreateLink(OutputPin &startPin, InputPin &endPin)
Called when a new link was established.
Definition Node.cpp:89
virtual void onDeleteLink(OutputPin &startPin, InputPin &endPin)
Called when a link is to be deleted.
Definition Node.cpp:87
virtual void afterDeleteLink(OutputPin &startPin, InputPin &endPin)
Called when a link was deleted.
Definition Node.cpp:91
virtual bool onCreateLink(OutputPin &startPin, InputPin &endPin)
Called when a new link is to be established.
Definition Node.cpp:82
virtual std::string type() const =0
String representation of the Class Type.
Output pins of nodes.
Definition Pin.hpp:338
bool recreateLink(InputPin &endPin)
Destroys and recreates a link from this pin to another.
Definition Pin.cpp:262
bool createLink(InputPin &endPin, ax::NodeEditor::LinkId linkId=0)
Creates a link from this pin to another, calling all node specific callbacks.
Definition Pin.cpp:257
void deleteLink(InputPin &endPin)
Disconnects the link.
Definition Pin.cpp:267
void deleteLinks()
Disconnects all links.
Definition Pin.cpp:272
void connect(InputPin &endPin, ax::NodeEditor::LinkId linkId=0)
Connects this pin to another.
Definition Pin.cpp:287
void disconnect(InputPin &endPin)
Disconnects the link.
Definition Pin.cpp:319
bool isPinLinked() const
Checks if the pin is linked.
Definition Pin.cpp:244
friend class InputPin
Definition Pin.hpp:476
std::vector< OutgoingLink > links
Info to identify the linked pins.
Definition Pin.hpp:433
bool canCreateLink(const InputPin &other) const
Checks if this pin can connect to the provided pin.
Definition Pin.cpp:239
Node * parentNode
Reference to the parent node.
Definition Pin.hpp:307
static void deleteLink(OutputPin &startPin, InputPin &endPin)
Disconnects the link.
Definition Pin.cpp:206
static bool recreateLink(OutputPin &startPin, InputPin &endPin)
Destroys and recreates a link from this pin to another.
Definition Pin.cpp:196
std::string name
Name of the Pin.
Definition Pin.hpp:299
static constexpr int m_PinIconSize
Size of the Pin Icons in [px].
Definition Pin.hpp:333
void drawPinIcon(bool connected, int alpha) const
Draw the Pin Icon.
Definition Pin.cpp:98
ax::NodeEditor::PinId id
Unique Id of the Pin.
Definition Pin.hpp:297
std::vector< std::string > dataIdentifier
One or multiple Data Identifiers (Unique name which is used for data flows)
Definition Pin.hpp:305
Type type
Type of the Pin.
Definition Pin.hpp:301
static bool dataIdentifierHaveCommon(const std::vector< std::string > &a, const std::vector< std::string > &b)
Checks if the first list of data identifiers has a common entry with the second.
Definition Pin.cpp:59
static bool createLink(OutputPin &startPin, InputPin &endPin, ax::NodeEditor::LinkId linkId=0)
Create a Link between the two given pins.
Definition Pin.cpp:143
Kind kind
Kind of the Pin (Input/Output)
Definition Pin.hpp:303
ImColor getIconColor() const
Get the Icon Color object.
Definition Pin.cpp:65
static bool canCreateLink(const OutputPin &startPin, const InputPin &endPin)
Checks if pins can connect.
Definition Pin.cpp:29
static float defaultFontRatio()
Ratio to multiply for default GUI elements.
ax::NodeEditor::LinkId GetNextLinkId()
Generates a new link id.
void AddLink(ax::NodeEditor::LinkId linkId)
Adds the link.
bool NodeDataTypeAnyIsChildOf(const std::vector< std::string > &childTypes, const std::vector< std::string > &parentTypes)
Checks if any of the provided child types is a child of any of the provided parent types.
void ApplyChanges()
Signals that there have been changes to the flow.
void Draw(const ImVec2 &size, Type type, bool filled, const ImVec4 &color=ImVec4(1, 1, 1, 1), const ImVec4 &innerColor=ImVec4(0, 0, 0, 0))
Draws an Icon for a Pin with the specified settings.
Definition PinIcon.cpp:253
void to_json(json &j, const Node &node)
Converts the provided node into a json object.
Definition Node.cpp:990
void from_json(const json &j, Node &node)
Converts the provided json object into a node object.
Definition Node.cpp:1007
Value
Type of the data on the Pin.
Definition Pin.hpp:50
@ Delegate
Reference to the Node object.
Definition Pin.hpp:59
@ None
Not initialized.
Definition Pin.hpp:51
@ Matrix
Matrix Object.
Definition Pin.hpp:58
@ Int
Integer Number.
Definition Pin.hpp:54
@ Float
Floating Point Number.
Definition Pin.hpp:55
@ String
std::string
Definition Pin.hpp:56
@ Flow
NodeData Trigger.
Definition Pin.hpp:52
@ Bool
Boolean.
Definition Pin.hpp:53
@ Object
Generic Object.
Definition Pin.hpp:57