0.4.1
Loading...
Searching...
No Matches
NodeManager.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
12#include "internal/Node/Pin.hpp"
13
15
16#include "util/Assert.h"
17
18#include <algorithm>
19#include <thread>
20#include <deque>
21
22#include "NodeRegistry.hpp"
23
25{
26/* -------------------------------------------------------------------------------------------------------- */
27/* Private Members */
28/* -------------------------------------------------------------------------------------------------------- */
29
30namespace
31{
32std::vector<NAV::Node*> m_nodes;
33size_t m_NextId = 1;
34
35} // namespace
36
37/* -------------------------------------------------------------------------------------------------------- */
38/* Public Members */
39/* -------------------------------------------------------------------------------------------------------- */
40
41#if !defined(WIN32) && !defined(_WIN32) && !defined(__WIN32)
44#else
47#endif
48
49} // namespace NAV::NodeManager
50
51/* -------------------------------------------------------------------------------------------------------- */
52/* Function Definitions */
53/* -------------------------------------------------------------------------------------------------------- */
54
55const std::vector<NAV::Node*>& NAV::NodeManager::m_Nodes()
56{
57 return m_nodes;
58}
59
61{
62 if (!node->id)
63 {
64 node->id = GetNextNodeId();
65 }
66 m_nodes.push_back(node);
67 LOG_DEBUG("Creating node: {}", node->nameId());
68
69 for (auto& pin : node->inputPins)
70 {
71 pin.parentNode = node;
72 }
73 for (auto& pin : node->outputPins)
74 {
75 pin.parentNode = node;
76 }
77
78 m_NextId = std::max(m_NextId, size_t(node->id) + 1);
79 for (const auto& pin : node->inputPins)
80 {
81 m_NextId = std::max(m_NextId, size_t(pin.id) + 1);
82 }
83 for (const auto& pin : node->outputPins)
84 {
85 m_NextId = std::max(m_NextId, size_t(pin.id) + 1);
86 }
87
89}
90
92{
93 LOG_TRACE("called for node: {}", node->nameId());
94 for (auto& pin : node->inputPins)
95 {
96 pin.parentNode = node;
97 }
98 for (auto& pin : node->outputPins)
99 {
100 pin.parentNode = node;
101 }
102
103 for (const auto& pin : node->inputPins)
104 {
105 m_NextId = std::max(m_NextId, size_t(pin.id) + 1);
106 }
107 for (const auto& pin : node->outputPins)
108 {
109 m_NextId = std::max(m_NextId, size_t(pin.id) + 1);
110 }
111}
112
113bool NAV::NodeManager::DeleteNode(ax::NodeEditor::NodeId nodeId)
114{
115 LOG_TRACE("called for node with id {}", size_t(nodeId));
116
117 auto it = std::ranges::find_if(m_nodes, [nodeId](const auto& node) { return node->id == nodeId; });
118 if (it != m_nodes.end())
119 {
120 Node* node = *it;
121 m_nodes.erase(it);
122 LOG_DEBUG("Deleting node: {}", node->nameId());
123
124 if (node->isInitialized())
125 {
126 node->doDeinitialize(true);
127 }
128 for (auto& inputPin : node->inputPins)
129 {
130 if (inputPin.isPinLinked())
131 {
132 inputPin.deleteLink();
133 }
134 }
135 for (auto& outputPin : node->outputPins)
136 {
137 if (outputPin.isPinLinked())
138 {
139 outputPin.deleteLinks();
140 }
141 }
142
143 delete node; // NOLINT(cppcoreguidelines-owning-memory)
144
146
147 return true;
148 }
149
150 return false;
151}
152
154{
155 LOG_TRACE("called");
156
157 bool saveLastActionsValue = NAV::flow::saveLastActions;
159
160 while (!m_nodes.empty())
161 {
162 NodeManager::DeleteNode(m_nodes.back()->id);
163 }
164
165 m_NextId = 1;
166
167 NAV::flow::saveLastActions = saveLastActionsValue;
169}
170
171void NAV::NodeManager::AddLink(ax::NodeEditor::LinkId linkId)
172{
173 m_NextId = std::max(m_NextId, size_t(linkId) + 1);
174}
175
176NAV::InputPin* NAV::NodeManager::CreateInputPin(NAV::Node* node, const char* name, NAV::Pin::Type pinType, const std::vector<std::string>& dataIdentifier,
177 InputPin::Callback callback, InputPin::FlowFirableCheckFunc firable, int priority, int idx)
178{
179 LOG_TRACE("called for pin ({}) of type ({}) for node [{}]", name, std::string(pinType), node->nameId());
180 if (idx < 0)
181 {
182 idx = static_cast<int>(node->inputPins.size());
183 }
184 idx = std::min(idx, static_cast<int>(node->inputPins.size()));
185 auto iter = std::next(node->inputPins.begin(), idx);
186
187 node->inputPins.emplace(iter, GetNextPinId(), name, pinType, node);
188
189 node->inputPins.at(static_cast<size_t>(idx)).callback = callback;
190 if (firable != nullptr)
191 {
192 node->inputPins.at(static_cast<size_t>(idx)).firable = firable;
193 }
194 node->inputPins.at(static_cast<size_t>(idx)).dataIdentifier = dataIdentifier;
195 node->inputPins.at(static_cast<size_t>(idx)).priority = priority;
196
198
199 return &node->inputPins.at(static_cast<size_t>(idx));
200}
201
202NAV::OutputPin* NAV::NodeManager::CreateOutputPin(NAV::Node* node, const char* name, NAV::Pin::Type pinType, const std::vector<std::string>& dataIdentifier, OutputPin::PinData data, int idx)
203{
204 LOG_TRACE("called for pin ({}) of type ({}) for node [{}]", name, std::string(pinType), node->nameId());
205 if (idx < 0)
206 {
207 idx = static_cast<int>(node->outputPins.size());
208 }
209 idx = std::min(idx, static_cast<int>(node->outputPins.size()));
210 auto iter = std::next(node->outputPins.begin(), idx);
211
212 node->outputPins.emplace(iter, GetNextPinId(), name, pinType, node);
213
214 node->outputPins.at(static_cast<size_t>(idx)).data = data;
215 node->outputPins.at(static_cast<size_t>(idx)).dataIdentifier = dataIdentifier;
216
218
219 return &node->outputPins.at(static_cast<size_t>(idx));
220}
221
223{
224 LOG_TRACE("called for pin ({})", size_t(pin.id));
225
226 pin.deleteLinks();
227
228 size_t pinIndex = pin.parentNode->outputPinIndexFromId(pin.id);
229 pin.parentNode->outputPins.erase(pin.parentNode->outputPins.begin() + static_cast<int64_t>(pinIndex));
230
231 return true;
232}
233
235{
236 LOG_TRACE("called for pin ({})", size_t(pin.id));
237
238 pin.deleteLink();
239
240 size_t pinIndex = pin.parentNode->inputPinIndexFromId(pin.id);
241 LOG_DEBUG("Erasing pin at idx {}", pinIndex);
242 pin.parentNode->inputPins.erase(pin.parentNode->inputPins.begin() + static_cast<int64_t>(pinIndex));
243
244 return true;
245}
246
247namespace NAV::NodeManager
248{
249namespace
250{
251
252size_t GetNextId()
253{
254 return m_NextId++;
255}
256
257} // namespace
258} // namespace NAV::NodeManager
259
260ax::NodeEditor::NodeId NAV::NodeManager::GetNextNodeId()
261{
262 return { GetNextId() };
263}
264
265ax::NodeEditor::LinkId NAV::NodeManager::GetNextLinkId()
266{
267 return { GetNextId() };
268}
269
270ax::NodeEditor::PinId NAV::NodeManager::GetNextPinId()
271{
272 return { GetNextId() };
273}
274
275NAV::Node* NAV::NodeManager::FindNode(ax::NodeEditor::NodeId id)
276{
277 for (auto& node : m_nodes)
278 {
279 if (node->id == id)
280 {
281 return node;
282 }
283 }
284
285 return nullptr;
286}
287
289{
290 if (!id) { return nullptr; }
291
292 for (auto& node : m_nodes)
293 {
294 if (!node || node->kind == Node::Kind::GroupBox) { continue; }
295 for (auto& pin : node->outputPins)
296 {
297 if (pin.id == id) { return &pin; }
298 }
299 }
300
301 return nullptr;
302}
303
305{
306 if (!id) { return nullptr; }
307
308 for (auto& node : m_nodes)
309 {
310 if (!node || node->kind == Node::Kind::GroupBox) { continue; }
311 for (auto& pin : node->inputPins)
312 {
313 if (pin.id == id) { return &pin; }
314 }
315 }
316
317 return nullptr;
318}
319
321{
322 LOG_TRACE("called");
323 for (auto* node : m_nodes)
324 {
325 if (node && !node->isDisabled() && node->kind != Node::Kind::GroupBox)
326 {
327 node->callbacksEnabled = true;
328 }
329 }
330}
331
333{
334 LOG_TRACE("called");
335 for (auto* node : m_nodes)
336 {
337 node->callbacksEnabled = false;
338 }
339}
340
342{
343 LOG_TRACE("called");
344 for (auto* node : m_nodes)
345 {
346 for (auto& inputPin : node->inputPins)
347 {
348 inputPin.queue.clear();
349 }
350 }
351}
352
354{
355 LOG_TRACE("called");
356 bool nodeCouldNotInitialize = false;
357
359
360 for (auto* node : m_nodes)
361 {
362 if (node && node->kind != Node::Kind::GroupBox && !node->isDisabled() && !node->isInitialized())
363 {
364 if (!node->doInitialize(true))
365 {
366 LOG_ERROR("Node '{}' could not initialize.", node->nameId());
367 nodeCouldNotInitialize = true;
368 }
369 }
370 }
371
372 return !nodeCouldNotInitialize;
373}
374
376{
377 LOG_TRACE("called");
378
379 for (auto* node : m_nodes)
380 {
381 if (node && node->kind != Node::Kind::GroupBox && !node->isDisabled() && !node->isInitialized())
382 {
383 node->doInitialize();
384 }
385 }
386}
387
388#ifdef TESTING
389
390namespace
391{
392std::vector<std::pair<ax::NodeEditor::PinId, NAV::InputPin::WatcherCallback>> watcherPinList;
393std::vector<std::pair<ax::NodeEditor::LinkId, NAV::InputPin::WatcherCallback>> watcherLinkList;
394
395std::function<void()> preInitCallback = nullptr;
396std::function<void()> cleanupCallback = nullptr;
397
398} // namespace
399
400void NAV::NodeManager::RegisterWatcherCallbackToInputPin(ax::NodeEditor::PinId id, const InputPin::WatcherCallback& callback)
401{
402 watcherPinList.emplace_back(id, callback);
403}
404
405void NAV::NodeManager::RegisterWatcherCallbackToLink(ax::NodeEditor::LinkId id, const InputPin::WatcherCallback& callback)
406{
407 watcherLinkList.emplace_back(id, callback);
408}
409
410void NAV::NodeManager::ApplyWatcherCallbacks()
411{
412 for (auto& [linkId, callback] : watcherLinkList)
413 {
414 for (auto& node : m_nodes)
415 {
416 for (size_t pinIdx = 0; pinIdx < node->inputPins.size(); pinIdx++)
417 {
418 auto& pin = node->inputPins[pinIdx];
419 if (pin.isPinLinked() && pin.link.linkId == linkId)
420 {
421 LOG_DEBUG("Adding watcher callback on node '{}' on pin with index {}", pin.parentNode->nameId(), pinIdx);
422 pin.watcherCallbacks.emplace_back(callback);
423 }
424 }
425 }
426 }
427
428 for (auto& [id, callback] : watcherPinList)
429 {
430 for (auto& node : m_nodes)
431 {
432 for (size_t pinIdx = 0; pinIdx < node->inputPins.size(); pinIdx++)
433 {
434 auto& pin = node->inputPins[pinIdx];
435 if (pin.id == id)
436 {
437 LOG_DEBUG("Adding watcher callback on node '{}' on pin with index {}", pin.parentNode->nameId(), pinIdx);
438 pin.watcherCallbacks.emplace_back(callback);
439 }
440 }
441 }
442 }
443}
444
445void NAV::NodeManager::RegisterPreInitCallback(std::function<void()> callback)
446{
447 preInitCallback = std::move(callback);
448}
449
450void NAV::NodeManager::CallPreInitCallback()
451{
452 if (preInitCallback)
453 {
454 preInitCallback();
455 }
456}
457
458void NAV::NodeManager::RegisterCleanupCallback(std::function<void()> callback)
459{
460 cleanupCallback = std::move(callback);
461}
462void NAV::NodeManager::CallCleanupCallback()
463{
464 if (cleanupCallback)
465 {
466 cleanupCallback();
467 }
468}
469
470void NAV::NodeManager::ClearRegisteredCallbacks()
471{
472 watcherPinList.clear();
473 watcherLinkList.clear();
474 preInitCallback = nullptr;
475 cleanupCallback = nullptr;
476}
477
478#endif
Assertion helpers.
Save/Load the Nodes.
#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
std::variant< FlowFirableCallbackFunc, DataChangedNotifyFunc > Callback
Callback function types.
Definition Pin.hpp:718
bool(*)(const Node *, const InputPin &) FlowFirableCheckFunc
Function type to call when checking if a pin is firable.
Definition Pin.hpp:725
void deleteLink()
Disconnects the link.
Definition Pin.cpp:370
Abstract parent class for all nodes.
Definition Node.hpp:92
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::vector< OutputPin > outputPins
List of output pins.
Definition Node.hpp:399
size_t outputPinIndexFromId(ax::NodeEditor::PinId pinId) const
Returns the index of the pin.
Definition Node.cpp:243
std::vector< InputPin > inputPins
List of input pins.
Definition Node.hpp:397
std::string nameId() const
Node name and id.
Definition Node.cpp:253
size_t inputPinIndexFromId(ax::NodeEditor::PinId pinId) const
Returns the index of the pin.
Definition Node.cpp:233
ax::NodeEditor::NodeId id
Unique Id of the Node.
Definition Node.hpp:391
Output pins of nodes.
Definition Pin.hpp:338
void deleteLinks()
Disconnects all links.
Definition Pin.cpp:272
std::variant< const void *, const bool *, const int *, const float *, const double *, const std::string *, PeekPollDataFunc, PollDataFunc > PinData
Possible Types represented by an output pin.
Definition Pin.hpp:448
Node * parentNode
Reference to the parent node.
Definition Pin.hpp:307
ax::NodeEditor::PinId id
Unique Id of the Pin.
Definition Pin.hpp:297
void ClearAllNodeQueues()
Clears all nodes queues.
OutputPin * CreateOutputPin(Node *node, const char *name, Pin::Type pinType, const std::vector< std::string > &dataIdentifier, OutputPin::PinData data=static_cast< void * >(nullptr), int idx=-1)
Create an Output Pin object.
ax::NodeEditor::LinkId GetNextLinkId()
Generates a new link id.
bool showFlowWhenNotifyingValueChange
Flag if notifyOutputValueChanged & notifyInputValueChanged triggers a GUI Flow event.
bool DeleteOutputPin(OutputPin &pin)
Deletes the output pin. Invalidates the pin reference given.
bool DeleteNode(ax::NodeEditor::NodeId nodeId)
Delete the node provided by id.
InputPin * FindInputPin(ax::NodeEditor::PinId id)
Finds the Pin for the PinId.
void InitializeAllNodesAsync()
Initializes all nodes in a separate thread.
void UpdateNode(Node *node)
Update the provided node object.
void AddLink(ax::NodeEditor::LinkId linkId)
Adds the link.
OutputPin * FindOutputPin(ax::NodeEditor::PinId id)
Finds the Pin for the PinId.
void EnableAllCallbacks()
Enables all Node callbacks.
void DisableAllCallbacks()
Disables all Node callbacks.
ax::NodeEditor::NodeId GetNextNodeId()
Generates a new node id.
bool InitializeAllNodes()
Initializes all nodes.
bool DeleteInputPin(InputPin &pin)
Deletes the input pin. Invalidates the pin reference given.
void DeleteAllNodes()
Delete all nodes.
const std::vector< Node * > & m_Nodes()
List of all registered Nodes.
void AddNode(Node *node)
Add the provided node object to the list of nodes.
ax::NodeEditor::PinId GetNextPinId()
Generates a new pin id.
Node * FindNode(ax::NodeEditor::NodeId id)
Finds the Node for the NodeId.
bool showFlowWhenInvokingCallbacks
Flag if invokeCallbacks triggers a GUI Flow event.
InputPin * CreateInputPin(Node *node, const char *name, Pin::Type pinType, const std::vector< std::string > &dataIdentifier={}, InputPin::Callback callback=static_cast< InputPin::FlowFirableCallbackFunc >(nullptr), InputPin::FlowFirableCheckFunc firable=nullptr, int priority=0, int idx=-1)
Create an Input Pin object.
bool saveLastActions
Whether actions should be saved to the last actions list.
void ApplyChanges()
Signals that there have been changes to the flow.
@ GroupBox
Group box which can group other nodes and drag them together.
Definition Node.hpp:102
Type of the data on the Pin.
Definition Pin.hpp:47