mirror of
https://github.com/OpenSpace/OpenSpace.git
synced 2026-03-10 15:28:36 -05:00
Do some restructuring
This commit is contained in:
@@ -29,8 +29,6 @@
|
||||
#include <openspace/engine/globals.h>
|
||||
#include <openspace/engine/windowdelegate.h>
|
||||
#include <openspace/interaction/navigationhandler.h>
|
||||
#include <openspace/rendering/renderengine.h>
|
||||
#include <openspace/scene/scene.h>
|
||||
#include <openspace/scene/scenegraphnode.h>
|
||||
#include <openspace/query/query.h>
|
||||
#include <openspace/util/camera.h>
|
||||
@@ -70,13 +68,6 @@ namespace {
|
||||
"no path is playing."
|
||||
};
|
||||
|
||||
constexpr openspace::properties::Property::PropertyInfo RelevantNodeTagsInfo = {
|
||||
"RelevantNodeTags",
|
||||
"Relevant Node Tags",
|
||||
"List of tags for the nodes that are relevant for path creation, for example "
|
||||
"when avoiding collisions."
|
||||
};
|
||||
|
||||
constexpr openspace::properties::Property::PropertyInfo SpeedScaleInfo = {
|
||||
"SpeedScale",
|
||||
"Speed Scale",
|
||||
@@ -99,7 +90,6 @@ AutoNavigationHandler::AutoNavigationHandler()
|
||||
properties::OptionProperty::DisplayType::Dropdown
|
||||
)
|
||||
, _applyStopBehaviorWhenIdle(ApplyStopBehaviorWhenIdleInfo, false)
|
||||
, _relevantNodeTags(RelevantNodeTagsInfo)
|
||||
, _speedScale(SpeedScaleInfo, 1.f, 0.01f, 2.f)
|
||||
{
|
||||
addPropertySubOwner(_atNodeNavigator);
|
||||
@@ -128,14 +118,6 @@ AutoNavigationHandler::AutoNavigationHandler()
|
||||
);
|
||||
});
|
||||
addProperty(_stopBehavior);
|
||||
|
||||
// Add the relevant tags
|
||||
_relevantNodeTags = std::vector<std::string>{
|
||||
"planet_solarSystem",
|
||||
"moon_solarSystem"
|
||||
};;
|
||||
_relevantNodeTags.onChange([this]() { _relevantNodes = findRelevantNodes(); });
|
||||
addProperty(_relevantNodeTags);
|
||||
}
|
||||
|
||||
AutoNavigationHandler::~AutoNavigationHandler() {} // NOLINT
|
||||
@@ -148,10 +130,6 @@ const SceneGraphNode* AutoNavigationHandler::anchor() const {
|
||||
return global::navigationHandler->anchorNode();
|
||||
}
|
||||
|
||||
const std::vector<SceneGraphNode*>& AutoNavigationHandler::relevantNodes() const {
|
||||
return _relevantNodes;
|
||||
}
|
||||
|
||||
double AutoNavigationHandler::speedScale() const {
|
||||
return _speedScale;
|
||||
}
|
||||
@@ -218,9 +196,6 @@ void AutoNavigationHandler::updateCamera(double deltaTime) {
|
||||
void AutoNavigationHandler::createPath(PathInstruction& instruction) {
|
||||
clearPath();
|
||||
|
||||
// TODO: do this in some initialize function instead
|
||||
_relevantNodes = findRelevantNodes();
|
||||
|
||||
// TODO: Improve how curve types are handled
|
||||
const int curveType = _defaultCurveOption;
|
||||
|
||||
@@ -228,26 +203,16 @@ void AutoNavigationHandler::createPath(PathInstruction& instruction) {
|
||||
Waypoint waypointToAdd;
|
||||
|
||||
if (waypoints.empty()) {
|
||||
if (instruction.type == PathInstruction::Type::Node) {
|
||||
// TODO: allow curves to compute default waypoint instead
|
||||
waypointToAdd = computeDefaultWaypoint(instruction);
|
||||
}
|
||||
else {
|
||||
LWARNING("No path was created from instruction. Failed creating waypoints");
|
||||
return;
|
||||
}
|
||||
LWARNING("No path was created from instruction. Failed creating waypoints");
|
||||
return;
|
||||
}
|
||||
else {
|
||||
// TODO: allow for an instruction to represent a list of waypoints
|
||||
waypointToAdd = waypoints[0];
|
||||
}
|
||||
|
||||
bool hasStartState = instruction.startState.has_value();
|
||||
Waypoint startState = hasStartState ? Waypoint(instruction.startState.value())
|
||||
: waypointFromCamera();
|
||||
|
||||
_currentPath = std::make_unique<Path>(
|
||||
startState,
|
||||
instruction.startPoint,
|
||||
waypointToAdd,
|
||||
CurveType(curveType),
|
||||
instruction.duration
|
||||
@@ -304,14 +269,14 @@ void AutoNavigationHandler::abortPath() {
|
||||
|
||||
// TODO: remove when not needed
|
||||
// Created for debugging
|
||||
std::vector<glm::dvec3> AutoNavigationHandler::curvePositions(int nPerSegment) {
|
||||
std::vector<glm::dvec3> AutoNavigationHandler::curvePositions(int nSteps) const {
|
||||
if (noCurrentPath()) {
|
||||
LERROR("There is no current path to sample points from.");
|
||||
return {};
|
||||
}
|
||||
|
||||
std::vector<glm::dvec3> positions;
|
||||
const double du = 1.0 / nPerSegment;
|
||||
const double du = 1.0 / nSteps;
|
||||
const double length = _currentPath->pathLength();
|
||||
for (double u = 0.0; u < 1.0; u += du) {
|
||||
glm::dvec3 position = _currentPath->interpolatedPose(u * length).position;
|
||||
@@ -324,14 +289,14 @@ std::vector<glm::dvec3> AutoNavigationHandler::curvePositions(int nPerSegment) {
|
||||
|
||||
// TODO: remove when not needed
|
||||
// Created for debugging
|
||||
std::vector<glm::dquat> AutoNavigationHandler::curveOrientations(int nPerSegment) {
|
||||
std::vector<glm::dquat> AutoNavigationHandler::curveOrientations(int nSteps) const {
|
||||
if (noCurrentPath()) {
|
||||
LERROR("There is no current path to sample points from.");
|
||||
return {};
|
||||
}
|
||||
|
||||
std::vector<glm::dquat> orientations;
|
||||
const double du = 1.0 / nPerSegment;
|
||||
const double du = 1.0 / nSteps;
|
||||
const double length = _currentPath->pathLength();
|
||||
for (double u = 0.0; u <= 1.0; u += du) {
|
||||
const glm::dquat orientation =
|
||||
@@ -346,14 +311,14 @@ std::vector<glm::dquat> AutoNavigationHandler::curveOrientations(int nPerSegment
|
||||
|
||||
// TODO: remove when not needed or combined into pose version
|
||||
// Created for debugging
|
||||
std::vector<glm::dvec3> AutoNavigationHandler::curveViewDirections(int nPerSegment) {
|
||||
std::vector<glm::dvec3> AutoNavigationHandler::curveViewDirections(int nSteps) const {
|
||||
if (noCurrentPath()) {
|
||||
LERROR("There is no current path to sample points from.");
|
||||
return {};
|
||||
}
|
||||
|
||||
std::vector<glm::dvec3> viewDirections;
|
||||
const double du = 1.0 / nPerSegment;
|
||||
const double du = 1.0 / nSteps;
|
||||
for (double u = 0.0; u < 1.0; u += du) {
|
||||
const glm::dquat orientation = _currentPath->interpolatedPose(u).rotation;
|
||||
const glm::dvec3 direction = glm::normalize(
|
||||
@@ -373,7 +338,7 @@ std::vector<glm::dvec3> AutoNavigationHandler::curveViewDirections(int nPerSegme
|
||||
|
||||
// TODO: remove when not needed
|
||||
// Created for debugging
|
||||
std::vector<glm::dvec3> AutoNavigationHandler::controlPoints() {
|
||||
std::vector<glm::dvec3> AutoNavigationHandler::controlPoints() const {
|
||||
if (noCurrentPath()) {
|
||||
LERROR("There is no current path to sample points from.");
|
||||
return {};
|
||||
@@ -386,13 +351,6 @@ std::vector<glm::dvec3> AutoNavigationHandler::controlPoints() {
|
||||
return points;
|
||||
}
|
||||
|
||||
Waypoint AutoNavigationHandler::waypointFromCamera() {
|
||||
const glm::dvec3 pos = camera()->positionVec3();
|
||||
const glm::dquat rot = camera()->rotationQuaternion();
|
||||
const std::string node = global::navigationHandler->anchorNode()->identifier();
|
||||
return Waypoint{ pos, rot, node };
|
||||
}
|
||||
|
||||
void AutoNavigationHandler::removeRollRotation(CameraPose& pose, double deltaTime) {
|
||||
const glm::dvec3 anchorPos = anchor()->worldPosition();
|
||||
const glm::dvec3 cameraDir = glm::normalize(
|
||||
@@ -409,136 +367,4 @@ void AutoNavigationHandler::removeRollRotation(CameraPose& pose, double deltaTim
|
||||
pose.rotation = rollFreeRotation;
|
||||
}
|
||||
|
||||
// Test if the node lies within a given proximity radius of any relevant node in the scene
|
||||
SceneGraphNode* AutoNavigationHandler::findNodeNearTarget(const SceneGraphNode* node) {
|
||||
const glm::dvec3 nodePos = node->worldPosition();
|
||||
const std::string nodeId = node->identifier();
|
||||
|
||||
const float proximityRadiusFactor = 3.f;
|
||||
|
||||
for (SceneGraphNode* n : _relevantNodes) {
|
||||
if (n->identifier() == nodeId) {
|
||||
continue;
|
||||
}
|
||||
|
||||
float bs = static_cast<float>(n->boundingSphere());
|
||||
float proximityRadius = proximityRadiusFactor * bs;
|
||||
const glm::dmat4 invModelTransform = glm::inverse(n->modelTransform());
|
||||
const glm::dvec3 posInModelCoords = invModelTransform * glm::dvec4(nodePos, 1.0);
|
||||
|
||||
bool isClose = helpers::isPointInsideSphere(
|
||||
posInModelCoords,
|
||||
glm::dvec3(0.0, 0.0, 0.0),
|
||||
proximityRadius
|
||||
);
|
||||
|
||||
if (isClose) {
|
||||
return n;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// OBS! The desired default waypoint may vary between curve types.
|
||||
// TODO: let the curves update the default position if no exact position is required
|
||||
Waypoint AutoNavigationHandler::computeDefaultWaypoint(const PathInstruction& ins) {
|
||||
const SceneGraphNode* targetNode = sceneGraphNode(ins.nodeIdentifier);
|
||||
if (!targetNode) {
|
||||
LERROR(fmt::format("Could not find target node '{}'", ins.nodeIdentifier));
|
||||
return Waypoint();
|
||||
}
|
||||
|
||||
const float epsilon = 1e-5f;
|
||||
const glm::dvec3 nodePos = targetNode->worldPosition();
|
||||
const glm::dvec3 sunPos = glm::dvec3(0.0, 0.0, 0.0);
|
||||
const SceneGraphNode* closeNode = findNodeNearTarget(targetNode);
|
||||
const glm::dvec3 prevPos = waypointFromCamera().position();
|
||||
|
||||
// Position
|
||||
glm::dvec3 stepDirection;
|
||||
if (closeNode) {
|
||||
// If the node is close to another node in the scene, make sure that the
|
||||
// position is set to minimize risk of collision
|
||||
stepDirection = glm::normalize(nodePos - closeNode->worldPosition());
|
||||
}
|
||||
else if (glm::length(sunPos - nodePos) < epsilon) {
|
||||
// Special case for when the target is the Sun. Assumption: want an overview of
|
||||
// the solar system, and not stay in the orbital plane
|
||||
stepDirection = glm::dvec3(0.0, 0.0, 1.0);
|
||||
}
|
||||
else {
|
||||
// Go to a point that is being lit up by the sun, slightly offsetted from sun
|
||||
// direction
|
||||
const glm::dvec3 targetToPrev = prevPos - nodePos;
|
||||
const glm::dvec3 targetToSun = sunPos - nodePos;
|
||||
|
||||
constexpr const float defaultPositionOffsetAngle = -30.f; // degrees
|
||||
constexpr const float angle = glm::radians(defaultPositionOffsetAngle);
|
||||
const glm::dvec3 axis = glm::normalize(glm::cross(targetToPrev, targetToSun));
|
||||
const glm::dquat offsetRotation = angleAxis(static_cast<double>(angle), axis);
|
||||
|
||||
stepDirection = glm::normalize(offsetRotation * targetToSun);
|
||||
}
|
||||
|
||||
const double radius = Waypoint::findValidBoundingSphere(targetNode);
|
||||
const double defaultHeight = 2.0 * radius;
|
||||
const double height = ins.height.has_value() ? ins.height.value() : defaultHeight;
|
||||
|
||||
const glm::dvec3 targetPos = nodePos + stepDirection * (radius + height);
|
||||
|
||||
// Up direction
|
||||
glm::dvec3 up = camera()->lookUpVectorWorldSpace();
|
||||
if (ins.useTargetUpDirection) {
|
||||
// @TODO (emmbr 2020-11-17) For now, this is hardcoded to look good for Earth,
|
||||
// which is where it matters the most. A better solution would be to make each
|
||||
// sgn aware of its own 'up' and query
|
||||
up = targetNode->worldRotationMatrix() * glm::dvec3(0.0, 0.0, 1.0);
|
||||
}
|
||||
|
||||
// Rotation
|
||||
const glm::dvec3 lookAtPos = targetNode->worldPosition();
|
||||
const glm::dquat targetRot = helpers::lookAtQuaternion(targetPos, lookAtPos, up);
|
||||
|
||||
return Waypoint(targetPos, targetRot, ins.nodeIdentifier);
|
||||
}
|
||||
|
||||
std::vector<SceneGraphNode*> AutoNavigationHandler::findRelevantNodes() {
|
||||
const std::vector<SceneGraphNode*>& allNodes =
|
||||
global::renderEngine->scene()->allSceneGraphNodes();
|
||||
|
||||
const std::vector<std::string> relevantTags = _relevantNodeTags;
|
||||
|
||||
if (allNodes.empty() || relevantTags.empty()) {
|
||||
return std::vector<SceneGraphNode*>();
|
||||
}
|
||||
|
||||
auto isRelevant = [&](const SceneGraphNode* node) {
|
||||
const std::vector<std::string> tags = node->tags();
|
||||
auto result = std::find_first_of(
|
||||
relevantTags.begin(),
|
||||
relevantTags.end(),
|
||||
tags.begin(),
|
||||
tags.end()
|
||||
);
|
||||
|
||||
// does not match any tags => not interesting
|
||||
if (result == relevantTags.end()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return node->renderable() && (node->boundingSphere() > 0.0);
|
||||
};
|
||||
|
||||
std::vector<SceneGraphNode*> resultingNodes;
|
||||
std::copy_if(
|
||||
allNodes.begin(),
|
||||
allNodes.end(),
|
||||
std::back_inserter(resultingNodes),
|
||||
isRelevant
|
||||
);
|
||||
|
||||
return resultingNodes;
|
||||
}
|
||||
|
||||
} // namespace openspace::autonavigation
|
||||
|
||||
@@ -38,7 +38,7 @@ namespace openspace {
|
||||
|
||||
namespace openspace::autonavigation {
|
||||
|
||||
struct Waypoint;
|
||||
//struct Waypoint;
|
||||
struct PathInstruction;
|
||||
|
||||
class AutoNavigationHandler : public properties::PropertyOwner {
|
||||
@@ -49,7 +49,6 @@ public:
|
||||
// Accessors
|
||||
Camera* camera() const;
|
||||
const SceneGraphNode* anchor() const;
|
||||
const std::vector<SceneGraphNode*>& relevantNodes() const;
|
||||
double speedScale() const;
|
||||
|
||||
bool noCurrentPath() const;
|
||||
@@ -65,27 +64,19 @@ public:
|
||||
//void continuePath();
|
||||
|
||||
// TODO: remove functions for debugging
|
||||
std::vector<glm::dvec3> curvePositions(int nPerSegment);
|
||||
std::vector<glm::dquat> curveOrientations(int nPerSegment);
|
||||
std::vector<glm::dvec3> curveViewDirections(int nPerSegment);
|
||||
std::vector<glm::dvec3> controlPoints();
|
||||
std::vector<glm::dvec3> curvePositions(int nSteps) const;
|
||||
std::vector<glm::dquat> curveOrientations(int nSteps) const;
|
||||
std::vector<glm::dvec3> curveViewDirections(int nSteps) const;
|
||||
std::vector<glm::dvec3> controlPoints() const;
|
||||
|
||||
private:
|
||||
Waypoint waypointFromCamera();
|
||||
void removeRollRotation(CameraPose& pose, double deltaTime);
|
||||
|
||||
SceneGraphNode* findNodeNearTarget(const SceneGraphNode* node);
|
||||
Waypoint computeDefaultWaypoint(const PathInstruction& ins);
|
||||
|
||||
std::vector<SceneGraphNode*> findRelevantNodes();
|
||||
|
||||
std::unique_ptr<Path> _currentPath = nullptr;
|
||||
|
||||
AtNodeNavigator _atNodeNavigator;
|
||||
bool _isPlaying = false;
|
||||
|
||||
std::vector<SceneGraphNode*> _relevantNodes;
|
||||
|
||||
properties::OptionProperty _defaultCurveOption;
|
||||
properties::BoolProperty _includeRoll;
|
||||
properties::FloatProperty _speedScale;
|
||||
@@ -94,8 +85,6 @@ private:
|
||||
// TODO: remove later, if it causes problems with regular navigation
|
||||
properties::BoolProperty _applyStopBehaviorWhenIdle;
|
||||
properties::OptionProperty _stopBehavior;
|
||||
|
||||
properties::StringListProperty _relevantNodeTags;
|
||||
};
|
||||
|
||||
} // namespace openspace::autonavigation
|
||||
|
||||
@@ -28,6 +28,8 @@
|
||||
#include <openspace/engine/globals.h>
|
||||
#include <openspace/engine/globalscallbacks.h>
|
||||
#include <openspace/engine/windowdelegate.h>
|
||||
#include <openspace/rendering/renderengine.h>
|
||||
#include <openspace/scene/scene.h>
|
||||
#include <ghoul/logging/logmanager.h>
|
||||
|
||||
namespace {
|
||||
@@ -38,16 +40,33 @@ namespace {
|
||||
"computation of target positions and path generation, to avoid issues when "
|
||||
"there is no bounding sphere."
|
||||
};
|
||||
|
||||
constexpr openspace::properties::Property::PropertyInfo RelevantNodeTagsInfo = {
|
||||
"RelevantNodeTags",
|
||||
"Relevant Node Tags",
|
||||
"List of tags for the nodes that are relevant for path creation, for example "
|
||||
"when avoiding collisions."
|
||||
};
|
||||
} // namespace
|
||||
|
||||
namespace openspace {
|
||||
|
||||
AutoNavigationModule::AutoNavigationModule()
|
||||
: OpenSpaceModule(Name),
|
||||
_minValidBoundingSphere(MinBoundingSphereInfo, 10.0, 1.0, 3e10)
|
||||
: OpenSpaceModule(Name)
|
||||
, _minValidBoundingSphere(MinBoundingSphereInfo, 10.0, 1.0, 3e10)
|
||||
, _relevantNodeTags(RelevantNodeTagsInfo)
|
||||
|
||||
{
|
||||
addPropertySubOwner(_autoNavigationHandler);
|
||||
addProperty(_minValidBoundingSphere);
|
||||
|
||||
// Add the relevant tags
|
||||
_relevantNodeTags = std::vector<std::string>{
|
||||
"planet_solarSystem",
|
||||
"moon_solarSystem"
|
||||
};;
|
||||
_relevantNodeTags.onChange([this]() { findRelevantNodes(); });
|
||||
addProperty(_relevantNodeTags);
|
||||
}
|
||||
|
||||
autonavigation::AutoNavigationHandler& AutoNavigationModule::AutoNavigationHandler() {
|
||||
@@ -58,6 +77,50 @@ double AutoNavigationModule::minValidBoundingSphere() const {
|
||||
return _minValidBoundingSphere;
|
||||
}
|
||||
|
||||
const std::vector<SceneGraphNode*>& AutoNavigationModule::relevantNodes() const {
|
||||
return _relevantNodes;
|
||||
}
|
||||
|
||||
void AutoNavigationModule::findRelevantNodes() {
|
||||
const std::vector<SceneGraphNode*>& allNodes =
|
||||
global::renderEngine->scene()->allSceneGraphNodes();
|
||||
|
||||
const std::vector<std::string> relevantTags = _relevantNodeTags;
|
||||
|
||||
if (allNodes.empty() || relevantTags.empty()) {
|
||||
_relevantNodes = std::vector<SceneGraphNode*>();
|
||||
return;
|
||||
}
|
||||
|
||||
auto isRelevant = [&](const SceneGraphNode* node) {
|
||||
const std::vector<std::string> tags = node->tags();
|
||||
auto result = std::find_first_of(
|
||||
relevantTags.begin(),
|
||||
relevantTags.end(),
|
||||
tags.begin(),
|
||||
tags.end()
|
||||
);
|
||||
|
||||
// does not match any tags => not interesting
|
||||
if (result == relevantTags.end()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return node->renderable() && (node->boundingSphere() > 0.0);
|
||||
};
|
||||
|
||||
std::vector<SceneGraphNode*> resultingNodes;
|
||||
std::copy_if(
|
||||
allNodes.begin(),
|
||||
allNodes.end(),
|
||||
std::back_inserter(resultingNodes),
|
||||
isRelevant
|
||||
);
|
||||
|
||||
_relevantNodes = resultingNodes;
|
||||
}
|
||||
|
||||
|
||||
std::vector<documentation::Documentation> AutoNavigationModule::documentations() const {
|
||||
return {
|
||||
autonavigation::PathInstruction::Documentation()
|
||||
|
||||
@@ -41,16 +41,21 @@ public:
|
||||
|
||||
autonavigation::AutoNavigationHandler& AutoNavigationHandler();
|
||||
double minValidBoundingSphere() const;
|
||||
const std::vector<SceneGraphNode*>& relevantNodes() const;
|
||||
|
||||
std::vector<documentation::Documentation> documentations() const override;
|
||||
scripting::LuaLibrary luaLibrary() const override;
|
||||
|
||||
private:
|
||||
void internalInitialize(const ghoul::Dictionary&) override;
|
||||
void findRelevantNodes();
|
||||
|
||||
autonavigation::AutoNavigationHandler _autoNavigationHandler;
|
||||
|
||||
properties::DoubleProperty _minValidBoundingSphere;
|
||||
properties::StringListProperty _relevantNodeTags;
|
||||
|
||||
std::vector<SceneGraphNode*> _relevantNodes;
|
||||
};
|
||||
|
||||
} // namespace openspace
|
||||
|
||||
@@ -49,8 +49,8 @@ namespace {
|
||||
namespace openspace::autonavigation {
|
||||
|
||||
AvoidCollisionCurve::AvoidCollisionCurve(const Waypoint& start, const Waypoint& end) {
|
||||
AutoNavigationModule* module = global::moduleEngine->module<AutoNavigationModule>();
|
||||
_relevantNodes = module->AutoNavigationHandler().relevantNodes();
|
||||
_relevantNodes =
|
||||
global::moduleEngine->module<AutoNavigationModule>()->relevantNodes();
|
||||
|
||||
const glm::dvec3 startNodeCenter = start.node()->worldPosition();
|
||||
const glm::dvec3 endNodeCenter = end.node()->worldPosition();
|
||||
|
||||
@@ -24,9 +24,11 @@
|
||||
|
||||
#include <modules/autonavigation/pathinstruction.h>
|
||||
|
||||
#include <modules/autonavigation/autonavigationmodule.h>
|
||||
#include <modules/autonavigation/helperfunctions.h>
|
||||
#include <openspace/documentation/verifier.h>
|
||||
#include <openspace/engine/globals.h>
|
||||
#include <openspace/engine/moduleengine.h>
|
||||
#include <openspace/interaction/navigationhandler.h>
|
||||
#include <openspace/scene/scenegraphnode.h>
|
||||
#include <openspace/query/query.h>
|
||||
@@ -35,6 +37,8 @@
|
||||
|
||||
namespace {
|
||||
constexpr const char* _loggerCat = "PathInstruction";
|
||||
constexpr const float Epsilon = 1e-5f;
|
||||
|
||||
|
||||
struct [[codegen::Dictionary(Instruction)]] Parameters {
|
||||
enum class Type {
|
||||
@@ -83,6 +87,9 @@ PathInstruction::PathInstruction(const ghoul::Dictionary& dictionary) {
|
||||
|
||||
duration = p.duration;
|
||||
|
||||
bool hasStart = p.startState.has_value();
|
||||
startPoint = hasStart ? Waypoint(p.startState.value()) : waypointFromCamera();
|
||||
|
||||
switch (p.type) {
|
||||
case Parameters::Type::NavigationState: {
|
||||
type = Type::NavigationState;
|
||||
@@ -114,29 +121,7 @@ PathInstruction::PathInstruction(const ghoul::Dictionary& dictionary) {
|
||||
position = p.position;
|
||||
height = p.height;
|
||||
useTargetUpDirection = p.useTargetUpDirection.value_or(false);
|
||||
|
||||
if (position.has_value()) {
|
||||
// Note that the anchor and reference frame is our targetnode.
|
||||
// The position in instruction is given is relative coordinates.
|
||||
glm::dvec3 targetPos = targetNode->worldPosition() +
|
||||
targetNode->worldRotationMatrix() * position.value();
|
||||
|
||||
Camera* camera = global::navigationHandler->camera();
|
||||
glm::dvec3 up = camera->lookUpVectorWorldSpace();
|
||||
|
||||
if (useTargetUpDirection) {
|
||||
// @TODO (emmbr 2020-11-17) For now, this is hardcoded to look good for Earth,
|
||||
// which is where it matters the most. A better solution would be to make each
|
||||
// sgn aware of its own 'up' and query
|
||||
up = targetNode->worldRotationMatrix() * glm::dvec3(0.0, 0.0, 1.0);
|
||||
}
|
||||
|
||||
const glm::dvec3 lookAtPos = targetNode->worldPosition();
|
||||
const glm::dquat targetRot = helpers::lookAtQuaternion(targetPos, lookAtPos, up);
|
||||
|
||||
Waypoint wp{ targetPos, targetRot, nodeIdentifier };
|
||||
waypoints = { wp };
|
||||
}
|
||||
waypoints = { computeDefaultWaypoint() };
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
@@ -147,5 +132,113 @@ PathInstruction::PathInstruction(const ghoul::Dictionary& dictionary) {
|
||||
}
|
||||
}
|
||||
|
||||
Waypoint PathInstruction::waypointFromCamera() const {
|
||||
Camera* camera = global::navigationHandler->camera();
|
||||
const glm::dvec3 pos = camera->positionVec3();
|
||||
const glm::dquat rot = camera->rotationQuaternion();
|
||||
const std::string node = global::navigationHandler->anchorNode()->identifier();
|
||||
return Waypoint{ pos, rot, node };
|
||||
}
|
||||
|
||||
// OBS! The desired default waypoint may vary between curve types.
|
||||
// TODO: let the curves update the default position if no exact position is required
|
||||
Waypoint PathInstruction::computeDefaultWaypoint() const {
|
||||
const SceneGraphNode* targetNode = sceneGraphNode(nodeIdentifier);
|
||||
if (!targetNode) {
|
||||
LERROR(fmt::format("Could not find target node '{}'", nodeIdentifier));
|
||||
return Waypoint();
|
||||
}
|
||||
|
||||
glm::dvec3 targetPos;
|
||||
if (position.has_value()) {
|
||||
// Note that the anchor and reference frame is our targetnode.
|
||||
// The position in instruction is given is relative coordinates
|
||||
targetPos = targetNode->worldPosition() +
|
||||
targetNode->worldRotationMatrix() * position.value();
|
||||
}
|
||||
else {
|
||||
const glm::dvec3 nodePos = targetNode->worldPosition();
|
||||
const glm::dvec3 sunPos = glm::dvec3(0.0, 0.0, 0.0);
|
||||
const SceneGraphNode* closeNode = findNodeNearTarget(targetNode);
|
||||
|
||||
glm::dvec3 stepDirection;
|
||||
if (closeNode) {
|
||||
// If the node is close to another node in the scene, make sure that the
|
||||
// position is set to minimize risk of collision
|
||||
stepDirection = glm::normalize(nodePos - closeNode->worldPosition());
|
||||
}
|
||||
else if (glm::length(sunPos - nodePos) < Epsilon) {
|
||||
// Special case for when the target is the Sun. Assumption: want an overview of
|
||||
// the solar system, and not stay in the orbital plane
|
||||
stepDirection = glm::dvec3(0.0, 0.0, 1.0);
|
||||
}
|
||||
else {
|
||||
// Go to a point that is being lit up by the sun, slightly offsetted from sun
|
||||
// direction
|
||||
const glm::dvec3 prevPos = startPoint.position();
|
||||
const glm::dvec3 targetToPrev = prevPos - nodePos;
|
||||
const glm::dvec3 targetToSun = sunPos - nodePos;
|
||||
|
||||
constexpr const float defaultPositionOffsetAngle = -30.f; // degrees
|
||||
constexpr const float angle = glm::radians(defaultPositionOffsetAngle);
|
||||
const glm::dvec3 axis = glm::normalize(glm::cross(targetToPrev, targetToSun));
|
||||
const glm::dquat offsetRotation = angleAxis(static_cast<double>(angle), axis);
|
||||
|
||||
stepDirection = glm::normalize(offsetRotation * targetToSun);
|
||||
}
|
||||
|
||||
const double radius = Waypoint::findValidBoundingSphere(targetNode);
|
||||
const double defaultHeight = 2.0 * radius;
|
||||
const double targetHeight = height.value_or(defaultHeight);
|
||||
|
||||
targetPos = nodePos + stepDirection * (radius + targetHeight);
|
||||
}
|
||||
|
||||
// Up direction
|
||||
glm::dvec3 up = global::navigationHandler->camera()->lookUpVectorWorldSpace();
|
||||
if (useTargetUpDirection) {
|
||||
// @TODO (emmbr 2020-11-17) For now, this is hardcoded to look good for Earth,
|
||||
// which is where it matters the most. A better solution would be to make each
|
||||
// sgn aware of its own 'up' and query
|
||||
up = targetNode->worldRotationMatrix() * glm::dvec3(0.0, 0.0, 1.0);
|
||||
}
|
||||
|
||||
// Rotation
|
||||
const glm::dvec3 lookAtPos = targetNode->worldPosition();
|
||||
const glm::dquat targetRot = helpers::lookAtQuaternion(targetPos, lookAtPos, up);
|
||||
|
||||
return Waypoint(targetPos, targetRot, nodeIdentifier);
|
||||
}
|
||||
|
||||
// Test if the node lies within a given proximity radius of any relevant node in the scene
|
||||
SceneGraphNode* PathInstruction::findNodeNearTarget(const SceneGraphNode* node) const {
|
||||
const std::vector<SceneGraphNode*>& relevantNodes =
|
||||
global::moduleEngine->module<AutoNavigationModule>()->relevantNodes();
|
||||
|
||||
for (SceneGraphNode* n : relevantNodes) {
|
||||
if (n->identifier() == node->identifier()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
constexpr const float proximityRadiusFactor = 3.f;
|
||||
|
||||
const float bs = static_cast<float>(n->boundingSphere());
|
||||
const float proximityRadius = proximityRadiusFactor * bs;
|
||||
const glm::dvec3 posInModelCoords =
|
||||
glm::inverse(n->modelTransform()) * glm::dvec4(node->worldPosition(), 1.0);
|
||||
|
||||
bool isClose = helpers::isPointInsideSphere(
|
||||
posInModelCoords,
|
||||
glm::dvec3(0.0, 0.0, 0.0),
|
||||
proximityRadius
|
||||
);
|
||||
|
||||
if (isClose) {
|
||||
return n;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
} // namespace openspace::autonavigation
|
||||
|
||||
@@ -43,10 +43,11 @@ struct PathInstruction {
|
||||
|
||||
static documentation::Documentation Documentation();
|
||||
|
||||
Type type;
|
||||
Waypoint waypointFromCamera() const;
|
||||
Waypoint computeDefaultWaypoint() const;
|
||||
SceneGraphNode* findNodeNearTarget(const SceneGraphNode* node) const;
|
||||
|
||||
std::optional<double> duration;
|
||||
std::optional<NavigationState> startState;
|
||||
Type type;
|
||||
|
||||
// Node details
|
||||
std::string nodeIdentifier;
|
||||
@@ -57,6 +58,8 @@ struct PathInstruction {
|
||||
// Navigation state details
|
||||
NavigationState navigationState;
|
||||
|
||||
std::optional<double> duration;
|
||||
Waypoint startPoint;
|
||||
std::vector<Waypoint> waypoints;
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user