Merge pull request #2570 from OpenSpace/feature/min-max-distance

Limit min/max distance
This commit is contained in:
Malin E
2023-04-13 17:18:27 +02:00
committed by GitHub
7 changed files with 258 additions and 32 deletions
@@ -50,6 +50,8 @@ namespace openspace {
struct SurfacePositionHandle;
} // namespace
namespace openspace::scripting { struct LuaLibrary; }
namespace openspace::interaction {
class MouseInputState;
@@ -112,6 +114,9 @@ public:
void setRetargetInterpolationTime(float durationInSeconds);
void updatePreviousStateVariables();
void setMinimumAllowedDistance(float distance);
void setMaximumAllowedDistance(float distance);
JoystickCameraStates& joystickStates();
const JoystickCameraStates& joystickStates() const;
@@ -131,6 +136,7 @@ public:
bool hasRollFriction() const;
double minAllowedDistance() const;
double maxAllowedDistance() const;
glm::dvec3 anchorNodeToCameraVector() const;
glm::quat anchorNodeToCameraRotation() const;
@@ -142,6 +148,12 @@ public:
*/
glm::dvec3 pushToSurfaceOfAnchor(const glm::dvec3& cameraPosition) const;
/**
* \return the Lua library that contains all Lua functions available to affect the
* OrbitalNavigator
*/
static scripting::LuaLibrary luaLibrary();
private:
struct CameraRotationDecomposition {
glm::dquat localRotation = glm::dquat(1.0, 0.0, 0.0, 0.0);
@@ -186,7 +198,19 @@ private:
properties::BoolProperty _followAnchorNodeRotation;
properties::FloatProperty _followAnchorNodeRotationDistance;
properties::FloatProperty _minimumAllowedDistance;
struct LimitZoom : public properties::PropertyOwner {
LimitZoom();
properties::BoolProperty enableZoomInLimit;
properties::FloatProperty minimumAllowedDistance;
properties::BoolProperty enableZoomOutLimit;
properties::FloatProperty maximumAllowedDistance;
};
LimitZoom _limitZoom;
properties::FloatProperty _mouseSensitivity;
properties::FloatProperty _joystickSensitivity;
+2 -1
View File
@@ -172,7 +172,8 @@ private:
properties::FloatProperty _zoomSensitivityExponential;
properties::FloatProperty _zoomSensitivityProportionalDist;
properties::FloatProperty _zoomSensitivityDistanceThreshold;
properties::FloatProperty _zoomBoundarySphereMultiplier;
properties::FloatProperty _zoomInBoundarySphereMultiplier;
properties::FloatProperty _zoomOutBoundarySphereMultiplier;
properties::DoubleProperty _zoomInLimit;
properties::DoubleProperty _zoomOutLimit;
properties::FloatProperty _inputStillThreshold;
+41 -15
View File
@@ -139,7 +139,8 @@ namespace {
};
constexpr openspace::properties::Property::PropertyInfo
ZoomSensitivityDistanceThresholdInfo = {
ZoomSensitivityDistanceThresholdInfo =
{
"ZoomSensitivityDistanceThreshold",
"Threshold of distance to target node for whether or not to use exponential "
"zooming",
@@ -147,13 +148,22 @@ namespace {
};
constexpr openspace::properties::Property::PropertyInfo
ZoomBoundarySphereMultiplierInfo = {
"ZoomBoundarySphereMultiplier",
"Multiplies a node's boundary sphere by this in order to limit zoom & prevent "
ZoomInBoundarySphereMultiplierInfo =
{
"ZoomInBoundarySphereMultiplier",
"Multiplies a node's boundary sphere by this in order to limit zoom in & prevent "
"surface collision",
"" // @TODO Missing documentation
};
constexpr openspace::properties::Property::PropertyInfo
ZoomOutBoundarySphereMultiplierInfo =
{
"ZoomOutBoundarySphereMultiplier",
"Multiplies a node's boundary sphere by this in order to limit zoom out",
"" // @TODO Missing documentation
};
constexpr openspace::properties::Property::PropertyInfo ConstantTimeDecaySecsInfo = {
"ConstantTimeDecaySecs",
"Time duration that a pitch/roll/zoom/pan should take to decay to zero (seconds)",
@@ -259,13 +269,19 @@ TouchInteraction::TouchInteraction()
0.01f,
0.25f
)
, _zoomBoundarySphereMultiplier(ZoomBoundarySphereMultiplierInfo, 1.001f, 0.01f, 10000.f)
, _zoomInLimit(ZoomInLimitInfo, -1.0, 0.0, std::numeric_limits<double>::max())
, _zoomInBoundarySphereMultiplier(ZoomInBoundarySphereMultiplierInfo, 1.001f, 0.01f, 4e+27)
, _zoomOutBoundarySphereMultiplier(
ZoomOutBoundarySphereMultiplierInfo,
4e+27,
1.f,
4e+27
)
, _zoomInLimit(ZoomInLimitInfo, -1.0, 0.0, 4e+27)
, _zoomOutLimit(
ZoomOutLimitInfo,
std::numeric_limits<double>::max(),
4e+27,
1000.0,
std::numeric_limits<double>::max()
4e+27
)
, _inputStillThreshold(InputSensitivityInfo, 0.0005f, 0.f, 0.001f, 0.0001f)
// Used to void wrongly interpreted roll interactions
@@ -300,7 +316,8 @@ TouchInteraction::TouchInteraction()
addProperty(_zoomSensitivityExponential);
addProperty(_zoomSensitivityProportionalDist);
addProperty(_zoomSensitivityDistanceThreshold);
addProperty(_zoomBoundarySphereMultiplier);
addProperty(_zoomInBoundarySphereMultiplier);
addProperty(_zoomOutBoundarySphereMultiplier);
addProperty(_zoomInLimit);
addProperty(_zoomOutLimit);
addProperty(_constTimeDecay_secs);
@@ -317,6 +334,10 @@ TouchInteraction::TouchInteraction()
addPropertySubOwner(_debugProperties);
#endif
_zoomInBoundarySphereMultiplier.setExponent(20.f);
_zoomOutBoundarySphereMultiplier.setExponent(20.f);
_zoomInLimit.setExponent(20.f);
_zoomOutLimit.setExponent(20.f);
_time = std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::high_resolution_clock::now().time_since_epoch()
);
@@ -921,7 +942,7 @@ void TouchInteraction::step(double dt, bool directTouch) {
// This is a rough estimate of the node surface
// If nobody has set another zoom in limit, use this as default zoom in bounds
double zoomInBounds = interactionSphere * _zoomBoundarySphereMultiplier;
double zoomInBounds = interactionSphere * _zoomInBoundarySphereMultiplier;
bool isZoomInLimitSet = (_zoomInLimit.value() >= 0.0);
if (isZoomInLimitSet && _zoomInLimit.value() < zoomInBounds) {
@@ -949,11 +970,16 @@ void TouchInteraction::step(double dt, bool directTouch) {
}
}
double zoomOutBounds = std::min(
interactionSphere *_zoomOutBoundarySphereMultiplier,
_zoomOutLimit.value()
);
// Make sure zoom in limit is not larger than zoom out limit
if (zoomInBounds > _zoomOutLimit.value()) {
if (zoomInBounds > zoomOutBounds) {
LWARNING(fmt::format(
"Zoom In Limit should be smaller than Zoom Out Limit",
_zoomOutLimit.value()
zoomOutBounds
));
}
const double currentPosDistance = length(centerToCamera);
@@ -983,9 +1009,9 @@ void TouchInteraction::step(double dt, bool directTouch) {
// Possible with other navigations performed outside touch interaction
const bool currentPosViolatingZoomOutLimit =
(currentPosDistance >= _zoomOutLimit);
(currentPosDistance >= zoomOutBounds);
const bool willNewPositionViolateZoomOutLimit =
(newPosDistance >= _zoomOutLimit);
(newPosDistance >= zoomOutBounds);
bool willNewPositionViolateZoomInLimit =
(newPosDistance < zoomInBounds);
bool willNewPositionViolateDirection =
@@ -1001,7 +1027,7 @@ void TouchInteraction::step(double dt, bool directTouch) {
#ifdef TOUCH_DEBUG_PROPERTIES
LINFO(fmt::format(
"You are outside zoom out {} limit, only zoom in allowed",
_zoomOutLimit.value()
zoomOutBounds
));
#endif
// Only allow zooming in if you are outside the zoom out limit
+1
View File
@@ -73,6 +73,7 @@ set(OPENSPACE_SOURCE
navigation/navigationhandler_lua.inl
navigation/navigationstate.cpp
navigation/orbitalnavigator.cpp
navigation/orbitalnavigator_lua.inl
navigation/path.cpp
navigation/pathcurve.cpp
navigation/pathnavigator.cpp
+1
View File
@@ -91,6 +91,7 @@ void registerCoreClasses(scripting::ScriptEngine& engine) {
engine.addLibrary(interaction::ActionManager::luaLibrary());
engine.addLibrary(interaction::KeybindingManager::luaLibrary());
engine.addLibrary(interaction::NavigationHandler::luaLibrary());
engine.addLibrary(interaction::OrbitalNavigator::luaLibrary());
engine.addLibrary(interaction::PathNavigator::luaLibrary());
engine.addLibrary(interaction::SessionRecording::luaLibrary());
engine.addLibrary(scripting::ScriptScheduler::luaLibrary());
+127 -15
View File
@@ -26,6 +26,7 @@
#include <openspace/engine/openspaceengine.h>
#include <openspace/interaction/mouseinputstate.h>
#include <openspace/interaction/keyboardinputstate.h>
#include <openspace/navigation/navigationhandler.h>
#include <openspace/navigation/orbitalnavigator.h>
#include <openspace/scene/scenegraphnode.h>
#include <openspace/util/updatestructures.h>
@@ -37,14 +38,15 @@
#include <ghoul/misc/easing.h>
#include <glm/gtx/rotate_vector.hpp>
#include <glm/gtx/vector_angle.hpp>
#include <cmath>
#include "orbitalnavigator_lua.inl"
namespace {
constexpr std::string_view _loggerCat = "OrbitalNavigator";
constexpr double AngleEpsilon = 1E-7;
constexpr double DistanceRatioAimThreshold = 1E-4;
constexpr double AngleEpsilon = 1e-7;
constexpr double DistanceRatioAimThreshold = 1e-4;
constexpr openspace::properties::Property::PropertyInfo AnchorInfo = {
"Anchor",
@@ -146,13 +148,6 @@ namespace {
"this factor with the approximate radius of the node"
};
constexpr openspace::properties::Property::PropertyInfo MinimumDistanceInfo = {
"MinimumAllowedDistance",
"Minimum Allowed Distance",
"Limits how close the camera can get to an object. The distance is given in "
"meters above the surface"
};
constexpr openspace::properties::Property::PropertyInfo StereoInterpolationTimeInfo =
{
"StereoInterpolationTime",
@@ -287,6 +282,43 @@ namespace {
"or canceled, in seconds"
};
static const openspace::properties::PropertyOwner::PropertyOwnerInfo LimitZoomInfo = {
"LimitZoom",
"Limit Zoom",
"Settings to limit the camera from going to close to or too far away from the "
"current focus"
};
constexpr openspace::properties::Property::PropertyInfo
EnabledMinimumAllowedDistanceInfo =
{
"EnabledMinimumAllowedDistance",
"Enable minimum allowed distance limit",
"Enables or disables that the camera cannot go closer to an object than "
"the set minimum allowed distance"
};
constexpr openspace::properties::Property::PropertyInfo MinimumDistanceInfo = {
"MinimumAllowedDistance",
"Minimum Allowed Distance",
"The limit of how close the camera can get to an object. The distance is given "
"in meters above the surface"
};
constexpr openspace::properties::Property::PropertyInfo EnabledMaximumDistanceInfo = {
"EnableMaximumAllowedDistance",
"Enable Maximum Allowed Distance limit",
"Enables or disables that the camera cannot go further away from an object than "
"the set maximum allowed distance"
};
constexpr openspace::properties::Property::PropertyInfo MaximumDistanceInfo = {
"MaximumAllowedDistance",
"Maximum Allowed Distance",
"The limit of how far away the camera can get from an object. The distance is "
"given in meters above the surface"
};
constexpr std::string_view IdleKeyOrbit = "Orbit";
constexpr std::string_view IdleKeyOrbitAtConstantLat = "OrbitAtConstantLatitude";
constexpr std::string_view IdleKeyOrbitAroundUp = "OrbitAroundUp";
@@ -344,6 +376,28 @@ OrbitalNavigator::IdleBehavior::IdleBehavior()
addProperty(dampenInterpolationTime);
}
OrbitalNavigator::LimitZoom::LimitZoom()
: properties::PropertyOwner(LimitZoomInfo)
, enableZoomInLimit(EnabledMinimumAllowedDistanceInfo, true)
, minimumAllowedDistance(MinimumDistanceInfo, 10.0f, 0.0f, 10000.f)
, enableZoomOutLimit(EnabledMaximumDistanceInfo, false)
, maximumAllowedDistance(
MaximumDistanceInfo,
4e+27,
50.f,
4e+27
)
{
// Min
addProperty(enableZoomInLimit);
addProperty(minimumAllowedDistance);
// Max
addProperty(enableZoomOutLimit);
addProperty(maximumAllowedDistance);
maximumAllowedDistance.setExponent(20.f);
}
OrbitalNavigator::OrbitalNavigator()
: properties::PropertyOwner({ "OrbitalNavigator", "Orbital Navigator" })
, _anchor(AnchorInfo)
@@ -352,7 +406,6 @@ OrbitalNavigator::OrbitalNavigator()
, _retargetAim(RetargetAimInfo)
, _followAnchorNodeRotation(FollowAnchorNodeInfo, true)
, _followAnchorNodeRotationDistance(FollowAnchorNodeDistanceInfo, 5.f, 0.f, 20.f)
, _minimumAllowedDistance(MinimumDistanceInfo, 10.0f, 0.0f, 10000.f)
, _mouseSensitivity(MouseSensitivityInfo, 15.f, 1.f, 50.f)
, _joystickSensitivity(JoystickSensitivityInfo, 10.f, 1.0f, 50.f)
, _websocketSensitivity(WebsocketSensitivityInfo, 5.f, 1.0f, 50.f)
@@ -484,6 +537,7 @@ OrbitalNavigator::OrbitalNavigator()
addPropertySubOwner(_friction);
addPropertySubOwner(_idleBehavior);
addPropertySubOwner(_limitZoom);
_idleBehaviorDampenInterpolator.setTransferFunction(
ghoul::quadraticEaseInOut<double>
@@ -520,7 +574,6 @@ OrbitalNavigator::OrbitalNavigator()
addProperty(_retargetAim);
addProperty(_followAnchorNodeRotation);
addProperty(_followAnchorNodeRotationDistance);
addProperty(_minimumAllowedDistance);
addProperty(_useAdaptiveStereoscopicDepth);
addProperty(_staticViewScaleExponent);
@@ -737,6 +790,7 @@ void OrbitalNavigator::updateCameraStateFromStates(double deltaTime) {
// Perform the vertical movements based on user input
pose.position = translateVertically(deltaTime, pose.position, anchorPos, posHandle);
pose.position = pushToSurface(
pose.position,
anchorPos,
@@ -923,6 +977,29 @@ void OrbitalNavigator::updatePreviousStateVariables() {
updatePreviousAimState();
}
void OrbitalNavigator::setMinimumAllowedDistance(float distance) {
if (_limitZoom.enableZoomOutLimit && distance > _limitZoom.maximumAllowedDistance) {
LWARNING("Setting minimum allowed distance larger than maximum allowed distance");
}
_limitZoom.minimumAllowedDistance = distance;
}
void OrbitalNavigator::setMaximumAllowedDistance(float distance) {
if (distance < 50.f) {
LWARNING("Setting maximum allowed distance below 50 meters is not allowed");
return;
}
if (_limitZoom.minimumAllowedDistance > distance) {
LWARNING(
"Setting maximum allowed distance smaller than minimum allowed distance"
);
}
_limitZoom.maximumAllowedDistance = distance;
}
void OrbitalNavigator::startRetargetAnchor() {
if (!_anchorNode) {
return;
@@ -1027,7 +1104,11 @@ bool OrbitalNavigator::hasRollFriction() const {
}
double OrbitalNavigator::minAllowedDistance() const {
return _minimumAllowedDistance;
return _limitZoom.minimumAllowedDistance;
}
double OrbitalNavigator::maxAllowedDistance() const {
return _limitZoom.maximumAllowedDistance;
}
OrbitalNavigator::CameraRotationDecomposition
@@ -1527,6 +1608,16 @@ glm::dvec3 OrbitalNavigator::pushToSurface(const glm::dvec3& cameraPosition,
const glm::dvec3& objectPosition,
const SurfacePositionHandle& positionHandle) const
{
double minHeight = _limitZoom.enableZoomInLimit ?
static_cast<double>(_limitZoom.minimumAllowedDistance) : 0.0;
double maxHeight = _limitZoom.enableZoomOutLimit ?
static_cast<double>(_limitZoom.maximumAllowedDistance) : -1.0;
if (maxHeight > 0.0 && minHeight > maxHeight) {
LWARNING("Minimum allowed distance is larger than maximum allowed distance");
}
const glm::dmat4 modelTransform = _anchorNode->modelTransform();
const glm::dvec3 posDiff = cameraPosition - objectPosition;
@@ -1543,8 +1634,19 @@ glm::dvec3 OrbitalNavigator::pushToSurface(const glm::dvec3& cameraPosition,
const double surfaceToCameraSigned = glm::length(actualSurfaceToCamera) *
glm::sign(dot(actualSurfaceToCamera, referenceSurfaceOutDirection));
return cameraPosition + referenceSurfaceOutDirection *
glm::max(_minimumAllowedDistance - surfaceToCameraSigned, 0.0);
// Adjustment for if the camera is inside the min distance
double adjustment =
std::abs(minHeight) > std::numeric_limits<double>::epsilon() ?
glm::max(minHeight - surfaceToCameraSigned, 0.0) :
0.0;
// Adjustment for if the camera is outside the max distance
// Only apply if the min adjustment not already applied
if (maxHeight > 0.0 && std::abs(adjustment) < std::numeric_limits<double>::epsilon()) {
adjustment = glm::min(maxHeight - surfaceToCameraSigned, 0.0);
}
return cameraPosition + referenceSurfaceOutDirection * adjustment;
}
glm::dquat OrbitalNavigator::interpolateRotationDifferential(double deltaTime,
@@ -1772,4 +1874,14 @@ void OrbitalNavigator::orbitAroundAxis(const glm::dvec3 axis, double deltaTime,
globalRotation = spinRotation * globalRotation;
}
scripting::LuaLibrary OrbitalNavigator::luaLibrary() {
return {
"orbitalnavigation",
{
codegen::lua::SetRelativeMinDistance,
codegen::lua::SetRelativeMaxDistance
}
};
}
} // namespace openspace::interaction
+61
View File
@@ -0,0 +1,61 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2023 *
* *
* 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. *
****************************************************************************************/
namespace {
/**
* Set minimum allowed distance to a multiplier of the interaction sphere of the focus node
*/
[[codegen::luawrap]] void setRelativeMinDistance(float multiplier) {
using namespace openspace;
const SceneGraphNode* node = global::navigationHandler->anchorNode();
if (!node) {
throw ghoul::lua::LuaError("Could not determine current focus node");
}
double is = node->interactionSphere();
global::navigationHandler->orbitalNavigator().setMinimumAllowedDistance(
is * multiplier
);
}
/**
* Set maximum allowed distance to a multiplier of the interaction sphere of the focus node
*/
[[codegen::luawrap]] void setRelativeMaxDistance(float multiplier) {
using namespace openspace;
const SceneGraphNode* node = global::navigationHandler->anchorNode();
if (!node) {
throw ghoul::lua::LuaError("Could not determine current focus node");
}
double is = node->interactionSphere();
global::navigationHandler->orbitalNavigator().setMaximumAllowedDistance(
is * multiplier
);
}
#include "orbitalnavigator_lua_codegen.cpp"
} // namespace