Files
OpenSpace/modules/spacecraftinstruments/util/labelparser.cpp
Alexander Bock 4952f8f977 Code cleanup branch (#618)
* Make height map fallback layer work again
  * Add documentation to joystick button bindings
  * Removed grouped property headers
  * Add new version number constant generated by CMake
  * Make Joystick deadzone work properly
  * Change the startup date on Earth to today
  * Fix key modifier handling
  * Add debugging indices for TreeNodeDebugging
  * Fix script schedule for OsirisRex
  * Do not open Mission schedule automatically
  * Upload default projection texture automatically

  * General code cleanup
  * Fix check_style_guide warnings
  * Remove .clang-format
  * MacOS compile fixes
  * Clang analyzer fixes
2018-06-10 04:47:34 +00:00

316 lines
13 KiB
C++

/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2018 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#include <modules/spacecraftinstruments/util/labelparser.h>
#include <openspace/util/spicemanager.h>
#include <ghoul/fmt.h>
#include <ghoul/filesystem/directory.h>
#include <ghoul/filesystem/file.h>
#include <ghoul/filesystem/filesystem.h>
#include <ghoul/io/texture/texturereader.h>
#include <ghoul/logging/logmanager.h>
#include <ghoul/misc/dictionary.h>
#include <fstream>
namespace {
constexpr const char* _loggerCat = "LabelParser";
constexpr const char* keySpecs = "Read";
constexpr const char* keyConvert = "Convert";
constexpr const char* PlaybookIdentifierName = "LabelParser";
} // namespace
namespace openspace {
LabelParser::LabelParser(std::string name, std::string fileName,
const ghoul::Dictionary& translationDictionary)
: _name(std::move(name))
, _fileName(std::move(fileName))
{
// get the different instrument types
const std::vector<std::string>& decoders = translationDictionary.keys();
// for each decoder (assuming might have more if hong makes changes)
for (const std::string& decoderStr : decoders) {
ghoul::Dictionary typeDictionary;
translationDictionary.getValue(decoderStr, typeDictionary);
//create dictionary containing all {playbookKeys , spice IDs}
if (decoderStr == "Instrument") {
// for each playbook call -> create a Decoder object
const std::vector<std::string>& keys = typeDictionary.keys();
for (const std::string& key : keys) {
std::string currentKey = decoderStr + "." + key;
ghoul::Dictionary decoderDictionary =
translationDictionary.value<ghoul::Dictionary>(currentKey);
std::unique_ptr<Decoder> decoder = Decoder::createFromDictionary(
decoderDictionary,
decoderStr
);
// insert decoder to map - this will be used in the parser to determine
// behavioral characteristics of each instrument
_fileTranslation[key] = std::move(decoder);
}
}
if (decoderStr == "Target") {
ghoul::Dictionary specsOfInterestDictionary;
typeDictionary.getValue(keySpecs, specsOfInterestDictionary);
_specsOfInterest.resize(specsOfInterestDictionary.size());
for (size_t n = 0; n < _specsOfInterest.size(); ++n) {
std::string readMe;
specsOfInterestDictionary.getValue(std::to_string(n + 1), readMe);
_specsOfInterest[n] = readMe;
}
ghoul::Dictionary convertDictionary;
typeDictionary.getValue(keyConvert, convertDictionary);
const std::vector<std::string>& keys = convertDictionary.keys();
for (const std::string& key : keys) {
ghoul::Dictionary itemDictionary;
convertDictionary.getValue(key, itemDictionary);
std::unique_ptr<Decoder> decoder = Decoder::createFromDictionary(
itemDictionary,
decoderStr
);
// insert decoder to map - this will be used in the parser to determine
// behavioral characteristics of each instrument
_fileTranslation[key] = std::move(decoder);
};
}
}
}
std::string LabelParser::decode(const std::string& line) {
for (std::pair<const std::string, std::unique_ptr<Decoder>>& key : _fileTranslation) {
std::size_t value = line.find(key.first);
if (value != std::string::npos) {
std::string toTranslate = line.substr(value);
return _fileTranslation[toTranslate]->translations()[0];
}
}
return "";
}
std::string LabelParser::encode(const std::string& line) const {
using K = std::string;
using V = std::unique_ptr<Decoder>;
for (const std::pair<const K, V>& key : _fileTranslation) {
std::size_t value = line.find(key.first);
if (value != std::string::npos) {
return line.substr(value);
}
}
return "";
}
bool LabelParser::create() {
using RawPath = ghoul::filesystem::Directory::RawPath;
ghoul::filesystem::Directory sequenceDir(_fileName, RawPath::Yes);
if (!FileSys.directoryExists(sequenceDir)) {
LERROR(fmt::format("Could not load Label Directory '{}'", sequenceDir.path()));
return false;
}
std::string previousTarget;
std::string lblName;
using Recursive = ghoul::filesystem::Directory::Recursive;
using Sort = ghoul::filesystem::Directory::Sort;
std::vector<std::string> sequencePaths = sequenceDir.read(Recursive::Yes, Sort::No);
for (std::string path : sequencePaths) {
size_t position = path.find_last_of('.') + 1;
if (position == 0 || position == std::string::npos) {
continue;
}
ghoul::filesystem::File currentFile(path);
const std::string& extension = currentFile.fileExtension();
if (extension != "lbl" && extension != "LBL") {
continue;
}
std::ifstream file(currentFile.path());
if (!file.good()) {
LERROR(fmt::format("Failed to open label file '{}'", currentFile.path()));
return false;
}
int count = 0;
// open up label files
//TimeRange instrumentRange;
double startTime = 0.0;
double stopTime = 0.0;
std::string line;
do {
std::getline(file, line);
line.erase(std::remove(line.begin(), line.end(), '"'), line.end());
line.erase(std::remove(line.begin(), line.end(), ' '), line.end());
line.erase(std::remove(line.begin(), line.end(), '\r'), line.end() );
std::string read = line.substr(0, line.find_first_of('='));
_detectorType = "CAMERA"; //default value
/* Add more */
if (read == "TARGET_NAME") {
_target = decode(line);
count++;
}
if (read == "INSTRUMENT_HOST_NAME") {
_instrumentHostID = decode(line);
count++;
}
if (read == "INSTRUMENT_ID") {
_instrumentID = decode(line);
lblName = encode(line);
count++;
}
if (read == "DETECTOR_TYPE") {
_detectorType = decode(line);
count++;
}
if (read == "START_TIME") {
std::string start = line.substr(line.find('=') + 1);
start.erase(std::remove(start.begin(), start.end(), ' '), start.end());
startTime = SpiceManager::ref().ephemerisTimeFromDate(start);
count++;
getline(file, line);
line.erase(std::remove(line.begin(), line.end(), '"'), line.end());
line.erase(std::remove(line.begin(), line.end(), ' '), line.end());
line.erase(std::remove(line.begin(), line.end(), '\r'), line.end());
read = line.substr(0, line.find_first_of('='));
if (read == "STOP_TIME"){
std::string stop = line.substr(line.find('=') + 1);
stop.erase(
std::remove_if(
stop.begin(),
stop.end(),
[](char c) { return c == ' ' || c == '\r'; }
),
stop.end()
);
stopTime = SpiceManager::ref().ephemerisTimeFromDate(stop);
count++;
}
else{
LERROR(fmt::format(
"Label file {} deviates from generic standard", currentFile.path()
));
LINFO(
"Please make sure input data adheres to format from \
https://pds.jpl.nasa.gov/documents/qs/labels.html"
);
}
}
if (count == static_cast<int>(_specsOfInterest.size())) {
const std::vector<std::string> extensions =
ghoul::io::TextureReader::ref().supportedExtensions();
count = 0;
using namespace std::literals;
std::string p = path.substr(0, path.size() - ("lbl"s).size());
for (const std::string& ext : extensions) {
path = p + ext;
if (FileSys.fileExists(path)) {
std::vector<std::string> spiceInstrument;
spiceInstrument.push_back(_instrumentID);
Image image = {
TimeRange(startTime, stopTime),
path,
spiceInstrument,
_target,
false,
false
};
_subsetMap[image.target]._subset.push_back(image);
_subsetMap[image.target]._range.include(startTime);
_captureProgression.push_back(startTime);
std::stable_sort(
_captureProgression.begin(),
_captureProgression.end()
);
break;
}
}
}
} while (!file.eof());
}
std::vector<Image> tmp;
for (const std::pair<const std::string, ImageSubset>& key : _subsetMap) {
for (const Image& image : key.second._subset) {
tmp.push_back(image);
}
}
std::sort(
tmp.begin(),
tmp.end(),
[](const Image& a, const Image& b) -> bool {
return a.timeRange.start < b.timeRange.start;
}
);
for (const Image& image : tmp) {
if (previousTarget != image.target) {
previousTarget = image.target;
_targetTimes.emplace_back(image.timeRange.start , image.target);
std::sort(
_targetTimes.begin(),
_targetTimes.end(),
[](const std::pair<double, std::string> &a,
const std::pair<double, std::string> &b) -> bool
{
return a.first < b.first;
}
);
}
}
for (const std::pair<const std::string, ImageSubset>& target : _subsetMap) {
_instrumentTimes.emplace_back(lblName, _subsetMap[target.first]._range);
}
sendPlaybookInformation(PlaybookIdentifierName);
return true;
}
} // namespace openspace