Split up path helper functions to separate, more specific, files

Some in Ghoul and some in OpenSpace core util
This commit is contained in:
Emma Broman
2021-07-14 10:10:04 +02:00
parent 18a0a89030
commit de8005be4d
15 changed files with 276 additions and 368 deletions

View File

@@ -40,7 +40,7 @@ public:
/*
* Compute and rteturn the position along the path at the specified relative
* distance. The input parameter should be in range [0, 1], where 1 correspond to
* distance. The input parameter should be in range [0, 1], where 1 correspond to
* the full length of the path
*/
glm::dvec3 positionAt(double relativeDistance);
@@ -58,7 +58,7 @@ public:
protected:
/*
* Precompute information related to the spline parameters, that are
* needed for arc length reparameterization. Must be called after
* needed for arc length reparameterization. Must be called after
* control point creation
*/
void initializeParameterData();
@@ -75,11 +75,11 @@ protected:
double arcLength(double lowerLimit, double upperLimit);
std::vector<glm::dvec3> _points;
unsigned int _nSegments;
unsigned int _nSegments = 0;
std::vector<double> _curveParameterSteps; // per segment
std::vector<double> _lengthSums; // per segment
double _totalLength;
double _totalLength = 0.0;
struct ParameterPair {
double u; // curve parameter

View File

@@ -1,110 +0,0 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2021 *
* *
* 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. *
****************************************************************************************/
#ifndef __OPENSPACE_CORE___PATHHELPERFUNCTIONS___H__
#define __OPENSPACE_CORE___PATHHELPERFUNCTIONS___H__
#include <ghoul/glm.h>
#include <ghoul/logging/logmanager.h>
#include <ghoul/misc/assert.h>
#include <algorithm>
#include <cmath>
#include <functional>
#include <vector>
namespace openspace::helpers {
// Make interpolator parameter t [0,1] progress only inside a subinterval
double shiftAndScale(double t, double newStart, double newEnd);
/*
* Compute a quaternion that represents the rotation looking from \p eye to
* \p center, with the specified \p up direction
*/
glm::dquat lookAtQuaternion(glm::dvec3 eye, glm::dvec3 center, glm::dvec3 up);
/*
* Compute a view direction vector from a quaternion representing a rotation
*/
glm::dvec3 viewDirection(const glm::dquat& q);
/*
* Calculate the intersection of a line and a sphere.
* The line segment is defined from \p p1 to \p p2.
* The sphere is defined by the radius \p r and center point \p center.
* The resulting intersection point is stored in the \p intersectionPoint parameter.
*
* In the case of two intersection points, only care anout the first one.
*
* \return True if the line between \p p1 and \p p2 intersects the sphere given by
* \p r and \p center, and false otherwise
*/
bool lineSphereIntersection(glm::dvec3 p1, glm::dvec3 p2, glm::dvec3 center,
double r, glm::dvec3& intersectionPoint);
/*
* Check if the point p is inside of the sphere defined by radius r and center
* point c
*/
bool isPointInsideSphere(const glm::dvec3& p, const glm::dvec3& c, double r);
/*
* Approximate integral of function f over inteval [t0, t1] using Simpson's rule.
* The integer n is the number of partitions and must be an even number.
*/
double simpsonsRule(double t0, double t1, int n, std::function<double(double)> f);
/*
* Approximate integral of function f over inteval [t0, t1] using
* 5-point Gauss-Legendre quadrature
* https://en.wikipedia.org/wiki/Gaussian_quadrature
*/
double fivePointGaussianQuadrature(double t0, double t1,
std::function<double(double)> f);
} // namespace openspace::helpers
namespace openspace::splines {
// TODO: Move these to ghoul's interpolator file (and make template versions)
/*
* Catmull-Rom curve interpolation based on implementation by Mika Rantanen
* https://qroph.github.io/2018/07/30/smooth-paths-using-catmull-rom-splines.html
* Centripetal version alpha = 0, uniform for alpha = 0.5 and chordal for alpha = 1
*/
glm::dvec3 catmullRom(double t, const glm::dvec3& p0, const glm::dvec3& p1,
const glm::dvec3& p2, const glm::dvec3& p3, double alpha = 0.5);
/*
* Compute the interpolation along the cubic Bézier curve defined by the points p0,
* p1, p2, and p3. The curve will pass through p0 and p3
*/
glm::dvec3 cubicBezier(double t, const glm::dvec3& p0, const glm::dvec3& p1,
const glm::dvec3& p2, const glm::dvec3& p3);
glm::dvec3 linear(double t, const glm::dvec3& cp1, const glm::dvec3& cp2);
} // namespace openspace::splines
#endif // __OPENSPACE_CORE___PATHHELPERFUNCTIONS___H__

View File

@@ -0,0 +1,59 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2021 *
* *
* 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. *
****************************************************************************************/
#ifndef __OPENSPACE_CORE___COLLISIONHELPER___H__
#define __OPENSPACE_CORE___COLLISIONHELPER___H__
#include <ghoul/glm.h>
namespace openspace::collision {
/*
* Calculate the intersection of a line segment and a sphere.
* The line segment is defined from \p p1 to \p p2.
* The sphere is defined by the radius \p r and center point \p center.
* The resulting intersection point is stored in the \p intersectionPoint parameter.
*
* In the case of two intersection points, only care about the first one.
*
* \param p1 The start point for the line segment
* \param p2 The end point for the line segment
* \param center The center point for the sphere
* \param r The radius of the sphere
* \param intersectionPoint A variable to store the resulting intersection point in
* \return True if the line between \p p1 and \p p2 intersects the sphere given by
* \p r and \p center, and false otherwise
*/
bool lineSphereIntersection(glm::dvec3 p1, glm::dvec3 p2, glm::dvec3 center,
double r, glm::dvec3& intersectionPoint);
/*
* Check if the point \p p is inside of the sphere defined by radius \p r and center
* point \p c
*/
bool isPointInsideSphere(const glm::dvec3& p, const glm::dvec3& c, double r);
} // namespace openspace::collision
#endif // __OPENSPACE_CORE___COLLISIONHELPER___H__

View File

@@ -0,0 +1,48 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2021 *
* *
* 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. *
****************************************************************************************/
#ifndef __OPENSPACE_CORE___UNIVERSALHELPERS___H__
#define __OPENSPACE_CORE___UNIVERSALHELPERS___H__
/*
* This file is meant to contain generally useful functions that is used a bit all over
* the place but that do not belong in any other, more specific, file.
*
* If you implement a function that can be useful in several other situations, feel free
* to document it and put it this file
*/
namespace openspace::helpers {
/*
* Remap a parameter t in [0,1] to a subinterval [start, end], by shifting and scaling
* the value to match the interval. If \p t is smaller than \p start, the return value
* will be 0 and if bigger than \p end it will be 1. Other values will be linearly
* interpolated within the range [start, end]
*/
double shiftAndScale(double t, double start, double end);
} // namespace openspace::helpers
#endif // __OPENSPACE_CORE___UNIVERSALHELPERS___H__

View File

@@ -73,7 +73,6 @@ set(OPENSPACE_SOURCE
${OPENSPACE_BASE_DIR}/src/navigation/orbitalnavigator.cpp
${OPENSPACE_BASE_DIR}/src/navigation/path.cpp
${OPENSPACE_BASE_DIR}/src/navigation/pathcurve.cpp
${OPENSPACE_BASE_DIR}/src/navigation/pathhelperfunctions.cpp
${OPENSPACE_BASE_DIR}/src/navigation/pathnavigator.cpp
${OPENSPACE_BASE_DIR}/src/navigation/pathnavigator_lua.inl
${OPENSPACE_BASE_DIR}/src/navigation/waypoint.cpp
@@ -161,6 +160,7 @@ set(OPENSPACE_SOURCE
${OPENSPACE_BASE_DIR}/src/scripting/systemcapabilitiesbinding.cpp
${OPENSPACE_BASE_DIR}/src/util/blockplaneintersectiongeometry.cpp
${OPENSPACE_BASE_DIR}/src/util/boxgeometry.cpp
${OPENSPACE_BASE_DIR}/src/util/collisionhelper.cpp
${OPENSPACE_BASE_DIR}/src/util/coordinateconversion.cpp
${OPENSPACE_BASE_DIR}/src/util/distanceconversion.cpp
${OPENSPACE_BASE_DIR}/src/util/factorymanager.cpp
@@ -189,6 +189,7 @@ set(OPENSPACE_SOURCE
${OPENSPACE_BASE_DIR}/src/util/timerange.cpp
${OPENSPACE_BASE_DIR}/src/util/touch.cpp
${OPENSPACE_BASE_DIR}/src/util/transformationmanager.cpp
${OPENSPACE_BASE_DIR}/src/util/universalhelpers.cpp
${OPENSPACE_BASE_DIR}/src/util/versionchecker.cpp
)
@@ -253,7 +254,6 @@ set(OPENSPACE_HEADER
${OPENSPACE_BASE_DIR}/include/openspace/navigation/orbitalnavigator.h
${OPENSPACE_BASE_DIR}/include/openspace/navigation/path.h
${OPENSPACE_BASE_DIR}/include/openspace/navigation/pathcurve.h
${OPENSPACE_BASE_DIR}/include/openspace/navigation/pathhelperfunctions.h
${OPENSPACE_BASE_DIR}/include/openspace/navigation/pathnavigator.h
${OPENSPACE_BASE_DIR}/include/openspace/navigation/waypoint.h
${OPENSPACE_BASE_DIR}/include/openspace/network/parallelconnection.h
@@ -344,6 +344,7 @@ set(OPENSPACE_HEADER
${OPENSPACE_BASE_DIR}/include/openspace/scripting/systemcapabilitiesbinding.h
${OPENSPACE_BASE_DIR}/include/openspace/util/blockplaneintersectiongeometry.h
${OPENSPACE_BASE_DIR}/include/openspace/util/boxgeometry.h
${OPENSPACE_BASE_DIR}/include/openspace/util/collisionhelper.h
${OPENSPACE_BASE_DIR}/include/openspace/util/concurrentjobmanager.h
${OPENSPACE_BASE_DIR}/include/openspace/util/concurrentjobmanager.inl
${OPENSPACE_BASE_DIR}/include/openspace/util/concurrentqueue.h
@@ -382,6 +383,7 @@ set(OPENSPACE_HEADER
${OPENSPACE_BASE_DIR}/include/openspace/util/timemanager.h
${OPENSPACE_BASE_DIR}/include/openspace/util/timerange.h
${OPENSPACE_BASE_DIR}/include/openspace/util/touch.h
${OPENSPACE_BASE_DIR}/include/openspace/util/universalhelpers.h
${OPENSPACE_BASE_DIR}/include/openspace/util/updatestructures.h
${OPENSPACE_BASE_DIR}/include/openspace/util/versionchecker.h
${OPENSPACE_BASE_DIR}/include/openspace/util/transformationmanager.h

View File

@@ -24,7 +24,6 @@
#include <openspace/camera/camerapose.h>
#include <openspace/navigation/orbitalnavigator.h>
#include <openspace/navigation/pathhelperfunctions.h>
#include <openspace/scene/scenegraphnode.h>
#include <openspace/util/updatestructures.h>
#include <openspace/query/query.h>
@@ -854,7 +853,7 @@ OrbitalNavigator::CameraRotationDecomposition
const SceneGraphNode& reference)
{
const glm::dvec3 cameraUp = cameraPose.rotation * Camera::UpDirectionCameraSpace;
const glm::dvec3 cameraViewDirection = helpers::viewDirection(cameraPose.rotation);
const glm::dvec3 cameraViewDirection = ghoul::viewDirection(cameraPose.rotation);
const glm::dmat4 modelTransform = reference.modelTransform();
const glm::dmat4 inverseModelTransform = glm::inverse(modelTransform);
@@ -871,7 +870,7 @@ OrbitalNavigator::CameraRotationDecomposition
);
// To avoid problem with lookup in up direction we adjust is with the view direction
const glm::dquat globalCameraRotation = helpers::lookAtQuaternion(
const glm::dquat globalCameraRotation = ghoul::lookAtQuaternion(
glm::dvec3(0.0),
-directionFromSurfaceToCamera,
normalize(cameraViewDirection + cameraUp)
@@ -888,10 +887,10 @@ OrbitalNavigator::CameraRotationDecomposition
glm::dvec3 reference)
{
const glm::dvec3 cameraUp = cameraPose.rotation * glm::dvec3(0.0, 1.0, 0.0);
const glm::dvec3 cameraViewDirection = helpers::viewDirection(cameraPose.rotation);
const glm::dvec3 cameraViewDirection = ghoul::viewDirection(cameraPose.rotation);
// To avoid problem with lookup in up direction we adjust is with the view direction
const glm::dquat globalCameraRotation = helpers::lookAtQuaternion(
const glm::dquat globalCameraRotation = ghoul::lookAtQuaternion(
glm::dvec3(0.0),
reference - cameraPose.position,
normalize(cameraViewDirection + cameraUp)
@@ -1068,7 +1067,7 @@ glm::dquat OrbitalNavigator::interpolateLocalRotation(double deltaTime,
const glm::dvec3 localUp =
localCameraRotation * Camera::UpDirectionCameraSpace;
const glm::dquat targetRotation = helpers::lookAtQuaternion(
const glm::dquat targetRotation = ghoul::lookAtQuaternion(
glm::dvec3(0.0),
Camera::ViewDirectionCameraSpace,
normalize(localUp)
@@ -1299,7 +1298,7 @@ glm::dquat OrbitalNavigator::rotateGlobally(const glm::dquat& globalCameraRotati
const glm::dvec3 cameraUpWhenFacingSurface = glm::inverse(focusNodeRotationDiff) *
globalCameraRotation * Camera::UpDirectionCameraSpace;
return helpers::lookAtQuaternion(
return ghoul::lookAtQuaternion(
glm::dvec3(0.0),
-directionFromSurfaceToCamera,
cameraUpWhenFacingSurface

View File

@@ -32,10 +32,11 @@
#include <openspace/navigation/pathcurve.h>
#include <openspace/navigation/pathcurves/avoidcollisioncurve.h>
#include <openspace/navigation/pathcurves/zoomoutoverviewcurve.h>
#include <openspace/navigation/pathhelperfunctions.h>
#include <openspace/navigation/pathnavigator.h>
#include <openspace/scene/scenegraphnode.h>
#include <openspace/query/query.h>
#include <openspace/util/collisionhelper.h>
#include <openspace/util/universalhelpers.h>
#include <ghoul/logging/logmanager.h>
#include <ghoul/misc/interpolator.h>
@@ -198,7 +199,7 @@ glm::dquat Path::lookAtTargetsRotation(double t) const {
if (t < t1) {
// Compute a position in front of the camera at the start orientation
const double inFrontDistance = glm::distance(startPos, startNodePos);
const glm::dvec3 viewDir = helpers::viewDirection(_start.rotation());
const glm::dvec3 viewDir = ghoul::viewDirection(_start.rotation());
const glm::dvec3 inFrontOfStart = startPos + inFrontDistance * viewDir;
const double tScaled = ghoul::cubicEaseInOut(t / t1);
@@ -212,7 +213,7 @@ glm::dquat Path::lookAtTargetsRotation(double t) const {
else if (t > t2) {
// Compute a position in front of the camera at the end orientation
const double inFrontDistance = glm::distance(endPos, endNodePos);
const glm::dvec3 viewDir = helpers::viewDirection(_end.rotation());
const glm::dvec3 viewDir = ghoul::viewDirection(_end.rotation());
const glm::dvec3 inFrontOfEnd = endPos + inFrontDistance * viewDir;
const double tScaled = ghoul::cubicEaseInOut((t - t2) / (1.0 - t2));
@@ -227,7 +228,7 @@ glm::dquat Path::lookAtTargetsRotation(double t) const {
tUp = ghoul::sineEaseInOut(tUp);
glm::dvec3 up = ghoul::interpolateLinear(tUp, startUp, endUp);
return helpers::lookAtQuaternion(_curve->positionAt(t), lookAtPos, up);
return ghoul::lookAtQuaternion(_curve->positionAt(t), lookAtPos, up);
}
double Path::speedAlongPath(double traveledDistance) {
@@ -303,7 +304,7 @@ SceneGraphNode* findNodeNearTarget(const SceneGraphNode* node) {
const glm::dvec3 posInModelCoords =
glm::inverse(n->modelTransform()) * glm::dvec4(node->worldPosition(), 1.0);
bool isClose = helpers::isPointInsideSphere(
bool isClose = collision::isPointInsideSphere(
posInModelCoords,
glm::dvec3(0.0, 0.0, 0.0),
proximityRadius
@@ -317,19 +318,19 @@ SceneGraphNode* findNodeNearTarget(const SceneGraphNode* node) {
return nullptr;
}
// Compute a target position close to the specified target node, using knowledge of
// Compute a target position close to the specified target node, using knowledge of
// the start point and a desired distance from the node's center
glm::dvec3 computeGoodStepDirection(const SceneGraphNode* targetNode,
glm::dvec3 computeGoodStepDirection(const SceneGraphNode* targetNode,
const Waypoint& startPoint)
{
const glm::dvec3 nodePos = targetNode->worldPosition();
const SceneGraphNode* closeNode = findNodeNearTarget(targetNode);
const SceneGraphNode* sun = sceneGraphNode(SunIdentifier);
// @TODO (2021-07-09, emmbr): Not nice to depend on a specific scene graph node,
// as it might not exist. Ideally, each SGN could know about their preferred
// direction to be viewed from (their "good side"), and then that could be queried
// and used instead.
// @TODO (2021-07-09, emmbr): Not nice to depend on a specific scene graph node,
// as it might not exist. Ideally, each SGN could know about their preferred
// direction to be viewed from (their "good side"), and then that could be queried
// and used instead.
if (closeNode) {
// If the node is close to another node in the scene, set the direction in a way
// that minimizes risk of collision
@@ -378,7 +379,7 @@ Waypoint computeWaypointFromNodeInfo(const NodeInfo& info, const Waypoint& start
glm::dvec3 targetPos;
if (info.position.has_value()) {
// The position in instruction is given in the targetNode's local coordinates.
// The position in instruction is given in the targetNode's local coordinates.
// Convert to world coordinates
targetPos = glm::dmat3(targetNode->modelTransform()) * info.position.value();
}
@@ -402,7 +403,7 @@ Waypoint computeWaypointFromNodeInfo(const NodeInfo& info, const Waypoint& start
// Compute rotation so the camera is looking at the targetted node
const glm::dvec3 lookAtPos = targetNode->worldPosition();
const glm::dquat targetRot = helpers::lookAtQuaternion(targetPos, lookAtPos, up);
const glm::dquat targetRot = ghoul::lookAtQuaternion(targetPos, lookAtPos, up);
return Waypoint(targetPos, targetRot, info.identifier);
}

View File

@@ -24,11 +24,12 @@
#include <openspace/navigation/pathcurve.h>
#include <openspace/navigation/pathhelperfunctions.h>
#include <openspace/navigation/waypoint.h>
#include <openspace/query/query.h>
#include <openspace/scene/scenegraphnode.h>
#include <ghoul/logging/logmanager.h>
#include <ghoul/misc/integration.h>
#include <ghoul/misc/interpolator.h>
#include <glm/gtx/projection.hpp>
#include <algorithm>
#include <vector>
@@ -188,7 +189,7 @@ double PathCurve::arcLength(double limit) {
}
double PathCurve::arcLength(double lowerLimit, double upperLimit) {
return helpers::fivePointGaussianQuadrature(
return ghoul::integrateGaussianQuadrature<double>(
lowerLimit,
upperLimit,
[this](double u) { return approximatedDerivative(u); }
@@ -196,7 +197,7 @@ double PathCurve::arcLength(double lowerLimit, double upperLimit) {
}
glm::dvec3 PathCurve::interpolate(double u) {
ghoul_assert(u >= 0 && u <= 1.0, "Interpolation variable out of range [0, 1]");
ghoul_assert(u >= 0 && u <= 1.0, "Interpolation variable must be in range [0,1]");
if (u < 0.0) {
return _points[1];
@@ -208,14 +209,14 @@ glm::dvec3 PathCurve::interpolate(double u) {
std::vector<double>::iterator segmentEndIt =
std::lower_bound(_curveParameterSteps.begin(), _curveParameterSteps.end(), u);
const int index =
const int index =
static_cast<int>((segmentEndIt - 1) - _curveParameterSteps.begin());
double segmentStart = _curveParameterSteps[index];
double segmentDuration = (_curveParameterSteps[index + 1] - segmentStart);
double uSegment = (u - segmentStart) / segmentDuration;
return splines::catmullRom(
return ghoul::interpolateCatmullRom(
uSegment,
_points[index],
_points[index + 1],

View File

@@ -27,11 +27,11 @@
#include <openspace/engine/globals.h>
#include <openspace/engine/moduleengine.h>
#include <openspace/navigation/navigationhandler.h>
#include <openspace/navigation/pathhelperfunctions.h>
#include <openspace/navigation/pathnavigator.h>
#include <openspace/navigation/waypoint.h>
#include <openspace/query/query.h>
#include <openspace/scene/scenegraphnode.h>
#include <openspace/util/collisionhelper.h>
#include <ghoul/logging/logmanager.h>
#include <glm/gtx/projection.hpp>
#include <algorithm>
@@ -60,7 +60,7 @@ AvoidCollisionCurve::AvoidCollisionCurve(const Waypoint& start, const Waypoint&
const glm::dvec3 endNodeCenter = end.node()->worldPosition();
const double startNodeRadius = start.validBoundingSphere();
const double endNodeRadius = end.validBoundingSphere();
const glm::dvec3 startViewDir = helpers::viewDirection(start.rotation());
const glm::dvec3 startViewDir = ghoul::viewDirection(start.rotation());
// Add control points for a catmull-rom spline, first and last will not be intersected
_points.push_back(start.position());
@@ -83,7 +83,7 @@ AvoidCollisionCurve::AvoidCollisionCurve(const Waypoint& start, const Waypoint&
if (targetInOppositeDirection) {
const glm::dquat midleRot = glm::slerp(start.rotation(), end.rotation(), 0.5);
const glm::dvec3 middleViewDir = helpers::viewDirection(midleRot);
const glm::dvec3 middleViewDir = ghoul::viewDirection(midleRot);
const double stepOutDistance = 0.4 * glm::length(startToEnd);
glm::dvec3 newPos = start.position() + 0.2 * startToEnd -
@@ -137,14 +137,14 @@ void AvoidCollisionCurve::removeCollisions(int step) {
// Add a buffer to avoid passing too close to the node.
// Dont't add it if any point is inside the buffer
double buffer = CollisionBufferSizeRadiusMultiplier * radius;
bool p1IsInside = helpers::isPointInsideSphere(p1, center, radius + buffer);
bool p2IsInside = helpers::isPointInsideSphere(p2, center, radius + buffer);
bool p1IsInside = collision::isPointInsideSphere(p1, center, radius + buffer);
bool p2IsInside = collision::isPointInsideSphere(p2, center, radius + buffer);
if (!p1IsInside && !p2IsInside) {
radius += buffer;
}
glm::dvec3 intersectionPointModelCoords;
bool collision = helpers::lineSphereIntersection(
bool collision = collision::lineSphereIntersection(
p1,
p2,
center,
@@ -157,8 +157,8 @@ void AvoidCollisionCurve::removeCollisions(int step) {
glm::dvec4(intersectionPointModelCoords, 1.0);
// before collision response, make sure none of the points are inside the node
bool isStartInsideNode = helpers::isPointInsideSphere(p1, center, radius);
bool isEndInsideNode = helpers::isPointInsideSphere(p2, center, radius);
bool isStartInsideNode = collision::isPointInsideSphere(p1, center, radius);
bool isEndInsideNode = collision::isPointInsideSphere(p2, center, radius);
if (isStartInsideNode || isEndInsideNode) {
LWARNING(fmt::format(
"Something went wrong! "
@@ -177,7 +177,7 @@ void AvoidCollisionCurve::removeCollisions(int step) {
const glm::dvec3 parallell = glm::proj(collisionPointToCenter, lineDirection);
const glm::dvec3 orthogonal = collisionPointToCenter - parallell;
const double avoidCollisionDistance =
const double avoidCollisionDistance =
AvoidCollisionDistanceRadiusMultiplier * radius;
glm::dvec3 extraKnot = collisionPoint -

View File

@@ -26,7 +26,6 @@
#include <openspace/engine/globals.h>
#include <openspace/engine/moduleengine.h>
#include <openspace/navigation/pathhelperfunctions.h>
#include <openspace/navigation/waypoint.h>
#include <openspace/query/query.h>
#include <openspace/scene/scenegraphnode.h>
@@ -48,7 +47,7 @@ ZoomOutOverviewCurve::ZoomOutOverviewCurve(const Waypoint& start, const Waypoint
if (!start.node() || !end.node()) { // guard, but should never happen
LERROR("Something went wrong. The start or end node does not exist");
return;
return;
}
const double endTangentsLengthFactor = 2.0;
@@ -73,7 +72,7 @@ ZoomOutOverviewCurve::ZoomOutOverviewCurve(const Waypoint& start, const Waypoint
// Decide the step direction for the "overview point" based on the directions
// at the start and end of the path, to try to get a nice curve shape
glm::dvec3 goodStepDirection;
if (glm::dot(n1, n2) < 0.0) {
if (glm::dot(n1, n2) < 0.0) {
// Facing in different directions => step in direction of the cross product
goodStepDirection = glm::normalize(glm::cross(-n1, n2));
}
@@ -83,13 +82,13 @@ ZoomOutOverviewCurve::ZoomOutOverviewCurve(const Waypoint& start, const Waypoint
// Find a direction that is orthogonal to the line between the start and end position
const glm::dvec3 startPosToEndPos = end.position() - start.position();
const glm::dvec3 outwardStepVector =
const glm::dvec3 outwardStepVector =
0.5 * glm::length(startPosToEndPos) * goodStepDirection;
const glm::dvec3 projectedVec = glm::proj(outwardStepVector, startPosToEndPos);
const glm::dvec3 orthogonalComponent = outwardStepVector - projectedVec;
const glm::dvec3 stepDirection = glm::normalize(orthogonalComponent);
// Step half-way along the line between the position and then orthogonally
const glm::dvec3 extraKnot = start.position() + 0.5 * startPosToEndPos
+ 1.5 * glm::length(startPosToEndPos) * stepDirection;

View File

@@ -1,202 +0,0 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2021 *
* *
* 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 <openspace/navigation/pathhelperfunctions.h>
#include <ghoul/logging/logmanager.h>
#include <ghoul/misc/easing.h>
namespace {
constexpr const char* _loggerCat = "Helpers";
} // namespace
namespace openspace::helpers {
// Shift and scale to a subinterval [start,end]
double shiftAndScale(double t, double start, double end) {
ghoul_assert(0.0 < start && start < end && end < 1.0,
"Values must be 0.0 < start < end < 1.0!");
double tScaled = t / (end - start) - start;
return std::max(0.0, std::min(tScaled, 1.0));
}
glm::dquat lookAtQuaternion(glm::dvec3 eye, glm::dvec3 center, glm::dvec3 up) {
glm::dmat4 lookAtMat = glm::lookAt(eye, center, up);
return glm::normalize(glm::inverse(glm::quat_cast(lookAtMat)));
}
glm::dvec3 viewDirection(const glm::dquat& q) {
return glm::normalize(q * glm::dvec3(0.0, 0.0, -1.0));
};
/*
* Source: http://paulbourke.net/geometry/circlesphere/raysphere.c
*/
bool lineSphereIntersection(glm::dvec3 p1, glm::dvec3 p2, glm::dvec3 center,
double r, glm::dvec3& intersectionPoint)
{
long double a, b, c;
glm::dvec3 dp = p2 - p1;
a = dp.x * dp.x + dp.y * dp.y + dp.z * dp.z;
b = 2.0 * (dp.x * (p1.x - center.x) + dp.y * (p1.y - center.y) +
dp.z * (p1.z - center.z));
c = center.x * center.x + center.y * center.y + center.z * center.z;
c += p1.x * p1.x + p1.y * p1.y + p1.z * p1.z;
c -= 2.0 * (center.x * p1.x + center.y * p1.y + center.z * p1.z);
c -= r * r;
long double intersectionTest = b * b - 4.0 * a * c;
// No intersection
if (std::abs(a) < 0 || intersectionTest < 0.0) {
return false;
}
// Intersection
else {
// Only care about the first intersection point if we have two
const double t = (-b - std::sqrt(intersectionTest)) / (2.0 *a);
// Check if utside of line segment between p1 and p2
if (t <= 0 || t >= 1.0) {
return false;
}
intersectionPoint = p1 + t * dp;
return true;
}
}
bool isPointInsideSphere(const glm::dvec3& p, const glm::dvec3& c, double r) {
const glm::dvec3 v = c - p;
const long double squaredDistance = v.x * v.x + v.y * v.y + v.z * v.z;
const long double squaredRadius = r * r;
return (squaredDistance <= squaredRadius);
}
double simpsonsRule(double t0, double t1, int n, std::function<double(double)> f) {
ghoul_assert(n % 2 == 0, "n must be an even number");
ghoul_assert(n >= 2, "Number of partitions, n, must be at least 2");
const double h = (t1 - t0) / static_cast<double>(n);
const double endpoints = f(t0) + f(t1);
double times4 = 0.0;
double times2 = 0.0;
// weight 4
for (int i = 1; i < n; i += 2) {
double t = t0 + i * h;
times4 += f(t);
}
// weight 2
for (int i = 2; i < n; i += 2) {
double t = t0 + i * h;
times2 += f(t);
}
return (h / 3) * (endpoints + 4 * times4 + 2 * times2);
}
double fivePointGaussianQuadrature(double t0, double t1,
std::function<double(double)> f)
{
struct GaussLengendreCoefficient {
double abscissa; // xi
double weight; // wi
};
static constexpr GaussLengendreCoefficient coefficients[] = {
{ 0.0, 0.5688889 },
{ -0.5384693, 0.47862867 },
{ 0.5384693, 0.47862867 },
{ -0.90617985, 0.23692688 },
{ 0.90617985, 0.23692688 }
};
const double a = t0;
const double b = t1;
double sum = 0.0;
for (auto coefficient : coefficients) {
// change of interval to [a, b] from [-1, 1] (also 0.5 * (b - a) below)
double const t = 0.5 * ((b - a) * coefficient.abscissa + (b + a));
sum += f(t) * coefficient.weight;
}
return 0.5 * (b - a) * sum;
}
} // namespace openspace::helpers
namespace openspace::splines {
// Based on implementation by Mika Rantanen, but without tension
// https://qroph.github.io/2018/07/30/smooth-paths-using-catmull-rom-splines.html
glm::dvec3 catmullRom(double t, const glm::dvec3& p0, const glm::dvec3& p1,
const glm::dvec3& p2, const glm::dvec3& p3, double alpha)
{
ghoul_assert(t >= 0 && t <= 1.0, "Interpolation variable out of range [0, 1]");
double t01 = std::pow(glm::distance(p0, p1), alpha);
double t12 = std::pow(glm::distance(p1, p2), alpha);
double t23 = std::pow(glm::distance(p2, p3), alpha);
constexpr const double Epsilon = 1E-7;
const glm::dvec3 zero = glm::dvec3(0.0);
glm::dvec3 m01 = (t01 > Epsilon) ? (p1 - p0) / t01 : zero;
glm::dvec3 m23 = (t23 > Epsilon) ? (p3 - p2) / t23 : zero;
glm::dvec3 m02 = (t01 + t12 > Epsilon) ? (p2 - p0) / (t01 + t12) : zero;
glm::dvec3 m13 = (t12 + t23 > Epsilon) ? (p3 - p1) / (t12 + t23) : zero;
glm::dvec3 m1 = p2 - p1 + t12 * (m01 - m02);
glm::dvec3 m2 = p2 - p1 + t12 * (m23 - m13);
glm::dvec3 a = 2.0 * (p1 - p2) + m1 + m2;
glm::dvec3 b = -3.0 * (p1 - p2) - m1 - m1 - m2;
glm::dvec3 c = m1;
glm::dvec3 d = p1;
return a * t * t * t
+ b * t * t
+ c * t
+ d;
}
glm::dvec3 cubicBezier(double t, const glm::dvec3& p0, const glm::dvec3& p1,
const glm::dvec3& p2, const glm::dvec3& p3)
{
ghoul_assert(t >= 0 && t <= 1.0, "Interpolation variable out of range [0, 1]");
double a = 1.0 - t;
return p0 * a * a * a
+ p1 * t * a * a * 3.0
+ p2 * t * t * a * 3.0
+ p3 * t * t * t;
}
glm::dvec3 linear(double t, const glm::dvec3 &cp1, const glm::dvec3 &cp2) {
ghoul_assert(t >= 0 && t <= 1.0, "Interpolation variable out of range [0, 1]");
return cp1 * (1.0 - t) + cp2 * t;
}
} // namespace openspace::splines

View File

@@ -29,7 +29,6 @@
#include <openspace/engine/globals.h>
#include <openspace/interaction/sessionrecording.h>
#include <openspace/navigation/navigationhandler.h>
#include <openspace/navigation/pathhelperfunctions.h>
#include <openspace/rendering/renderengine.h>
#include <openspace/scene/scene.h>
#include <openspace/scene/scenegraphnode.h>
@@ -61,8 +60,8 @@ namespace {
"A camera motion behavior that is applied when no path is being played"
};
constexpr openspace::properties::Property::PropertyInfo
ApplyStopBehaviorWhenIdleInfo =
constexpr openspace::properties::Property::PropertyInfo
ApplyStopBehaviorWhenIdleInfo =
{
"ApplyStopBehaviorWhenIdle",
"Apply Stop Behavior When Idle",
@@ -107,12 +106,12 @@ namespace openspace::interaction {
PathNavigator::PathNavigator()
: properties::PropertyOwner({ "PathNavigator" })
, _defaultCurveOption(
DefaultCurveOptionInfo,
DefaultCurveOptionInfo,
properties::OptionProperty::DisplayType::Dropdown
)
, _includeRoll(IncludeRollInfo, false)
, _stopBehavior(
StopBehaviorInfo,
StopBehaviorInfo,
properties::OptionProperty::DisplayType::Dropdown
)
, _applyStopBehaviorWhenIdle(ApplyStopBehaviorWhenIdleInfo, false)
@@ -203,7 +202,7 @@ void PathNavigator::updateCamera(double deltaTime) {
return;
}
// Prevent long delta times due to e.g. computations from other actions to cause
// Prevent long delta times due to e.g. computations from other actions to cause
// really big jumps in the motion along the path
// OBS! Causes problems if the general FPS is lower than 10, but then the user should
// probably not use the camera paths anyways
@@ -388,7 +387,7 @@ void PathNavigator::removeRollRotation(CameraPose& pose, double deltaTime) {
const double anchorToPosDistance = glm::distance(anchorPos, pose.position);
const double notTooCloseDistance = deltaTime * anchorToPosDistance;
glm::dvec3 lookAtPos = pose.position + notTooCloseDistance * cameraDir;
glm::dquat rollFreeRotation = helpers::lookAtQuaternion(
glm::dquat rollFreeRotation = ghoul::lookAtQuaternion(
pose.position,
lookAtPos,
camera()->lookUpVectorWorldSpace()
@@ -414,7 +413,7 @@ void PathNavigator::orbitAnchorNode(double deltaTime) {
const glm::dvec3 prevPosition = camera()->positionVec3();
const glm::dquat prevRotation = camera()->rotationQuaternion();
const glm::dvec3 nodeCenter = anchor()->worldPosition();
const glm::dvec3 nodeCenter = anchor()->worldPosition();
const double speedFactor = 0.1 * _orbitSpeedFactor;
@@ -425,7 +424,7 @@ void PathNavigator::orbitAnchorNode(double deltaTime) {
// Compute a new position along the orbit
const glm::dvec3 up = camera()->lookUpVectorWorldSpace();
const glm::dquat lookAtNodeRotation = helpers::lookAtQuaternion(
const glm::dquat lookAtNodeRotation = ghoul::lookAtQuaternion(
prevPosition,
nodeCenter,
up
@@ -444,7 +443,7 @@ void PathNavigator::orbitAnchorNode(double deltaTime) {
// Rotate along the orbit, but keep relative orientation with regards to the anchor
const glm::dquat localRotation = glm::inverse(lookAtNodeRotation) * prevRotation;
const glm::dquat newLookAtRotation =
helpers::lookAtQuaternion(newPosition, nodeCenter, up);
ghoul::lookAtQuaternion(newPosition, nodeCenter, up);
const glm::dquat newRotation = newLookAtRotation * localRotation;

View File

@@ -0,0 +1,75 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2021 *
* *
* 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 <openspace/util/collisionhelper.h>
namespace openspace::collision {
// Source: http://paulbourke.net/geometry/circlesphere/raysphere.c
bool lineSphereIntersection(glm::dvec3 p1, glm::dvec3 p2, glm::dvec3 center,
double r, glm::dvec3& intersectionPoint)
{
long double a, b, c;
const glm::dvec3 diffp = p2 - p1;
a = diffp.x * diffp.x + diffp.y * diffp.y + diffp.z * diffp.z;
b = 2.0 * (diffp.x * (p1.x - center.x) + diffp.y * (p1.y - center.y) +
diffp.z * (p1.z - center.z));
c = center.x * center.x + center.y * center.y + center.z * center.z;
c += p1.x * p1.x + p1.y * p1.y + p1.z * p1.z;
c -= 2.0 * (center.x * p1.x + center.y * p1.y + center.z * p1.z);
c -= r * r;
long double intersectionTest = b * b - 4.0 * a * c;
// No intersection
if (std::abs(a) < 0 || intersectionTest < 0.0) {
return false;
}
// Intersection
else {
// Only care about the first intersection point if we have two
const double t = static_cast<double>(
(-b - std::sqrt(intersectionTest)) / (2.0 * a)
);
// Check if utside of line segment between p1 and p2
if (t <= 0 || t >= 1.0) {
return false;
}
intersectionPoint = p1 + t * diffp;
return true;
}
}
bool isPointInsideSphere(const glm::dvec3& p, const glm::dvec3& c, double r) {
const glm::dvec3 v = c - p;
const long double squaredDistance = v.x * v.x + v.y * v.y + v.z * v.z;
const long double squaredRadius = r * r;
return (squaredDistance <= squaredRadius);
}
} // namespace openspace::collision

View File

@@ -0,0 +1,37 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2021 *
* *
* 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 <openspace/util/universalhelpers.h>
namespace openspace::helpers {
double shiftAndScale(double t, double start, double end) {
ghoul_assert(0.0 < start && start < end && end < 1.0,
"Values must be 0.0 < start < end < 1.0!");
double tScaled = t / (end - start) - start;
return std::max(0.0, std::min(tScaled, 1.0));
}
} // namespace openspace::helpers