NavigationState handling (#3023)

* Change the navigation state format from Lua to JSON.  Add the ability to set the navigation state in the profile editor based on a file
This commit is contained in:
Alexander Bock
2024-02-25 01:09:32 +01:00
committed by GitHub
parent 7a551774bc
commit 2fbcb0544e
5 changed files with 143 additions and 30 deletions
@@ -25,15 +25,18 @@
#include "profile/cameradialog.h"
#include "profile/line.h"
#include <openspace/navigation/navigationstate.h>
#include <QDialogButtonBox>
#include <QDoubleValidator>
#include <QFileDialog>
#include <QFrame>
#include <QGridLayout>
#include <QKeyEvent>
#include <QLabel>
#include <QLineEdit>
#include <QTabWidget>
#include <QPlainTextEdit>
#include <QPushButton>
#include <QTabWidget>
namespace {
constexpr int CameraTypeNode = 0;
@@ -345,6 +348,45 @@ QWidget* CameraDialog::createNavStateWidget() {
mainLayout->addWidget(box);
}
QPushButton* loadFile = new QPushButton("Load state from file");
loadFile->setIcon(loadFile->style()->standardIcon(QStyle::SP_FileIcon));
connect(
loadFile, &QPushButton::clicked,
[this]() {
QString file = QFileDialog::getOpenFileName(
this,
"Select navigate state file"
);
std::ifstream f(file.toStdString());
std::string contents = std::string(
(std::istreambuf_iterator<char>(f)),
std::istreambuf_iterator<char>()
);
nlohmann::json json = nlohmann::json::parse(contents);
using namespace openspace::interaction;
NavigationState state = NavigationState(json);
_navState.anchor->setText(QString::fromStdString(state.anchor));
_navState.aim->setText(QString::fromStdString(state.aim));
_navState.refFrame->setText(QString::fromStdString(state.referenceFrame));
_navState.positionX->setText(QString::number(state.position.x));
_navState.positionY->setText(QString::number(state.position.y));
_navState.positionZ->setText(QString::number(state.position.z));
if (state.up.has_value()) {
_navState.upX->setText(QString::number(state.up->x));
_navState.upY->setText(QString::number(state.up->y));
_navState.upZ->setText(QString::number(state.up->z));
}
_navState.yaw->setText(QString::number(state.yaw));
_navState.pitch->setText(QString::number(state.pitch));
}
);
mainLayout->addWidget(loadFile);
return tab;
}
@@ -26,6 +26,7 @@
#define __OPENSPACE_CORE___NAVIGATIONSTATE___H__
#include <openspace/documentation/documentation.h>
#include <openspace/json.h>
#include <optional>
namespace openspace {
@@ -37,12 +38,14 @@ namespace openspace::interaction {
struct NavigationState {
NavigationState() = default;
explicit NavigationState(const ghoul::Dictionary& dictionary);
explicit NavigationState(const nlohmann::json& json);
NavigationState(std::string anchor, std::string aim, std::string referenceFrame,
glm::dvec3 position, std::optional<glm::dvec3> up = std::nullopt,
double yaw = 0.0, double pitch = 0.0);
CameraPose cameraPose() const;
ghoul::Dictionary dictionary() const;
nlohmann::json toJson() const;
static documentation::Documentation Documentation();
std::string anchor;
+14 -17
View File
@@ -557,6 +557,10 @@ void NavigationHandler::saveNavigationState(const std::filesystem::path& filepat
}
std::filesystem::path absolutePath = absPath(filepath);
if (!absolutePath.has_extension()) {
// Adding the .navstate extension to the filepath if it came without one
absolutePath.replace_extension(".navstate");
}
LINFO(fmt::format("Saving camera position: {}", absolutePath));
std::ofstream ofs(absolutePath);
@@ -567,7 +571,7 @@ void NavigationHandler::saveNavigationState(const std::filesystem::path& filepat
));
}
ofs << "return " << ghoul::formatLua(state.dictionary());
ofs << state.toJson().dump(2);
}
void NavigationHandler::loadNavigationState(const std::string& filepath) {
@@ -578,22 +582,15 @@ void NavigationHandler::loadNavigationState(const std::string& filepath) {
throw ghoul::FileNotFoundError(absolutePath.string(), "NavigationState");
}
ghoul::Dictionary navigationStateDictionary;
try {
ghoul::lua::loadDictionaryFromFile(
absolutePath.string(),
navigationStateDictionary
);
openspace::documentation::testSpecificationAndThrow(
NavigationState::Documentation(),
navigationStateDictionary,
"NavigationState"
);
setNavigationStateNextFrame(NavigationState(navigationStateDictionary));
}
catch (ghoul::RuntimeError& e) {
LERROR(fmt::format("Unable to set camera position: {}", e.message));
}
std::ifstream f(filepath);
std::string contents = std::string(
std::istreambuf_iterator<char>(f),
std::istreambuf_iterator<char>()
);
nlohmann::json json = nlohmann::json::parse(contents);
NavigationState state = NavigationState(json);
setNavigationStateNextFrame(state);
}
std::vector<std::string> NavigationHandler::listAllJoysticks() const {
+1 -1
View File
@@ -38,7 +38,7 @@ namespace {
}
/**
* Return the current navigation state as a lua table. The optional argument is the scene
* Return the current navigation state as a Lua table. The optional argument is the scene
* graph node to use as reference frame. By default, the reference frame will picked based
* on whether the orbital navigator is currently following the anchor node rotation. If it
* is, the anchor will be chosen as reference frame. If not, the reference frame will be
+82 -11
View File
@@ -89,11 +89,42 @@ NavigationState::NavigationState(const ghoul::Dictionary& dictionary) {
referenceFrame = p.referenceFrame.value_or(anchor);
aim = p.aim.value_or(aim);
if (p.up.has_value()) {
up = *p.up;
up = p.up;
yaw = p.yaw.value_or(yaw);
pitch = p.pitch.value_or(pitch);
}
yaw = p.yaw.value_or(yaw);
pitch = p.pitch.value_or(pitch);
NavigationState::NavigationState(const nlohmann::json& json) {
position.x = json["position"]["x"].get<double>();
position.y = json["position"]["y"].get<double>();
position.z = json["position"]["z"].get<double>();
anchor = json["anchor"];
if (auto it = json.find("referenceframe"); it != json.end()) {
referenceFrame = it->get<std::string>();
}
else {
referenceFrame = anchor;
}
if (auto it = json.find("aim"); it != json.end()) {
aim = it->get<std::string>();
}
if (auto it = json.find("up"); it != json.end()) {
up = glm::dvec3();
up->x = it->at("x").get<double>();
up->y = it->at("y").get<double>();
up->z = it->at("z").get<double>();
}
if (auto it = json.find("yaw"); it != json.end()) {
yaw = it->get<double>();
}
if (auto it = json.find("pitch"); it != json.end()) {
pitch = it->get<double>();
}
}
@@ -174,16 +205,56 @@ ghoul::Dictionary NavigationState::dictionary() const {
}
if (up.has_value()) {
cameraDict.setValue("Up", *up);
}
if (std::abs(yaw) > Epsilon) {
cameraDict.setValue("Yaw", yaw);
}
if (std::abs(pitch) > Epsilon) {
cameraDict.setValue("Pitch", pitch);
}
return cameraDict;
}
if (std::abs(yaw) > Epsilon) {
cameraDict.setValue("Yaw", yaw);
}
if (std::abs(pitch) > Epsilon) {
cameraDict.setValue("Pitch", pitch);
}
nlohmann::json NavigationState::toJson() const {
nlohmann::json result = nlohmann::json::object();
// Obligatory version number
result["version"] = 1;
{
nlohmann::json posObj = nlohmann::json::object();
posObj["x"] = position.x;
posObj["y"] = position.y;
posObj["z"] = position.z;
result["position"] = posObj;
}
return cameraDict;
result["anchor"] = anchor;
if (anchor != referenceFrame) {
result["referenceframe"] = referenceFrame;
}
if (!aim.empty()) {
result["aim"] = aim;
}
if (up.has_value()) {
nlohmann::json upObj = nlohmann::json::object();
upObj["x"] = up->x;
upObj["y"] = up->y;
upObj["z"] = up->z;
result["up"] = upObj;
}
if (std::abs(yaw) > Epsilon) {
result["yaw"] = yaw;
}
if (std::abs(pitch) > Epsilon) {
result["pitch"] = pitch;
}
return result;
}
documentation::Documentation NavigationState::Documentation() {