Use the correct type for the navigation state

Add unit tests to verify parsing of these parameters
This commit is contained in:
Alexander Bock
2020-06-21 12:31:18 +02:00
parent 3ed2e25188
commit 12611b1a9a
11 changed files with 274 additions and 50 deletions
+4 -4
View File
@@ -92,10 +92,10 @@ public:
std::string anchor;
std::string aim;
std::string referenceFrame;
std::string position; // @TODO (abock, 2020-06-17) change to vec3
std::string up;// @TODO (abock, 2020-06-17) change to vec3
std::string yaw;
std::string pitch;
glm::dvec3 position;
std::optional<glm::dvec3> up;
std::optional<double> yaw;
std::optional<double> pitch;
};
struct CameraGoToGeo {
static constexpr const char* Type = "goToGeo";
+109 -25
View File
@@ -289,10 +289,80 @@ namespace {
camera.anchor = fields[1];
camera.aim = fields[2];
camera.referenceFrame = fields[3];
camera.position = fields[4];
camera.up = fields[5];
camera.yaw = fields[6];
camera.pitch = fields[7];
std::vector<std::string> position = ghoul::tokenizeString(fields[4], ' ');
if (position.size() != 3) {
throw ProfileParsingError(
lineNumber,
fmt::format(
"Expected 3 fields for the camera's position, got {}",
position.size()
)
);
}
try {
camera.position = glm::dvec3(
std::stod(position[0]),
std::stod(position[1]),
std::stod(position[2])
);
}
catch (const std::invalid_argument&) {
throw ProfileParsingError(
lineNumber,
"Camera's position components must be numbers"
);
}
std::vector<std::string> up = ghoul::tokenizeString(fields[5], ' ');
if (up.size() != 0 && up.size() != 3) {
throw ProfileParsingError(
lineNumber,
fmt::format(
"Expected 0 or 3 fields for the camera's up vector, got {}",
up.size()
)
);
}
if (up.size() == 3) {
try {
camera.up = glm::dvec3(
std::stod(up[0]),
std::stod(up[1]),
std::stod(up[2])
);
}
catch (const std::invalid_argument&) {
throw ProfileParsingError(
lineNumber,
"Camera's up vector components must be numbers"
);
}
}
if (!fields[6].empty()) {
try {
camera.yaw = std::stod(fields[6]);
}
catch (const std::invalid_argument&) {
throw ProfileParsingError(
lineNumber,
"Camera's yaw value must be a number"
);
}
}
if (!fields[7].empty()) {
try {
camera.pitch = std::stod(fields[7]);
}
catch (const std::invalid_argument&) {
throw ProfileParsingError(
lineNumber,
"Camera's pitch value must be a number"
);
}
}
return camera;
}
if (type == Profile::CameraGoToGeo::Type) {
@@ -364,18 +434,10 @@ void Profile::saveCurrentSettingsToProfile(const properties::PropertyOwner& root
c.anchor = navState.anchor;
c.aim = navState.aim;
c.referenceFrame = navState.referenceFrame;
c.position = fmt::format(
"{},{},{}",
navState.position.x, navState.position.y, navState.position.z
);
if (navState.up.has_value()) {
c.up = fmt::format(
"{},{},{}",
navState.up->x, navState.up->y, navState.up->z
);
}
c.yaw = std::to_string(navState.yaw);
c.pitch = std::to_string(navState.pitch);
c.position = navState.position;
c.up = navState.up;
c.yaw = navState.yaw;
c.pitch = navState.pitch;
camera = std::move(c);
}
@@ -524,11 +586,27 @@ std::string Profile::serialize() const {
output += std::visit(
overloaded {
[](const CameraNavState& camera) {
std::string position = fmt::format(
"{}, {}, {}",
camera.position.x, camera.position.y, camera.position.z
);
std::string up = camera.up.has_value() ?
fmt::format(
"{}, {}, {}", camera.up->x, camera.up->y, camera.up->z
) :
"";
std::string yaw = camera.yaw.has_value() ?
fmt::format("{}", *camera.yaw) :
"";
std::string pitch = camera.pitch.has_value() ?
fmt::format("{}", *camera.pitch) :
"";
return fmt::format(
"{}\t{}\t{}\t{}\t{}\t{}\t{}\t{}\n",
CameraNavState::Type,
camera.anchor, camera.aim, camera.referenceFrame, camera.position,
camera.up, camera.yaw, camera.pitch
camera.anchor, camera.aim, camera.referenceFrame, position, up,
yaw, pitch
);
},
[](const Profile::CameraGoToGeo& camera) {
@@ -771,15 +849,21 @@ std::string Profile::convertToScene() const {
if (!camera.referenceFrame.empty()) {
result += fmt::format("ReferenceFrame = {}, ", camera.referenceFrame);
}
result += fmt::format("Position = {{ {} }}, ", camera.position);
if (!camera.up.empty()) {
result += fmt::format("Up = {{ {} }}, ", camera.up);
result += fmt::format(
"Position = {{ {}, {}, {} }}, ",
camera.position.x, camera.position.y, camera.position.z
);
if (camera.up.has_value()) {
result += fmt::format(
"Up = {{ {}, {}, {} }}, ",
camera.up->x, camera.up->y, camera.up->z
);
}
if (!camera.yaw.empty()) {
result += fmt::format("Yaw = {}, ", camera.yaw);
if (camera.yaw.has_value()) {
result += fmt::format("Yaw = {}, ", *camera.yaw);
}
if (!camera.pitch.empty()) {
result += fmt::format("Pitch = {} ", camera.pitch);
if (camera.pitch.has_value()) {
result += fmt::format("Pitch = {} ", *camera.pitch);
}
result += "})\n";
return result;
+1 -1
View File
@@ -2,4 +2,4 @@
12.13
#Camera
setNavigationState "node" "root" 1.0, 2.0, 3.0 4.0, 5.0, 6.0
setNavigationState "node" "root" 1.0, 2.0, 3.0 4.0, 5.0, 6.0 10.0 -10.0
@@ -0,0 +1,5 @@
#Version
12.13
#Camera
setNavigationState "node" "root" 1.0, 2.0 4.0, 5.0, 6.0
@@ -0,0 +1,5 @@
#Version
12.13
#Camera
setNavigationState "node" "root" 1.0, 2.0, 3.0 4.0, 5.0
@@ -0,0 +1,5 @@
#Version
12.13
#Camera
setNavigationState "node" "root" 1.0, 2.0, 3.0, 4.0 4.0, 5.0, 6.0
@@ -0,0 +1,5 @@
#Version
12.13
#Camera
setNavigationState "node" "root" 1.0, 2.0, 3.0 4.0, 5.0, 6.0 def
@@ -0,0 +1,5 @@
#Version
12.13
#Camera
setNavigationState "node" "root" 1.0, 2.0, 3.0 4.0, 5.0, 6.0 abc
@@ -0,0 +1,5 @@
#Version
12.13
#Camera
setNavigationState "node" "root" 1.0, 2.0, abc 4.0, 5.0, 6.0
@@ -0,0 +1,5 @@
#Version
12.13
#Camera
setNavigationState "node" "root" 1.0, 2.0, 3.0 4.0, abc, 6.0
+125 -20
View File
@@ -23,26 +23,11 @@
****************************************************************************************/
#include "catch2/catch.hpp"
//#include "test_common.h"
//#include <openspace/engine/configuration.h>
//#include <openspace/engine/globals.h>
//#include <openspace/engine/openspaceengine.h>
//
//#include <openspace/scene/assetloader.h>
//#include <openspace/scene/asset.h>
//#include "openspace/scene/profile.h"
//#include <openspace/scene/scene.h>
//#include <openspace/scene/scenegraphnode.h>
//#include <openspace/scene/sceneinitializer.h>
//#include <openspace/scripting/scriptengine.h>
//#include <ghoul/misc/exception.h>
//#include <ghoul/lua/lua_helper.h>
//
//#include <iostream>
//#include <iomanip>
//#include <memory>
#include <openspace/interaction/navigationhandler.h>
#include <openspace/properties/propertyowner.h>
#include <openspace/properties/stringproperty.h>
#include <openspace/properties/scalar/floatproperty.h>
#include <openspace/scene/profile.h>
#include <ghoul/filesystem/filesystem.h>
#include <filesystem>
@@ -393,7 +378,6 @@ TEST_CASE("Removing non-exisiting asset", "[profile]") {
);
}
TEST_CASE("Removing non-exisiting asset (ignored)", "[profile]") {
std::vector<std::string> source = {
"#Version",
@@ -409,6 +393,55 @@ TEST_CASE("Removing non-exisiting asset (ignored)", "[profile]") {
REQUIRE_NOTHROW(p.removeAsset("unknown-asset"));
}
//
// Save settings to profile
//
TEST_CASE("Save settings to profile", "[profile]") {
properties::PropertyOwner owner({ "base" });
properties::FloatProperty p1(properties::Property::PropertyInfo("p1", "a", "b"), 1.f);
owner.addProperty(p1);
properties::StringProperty p2(properties::Property::PropertyInfo("p2", "c", "d"));
owner.addProperty(p2);
p1 = 2.f;
p2 = "test-string";
interaction::NavigationHandler::NavigationState state;
state.anchor = "anchor";
state.aim = "aim";
state.referenceFrame = "refFrame";
state.position = glm::dvec3(1.0, 2.0, 3.0);
state.up = glm::dvec3(4.0, 5.0, 6.0);
state.yaw = -1.0;
state.pitch = -2.0;
std::vector<std::string> baseSource = {
"#Version",
"1.0"
};
Profile p(baseSource);
p.saveCurrentSettingsToProfile(owner, "current-time", state);
std::string serialized = p.serialize();
std::vector<std::string> targetSource = baseSource;
targetSource.push_back("");
targetSource.push_back("#Property");
targetSource.push_back("setPropertyValueSingle\tbase.p1\t2.000000");
targetSource.push_back("setPropertyValueSingle\tbase.p2\t\"test-string\"");
targetSource.push_back("");
targetSource.push_back("#Camera");
targetSource.push_back(
"setNavigationState\tanchor\taim\trefFrame\t1.0, 2.0, 3.0\t4.0, 5.0, 6.0\t"
"-1.0\t-2.0"
);
targetSource.push_back("");
targetSource.push_back("#Time");
targetSource.push_back("absolute\tcurrent-time");
std::string targetSerialized = Profile(targetSource).serialize();
REQUIRE(serialized == targetSerialized);
}
//
// Error states
@@ -609,6 +642,78 @@ TEST_CASE("Error camera navigation state too many parameters", "[profile]") {
);
}
TEST_CASE("Error camera navigation state too few parameters in position", "[profile]") {
constexpr const char* TestFile =
"${TESTDIR}/profile/"
"error_camera_navstate_wrong_parameter_too_few_components_position.profile";
REQUIRE_THROWS_WITH(
loadProfile(TestFile),
Catch::Matchers::Contains("Expected 3 fields for the camera's position, got 2")
);
}
TEST_CASE("Error camera navigation state too many parameters in position", "[profile]") {
constexpr const char* TestFile =
"${TESTDIR}/profile/"
"error_camera_navstate_wrong_parameter_too_many_components_position.profile";
REQUIRE_THROWS_WITH(
loadProfile(TestFile),
Catch::Matchers::Contains("Expected 3 fields for the camera's position, got 4")
);
}
TEST_CASE("Error camera navigation state wrong parameter type position", "[profile]") {
constexpr const char* TestFile =
"${TESTDIR}/profile/"
"error_camera_navstate_wrong_parameter_wrong_component_type_position.profile";
REQUIRE_THROWS_WITH(
loadProfile(TestFile),
Catch::Matchers::Contains("Camera's position components must be numbers")
);
}
TEST_CASE("Error camera navigation state too few parameters in up vector", "[profile]") {
constexpr const char* TestFile =
"${TESTDIR}/profile/"
"error_camera_navstate_wrong_parameter_too_few_components_up.profile";
REQUIRE_THROWS_WITH(
loadProfile(TestFile),
Catch::Matchers::Contains(
"Expected 0 or 3 fields for the camera's up vector, got 2"
)
);
}
TEST_CASE("Error camera navigation state wrong parameter type up vector", "[profile]") {
constexpr const char* TestFile =
"${TESTDIR}/profile/"
"error_camera_navstate_wrong_parameter_wrong_component_type_up.profile";
REQUIRE_THROWS_WITH(
loadProfile(TestFile),
Catch::Matchers::Contains("Camera's up vector components must be numbers")
);
}
TEST_CASE("Error camera navigation state wrong parameter type up yaw", "[profile]") {
constexpr const char* TestFile =
"${TESTDIR}/profile/"
"error_camera_navstate_wrong_parameter_type_yaw.profile";
REQUIRE_THROWS_WITH(
loadProfile(TestFile),
Catch::Matchers::Contains("Camera's yaw value must be a number")
);
}
TEST_CASE("Error camera navigation state wrong parameter type up pitch", "[profile]") {
constexpr const char* TestFile =
"${TESTDIR}/profile/"
"error_camera_navstate_wrong_parameter_type_pitch.profile";
REQUIRE_THROWS_WITH(
loadProfile(TestFile),
Catch::Matchers::Contains("Camera's pitch value must be a number")
);
}
TEST_CASE("Error camera goToGeo too few parameters", "[profile]") {
constexpr const char* TestFile =
"${TESTDIR}/profile/error_camera_gotogeo_too_few_parameters.profile";