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