0.3.0
Loading...
Searching...
No Matches
Demo.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
9#include "Demo.hpp"
10#include <cstddef>
11#include <imgui.h>
12#include <optional>
13
14#include "util/Logger.hpp"
15
17namespace nm = NAV::NodeManager;
19
23
25
26#include <chrono>
27#include <thread>
28#include <random>
29
30namespace NAV
31{
32namespace
33{
34InsTime getCurrentInsTime()
35{
36 std::time_t now = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
37 auto* t = std::localtime(&now); // NOLINT(concurrency-mt-unsafe)
38
39 return { static_cast<uint16_t>(t->tm_year + 1900),
40 static_cast<uint16_t>(t->tm_mon),
41 static_cast<uint16_t>(t->tm_mday),
42 static_cast<uint16_t>(t->tm_hour),
43 static_cast<uint16_t>(t->tm_min),
44 static_cast<long double>(t->tm_sec) };
45}
46} // namespace
47
48/// @brief Write info to a json object
49/// @param[out] j Json output
50/// @param[in] data Object to read info from
51static void to_json(json& j, const Demo::DemoData& data) // NOLINT(misc-use-anonymous-namespace)
52{
53 j = json{
54 { "boolean", data.boolean },
55 { "integer", data.integer },
56 };
57}
58/// @brief Read info from a json object
59/// @param[in] j Json variable to read info from
60/// @param[out] data Output object
61static void from_json(const json& j, Demo::DemoData& data) // NOLINT(misc-use-anonymous-namespace)
62{
63 if (j.contains("boolean"))
64 {
65 j.at("boolean").get_to(data.boolean);
66 }
67 if (j.contains("integer"))
68 {
69 j.at("integer").get_to(data.integer);
70 }
71}
72
73} // namespace NAV
74
76 : Node(typeStatic())
77{
78 LOG_TRACE("{}: called", name);
79
80 _onlyRealTime = false; // Set this to true if you have a sensor, network stream, ...
81 _hasConfig = true;
83 _guiConfigDefaultWindowSize = { 630, 410 };
84
85 // Pins are usually created by calling the following functions in the constructor
87 nm::CreateOutputPin(this, "Sensor\nData", Pin::Type::Flow, { NAV::ImuObs::type() });
88
89 // To create or delete pins depending on GUI options we use a function as it needs to be called from multiple places
90 updatePins();
91}
92
94{
95 LOG_TRACE("{}: called", nameId());
96}
97
99{
100 return "Demo";
101}
102
103std::string NAV::Demo::type() const
104{
105 return typeStatic();
106}
107
109{
110 return "Utility";
111}
112
114{
115 if (ImGui::BeginTable("##DemoValues", 3, ImGuiTableFlags_Borders))
116 {
117 ImGui::TableSetupColumn("Enable");
118 ImGui::TableSetupColumn("Input");
119 ImGui::TableSetupColumn("Output");
120 ImGui::TableHeadersRow();
121
122 /* ----------------------------------------------- Delegate ----------------------------------------------- */
123 ImGui::TableNextRow();
124 ImGui::TableSetColumnIndex(0);
125 if (ImGui::Checkbox(fmt::format("Delegate##enable {}", size_t(id)).c_str(), &_enableDelegate))
126 {
127 updatePins();
129 }
130 if (_enableDelegate)
131 {
132 ImGui::TableSetColumnIndex(1);
133 {
134 // The returned type automatically blocks editing on the other side of the link. Like a scoped_lock for mutexes
135 auto connectedNode = getInputValue<Demo>(getPinIdx(DemoPins::Delegate).value());
136 ImGui::Text("Delegate: %s", connectedNode ? connectedNode->v->nameId().c_str() : "N/A");
137 }
138 }
139 /* ------------------------------------------------ Flow ------------------------------------------------ */
140 ImGui::TableNextRow();
141 ImGui::TableSetColumnIndex(0);
142 if (ImGui::Checkbox(fmt::format("Flow##enable {}", size_t(id)).c_str(), &_enableFlow))
143 {
144 updatePins();
146 }
147 if (_enableFlow)
148 {
149 ImGui::TableSetColumnIndex(1);
150 ImGui::Text("Flow Data Count: %d", _receivedDataCnt);
151 ImGui::TableSetColumnIndex(2);
152 if (ImGui::Checkbox(fmt::format("Simulate File Reader##{}", size_t(id)).c_str(), &_fileReaderInsteadSensor))
153 {
155 {
156 if (_timer.is_running()) { _timer.stop(); }
157 }
158 else
159 {
160 if (isInitialized() && !_timer.is_running())
161 {
162 int outputInterval = static_cast<int>(1.0 / static_cast<double>(_outputFrequency) * 1000.0);
163 _timer.start(outputInterval, readSensorDataThread, this);
164 }
165 }
168 }
170 {
171 ImGui::SetNextItemWidth(100.0F);
172 if (ImGui::InputInt(fmt::format("FileReader Obs Count##{}", size_t(id)).c_str(), &_nPollData))
173 {
175 }
176 }
177 else
178 {
179 if (ImGui::SliderInt(fmt::format("Frequency##{}", size_t(id)).c_str(), &_outputFrequency, 1, 10))
180 {
181 int outputInterval = static_cast<int>(1.0 / static_cast<double>(_outputFrequency) * 1000.0);
182 _timer.setInterval(outputInterval);
184 }
185 }
186 }
187 /* ------------------------------------------------- Bool ------------------------------------------------- */
188 ImGui::TableNextRow();
189 ImGui::TableSetColumnIndex(0);
190 if (ImGui::Checkbox(fmt::format("Bool##enable {}", size_t(id)).c_str(), &_enableBool))
191 {
192 updatePins();
194 }
195 if (_enableBool)
196 {
197 ImGui::TableSetColumnIndex(1);
198 {
199 auto connectedBool = getInputValue<bool>(getPinIdx(DemoPins::Bool).value());
200 ImGui::Text("Bool: %s", connectedBool ? (connectedBool->v ? "true" : "false") : "N/A");
201 }
202
203 ImGui::TableSetColumnIndex(2);
204 {
205 auto guard = requestOutputValueLock(getPinIdx(DemoPins::Bool).value());
206 if (ImGui::Checkbox(fmt::format("Bool##{}", size_t(id)).c_str(), &_valueBool))
207 {
209 }
210 }
211 }
212 /* -------------------------------------------------- Int ------------------------------------------------- */
213 ImGui::TableNextRow();
214 ImGui::TableSetColumnIndex(0);
215 if (ImGui::Checkbox(fmt::format("Int##enable {}", size_t(id)).c_str(), &_enableInt))
216 {
217 updatePins();
219 }
220 if (_enableInt)
221 {
222 ImGui::TableSetColumnIndex(1);
223 if (auto connectedInt = getInputValue<int>(getPinIdx(DemoPins::Int).value()))
224 {
225 ImGui::Text("Int: %d", *connectedInt->v);
226 }
227 else
228 {
229 ImGui::TextUnformatted("Int: N/A");
230 }
231
232 ImGui::TableSetColumnIndex(2);
233 {
234 auto guard = requestOutputValueLock(getPinIdx(DemoPins::Int).value());
235 if (ImGui::InputInt(fmt::format("Int##{}", size_t(id)).c_str(), &_valueInt)) // Returns true if a change was made
236 {
237 // Limit the values to [-2,5]
238 _valueInt = std::max(_valueInt, -2);
239 _valueInt = std::min(_valueInt, 5);
240
242 }
243 }
244 }
245 /* ------------------------------------------------- Float ------------------------------------------------ */
246 ImGui::TableNextRow();
247 ImGui::TableSetColumnIndex(0);
248 if (ImGui::Checkbox(fmt::format("Float##enable {}", size_t(id)).c_str(), &_enableFloat))
249 {
250 updatePins();
252 }
253 if (_enableFloat)
254 {
255 ImGui::TableSetColumnIndex(1);
256 if (auto connectedFloat = getInputValue<float>(getPinIdx(DemoPins::Float).value()))
257 {
258 ImGui::Text("Float: %.3f", *connectedFloat->v);
259 }
260 else
261 {
262 ImGui::TextUnformatted("Float: N/A");
263 }
264
265 ImGui::TableSetColumnIndex(2);
266 {
267 auto guard = requestOutputValueLock(getPinIdx(DemoPins::Float).value());
268 if (ImGui::DragFloat(fmt::format("Float##{}", size_t(id)).c_str(), &_valueFloat))
269 {
271 }
272 }
273 }
274 /* ------------------------------------------------ Double ------------------------------------------------ */
275 ImGui::TableNextRow();
276 ImGui::TableSetColumnIndex(0);
277 if (ImGui::Checkbox(fmt::format("Double##enable {}", size_t(id)).c_str(), &_enableDouble))
278 {
279 updatePins();
281 }
282 if (_enableDouble)
283 {
284 ImGui::TableSetColumnIndex(1);
285 if (auto connectedDouble = getInputValue<double>(getPinIdx(DemoPins::Double).value()))
286 {
287 ImGui::Text("Double : %.3f", *connectedDouble->v);
288 }
289 else
290 {
291 ImGui::TextUnformatted("Double: N/A");
292 }
293
294 ImGui::TableSetColumnIndex(2);
295 {
297 if (ImGui::DragDouble(fmt::format("Double##{}", size_t(id)).c_str(), &_valueDouble))
298 {
300 }
301 }
302 }
303 /* ------------------------------------------------ String ------------------------------------------------ */
304 ImGui::TableNextRow();
305 ImGui::TableSetColumnIndex(0);
306 if (ImGui::Checkbox(fmt::format("String##enable {}", size_t(id)).c_str(), &_enableString))
307 {
308 updatePins();
310 }
311 if (_enableString)
312 {
313 ImGui::TableSetColumnIndex(1);
314 if (auto connectedString = getInputValue<std::string>(getPinIdx(DemoPins::String).value()))
315 {
316 ImGui::Text("String: %s", connectedString->v->c_str());
317 }
318 else
319 {
320 ImGui::TextUnformatted("String: N/A");
321 }
322 ImGui::Text("The String was updated %lu time%s", _stringUpdateCounter, _stringUpdateCounter > 1 || _stringUpdateCounter == 0 ? "s" : "");
323
324 ImGui::TableSetColumnIndex(2);
325 {
326 // Before accessing and changing the value. A lock has to be requested to ensure it is not changed before all linked nodes received the value.
328 if (ImGui::InputText(fmt::format("String##{}", size_t(id)).c_str(), &_valueString))
329 {
331 const auto& outputPin = outputPins[getPinIdx(DemoPins::String).value()];
332 if (outputPin.isPinLinked())
333 {
334 if (!isInitialized()) { LOG_WARN("{}: Notifying connected nodes requires this node to be initialized.", nameId()); }
335 else if (!callbacksEnabled) { LOG_WARN("{}: Notifying connected nodes requires enabled callbacks on this node. Do this by running the flow.", nameId()); }
336 else if (std::ranges::none_of(outputPin.links, [](const OutputPin::OutgoingLink& link) { return link.connectedNode->isInitialized(); }))
337 {
338 LOG_WARN("{}: Notifying connected nodes requires at least one connected node to be initialized.", nameId());
339 }
340 }
341 notifyOutputValueChanged(getPinIdx(DemoPins::String).value(), getCurrentInsTime(), std::move(guard));
342 }
343 }
344 ImGui::SameLine();
345 gui::widgets::HelpMarker("The string notifies about changes.\nInitialize both nodes for this to work.");
346 }
347 /* ------------------------------------------------ Object ------------------------------------------------ */
348 ImGui::TableNextRow();
349 ImGui::TableSetColumnIndex(0);
350 if (ImGui::Checkbox(fmt::format("Object##enable {}", size_t(id)).c_str(), &_enableObject))
351 {
352 updatePins();
354 }
355 if (_enableObject)
356 {
357 ImGui::TableSetColumnIndex(1);
358 if (auto connectedObject = getInputValue<DemoData>(getPinIdx(DemoPins::Object).value()))
359 {
360 ImGui::Text("Object: [%d, %d, %d], %s", connectedObject->v->integer.at(0), connectedObject->v->integer.at(1), connectedObject->v->integer.at(2),
361 connectedObject->v->boolean ? "true" : "false");
362 }
363 else
364 {
365 ImGui::TextUnformatted("Object: N/A");
366 }
367
368 ImGui::TableSetColumnIndex(2);
369 {
371 if (ImGui::InputInt3(fmt::format("##object.integer {}", size_t(id)).c_str(), _valueObject.integer.data()))
372 {
374 }
375 ImGui::SameLine();
376 if (ImGui::Checkbox(fmt::format("Object##{}", size_t(id)).c_str(), &_valueObject.boolean))
377 {
379 }
380 }
381 }
382 /* ------------------------------------------------ Matrix ------------------------------------------------ */
383 ImGui::TableNextRow();
384 ImGui::TableSetColumnIndex(0);
385 if (ImGui::Checkbox(fmt::format("Matrix##enable {}", size_t(id)).c_str(), &_enableMatrix))
386 {
387 updatePins();
389 }
390 if (_enableMatrix)
391 {
392 ImGui::TableSetColumnIndex(1);
393 if (auto connectedMatrix = getInputValue<Eigen::MatrixXd>(getPinIdx(DemoPins::Matrix).value()))
394 {
395 gui::widgets::MatrixView("Current Matrix", connectedMatrix->v, GuiMatrixViewFlags_Header, ImGuiTableFlags_Borders | ImGuiTableFlags_NoHostExtendX | ImGuiTableFlags_SizingFixedFit, "%.1f");
396 }
397 else
398 {
399 ImGui::TextUnformatted("Matrix: N/A");
400 }
401
402 ImGui::TableSetColumnIndex(2);
403 {
405 if (gui::widgets::InputMatrix(fmt::format("Init Matrix##{}", size_t(id)).c_str(), &_valueMatrix, GuiMatrixViewFlags_Header, ImGuiTableFlags_Borders | ImGuiTableFlags_NoHostExtendX | ImGuiTableFlags_SizingFixedFit, 30.0F, 0.0, 0.0, "%.1f"))
406 {
408 }
409 }
410 }
411
412 ImGui::EndTable();
413 }
414}
415
416[[nodiscard]] json NAV::Demo::save() const
417{
418 LOG_TRACE("{}: called", nameId());
419
420 json j;
421
422 return {
423 { "outputFrequency", _outputFrequency },
424 { "nPollData", _nPollData },
425 { "enableDelegate", _enableDelegate },
426 { "enableFlow", _enableFlow },
427 { "enableBool", _enableBool },
428 { "enableInt", _enableInt },
429 { "enableFloat", _enableFloat },
430 { "enableDouble", _enableDouble },
431 { "enableString", _enableString },
432 { "enableObject", _enableObject },
433 { "enableMatrix", _enableMatrix },
434 { "valueBool", _valueBool },
435 { "valueInt", _valueInt },
436 { "valueFloat", _valueFloat },
437 { "valueDouble", _valueDouble },
438 { "valueString", _valueString },
439 { "valueObject", _valueObject },
440 { "valueMatrix", _valueMatrix },
441 { "fileReaderInsteadSensor", _fileReaderInsteadSensor },
442 };
443}
444
446{
447 LOG_TRACE("{}: called", nameId());
448
449 if (j.contains("outputFrequency")) { j.at("outputFrequency").get_to(_outputFrequency); }
450 if (j.contains("nPollData")) { j.at("nPollData").get_to(_nPollData); }
451 if (j.contains("enableDelegate")) { j.at("enableDelegate").get_to(_enableDelegate); }
452 if (j.contains("enableFlow")) { j.at("enableFlow").get_to(_enableFlow); }
453 if (j.contains("enableBool")) { j.at("enableBool").get_to(_enableBool); }
454 if (j.contains("enableInt")) { j.at("enableInt").get_to(_enableInt); }
455 if (j.contains("enableFloat")) { j.at("enableFloat").get_to(_enableFloat); }
456 if (j.contains("enableDouble")) { j.at("enableDouble").get_to(_enableDouble); }
457 if (j.contains("enableString")) { j.at("enableString").get_to(_enableString); }
458 if (j.contains("enableObject")) { j.at("enableObject").get_to(_enableObject); }
459 if (j.contains("enableMatrix")) { j.at("enableMatrix").get_to(_enableMatrix); }
460 if (j.contains("valueBool")) { j.at("valueBool").get_to(_valueBool); }
461 if (j.contains("valueInt")) { j.at("valueInt").get_to(_valueInt); }
462 if (j.contains("valueFloat")) { j.at("valueFloat").get_to(_valueFloat); }
463 if (j.contains("valueDouble")) { j.at("valueDouble").get_to(_valueDouble); }
464 if (j.contains("valueString")) { j.at("valueString").get_to(_valueString); }
465 if (j.contains("valueObject")) { j.at("valueObject").get_to(_valueObject); }
466 if (j.contains("valueMatrix")) { j.at("valueMatrix").get_to(_valueMatrix); }
467 if (j.contains("fileReaderInsteadSensor"))
468 {
469 j.at("fileReaderInsteadSensor").get_to(_fileReaderInsteadSensor);
471 }
472 updatePins();
473}
474
476{
477 LOG_TRACE("{}: called", nameId());
478
479 // To Show the Initialization in the GUI
480 std::this_thread::sleep_for(std::chrono::milliseconds(2000));
481
483
485
487 {
488 // The Timer is used to simulate a sensor reader
489 int outputInterval = static_cast<int>(1.0 / static_cast<double>(_outputFrequency) * 1000.0);
490 _timer.start(outputInterval, readSensorDataThread, this);
491 }
492
493 return true;
494}
495
497{
498 LOG_TRACE("{}: called", nameId());
499
500 if (_timer.is_running())
501 {
502 _timer.stop();
503 }
504
505 // To Show the Deinitialization in the GUI
506 std::this_thread::sleep_for(std::chrono::milliseconds(1000));
507}
508
510{
511 size_t pinIdx = 0;
512
513 auto updatePin = [&](bool pinExists, bool enabled,
514 const char* pinName, Pin::Type pinType, const std::vector<std::string>& dataIdentifier = {}, // BUG: Bug in clang-format, so we need to disable formatting
515 OutputPin::PinData data = static_cast<void*>(nullptr), // clang-format off
516 void(NAV::Demo::*notifyFunc)(const InsTime&, size_t) = nullptr) { // clang-format on
517 if (!pinExists && enabled)
518 {
519 nm::CreateInputPin(this, pinName, pinType, dataIdentifier, notifyFunc, static_cast<int>(pinIdx));
520 nm::CreateOutputPin(this, pinName, pinType, dataIdentifier, data, static_cast<int>(pinIdx));
521 }
522 else if (pinExists && !enabled)
523 {
524 nm::DeleteInputPin(inputPins.at(pinIdx));
526 }
527 if (enabled) { pinIdx++; }
528 };
529
531 "Demo Node", Pin::Type::Delegate, { typeStatic() }, this);
532 // nm::CreateInputPin(this, "Demo Node", Pin::Type::Delegate, { typeStatic() });
533 // nm::CreateOutputPin(this, "", Pin::Type::Delegate, { typeStatic() }, this, 0);
534
535 {
537 if (!pinExists && _enableFlow)
538 {
540 nm::CreateOutputPin(this, "Sensor\nData", Pin::Type::Flow, { NAV::ImuObs::type() });
541 }
542 else if (pinExists && !_enableFlow)
543 {
544 nm::DeleteInputPin(inputPins.at(pinIdx));
546 }
547 if (_enableFlow) { pinIdx++; }
548 }
549
551 "Bool", Pin::Type::Bool, { "" }, &_valueBool);
552 // nm::CreateInputPin(this, "Bool", Pin::Type::Bool);
553 // nm::CreateOutputPin(this, "Bool", Pin::Type::Bool, { "" }, &_valueBool);
554
556 "Int", Pin::Type::Int, { "" }, &_valueInt);
557 // nm::CreateInputPin(this, "Int", Pin::Type::Int);
558 // nm::CreateOutputPin(this, "Int", Pin::Type::Int, { "" }, &_valueInt);
559
561 "Float", Pin::Type::Float, { "Float" }, &_valueFloat);
562 // nm::CreateInputPin(this, "Float", Pin::Type::Float);
563 // nm::CreateOutputPin(this, "Float", Pin::Type::Float, { "" }, &_valueFloat);
564
566 "Double", Pin::Type::Float, { "Double" }, &_valueDouble);
567 // nm::CreateInputPin(this, "Double", Pin::Type::Float);
568 // nm::CreateOutputPin(this, "Double", Pin::Type::Float, { "" }, &_valueDouble);
569
572 // nm::CreateInputPin(this, "String", Pin::Type::String, {}, &Demo::stringUpdatedNotifyFunction);
573 // nm::CreateOutputPin(this, "String", Pin::Type::String, { "" }, &_valueString);
574
576 "Object", Pin::Type::Object, { "Demo::DemoData" }, &_valueObject);
577 // nm::CreateInputPin(this, "Object", Pin::Type::Object, { "Demo::DemoData" });
578 // nm::CreateOutputPin(this, "Object", Pin::Type::Object, { "Demo::DemoData" }, &_valueObject);
579
581 "Matrix", Pin::Type::Matrix, { "Eigen::MatrixXd" }, &_valueMatrix);
582 // nm::CreateInputPin(this, "Matrix", Pin::Type::Matrix, { "Eigen::MatrixXd" });
583 // nm::CreateOutputPin(this, "Matrix", Pin::Type::Matrix, { "Eigen::MatrixXd" }, &_valueMatrix);
584}
585
586std::optional<size_t> NAV::Demo::getPinIdx(DemoPins pinType) const
587{
588 for (size_t i = 0; i < inputPins.size(); i++)
589 {
590 switch (pinType)
591 {
593 if (inputPins.at(i).type == Pin::Type::Delegate) { return i; }
594 break;
595 case DemoPins::Flow:
596 if (inputPins.at(i).type == Pin::Type::Flow) { return i; }
597 break;
598 case DemoPins::Bool:
599 if (inputPins.at(i).type == Pin::Type::Bool) { return i; }
600 break;
601 case DemoPins::Int:
602 if (inputPins.at(i).type == Pin::Type::Int) { return i; }
603 break;
604 case DemoPins::Float:
605 if (inputPins.at(i).type == Pin::Type::Float && inputPins.at(i).dataIdentifier.front() == "Float") { return i; }
606 break;
607 case DemoPins::Double:
608 if (inputPins.at(i).type == Pin::Type::Float && inputPins.at(i).dataIdentifier.front() == "Double") { return i; }
609 break;
610 case DemoPins::String:
611 if (inputPins.at(i).type == Pin::Type::String) { return i; }
612 break;
613 case DemoPins::Object:
614 if (inputPins.at(i).type == Pin::Type::Object) { return i; }
615 break;
616 case DemoPins::Matrix:
617 if (inputPins.at(i).type == Pin::Type::Matrix) { return i; }
618 break;
619 }
620 }
621
622 return std::nullopt;
623}
624
626{
627 LOG_TRACE("{}: called", nameId());
628 // Here you could reset a FileReader
629 _iPollData = 0;
631
632 return true;
633}
634
636{
637 size_t flowPinIdx = getPinIdx(DemoPins::Flow).value();
638 std::vector<ax::NodeEditor::PinId> connectedPins;
639 for (const auto& link : outputPins.at(flowPinIdx).links)
640 {
641 connectedPins.push_back(link.connectedPinId);
642 }
643 nm::DeleteOutputPin(outputPins.at(flowPinIdx));
645 {
646 nm::CreateOutputPin(this, "FileReader\n Data", Pin::Type::Flow, { NAV::NodeData::type() }, &Demo::pollData, static_cast<int>(flowPinIdx));
647 }
648 else
649 {
650 nm::CreateOutputPin(this, "Sensor\nData", Pin::Type::Flow, { NAV::ImuObs::type() }, static_cast<void*>(nullptr), static_cast<int>(flowPinIdx));
651 }
652 for (const auto& pinId : connectedPins)
653 {
654 if (auto* targetPin = nm::FindInputPin(pinId))
655 {
656 if (outputPins.at(flowPinIdx).canCreateLink(*targetPin))
657 {
658 outputPins.at(flowPinIdx).createLink(*targetPin);
659 }
660 }
661 }
662}
663
664bool NAV::Demo::onCreateLink([[maybe_unused]] OutputPin& startPin, [[maybe_unused]] InputPin& endPin)
665{
666 LOG_TRACE("{}: called for {} ==> {}", nameId(), size_t(startPin.id), size_t(endPin.id));
667
668 if (_enableFlow && outputPins.at(getPinIdx(DemoPins::Flow).value()).isPinLinked())
669 {
671 }
672
673 return true;
674}
675
676void NAV::Demo::afterDeleteLink([[maybe_unused]] OutputPin& startPin, [[maybe_unused]] InputPin& endPin)
677{
678 LOG_TRACE("{}: called for {} ==> {}", nameId(), size_t(startPin.id), size_t(endPin.id));
679
680 if (_enableFlow && !outputPins.at(getPinIdx(DemoPins::Flow).value()).isPinLinked())
681 {
682 _onlyRealTime = false;
683 }
684}
685
687{
688 std::shared_ptr<const NAV::NodeData> obs = queue.extract_front(); // Either 'extract_front()' or 'pop_front()' needs to be called
690
691 LOG_DEBUG("{}: received {} data at [{} GPST]", nameId(), _receivedDataCnt, obs->insTime.toYMDHMS(GPST));
692}
693
695{
696 auto* node = static_cast<Demo*>(userData);
697
698 if (!node->_enableFlow || !node->getPinIdx(DemoPins::Flow).has_value()) { return; }
699
700 if (!node->outputPins.at(node->getPinIdx(DemoPins::Flow).value()).isPinLinked() || !node->callbacksEnabled)
701 {
702 return;
703 }
704
705 if (node->getMode() == Mode::POST_PROCESSING)
706 {
707 LOG_WARN("{}: Flow contains nodes which can only do post-processing. Sensor output is suppressed.");
708
709 return;
710 }
711
712 auto imuPos = ImuPos();
713 auto obs = std::make_shared<ImuObs>(imuPos);
714
715 std::time_t now = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
716 auto* t = std::gmtime(&now); // NOLINT(concurrency-mt-unsafe)
717
718 obs->insTime = InsTime(static_cast<uint16_t>(t->tm_year + 1900), static_cast<uint16_t>(t->tm_mon) + 1, static_cast<uint16_t>(t->tm_mday),
719 static_cast<uint16_t>(t->tm_hour), static_cast<uint16_t>(t->tm_min), static_cast<long double>(t->tm_sec), GPST);
720
721 std::random_device rd;
722 std::default_random_engine generator(rd());
723
724 std::uniform_real_distribution<double> distribution(-9.0, 9.0);
725 obs->p_acceleration = Eigen::Vector3d(distribution(generator), distribution(generator), distribution(generator));
726
727 distribution = std::uniform_real_distribution<double>(-3.0, 3.0);
728 obs->p_angularRate = Eigen::Vector3d(distribution(generator), distribution(generator), distribution(generator));
729
730 distribution = std::uniform_real_distribution<double>(-1.0, 1.0);
731 obs->p_magneticField = Eigen::Vector3d(distribution(generator), distribution(generator), distribution(generator));
732
733 distribution = std::uniform_real_distribution<double>(15.0, 25.0);
734 obs->temperature = distribution(generator);
735
736 LOG_INFO("{}: Sending Sensor data with time [{} GPST]", node->nameId(), obs->insTime.toYMDHMS(GPST));
737
738 node->invokeCallbacks(node->getPinIdx(DemoPins::Flow).value(), obs);
739}
740
741std::shared_ptr<const NAV::NodeData> NAV::Demo::peekPollData(bool peek)
742{
743 // This function is only an example of how to implement peek/poll logic. It is not used in this node.
744 if (_iPollData >= _nPollData)
745 {
746 return nullptr;
747 }
748
749 if (peek) // Early return with time to let the Node sort the observations
750 {
751 auto obs = std::make_shared<NodeData>(); // Construct the real observation (here in example also from type NodeData)
752 obs->insTime = InsTime(2000, 1, 1, 0, 0, _iPollData);
753 return obs;
754 }
755
756 auto obs = std::make_shared<NodeData>(); // Construct the real observation (here in example also from type NodeData)
757 obs->insTime = InsTime(2000, 1, 1, 0, 0, _iPollData);
758
759 _iPollData++;
760 // Calls all the callbacks
762
763 return obs;
764}
765
766std::shared_ptr<const NAV::NodeData> NAV::Demo::pollData()
767{
768 if (_iPollData >= _nPollData)
769 {
770 return nullptr; // Tells the node that the last message was read
771 }
772
773 auto obs = std::make_shared<NodeData>(); // Construct the real observation (here in example also from type NodeData)
774 obs->insTime = InsTime(2000, 1, 1, 0, 0, _iPollData);
775
776 _iPollData++;
777
778 invokeCallbacks(getPinIdx(DemoPins::Flow).value(), obs); // Calls all the callbacks
779 return obs;
780}
781
782void NAV::Demo::stringUpdatedNotifyFunction([[maybe_unused]] const InsTime& insTime, size_t pinIdx)
783{
785
786 if (auto value = getInputValue<std::string>(pinIdx))
787 {
788 LOG_DEBUG("String value updated to '{}' at time {}", *value->v, insTime);
789 }
790}
Demo Node which demonstrates all capabilities.
Save/Load the Nodes.
nlohmann::json json
json namespace
Text Help Marker (?) with Tooltip.
Parent Class for all IMU Observations.
Utility class for logging to console and file.
#define LOG_DEBUG
Debug information. Should not be called on functions which receive observations (spamming)
Definition Logger.hpp:67
#define LOG_WARN
Error occurred, but a fallback option exists and program continues to work normally.
Definition Logger.hpp:71
#define LOG_INFO
Info to the user on the state of the program.
Definition Logger.hpp:69
#define LOG_TRACE
Detailled info to trace the execution of the program. Should not be called on functions which receive...
Definition Logger.hpp:65
Widgets related to Matrices.
@ GuiMatrixViewFlags_Header
Print all Header.
Definition Matrix.hpp:29
Manages all Nodes.
Demonstrates the basic GUI functionality of nodes.
Definition Demo.hpp:28
bool _fileReaderInsteadSensor
Whether to have a file reader instead of a sensor output pin.
Definition Demo.hpp:133
int _iPollData
Counter for data Reading.
Definition Demo.hpp:148
bool _valueBool
Value which is represented over the Bool pin.
Definition Demo.hpp:162
bool _enableInt
Switch to enable the int pin.
Definition Demo.hpp:155
void afterDeleteLink(OutputPin &startPin, InputPin &endPin) override
Called when a link was deleted.
Definition Demo.cpp:676
bool onCreateLink(OutputPin &startPin, InputPin &endPin) override
Called when a new link is to be established.
Definition Demo.cpp:664
CallbackTimer _timer
Timer object to handle async data requests.
Definition Demo.hpp:136
bool _enableFlow
Switch to enable the flow pin.
Definition Demo.hpp:153
int _receivedDataCnt
Counter how often data was received.
Definition Demo.hpp:145
bool _enableDouble
Switch to enable the double pin.
Definition Demo.hpp:157
std::optional< size_t > getPinIdx(DemoPins pinType) const
Calculates the pin index for the given type.
Definition Demo.cpp:586
bool _enableObject
Switch to enable the object pin.
Definition Demo.hpp:159
float _valueFloat
Value which is represented over the Float pin.
Definition Demo.hpp:164
bool _enableString
Switch to enable the string pin.
Definition Demo.hpp:158
bool initialize() override
Initialize the node.
Definition Demo.cpp:475
bool _enableFloat
Switch to enable the float pin.
Definition Demo.hpp:156
void updatePins()
Update the pins depending on the GUI.
Definition Demo.cpp:509
bool _enableBool
Switch to enable the bool pin.
Definition Demo.hpp:154
size_t _stringUpdateCounter
Counter of how often the string was updated.
Definition Demo.hpp:169
bool resetNode() override
Resets the node. It is guaranteed that the node is initialized when this is called.
Definition Demo.cpp:625
static void readSensorDataThread(void *userData)
Function which performs the async data reading.
Definition Demo.cpp:694
void stringUpdatedNotifyFunction(const InsTime &insTime, size_t pinIdx)
Function to call when the string is updated.
Definition Demo.cpp:782
void restore(const json &j) override
Restores the node from a json object.
Definition Demo.cpp:445
void updateOutputFlowPin()
Updates the output flow pin depending on the GUI selection.
Definition Demo.cpp:635
std::shared_ptr< const NodeData > peekPollData(bool peek=false)
Polls data from the file. This function is needed, if we have multiple output pins,...
Definition Demo.cpp:741
static std::string typeStatic()
String representation of the Class Type.
Definition Demo.cpp:98
int _valueInt
Value which is represented over the Int pin.
Definition Demo.hpp:163
Eigen::MatrixXd _valueMatrix
Value which is represented over the Matrix pin.
Definition Demo.hpp:168
void deinitialize() override
Deinitialize the node.
Definition Demo.cpp:496
int _nPollData
Amount of Observations to be read.
Definition Demo.hpp:150
std::shared_ptr< const NodeData > pollData()
Polls data from the file.
Definition Demo.cpp:766
bool _enableMatrix
Switch to enable the matrix pin.
Definition Demo.hpp:160
std::string type() const override
String representation of the Class Type.
Definition Demo.cpp:103
DemoPins
Pin types used in this demo.
Definition Demo.hpp:97
@ Int
Integer numbers.
Definition Demo.hpp:101
@ Float
Float numbers.
Definition Demo.hpp:102
@ Delegate
Delegate pins giving access to the complete connected node.
Definition Demo.hpp:98
@ String
Strings.
Definition Demo.hpp:104
@ Object
Custom objects.
Definition Demo.hpp:105
@ Bool
Booleans.
Definition Demo.hpp:100
@ Double
Double numbers.
Definition Demo.hpp:103
@ Flow
Flow pins transmitting data as timestamped shared pointers.
Definition Demo.hpp:99
@ Matrix
Matrix objects.
Definition Demo.hpp:106
int _outputFrequency
Output frequency for the simulated sensor data.
Definition Demo.hpp:143
void receiveData(InputPin::NodeDataQueue &queue, size_t pinIdx)
Receive callback on the Flow pin.
Definition Demo.cpp:686
std::string _valueString
Value which is represented over the String pin.
Definition Demo.hpp:166
static std::string category()
String representation of the Class Category.
Definition Demo.cpp:108
bool _enableDelegate
Switch to enable the delegate pin.
Definition Demo.hpp:152
void guiConfig() override
ImGui config window which is shown on double click.
Definition Demo.cpp:113
Demo()
Default constructor.
Definition Demo.cpp:75
json save() const override
Saves the node into a json object.
Definition Demo.cpp:416
DemoData _valueObject
Value which is represented over the Object pin.
Definition Demo.hpp:167
double _valueDouble
Value which is represented over the Double pin.
Definition Demo.hpp:165
~Demo() override
Destructor.
Definition Demo.cpp:93
static std::string type()
Returns the type of the data class.
Definition ImuObs.hpp:33
IMU Position.
Definition ImuPos.hpp:26
Input pins of nodes.
Definition Pin.hpp:491
TsDeque< std::shared_ptr< const NAV::NodeData > > NodeDataQueue
Node data queue type.
Definition Pin.hpp:707
The class is responsible for all time-related tasks.
Definition InsTime.hpp:710
static std::string type()
Returns the type of the data class.
Definition NodeData.hpp:45
bool isInitialized() const
Checks if the node is initialized.
Definition Node.cpp:504
ImVec2 _guiConfigDefaultWindowSize
Definition Node.hpp:410
void notifyOutputValueChanged(size_t pinIdx, const InsTime &insTime, const std::scoped_lock< std::mutex > &&guard)
Notifies connected nodes about the change.
Definition Node.cpp:93
std::vector< OutputPin > outputPins
List of output pins.
Definition Node.hpp:399
Node(std::string name)
Constructor.
Definition Node.cpp:30
std::optional< InputPin::IncomingLink::ValueWrapper< T > > getInputValue(size_t portIndex) const
Get Input Value connected on the pin. Only const data types.
Definition Node.hpp:290
std::vector< InputPin > inputPins
List of input pins.
Definition Node.hpp:397
@ POST_PROCESSING
Node running in post-processing mode.
Definition Node.hpp:192
bool callbacksEnabled
Enables the callbacks.
Definition Node.hpp:402
std::string nameId() const
Node name and id.
Definition Node.cpp:253
bool _lockConfigDuringRun
Lock the config when executing post-processing.
Definition Node.hpp:416
std::string name
Name of the Node.
Definition Node.hpp:395
bool _onlyRealTime
Whether the node can run in post-processing or only real-time.
Definition Node.hpp:419
std::scoped_lock< std::mutex > requestOutputValueLock(size_t pinIdx)
Blocks the thread till the output values was read by all connected nodes.
Definition Node.cpp:133
void invokeCallbacks(size_t portIndex, const std::shared_ptr< const NodeData > &data)
Calls all registered callbacks on the specified output port.
Definition Node.cpp:180
bool _hasConfig
Flag if the config window should be shown.
Definition Node.hpp:413
Output pins of nodes.
Definition Pin.hpp:338
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
auto extract_front()
Returns a copy of the first element in the container and removes it from the container.
Definition TsDeque.hpp:494
ImGui extensions.
bool DragDouble(const char *label, double *v, float v_speed, double v_min, double v_max, const char *format, ImGuiSliderFlags flags)
Shows a Drag GUI element for 'double'.
Definition imgui_ex.cpp:19
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.
bool DeleteOutputPin(OutputPin &pin)
Deletes the output pin. Invalidates the pin reference given.
InputPin * FindInputPin(ax::NodeEditor::PinId id)
Finds the Pin for the PinId.
bool DeleteInputPin(InputPin &pin)
Deletes the input pin. Invalidates the pin reference given.
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.
void ApplyChanges()
Signals that there have been changes to the flow.
void MatrixView(const char *label, const Eigen::Matrix< _Scalar, _Rows, _Cols > *matrix, GuiMatrixViewFlags flags=GuiMatrixViewFlags_None, ImGuiTableFlags tableFlags=ImGuiTableFlags_None, const char *format="%.6f")
Shows GUI elements to display the coefficients of a matrix.
Definition Matrix.hpp:49
bool InputMatrix(const char *label, Eigen::Matrix< _Scalar, _Rows, _Cols > *matrix, GuiMatrixViewFlags flags=GuiMatrixViewFlags_None, ImGuiTableFlags tableFlags=ImGuiTableFlags_None, float inputTextWidth=50.0F, double step=0.0, double step_fast=0.0, const char *format="%.6f", ImGuiInputTextFlags inputTextFlags=ImGuiInputTextFlags_None)
Shows GUI elements to modify the coefficients of a matrix with.
Definition Matrix.hpp:105
void HelpMarker(const char *desc, const char *symbol="(?)")
Text Help Marker, e.g. '(?)', with Tooltip.
@ GPST
GPS Time.
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
Data struct transmitted over an output port.
Definition Demo.hpp:79
bool boolean
Boolean inside the DemoData.
Definition Demo.hpp:81
std::array< int, 3 > integer
Integer inside the DemoData.
Definition Demo.hpp:80
Type of the data on the Pin.
Definition Pin.hpp:47
@ Delegate
Reference to the Node object.
Definition Pin.hpp:59
@ 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