0.5.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
20
23
25
27
28#include "util/Logger.hpp"
29
31 : Node(typeStatic())
32{
33 LOG_TRACE("{}: called", name);
34
36
37 _hasConfig = true;
38 _guiConfigDefaultWindowSize = { 643, 728 };
39
40 _dynamicInputPins.addPin(this);
41}
42
47
49{
50 return "RinexObsLogger";
51}
52
53std::string NAV::RinexObsLogger::type() const
54{
55 return typeStatic();
56}
57
59{
60 return "Data Logger";
61}
62
64{
65 if (_dynamicInputPins.ShowGuiWidgets(size_t(id), inputPins, this, {}))
66 {
68 }
69
70 constexpr float COL1_WIDTH = 470.0F;
71
72 const auto now = std::chrono::system_clock::now();
73 ImGui::SetNextItemWidth(COL1_WIDTH);
74 if (FileWriter::guiConfig(fmt::format(".obs,.rnx,.{:%y}O", now).c_str(), { ".obs", ".rnx", fmt::format(".{:%y}O", now) }, size_t(id), nameId()))
75 {
78 }
79
80 if (ImGui::CollapsingHeader(fmt::format("General##{}", size_t(id)).c_str(), ImGuiTreeNodeFlags_DefaultOpen))
81 {
82 if (ImGui::BeginTable(fmt::format("Table1##{}", size_t(id)).c_str(), 2, ImGuiTableFlags_SizingFixedFit))
83 {
84 ImGui::TableNextColumn();
85 ImGui::BeginDisabled();
86 ImGui::SetNextItemWidth(COL1_WIDTH);
87 if (ImGui::BeginCombo(fmt::format("##Version {}", size_t(id)).c_str(), fmt::format("{}", _header.version).c_str()))
88 {
89 for (const auto& version : _supportedVersions)
90 {
91 const bool is_selected = _header.version == version;
92 if (ImGui::Selectable(fmt::format("{}##Version {}", version, size_t(id)).c_str(), is_selected))
93 {
94 _header.version = version;
96 }
97 if (is_selected) { ImGui::SetItemDefaultFocus(); }
98 }
99 ImGui::EndCombo();
100 }
101 ImGui::EndDisabled();
102 ImGui::TableNextColumn();
103 ImGui::TextUnformatted("Version");
104
105 ImGui::TableNextColumn();
106 ImGui::SetNextItemWidth(COL1_WIDTH);
107 if (ImGui::InputTextL(fmt::format("##Run By {}", size_t(id)).c_str(), &_header.runBy, 20))
108 {
110 }
111 ImGui::TableNextColumn();
112 ImGui::TextUnformatted("Run By");
113
114 ImGui::TableNextColumn();
115 ImGui::SetNextItemWidth(COL1_WIDTH);
116 if (ImGui::InputTextL(fmt::format("##Observer {}", size_t(id)).c_str(), &_header.observer, 20))
117 {
119 }
120 ImGui::TableNextColumn();
121 ImGui::TextUnformatted("Observer");
122
123 ImGui::TableNextColumn();
124 ImGui::SetNextItemWidth(COL1_WIDTH);
125 if (ImGui::InputTextL(fmt::format("##Agency {}", size_t(id)).c_str(), &_header.agency, 40))
126 {
128 }
129 ImGui::TableNextColumn();
130 ImGui::TextUnformatted("Agency");
131
132 ImGui::EndTable();
133 }
134 }
135
136 if (ImGui::CollapsingHeader(fmt::format("Comments##{}", size_t(id)).c_str(), ImGuiTreeNodeFlags_DefaultOpen))
137 {
138 std::vector<size_t> commentsToRemove;
139 if (ImGui::BeginTable(fmt::format("Table2##{}", size_t(id)).c_str(), 2, ImGuiTableFlags_SizingFixedFit))
140 {
141 for (size_t i = 0; i < _header.comments.size(); i++)
142 {
143 ImGui::TableNextRow();
144 ImGui::TableNextColumn();
145 auto& comment = _header.comments.at(i);
146 float startPos = ImGui::GetCursorPosX();
147 if (ImGui::Button(fmt::format("X##Remove comment {} {}", i, size_t(id)).c_str()))
148 {
149 commentsToRemove.push_back(i);
150 }
151 ImGui::SameLine();
152 ImGui::SetNextItemWidth(COL1_WIDTH - (ImGui::GetCursorPosX() - startPos));
153 if (ImGui::InputTextL(fmt::format("##Comment {} {}", i, size_t(id)).c_str(), &comment, 60))
154 {
156 }
157 }
158 ImGui::EndTable();
159 }
160 for (const size_t& idx : commentsToRemove)
161 {
162 _header.comments.erase(std::next(_header.comments.begin(), static_cast<int>(idx)));
164 }
165 if (ImGui::Button(fmt::format("Add##Comment {}", size_t(id)).c_str()))
166 {
167 _header.comments.emplace_back();
169 }
170 }
171
172 if (ImGui::CollapsingHeader(fmt::format("Marker##{}", size_t(id)).c_str(), ImGuiTreeNodeFlags_DefaultOpen))
173 {
174 if (ImGui::BeginTable(fmt::format("Table3##{}", size_t(id)).c_str(), 2, ImGuiTableFlags_SizingFixedFit))
175 {
176 ImGui::TableNextColumn();
177 ImGui::SetNextItemWidth(COL1_WIDTH);
178 if (gui::widgets::EnumComboWithToolTip(fmt::format("##Marker Type {}", size_t(id)).c_str(), _header.markerType))
179 {
181 }
182 if (_header.markerType != vendor::RINEX::ObsHeader::MarkerTypes::USER_DEFINED) { ImGui::BeginDisabled(); }
183 ImGui::TableNextColumn();
184 ImGui::TextUnformatted("Type");
185
186 ImGui::TableNextColumn();
187 ImGui::SetNextItemWidth(COL1_WIDTH);
188 if (ImGui::InputTextL(fmt::format("##Marker User Type {}", size_t(id)).c_str(), &_header.markerTypeUser, 20))
189 {
191 }
192 if (_header.markerType != vendor::RINEX::ObsHeader::MarkerTypes::USER_DEFINED) { ImGui::EndDisabled(); }
193 ImGui::TableNextColumn();
194 ImGui::TextUnformatted("User Type");
195 ImGui::SameLine();
196 ImGui::Dummy(ImVec2(ImGui::GetContentRegionAvail().x, 0.0F));
197
198 ImGui::TableNextColumn();
199 ImGui::SetNextItemWidth(COL1_WIDTH);
200 if (ImGui::InputTextL(fmt::format("##Marker Name {}", size_t(id)).c_str(), &_header.markerName, 60))
201 {
203 }
204 ImGui::TableNextColumn();
205 ImGui::TextUnformatted("Name");
206
207 ImGui::TableNextColumn();
208 ImGui::SetNextItemWidth(COL1_WIDTH);
209 if (ImGui::InputTextL(fmt::format("##Marker Number {}", size_t(id)).c_str(), &_header.markerNumber, 20))
210 {
212 }
213 ImGui::TableNextColumn();
214 ImGui::TextUnformatted("Number");
215
216 ImGui::EndTable();
217 }
218 }
219
220 if (ImGui::CollapsingHeader(fmt::format("Receiver##{}", size_t(id)).c_str(), ImGuiTreeNodeFlags_DefaultOpen))
221 {
222 if (ImGui::BeginTable(fmt::format("Table4##{}", size_t(id)).c_str(), 2, ImGuiTableFlags_SizingFixedFit))
223 {
224 ImGui::TableNextColumn();
225 ImGui::SetNextItemWidth(COL1_WIDTH);
226 if (ImGui::InputTextL(fmt::format("##Receiver Number {}", size_t(id)).c_str(), &_header.receiverNumber, 20))
227 {
229 }
230 ImGui::TableNextColumn();
231 ImGui::TextUnformatted("Number");
232
233 ImGui::TableNextColumn();
234 ImGui::SetNextItemWidth(COL1_WIDTH);
235 if (ImGui::InputTextL(fmt::format("##Receiver Type {}", size_t(id)).c_str(), &_header.receiverType, 20))
236 {
238 }
239 ImGui::TableNextColumn();
240 ImGui::TextUnformatted("Type");
241
242 ImGui::TableNextColumn();
243 ImGui::SetNextItemWidth(COL1_WIDTH);
244 if (ImGui::InputTextL(fmt::format("##Receiver Version {}", size_t(id)).c_str(), &_header.receiverVersion, 20))
245 {
247 }
248 ImGui::TableNextColumn();
249 ImGui::TextUnformatted("Version");
250
251 ImGui::EndTable();
252 }
253 }
254
255 if (ImGui::CollapsingHeader(fmt::format("Antenna##{}", size_t(id)).c_str(), ImGuiTreeNodeFlags_DefaultOpen))
256 {
257 if (ImGui::BeginTable(fmt::format("Table5##{}", size_t(id)).c_str(), 2, ImGuiTableFlags_SizingFixedFit))
258 {
259 ImGui::TableNextColumn();
260 ImGui::SetNextItemWidth(COL1_WIDTH);
261 if (ImGui::InputTextL(fmt::format("##Antenna Number {}", size_t(id)).c_str(), &_header.antennaNumber, 20))
262 {
264 }
265 ImGui::TableNextColumn();
266 ImGui::TextUnformatted("Number");
267
268 ImGui::TableNextColumn();
269 ImGui::SetNextItemWidth(COL1_WIDTH);
270 if (ImGui::InputTextL(fmt::format("##Antenna Type {}", size_t(id)).c_str(), &_header.antennaType, 20))
271 {
273 }
274 ImGui::TableNextColumn();
275 ImGui::TextUnformatted("Type");
276
277 ImGui::TableNextColumn();
278 float startPos = ImGui::GetCursorPosX();
279 if (ImGui::Checkbox(fmt::format("##ApproxEnabled {}", size_t(id)).c_str(), &_header.approxPositionEnabled))
280 {
282 }
283 ImGui::SameLine();
284 ImGui::SetNextItemWidth(COL1_WIDTH - (ImGui::GetCursorPosX() - startPos));
285 if (!_header.approxPositionEnabled) { ImGui::BeginDisabled(); }
286 if (ImGui::InputDouble3L(fmt::format("##Approx position XYZ {}", size_t(id)).c_str(), _header.approxPositionXYZ.data(), -99999999.9999, 99999999.9999, "%.4f m"))
287 {
289 }
290 if (!_header.approxPositionEnabled) { ImGui::EndDisabled(); }
291 ImGui::TableNextColumn();
292 ImGui::TextUnformatted("Approx position XYZ");
293 ImGui::SameLine();
294 gui::widgets::HelpMarker("Geocentric approximate marker position\n"
295 "System: ITRS recommended\n"
296 "Optional for moving platforms");
297
298 ImGui::TableNextColumn();
299 ImGui::SetNextItemWidth(COL1_WIDTH);
300 if (ImGui::InputDouble3L(fmt::format("##Antenna delta HEN {}", size_t(id)).c_str(), _header.antennaDeltaHeightEastNorth.data(), -99999999.9999, 99999999.9999, "%.4f m"))
301 {
303 }
304 ImGui::TableNextColumn();
305 ImGui::TextUnformatted("Delta HEN");
306
307 ImGui::EndTable();
308 }
309 }
310}
311
312[[nodiscard]] json NAV::RinexObsLogger::save() const
313{
314 LOG_TRACE("{}: called", nameId());
315
316 return {
317 { "dynamicInputPins", _dynamicInputPins },
318 { "FileWriter", FileWriter::save() },
319 { "HeaderInfo", _header },
320 };
321}
322
324{
325 LOG_TRACE("{}: called", nameId());
326
327 if (j.contains("dynamicInputPins")) { NAV::gui::widgets::from_json(j.at("dynamicInputPins"), _dynamicInputPins, this); }
328 if (j.contains("FileWriter")) { FileWriter::restore(j.at("FileWriter")); }
329 if (j.contains("HeaderInfo")) { j.at("HeaderInfo").get_to(_header); }
330}
331
333{
334 LOG_TRACE("{}: called", nameId());
335 _filestream.close();
336
337 LOG_DATA("{}: ", nameId());
338
339 auto fs = std::fstream(getFilepath(), std::ios::in | std::ios::out | std::ios::binary);
340 if (!fs.good()) { LOG_CRITICAL("{}: Could not open file: {}", nameId(), getFilepath()); }
341
342 while (!fs.eof())
343 {
344 std::string line;
345 auto pos = fs.tellg();
346 std::getline(fs, line);
347 LOG_DATA("{}: line: {}", nameId(), line);
348 if (line.find("RINEX VERSION / TYPE", 60) != std::string::npos)
349 {
350 fs.seekg(pos);
351 LOG_DATA("{}: new : {}", nameId(), _header.headerLineRinexVersionType());
352 fs << _header.headerLineRinexVersionType();
353 fs.flush();
354 }
355 else if (line.find("TIME OF LAST OBS", 60) != std::string::npos)
356 {
357 fs.seekg(pos);
358 LOG_DATA("{}: new : {}", nameId(), _header.headerLineTimeOfLastObs());
359 fs << _header.headerLineTimeOfLastObs();
360 fs.flush();
361 }
362 else if (line.find("INTERVAL", 60) != std::string::npos)
363 {
364 fs.seekg(pos);
365 LOG_DATA("{}: new : {}", nameId(), _header.headerLineInterval());
366 fs << _header.headerLineInterval();
367 fs.flush();
368 }
369 else if (line.find("# OF SATELLITES", 60) != std::string::npos)
370 {
371 fs.seekg(pos);
372 LOG_DATA("{}: new : {}", nameId(), _header.headerLineNumSatellites());
373 fs << _header.headerLineNumSatellites();
374 fs.flush();
375 }
376 else if (line[0] == '>') { break; }
377 }
378}
379
381{
382 LOG_TRACE("{}: called", nameId());
383
385 {
386 return false;
387 }
388
389 _header.reset();
390
391 _filestream << _header.generateHeader();
392 _filestream.flush();
393
394 return true;
395}
396
398{
399 LOG_TRACE("{}: called", nameId());
400
402}
403
408
410{
411 node->DeleteInputPin(pinIdx);
412}
413
415{
416 LOG_TRACE("{}: called", nameId());
417
418 _filestream.close();
419 _filestream.clear();
420
421 std::string pathTmp = getFilepath().string() + ".tmp";
422 {
423 auto fsTmp = std::ofstream(pathTmp, std::ios_base::trunc | std::ios_base::binary);
424 if (!fsTmp.good()) { LOG_CRITICAL("{}: Could not create temporary file: {}", nameId(), pathTmp); }
425
426 auto fsOld = std::ifstream(getFilepath(), std::ios_base::in);
427 if (!fsOld.good()) { LOG_CRITICAL("{}: Could not open old file: {}", nameId(), getFilepath()); }
428
429 fsTmp << _header.generateHeader();
430 LOG_DATA("{}: New Header\n{}", nameId(), _header.generateHeader());
431
432 bool dataRecords = false;
433 while (!fsOld.eof())
434 {
435 std::string line;
436 std::getline(fsOld, line);
437 LOG_DATA("{}: Line: {}", nameId(), line);
438 if (line[0] == '>')
439 {
440 dataRecords = true;
441 if (oldTimeSys == _header.timeSys)
442 {
443 LOG_DATA("{}: Read whole file", nameId());
444 fsTmp << line << '\n';
445 fsTmp << fsOld.rdbuf(); // Read whole data record at once
446 break;
447 }
448
449 LOG_DATA("{}: Read epoch [{}][{}][{}][{}][{}][{}] [{}]", nameId(), line.substr(2, 4), line.substr(7, 2), line.substr(10, 2),
450 line.substr(13, 2), line.substr(16, 2), line.substr(18, 11), line.substr(29 + 3, 3));
451 auto epochTime = InsTime{ static_cast<uint16_t>(std::stoi(line.substr(2, 4))), // year [1X,I4]
452 static_cast<uint16_t>(std::stoi(line.substr(7, 2))), // month [1X,I2.2]
453 static_cast<uint16_t>(std::stoi(line.substr(10, 2))), // day [1X,I2.2]
454 static_cast<uint16_t>(std::stoi(line.substr(13, 2))), // hour [1X,I2.2]
455 static_cast<uint16_t>(std::stoi(line.substr(16, 2))), // min [1X,I2.2]
456 std::stold(line.substr(18, 11)), // sec [F11.7,2X,I1,]
457 oldTimeSys };
458 fsTmp << _header.epochRecordLine(epochTime, std::stoul(line.substr(29 + 3, 3))); // Num satellites I3,6X,F15.12
459 }
460 else if (dataRecords)
461 {
462 fsTmp << line;
463 if (!line.empty()) { fsTmp << '\n'; }
464 }
465 }
466 }
467 std::filesystem::rename(pathTmp, getFilepath());
468
469 _filestream.open(getFilepath(), std::ios_base::app | std::ios_base::binary);
470 if (!_filestream.good()) { LOG_CRITICAL("{}: Could not open file: {}", nameId(), getFilepath()); }
471}
472
474{
475 auto obs = std::static_pointer_cast<const GnssObs>(queue.extract_front());
476 LOG_DATA("{}: [{}]", nameId(), obs->insTime.toYMDHMS(GPST));
477
478 _header.interval = std::min(_header.interval, std::round(static_cast<double>((obs->insTime - _header.timeLastObs).count()) * 1e3) / 1e3);
479 if (_header.timeFirstObs.empty()) { _header.timeFirstObs = obs->insTime; }
480 _header.timeLastObs = obs->insTime;
481
482 std::set<SatId> satellites;
483 bool satelliteSystemDescriptionChanged = false;
484 for (const auto& sig : obs->data)
485 {
486 auto satId = sig.satSigId.toSatId();
487 satellites.insert(satId);
488 _header.satellites.insert(satId);
489 _header.satSys |= satId.satSys;
490
491 if (sig.pseudorange) { satelliteSystemDescriptionChanged |= _header.addObsType(sig.satSigId.code, vendor::RINEX::ObsType::C); }
492 if (sig.carrierPhase) { satelliteSystemDescriptionChanged |= _header.addObsType(sig.satSigId.code, vendor::RINEX::ObsType::L); }
493 if (sig.doppler) { satelliteSystemDescriptionChanged |= _header.addObsType(sig.satSigId.code, vendor::RINEX::ObsType::D); }
494 if (sig.CN0) { satelliteSystemDescriptionChanged |= _header.addObsType(sig.satSigId.code, vendor::RINEX::ObsType::S); }
495 }
496 if (satelliteSystemDescriptionChanged)
497 {
498 TimeSystem oldTimeSys = _header.timeSys;
499 _header.timeSys = vendor::RINEX::timeSystem(_header.satSys);
500 updateFileHeader(oldTimeSys);
501 }
502
503 _filestream << _header.epochRecordLine(obs->insTime, satellites.size());
504
505 for (const auto& satId : satellites)
506 {
507 _filestream << fmt::format("{0}{1:02d}", satId.satSys.toChar(),
508 satId.satSys == SBAS && satId.satNum > 100 ? satId.satNum - 100 : satId.satNum);
509 const auto& obsDescriptions = _header.systemObsTypes.at(satId.satSys);
510 for (size_t i = 0; i < obsDescriptions.size(); i++)
511 {
512 const auto& obsDesc = obsDescriptions.at(i);
513
514 auto signal = std::ranges::find_if(obs->data, [&obsDesc, &satId](const auto& sig) {
515 return sig.satSigId == SatSigId{ obsDesc.code, satId.satNum };
516 });
517
518 bool obsWritten = false;
519 if (signal != obs->data.end())
520 {
521 switch (obsDesc.type)
522 {
524 if (signal->pseudorange && signal->pseudorange->value < 100'000'000.0)
525 {
526 _filestream << fmt::format("{obs:14.3f} {SSI}",
527 "obs"_a = signal->pseudorange->value,
528 "SSI"_a = signal->pseudorange->SSI == 0 ? " " : std::to_string(signal->pseudorange->SSI));
529 obsWritten = true;
530 }
531 break;
533 if (signal->carrierPhase && signal->carrierPhase->value < 1'000'000'000.0)
534 {
535 _filestream << fmt::format("{obs:14.3f}{LLI:1}{SSI:1}",
536 "obs"_a = signal->carrierPhase->value,
537 "LLI"_a = signal->carrierPhase->LLI == 0 ? " " : std::to_string(signal->carrierPhase->LLI),
538 "SSI"_a = signal->carrierPhase->SSI == 0 ? " " : std::to_string(signal->carrierPhase->SSI));
539 obsWritten = true;
540 }
541 break;
543 if (signal->doppler)
544 {
545 _filestream << fmt::format("{:14.3f} ", signal->doppler.value());
546 obsWritten = true;
547 }
548 break;
550 if (signal->CN0)
551 {
552 _filestream << fmt::format("{:14.3f} ", signal->CN0.value());
553 obsWritten = true;
554 }
555 break;
559 break;
560 }
561 }
562 if (!obsWritten)
563 {
564 _filestream << fmt::format("{X:16}", "X"_a = "");
565 }
566 if (i == obsDescriptions.size() - 1)
567 {
568 _filestream << "\n";
569 }
570 }
571 }
572}
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
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:151
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:465
ImVec2 _guiConfigDefaultWindowSize
Definition Node.hpp:522
Node(std::string name)
Constructor.
Definition Node.cpp:29
std::vector< InputPin > inputPins
List of input pins.
Definition Node.hpp:509
std::string nameId() const
Node name and id.
Definition Node.cpp:323
std::string name
Name of the Node.
Definition Node.hpp:507
InputPin * CreateInputPin(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.
Definition Node.cpp:252
bool DeleteInputPin(size_t pinIndex)
Deletes the input pin. Invalidates the pin reference given.
Definition Node.cpp:310
bool _hasConfig
Flag if the config window should be shown.
Definition Node.hpp:525
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
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.