/***************************************************************************************** * * * 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 #include #include #include #include #include #include #include #include #include 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& 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& keys = typeDictionary.keys(); for (const std::string& key : keys) { std::string currentKey = decoderStr + "." + key; ghoul::Dictionary decoderDictionary = translationDictionary.value(currentKey); std::unique_ptr 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& keys = convertDictionary.keys(); for (const std::string& key : keys) { ghoul::Dictionary itemDictionary; convertDictionary.getValue(key, itemDictionary); std::unique_ptr 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>& 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; for (const std::pair& 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 sequencePaths = sequenceDir.read(Recursive::Yes, Sort::No); for (const 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 constexpr const char* ErrorMsg = "Unrecognized '{}' in line {} in file {}. The 'Convert' table must " "contain the identity tranformation for all values encountered in the " "label files, for example: ROSETTA = {{ \"ROSETTA\" }}"; /* Add more */ if (read == "TARGET_NAME") { _target = decode(line); if (_target.empty()) { LWARNING(fmt::format(ErrorMsg, "TARGET_NAME", line, path)); } count++; } if (read == "INSTRUMENT_HOST_NAME") { _instrumentHostID = decode(line); if (_instrumentHostID.empty()) { LWARNING(fmt::format(ErrorMsg, "INSTRUMENT_HOST_NAME", line, path)); } count++; } if (read == "INSTRUMENT_ID") { _instrumentID = decode(line); if (_instrumentID.empty()) { LWARNING(fmt::format(ErrorMsg, "INSTRUMENT_ID", line, path)); } lblName = encode(line); count++; } if (read == "DETECTOR_TYPE") { _detectorType = decode(line); if (_detectorType.empty()) { LWARNING(fmt::format(ErrorMsg, "DETECTOR_TYPE", line, path)); } 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(_specsOfInterest.size())) { const std::vector 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) { std::string imagePath = p + ext; if (FileSys.fileExists(imagePath)) { std::vector spiceInstrument; spiceInstrument.push_back(_instrumentID); Image image = { TimeRange(startTime, stopTime), imagePath, 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 tmp; for (const std::pair& 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 &a, const std::pair &b) -> bool { return a.first < b.first; } ); } } for (const std::pair& target : _subsetMap) { _instrumentTimes.emplace_back(lblName, _subsetMap[target.first]._range); } sendPlaybookInformation(PlaybookIdentifierName); return true; } } // namespace openspace