0.4.1
Loading...
Searching...
No Matches
RinexObsLogger.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 "RinexObsLogger.hpp"
10
11#include <chrono>
12#include <string>
14#include <fmt/chrono.h>
15#include <fmt/format.h>
16using namespace fmt::literals; // NOLINT(google-build-using-namespace)
17
20namespace nm = NAV::NodeManager;
22
25
27
29
30#include "util/Logger.hpp"
31
33 : Node(typeStatic())
34{
35 LOG_TRACE("{}: called", name);
36
38
39 _hasConfig = true;
40 _guiConfigDefaultWindowSize = { 643, 728 };
41
42 _dynamicInputPins.addPin(this);
43}
44
49
51{
52 return "RinexObsLogger";
53}
54
55std::string NAV::RinexObsLogger::type() const
56{
57 return typeStatic();
58}
59
61{
62 return "Data Logger";
63}
64
66{
67 if (_dynamicInputPins.ShowGuiWidgets(size_t(id), inputPins, this, {}))
68 {
70 }
71
72 constexpr float COL1_WIDTH = 470.0F;
73
74 const auto now = std::chrono::system_clock::now();
75 ImGui::SetNextItemWidth(COL1_WIDTH);
76 if (FileWriter::guiConfig(fmt::format(".obs,.rnx,.{:%y}O", now).c_str(), { ".obs", ".rnx", fmt::format(".{:%y}O", now) }, size_t(id), nameId()))
77 {
80 }
81
82 if (ImGui::CollapsingHeader(fmt::format("General##{}", size_t(id)).c_str(), ImGuiTreeNodeFlags_DefaultOpen))
83 {
84 if (ImGui::BeginTable(fmt::format("Table1##{}", size_t(id)).c_str(), 2, ImGuiTableFlags_SizingFixedFit))
85 {
86 ImGui::TableNextColumn();
87 ImGui::BeginDisabled();
88 ImGui::SetNextItemWidth(COL1_WIDTH);
89 if (ImGui::BeginCombo(fmt::format("##Version {}", size_t(id)).c_str(), fmt::format("{}", _header.version).c_str()))
90 {
91 for (const auto& version : _supportedVersions)
92 {
93 const bool is_selected = _header.version == version;
94 if (ImGui::Selectable(fmt::format("{}##Version {}", version, size_t(id)).c_str(), is_selected))
95 {
96 _header.version = version;
98 }
99 if (is_selected) { ImGui::SetItemDefaultFocus(); }
100 }
101 ImGui::EndCombo();
102 }
103 ImGui::EndDisabled();
104 ImGui::TableNextColumn();
105 ImGui::TextUnformatted("Version");
106
107 ImGui::TableNextColumn();
108 ImGui::SetNextItemWidth(COL1_WIDTH);
109 if (ImGui::InputTextL(fmt::format("##Run By {}", size_t(id)).c_str(), &_header.runBy, 20))
110 {
112 }
113 ImGui::TableNextColumn();
114 ImGui::TextUnformatted("Run By");
115
116 ImGui::TableNextColumn();
117 ImGui::SetNextItemWidth(COL1_WIDTH);
118 if (ImGui::InputTextL(fmt::format("##Observer {}", size_t(id)).c_str(), &_header.observer, 20))
119 {
121 }
122 ImGui::TableNextColumn();
123 ImGui::TextUnformatted("Observer");
124
125 ImGui::TableNextColumn();
126 ImGui::SetNextItemWidth(COL1_WIDTH);
127 if (ImGui::InputTextL(fmt::format("##Agency {}", size_t(id)).c_str(), &_header.agency, 40))
128 {
130 }
131 ImGui::TableNextColumn();
132 ImGui::TextUnformatted("Agency");
133
134 ImGui::EndTable();
135 }
136 }
137
138 if (ImGui::CollapsingHeader(fmt::format("Comments##{}", size_t(id)).c_str(), ImGuiTreeNodeFlags_DefaultOpen))
139 {
140 std::vector<size_t> commentsToRemove;
141 if (ImGui::BeginTable(fmt::format("Table2##{}", size_t(id)).c_str(), 2, ImGuiTableFlags_SizingFixedFit))
142 {
143 for (size_t i = 0; i < _header.comments.size(); i++)
144 {
145 ImGui::TableNextRow();
146 ImGui::TableNextColumn();
147 auto& comment = _header.comments.at(i);
148 float startPos = ImGui::GetCursorPosX();
149 if (ImGui::Button(fmt::format("X##Remove comment {} {}", i, size_t(id)).c_str()))
150 {
151 commentsToRemove.push_back(i);
152 }
153 ImGui::SameLine();
154 ImGui::SetNextItemWidth(COL1_WIDTH - (ImGui::GetCursorPosX() - startPos));
155 if (ImGui::InputTextL(fmt::format("##Comment {} {}", i, size_t(id)).c_str(), &comment, 60))
156 {
158 }
159 }
160 ImGui::EndTable();
161 }
162 for (const size_t& idx : commentsToRemove)
163 {
164 _header.comments.erase(std::next(_header.comments.begin(), static_cast<int>(idx)));
166 }
167 if (ImGui::Button(fmt::format("Add##Comment {}", size_t(id)).c_str()))
168 {
169 _header.comments.emplace_back();
171 }
172 }
173
174 if (ImGui::CollapsingHeader(fmt::format("Marker##{}", size_t(id)).c_str(), ImGuiTreeNodeFlags_DefaultOpen))
175 {
176 if (ImGui::BeginTable(fmt::format("Table3##{}", size_t(id)).c_str(), 2, ImGuiTableFlags_SizingFixedFit))
177 {
178 ImGui::TableNextColumn();
179 ImGui::SetNextItemWidth(COL1_WIDTH);
180 if (gui::widgets::EnumComboWithToolTip(fmt::format("##Marker Type {}", size_t(id)).c_str(), _header.markerType))
181 {
183 }
184 if (_header.markerType != vendor::RINEX::ObsHeader::MarkerTypes::USER_DEFINED) { ImGui::BeginDisabled(); }
185 ImGui::TableNextColumn();
186 ImGui::TextUnformatted("Type");
187
188 ImGui::TableNextColumn();
189 ImGui::SetNextItemWidth(COL1_WIDTH);
190 if (ImGui::InputTextL(fmt::format("##Marker User Type {}", size_t(id)).c_str(), &_header.markerTypeUser, 20))
191 {
193 }
194 if (_header.markerType != vendor::RINEX::ObsHeader::MarkerTypes::USER_DEFINED) { ImGui::EndDisabled(); }
195 ImGui::TableNextColumn();
196 ImGui::TextUnformatted("User Type");
197 ImGui::SameLine();
198 ImGui::Dummy(ImVec2(ImGui::GetContentRegionAvail().x, 0.0F));
199
200 ImGui::TableNextColumn();
201 ImGui::SetNextItemWidth(COL1_WIDTH);
202 if (ImGui::InputTextL(fmt::format("##Marker Name {}", size_t(id)).c_str(), &_header.markerName, 60))
203 {
205 }
206 ImGui::TableNextColumn();
207 ImGui::TextUnformatted("Name");
208
209 ImGui::TableNextColumn();
210 ImGui::SetNextItemWidth(COL1_WIDTH);
211 if (ImGui::InputTextL(fmt::format("##Marker Number {}", size_t(id)).c_str(), &_header.markerNumber, 20))
212 {
214 }
215 ImGui::TableNextColumn();
216 ImGui::TextUnformatted("Number");
217
218 ImGui::EndTable();
219 }
220 }
221
222 if (ImGui::CollapsingHeader(fmt::format("Receiver##{}", size_t(id)).c_str(), ImGuiTreeNodeFlags_DefaultOpen))
223 {
224 if (ImGui::BeginTable(fmt::format("Table4##{}", size_t(id)).c_str(), 2, ImGuiTableFlags_SizingFixedFit))
225 {
226 ImGui::TableNextColumn();
227 ImGui::SetNextItemWidth(COL1_WIDTH);
228 if (ImGui::InputTextL(fmt::format("##Receiver Number {}", size_t(id)).c_str(), &_header.receiverNumber, 20))
229 {
231 }
232 ImGui::TableNextColumn();
233 ImGui::TextUnformatted("Number");
234
235 ImGui::TableNextColumn();
236 ImGui::SetNextItemWidth(COL1_WIDTH);
237 if (ImGui::InputTextL(fmt::format("##Receiver Type {}", size_t(id)).c_str(), &_header.receiverType, 20))
238 {
240 }
241 ImGui::TableNextColumn();
242 ImGui::TextUnformatted("Type");
243
244 ImGui::TableNextColumn();
245 ImGui::SetNextItemWidth(COL1_WIDTH);
246 if (ImGui::InputTextL(fmt::format("##Receiver Version {}", size_t(id)).c_str(), &_header.receiverVersion, 20))
247 {
249 }
250 ImGui::TableNextColumn();
251 ImGui::TextUnformatted("Version");
252
253 ImGui::EndTable();
254 }
255 }
256
257 if (ImGui::CollapsingHeader(fmt::format("Antenna##{}", size_t(id)).c_str(), ImGuiTreeNodeFlags_DefaultOpen))
258 {
259 if (ImGui::BeginTable(fmt::format("Table5##{}", size_t(id)).c_str(), 2, ImGuiTableFlags_SizingFixedFit))
260 {
261 ImGui::TableNextColumn();
262 ImGui::SetNextItemWidth(COL1_WIDTH);
263 if (ImGui::InputTextL(fmt::format("##Antenna Number {}", size_t(id)).c_str(), &_header.antennaNumber, 20))
264 {
266 }
267 ImGui::TableNextColumn();
268 ImGui::TextUnformatted("Number");
269
270 ImGui::TableNextColumn();
271 ImGui::SetNextItemWidth(COL1_WIDTH);
272 if (ImGui::InputTextL(fmt::format("##Antenna Type {}", size_t(id)).c_str(), &_header.antennaType, 20))
273 {
275 }
276 ImGui::TableNextColumn();
277 ImGui::TextUnformatted("Type");
278
279 ImGui::TableNextColumn();
280 float startPos = ImGui::GetCursorPosX();
281 if (ImGui::Checkbox(fmt::format("##ApproxEnabled {}", size_t(id)).c_str(), &_header.approxPositionEnabled))
282 {
284 }
285 ImGui::SameLine();
286 ImGui::SetNextItemWidth(COL1_WIDTH - (ImGui::GetCursorPosX() - startPos));
287 if (!_header.approxPositionEnabled) { ImGui::BeginDisabled(); }
288 if (ImGui::InputDouble3L(fmt::format("##Approx position XYZ {}", size_t(id)).c_str(), _header.approxPositionXYZ.data(), -99999999.9999, 99999999.9999, "%.4f m"))
289 {
291 }
292 if (!_header.approxPositionEnabled) { ImGui::EndDisabled(); }
293 ImGui::TableNextColumn();
294 ImGui::TextUnformatted("Approx position XYZ");
295 ImGui::SameLine();
296 gui::widgets::HelpMarker("Geocentric approximate marker position\n"
297 "System: ITRS recommended\n"
298 "Optional for moving platforms");
299
300 ImGui::TableNextColumn();
301 ImGui::SetNextItemWidth(COL1_WIDTH);
302 if (ImGui::InputDouble3L(fmt::format("##Antenna delta HEN {}", size_t(id)).c_str(), _header.antennaDeltaHeightEastNorth.data(), -99999999.9999, 99999999.9999, "%.4f m"))
303 {
305 }
306 ImGui::TableNextColumn();
307 ImGui::TextUnformatted("Delta HEN");
308
309 ImGui::EndTable();
310 }
311 }
312}
313
314[[nodiscard]] json NAV::RinexObsLogger::save() const
315{
316 LOG_TRACE("{}: called", nameId());
317
318 return {
319 { "dynamicInputPins", _dynamicInputPins },
320 { "FileWriter", FileWriter::save() },
321 { "HeaderInfo", _header },
322 };
323}
324
326{
327 LOG_TRACE("{}: called", nameId());
328
329 if (j.contains("dynamicInputPins")) { NAV::gui::widgets::from_json(j.at("dynamicInputPins"), _dynamicInputPins, this); }
330 if (j.contains("FileWriter")) { FileWriter::restore(j.at("FileWriter")); }
331 if (j.contains("HeaderInfo")) { j.at("HeaderInfo").get_to(_header); }
332}
333
335{
336 LOG_TRACE("{}: called", nameId());
337 _filestream.close();
338
339 LOG_DATA("{}: ", nameId());
340
341 auto fs = std::fstream(getFilepath(), std::ios::in | std::ios::out | std::ios::binary);
342 if (!fs.good()) { LOG_CRITICAL("{}: Could not open file: {}", nameId(), getFilepath()); }
343
344 while (!fs.eof())
345 {
346 std::string line;
347 auto pos = fs.tellg();
348 std::getline(fs, line);
349 LOG_DATA("{}: line: {}", nameId(), line);
350 if (line.find("RINEX VERSION / TYPE", 60) != std::string::npos)
351 {
352 fs.seekg(pos);
353 LOG_DATA("{}: new : {}", nameId(), _header.headerLineRinexVersionType());
354 fs << _header.headerLineRinexVersionType();
355 fs.flush();
356 }
357 else if (line.find("TIME OF LAST OBS", 60) != std::string::npos)
358 {
359 fs.seekg(pos);
360 LOG_DATA("{}: new : {}", nameId(), _header.headerLineTimeOfLastObs());
361 fs << _header.headerLineTimeOfLastObs();
362 fs.flush();
363 }
364 else if (line.find("INTERVAL", 60) != std::string::npos)
365 {
366 fs.seekg(pos);
367 LOG_DATA("{}: new : {}", nameId(), _header.headerLineInterval());
368 fs << _header.headerLineInterval();
369 fs.flush();
370 }
371 else if (line.find("# OF SATELLITES", 60) != std::string::npos)
372 {
373 fs.seekg(pos);
374 LOG_DATA("{}: new : {}", nameId(), _header.headerLineNumSatellites());
375 fs << _header.headerLineNumSatellites();
376 fs.flush();
377 }
378 else if (line[0] == '>') { break; }
379 }
380}
381
383{
384 LOG_TRACE("{}: called", nameId());
385
387 {
388 return false;
389 }
390
391 _header.reset();
392
393 _filestream << _header.generateHeader();
394 _filestream.flush();
395
396 return true;
397}
398
400{
401 LOG_TRACE("{}: called", nameId());
402
404}
405
410
412{
413 nm::DeleteInputPin(node->inputPins.at(pinIdx));
414}
415
417{
418 LOG_TRACE("{}: called", nameId());
419
420 _filestream.close();
421 _filestream.clear();
422
423 std::string pathTmp = getFilepath().string() + ".tmp";
424 {
425 auto fsTmp = std::ofstream(pathTmp, std::ios_base::trunc | std::ios_base::binary);
426 if (!fsTmp.good()) { LOG_CRITICAL("{}: Could not create temporary file: {}", nameId(), pathTmp); }
427
428 auto fsOld = std::ifstream(getFilepath(), std::ios_base::in);
429 if (!fsOld.good()) { LOG_CRITICAL("{}: Could not open old file: {}", nameId(), getFilepath()); }
430
431 fsTmp << _header.generateHeader();
432 LOG_DATA("{}: New Header\n{}", nameId(), _header.generateHeader());
433
434 bool dataRecords = false;
435 while (!fsOld.eof())
436 {
437 std::string line;
438 std::getline(fsOld, line);
439 LOG_DATA("{}: Line: {}", nameId(), line);
440 if (line[0] == '>')
441 {
442 dataRecords = true;
443 if (oldTimeSys == _header.timeSys)
444 {
445 LOG_DATA("{}: Read whole file", nameId());
446 fsTmp << line << '\n';
447 fsTmp << fsOld.rdbuf(); // Read whole data record at once
448 break;
449 }
450
451 LOG_DATA("{}: Read epoch [{}][{}][{}][{}][{}][{}] [{}]", nameId(), line.substr(2, 4), line.substr(7, 2), line.substr(10, 2),
452 line.substr(13, 2), line.substr(16, 2), line.substr(18, 11), line.substr(29 + 3, 3));
453 auto epochTime = InsTime{ static_cast<uint16_t>(std::stoi(line.substr(2, 4))), // year [1X,I4]
454 static_cast<uint16_t>(std::stoi(line.substr(7, 2))), // month [1X,I2.2]
455 static_cast<uint16_t>(std::stoi(line.substr(10, 2))), // day [1X,I2.2]
456 static_cast<uint16_t>(std::stoi(line.substr(13, 2))), // hour [1X,I2.2]
457 static_cast<uint16_t>(std::stoi(line.substr(16, 2))), // min [1X,I2.2]
458 std::stold(line.substr(18, 11)), // sec [F11.7,2X,I1,]
459 oldTimeSys };
460 fsTmp << _header.epochRecordLine(epochTime, std::stoul(line.substr(29 + 3, 3))); // Num satellites I3,6X,F15.12
461 }
462 else if (dataRecords)
463 {
464 fsTmp << line;
465 if (!line.empty()) { fsTmp << '\n'; }
466 }
467 }
468 }
469 std::filesystem::rename(pathTmp, getFilepath());
470
471 _filestream.open(getFilepath(), std::ios_base::app | std::ios_base::binary);
472 if (!_filestream.good()) { LOG_CRITICAL("{}: Could not open file: {}", nameId(), getFilepath()); }
473}
474
476{
477 auto obs = std::static_pointer_cast<const GnssObs>(queue.extract_front());
478 LOG_DATA("{}: [{}]", nameId(), obs->insTime.toYMDHMS(GPST));
479
480 _header.interval = std::min(_header.interval, std::round(static_cast<double>((obs->insTime - _header.timeLastObs).count()) * 1e3) / 1e3);
481 if (_header.timeFirstObs.empty()) { _header.timeFirstObs = obs->insTime; }
482 _header.timeLastObs = obs->insTime;
483
484 std::set<SatId> satellites;
485 bool satelliteSystemDescriptionChanged = false;
486 for (const auto& sig : obs->data)
487 {
488 auto satId = sig.satSigId.toSatId();
489 satellites.insert(satId);
490 _header.satellites.insert(satId);
491 _header.satSys |= satId.satSys;
492
493 if (sig.pseudorange) { satelliteSystemDescriptionChanged |= _header.addObsType(sig.satSigId.code, vendor::RINEX::ObsType::C); }
494 if (sig.carrierPhase) { satelliteSystemDescriptionChanged |= _header.addObsType(sig.satSigId.code, vendor::RINEX::ObsType::L); }
495 if (sig.doppler) { satelliteSystemDescriptionChanged |= _header.addObsType(sig.satSigId.code, vendor::RINEX::ObsType::D); }
496 if (sig.CN0) { satelliteSystemDescriptionChanged |= _header.addObsType(sig.satSigId.code, vendor::RINEX::ObsType::S); }
497 }
498 if (satelliteSystemDescriptionChanged)
499 {
500 TimeSystem oldTimeSys = _header.timeSys;
501 _header.timeSys = vendor::RINEX::timeSystem(_header.satSys);
502 updateFileHeader(oldTimeSys);
503 }
504
505 _filestream << _header.epochRecordLine(obs->insTime, satellites.size());
506
507 for (const auto& satId : satellites)
508 {
509 _filestream << fmt::format("{0}{1:02d}", satId.satSys.toChar(),
510 satId.satSys == SBAS && satId.satNum > 100 ? satId.satNum - 100 : satId.satNum);
511 const auto& obsDescriptions = _header.systemObsTypes.at(satId.satSys);
512 for (size_t i = 0; i < obsDescriptions.size(); i++)
513 {
514 const auto& obsDesc = obsDescriptions.at(i);
515
516 auto signal = std::ranges::find_if(obs->data, [&obsDesc, &satId](const auto& sig) {
517 return sig.satSigId == SatSigId{ obsDesc.code, satId.satNum };
518 });
519
520 bool obsWritten = false;
521 if (signal != obs->data.end())
522 {
523 switch (obsDesc.type)
524 {
526 if (signal->pseudorange && signal->pseudorange->value < 100'000'000.0)
527 {
528 _filestream << fmt::format("{obs:14.3f} {SSI}",
529 "obs"_a = signal->pseudorange->value,
530 "SSI"_a = signal->pseudorange->SSI == 0 ? " " : std::to_string(signal->pseudorange->SSI));
531 obsWritten = true;
532 }
533 break;
535 if (signal->carrierPhase && signal->carrierPhase->value < 1'000'000'000.0)
536 {
537 _filestream << fmt::format("{obs:14.3f}{LLI:1}{SSI:1}",
538 "obs"_a = signal->carrierPhase->value,
539 "LLI"_a = signal->carrierPhase->LLI == 0 ? " " : std::to_string(signal->carrierPhase->LLI),
540 "SSI"_a = signal->carrierPhase->SSI == 0 ? " " : std::to_string(signal->carrierPhase->SSI));
541 obsWritten = true;
542 }
543 break;
545 if (signal->doppler)
546 {
547 _filestream << fmt::format("{:14.3f} ", signal->doppler.value());
548 obsWritten = true;
549 }
550 break;
552 if (signal->CN0)
553 {
554 _filestream << fmt::format("{:14.3f} ", signal->CN0.value());
555 obsWritten = true;
556 }
557 break;
561 break;
562 }
563 }
564 if (!obsWritten)
565 {
566 _filestream << fmt::format("{X:16}", "X"_a = "");
567 }
568 if (i == obsDescriptions.size() - 1)
569 {
570 _filestream << "\n";
571 }
572 }
573 }
574}
Combo representing an enumeration with tooltip.
Save/Load the Nodes.
nlohmann::json json
json namespace
GNSS Observation messages.
Text Help Marker (?) with Tooltip.
Utility class for logging to console and file.
#define LOG_CRITICAL(...)
Critical Event, which causes the program to work entirely and throws an exception.
Definition Logger.hpp:75
#define LOG_DATA
All output which occurs repeatedly every time observations are received.
Definition Logger.hpp:29
#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.
File reader for RINEX Observation messages.
Logger for GnssObs to RINEX observation files.
GNSS Satellite System.
@ ASCII
Ascii text data.
FileType _fileType
File Type.
void deinitialize()
Deinitialize the file reader.
bool guiConfig(const char *vFilters, const std::vector< std::string > &extensions, size_t id, const std::string &nameId)
ImGui config.
std::filesystem::path getFilepath()
Returns the path of the file.
void restore(const json &j)
Restores the node from a json object.
json save() const
Saves the node into a json object.
bool initialize()
Initialize the file reader.
std::ofstream _filestream
File stream to write the file.
static std::string type()
Returns the type of the data class.
Definition GnssObs.hpp:150
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
bool doDeinitialize(bool wait=false)
Asks the node worker to deinitialize the node.
Definition Node.cpp:395
ImVec2 _guiConfigDefaultWindowSize
Definition Node.hpp:410
Node(std::string name)
Constructor.
Definition Node.cpp:30
std::vector< InputPin > inputPins
List of input pins.
Definition Node.hpp:397
std::string nameId() const
Node name and id.
Definition Node.cpp:253
std::string name
Name of the Node.
Definition Node.hpp:395
bool _hasConfig
Flag if the config window should be shown.
Definition Node.hpp:413
static void pinAddCallback(Node *node)
Function to call to add a new pin.
gui::widgets::DynamicInputPins _dynamicInputPins
Dynamic input pins.
vendor::RINEX::ObsHeader _header
Header information.
void deinitialize() override
Deinitialize the node.
void updateFileHeader(TimeSystem oldTimeSys)
Update the file header and eventually rewrite the file.
std::string type() const override
String representation of the Class Type.
void writeObservation(InputPin::NodeDataQueue &queue, size_t pinIdx)
Write Observation to the file.
bool initialize() override
Initialize the node.
void guiConfig() override
ImGui config window which is shown on double click.
void flush() override
Function called by the flow executer after finishing to flush out remaining data.
static std::string typeStatic()
String representation of the Class Type.
json save() const override
Saves the node into a json object.
static const std::set< double > _supportedVersions
Supported RINEX versions.
static std::string category()
String representation of the Class Category.
RinexObsLogger()
Default constructor.
static void pinDeleteCallback(Node *node, size_t pinIdx)
Function to call to delete a pin.
~RinexObsLogger() override
Destructor.
void restore(const json &j) override
Restores the node from a json object.
Time System defintions.
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 InputTextL(const char *label, std::string *str, size_t limit, ImGuiInputTextFlags flags)
Shows a InputText GUI element with limited amount of characters.
Definition imgui_ex.cpp:346
bool InputDouble3L(const char *label, double v[3], double v_min, double v_max, const char *format, ImGuiInputTextFlags flags)
Shows a value limited InputText GUI element for an array of 'double[3]'.
Definition imgui_ex.cpp:318
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 from_json(const json &j, DynamicInputPins &obj, Node *node)
Converts the provided json object into a node object.
bool EnumComboWithToolTip(const char *label, T &enumeration, size_t startIdx=0)
Combo representing an enumeration.
void HelpMarker(const char *desc, const char *symbol="(?)")
Text Help Marker, e.g. '(?)', with Tooltip.
@ X
Receiver channel numbers.
@ S
Raw signal strength(carrier to noise ratio)
@ I
Ionosphere phase delay.
TimeSystem timeSystem(SatelliteSystem satSys)
Converts the satellite system(s) to the time system.
@ GPST
GPS Time.
@ SBAS
Satellite Based Augmentation System.
@ Flow
NodeData Trigger.
Definition Pin.hpp:52
@ USER_DEFINED
Users may define other project-dependent keywords.