Improve parsing of matching targets and observers

This commit is contained in:
Malin E
2022-02-10 13:05:26 +01:00
parent 8b81b9ef7c
commit d00a2bc187
2 changed files with 94 additions and 57 deletions

View File

@@ -106,7 +106,7 @@ namespace {
result = result.erase(start, step);
// Add one whitespace for readability
result = result.insert(start, " ");
result = result.insert(start, " | ");
step = 1;
offset = start;
@@ -120,53 +120,59 @@ namespace {
return result;
}
std::map<int, std::string> parseBodies(std::filesystem::path& file) {
std::vector<std::string> parseMatches(std::filesystem::path& file,
std::string startPhrase, std::string endPhrase)
{
std::ifstream fileStream(file);
std::string startPhrase = "Name";
std::string endPhrase = "matches";
std::vector<std::string> matches;
if (!fileStream.good()) {
fileStream.close();
return std::map<int, std::string>();
return matches;
}
// The beginning of a Horizons file has a header with a lot of information about the
// query that we do not care about. Ignore everything until head of matching body list
std::map<int, std::string> matchingBodies;
// Ignore everything until start of matches
std::string line;
while (fileStream.good() && line.find(startPhrase) == std::string::npos) {
while (fileStream.good()) {
// Add the line with the start phrase first, to give context
if (line.find(startPhrase) != std::string::npos) {
matches.push_back(trim(line));
break;
}
std::getline(fileStream, line);
}
if (!fileStream.good()) {
fileStream.close();
return std::map<int, std::string>();
return std::vector<std::string>();
}
// There will be one empty line before the list of matching bodies, skip
// There will be one empty line before the list of matches, skip
std::getline(fileStream, line);
std::getline(fileStream, line);
while (fileStream.good()) {
// End of matches or file
if (line == " " || line.empty() || line.find(endPhrase) != std::string::npos) {
fileStream.close();
return matchingBodies;
return matches;
}
std::cout << "Matching body: " << line << std::endl;
// Matching body format: id, other information...
std::stringstream str(line);
int id;
std::string info;
str >> id;
std::getline(str, info);
matchingBodies.insert(std::pair<int, std::string>(id, trim(info)));
matches.push_back(trim(line));
std::getline(fileStream, line);
}
fileStream.close();
return std::map<int, std::string>();
return std::vector<std::string>();
}
int findId(const std::string& match) {
// Format: id, other information...
std::stringstream str(match);
int id;
str >> id;
return id;
}
std::pair<std::string, std::string> parseValidTimeRange(std::filesystem::path& file) {
@@ -572,7 +578,7 @@ std::string HorizonsDialog::constructUrl() {
if (_chooseTargetCombo->count() > 0 && _chooseTargetCombo->currentIndex() != 0) {
command = _chooseTargetCombo->itemData(_chooseTargetCombo->currentIndex()).toString().toStdString();
_targetName = _chooseTargetCombo->currentText().toStdString();
_targetEdit->setText(_targetName.c_str());
_targetEdit->setText(command.c_str());
}
else {
command = _targetEdit->text().toStdString();
@@ -585,10 +591,12 @@ std::string HorizonsDialog::constructUrl() {
std::string center;
if (_chooseObserverCombo->count() > 0 && _chooseObserverCombo->currentIndex() != 0) {
center = "@" +
_chooseObserverCombo->itemData(_chooseObserverCombo->currentIndex()).toString().toStdString();
std::string id =_chooseObserverCombo->itemData(
_chooseObserverCombo->currentIndex()
).toString().toStdString();
center = "@" + id;
_observerName = _chooseObserverCombo->currentText().toStdString();
_centerEdit->setText(_observerName.c_str());
_centerEdit->setText(id.c_str());
}
else {
center = _centerEdit->text().toStdString();
@@ -751,7 +759,11 @@ bool HorizonsDialog::checkHttpStatus(const QVariant& statusCode) {
std::filesystem::path HorizonsDialog::handleAnswer(json& answer) {
openspace::HorizonsFile::HorizonsResult isValid = openspace::HorizonsFile::isValidAnswer(answer);
if (isValid != openspace::HorizonsFile::HorizonsResult::Valid) {
if (isValid != openspace::HorizonsFile::HorizonsResult::Valid &&
isValid != openspace::HorizonsFile::HorizonsResult::MultipleObserverStations)
{
// Special case with MultipleObserverStations since it is detected as an error
// but could be fixed by parsing the matches and let user choose
handleResult(isValid);
return std::filesystem::path();
}
@@ -864,15 +876,34 @@ bool HorizonsDialog::handleResult(openspace::HorizonsFile::HorizonsResult& resul
);
break;
case openspace::HorizonsFile::HorizonsResult::MultipleObserverStations:
appendLog("Multiple observer stations was found for observer '" +
case openspace::HorizonsFile::HorizonsResult::MultipleObserverStations: {
appendLog("Multiple matching observer stations were found for observer '" +
_observerName + "'. ", HorizonsDialog::LogLevel::Warning
);
appendLog("Did not find what you were looking for? Use '@" + _observerName +
"' as observer to search for alternatives.",
HorizonsDialog::LogLevel::Info
);
std::vector<std::string> matchingstations =
parseMatches(_horizonsFile, "Observatory Name", "Multiple matching stations found");
if (matchingstations.empty()) {
appendLog("Could not parse the matching stations",
HorizonsDialog::LogLevel::Error
);
break;
}
_chooseObserverCombo->clear();
for (std::string station : matchingstations) {
_chooseObserverCombo->addItem(
station.c_str(),
findId(station)
);
}
_chooseObserverCombo->setCurrentIndex(0);
_chooseObserverCombo->show();
break;
}
case openspace::HorizonsFile::HorizonsResult::MultipleObserver: {
appendLog("Multiple matches were found for observer '" +
@@ -880,8 +911,8 @@ bool HorizonsDialog::handleResult(openspace::HorizonsFile::HorizonsResult& resul
HorizonsDialog::LogLevel::Warning
);
std::map<int, std::string> matchingObservers =
parseBodies(_horizonsFile);
std::vector<std::string> matchingObservers =
parseMatches(_horizonsFile, "Name", "matches");
if (matchingObservers.empty()) {
appendLog("Could not parse the matching observers",
HorizonsDialog::LogLevel::Error
@@ -889,11 +920,10 @@ bool HorizonsDialog::handleResult(openspace::HorizonsFile::HorizonsResult& resul
break;
}
_chooseObserverCombo->clear();
_chooseObserverCombo->addItem("Choose Observer");
for (std::pair matchingObserver : matchingObservers) {
for (std::string observer : matchingObservers) {
_chooseObserverCombo->addItem(
matchingObserver.second.c_str(),
matchingObserver.first
observer.c_str(),
findId(observer)
);
}
_chooseObserverCombo->setCurrentIndex(0);
@@ -922,8 +952,8 @@ bool HorizonsDialog::handleResult(openspace::HorizonsFile::HorizonsResult& resul
HorizonsDialog::LogLevel::Warning
);
std::map<int, std::string> matchingTargets =
parseBodies(_horizonsFile);
std::vector<std::string> matchingTargets =
parseMatches(_horizonsFile, "Name", "matches");
if (matchingTargets.empty()) {
appendLog("Could not parse the matching targets",
HorizonsDialog::LogLevel::Error
@@ -931,11 +961,10 @@ bool HorizonsDialog::handleResult(openspace::HorizonsFile::HorizonsResult& resul
break;
}
_chooseTargetCombo->clear();
_chooseTargetCombo->addItem("Choose Target");
for (std::pair matchingTarget : matchingTargets) {
for (std::string target : matchingTargets) {
_chooseTargetCombo->addItem(
matchingTarget.second.c_str(),
matchingTarget.first
target.c_str(),
findId(target)
);
}
_chooseTargetCombo->setCurrentIndex(0);

View File

@@ -108,7 +108,9 @@ HorizonsFile::HorizonsResult HorizonsFile::isValidAnswer(const json& answer) {
return HorizonsFile::HorizonsResult::ErrorTimeRange;
}
// No site matches. Use "*@body" to list, "c@body" to enter coords, ?! for help.
else if (errorMessage.find("No site matches") != std::string::npos) {
else if (errorMessage.find("No site matches") != std::string::npos ||
errorMessage.find("Cannot find central body") != std::string::npos)
{
return HorizonsFile::HorizonsResult::ErrorNoObserver;
}
// Observer table for X / Y->Y disallowed.
@@ -149,13 +151,18 @@ HorizonsFile::HorizonsResult HorizonsFile::isValidHorizonsFile() const {
// The line $$SOE indicates start of data.
std::string line;
bool foundTarget = false;
while (fileStream.good() && line.find("$$SOE") == std::string::npos) {
// Valid Target?
if (line.find("Revised") != std::string::npos) {
// If the target is valid, the first line is the date it was last revised
foundTarget = true;
}
std::getline(fileStream, line);
std::getline(fileStream, line); // First line is just stars (*) no information, skip
// Valid Target?
if (fileStream.good() && (line.find("Revised") != std::string::npos || line.find("JPL") != std::string::npos)) {
// If the target is valid, the first line is the date it was last revised
// In case of comets it says the Source in the top
foundTarget = true;
}
HorizonsFile::HorizonsResult result = HorizonsFile::HorizonsResult::UnknownError;
while (fileStream.good() && line.find("$$SOE") == std::string::npos) {
// Selected time range too big and step size too small?
if (line.find("change step-size") != std::string::npos) {
fileStream.close();
@@ -200,8 +207,7 @@ HorizonsFile::HorizonsResult HorizonsFile::isValidHorizonsFile() const {
// Multiple Observer stations?
if (line.find("Multiple matching stations found") != std::string::npos) {
fileStream.close();
return HorizonsFile::HorizonsResult::MultipleObserverStations;
result = HorizonsFile::HorizonsResult::MultipleObserverStations;
}
// Multiple matching major bodies?
@@ -209,21 +215,18 @@ HorizonsFile::HorizonsResult HorizonsFile::isValidHorizonsFile() const {
// Target
if (!foundTarget) {
// If target was not found then it is the target that has multiple matches
fileStream.close();
return HorizonsFile::HorizonsResult::MultipleTarget;
result = HorizonsFile::HorizonsResult::MultipleTarget;
}
// Observer
else {
fileStream.close();
return HorizonsFile::HorizonsResult::MultipleObserver;
result = HorizonsFile::HorizonsResult::MultipleObserver;
}
}
// Multiple matching small bodies?
if (line.find("Small-body Index Search Results") != std::string::npos) {
// Small bodies can only be targets not observers
fileStream.close();
return HorizonsFile::HorizonsResult::MultipleTarget;
result = HorizonsFile::HorizonsResult::MultipleTarget;
}
// No Target?
@@ -235,6 +238,11 @@ HorizonsFile::HorizonsResult HorizonsFile::isValidHorizonsFile() const {
std::getline(fileStream, line);
}
if (result != HorizonsFile::HorizonsResult::UnknownError) {
fileStream.close();
return result;
}
// If we reached end of file before we found the start of data then it is
// not a valid file
if (fileStream.good()) {