Refactor path curve generation in PathSegment

This commit is contained in:
Emma Broman
2020-01-15 18:16:24 -05:00
parent 42c797093a
commit 83037f8c47
3 changed files with 133 additions and 93 deletions
@@ -56,7 +56,7 @@ Camera* AutoNavigationHandler::camera() const {
const double AutoNavigationHandler::pathDuration() const {
double sum = 0.0;
for (auto ps : _pathSegments) {
for (const PathSegment& ps : _pathSegments) {
sum += ps.duration();
}
return sum;
@@ -66,7 +66,6 @@ const bool AutoNavigationHandler::hasFinished() const {
return _currentTime > pathDuration();
}
const int AutoNavigationHandler::currentPathSegmentIndex() const {
for (int i = 0; i < _pathSegments.size(); ++i) {
const PathSegment& ps = _pathSegments[i];
+93 -84
View File
@@ -39,6 +39,93 @@ namespace {
namespace openspace::autonavigation {
// TODO: move all these later --------------------
PathCurve::~PathCurve() {}
BezierCurve::BezierCurve(CameraState& start, CameraState& end) {
glm::dvec3 startNodePos = sceneGraphNode(start.referenceNode)->worldPosition();
glm::dvec3 endNodePos = sceneGraphNode(start.referenceNode)->worldPosition();
// vectors pointing away from target nodes
glm::dvec3 startDirection = start.position - startNodePos;
glm::dvec3 endDirection = end.position - endNodePos;
_points.push_back(start.position);
_points.push_back(start.position + 10.0 * startDirection);
_points.push_back(end.position + 10.0 * endDirection);
_points.push_back(end.position);
}
glm::dvec3 BezierCurve::interpolate(double t) {
return interpolator::cubicBezier(t,
_points[0], _points[1], _points[2], _points[3]);
}
Bezier2Curve::Bezier2Curve(CameraState& start, CameraState& end) {
// START:
glm::dvec3 startNodePos = sceneGraphNode(start.referenceNode)->worldPosition();
glm::dvec3 startDirection = start.position - startNodePos;
// END:
glm::dvec3 endNodePos = sceneGraphNode(end.referenceNode)->worldPosition();
glm::dvec3 endDirection = end.position - endNodePos;
// MIDDLE: one knot and two control points parallell to target nodes
glm::dvec3 AB = endNodePos - startNodePos;
glm::dvec3 C = normalize(startDirection + endDirection);
glm::dvec3 CparAB = glm::dot(C, normalize(AB))* normalize(AB);
glm::dvec3 CortAB = normalize(C - CparAB);
double d = length(AB);
// TODO: set points that actually look good
_points.push_back(start.position);
_points.push_back(start.position + 2.0 * startDirection);
_points.push_back(start.position + 1.5 * d * CortAB);
_points.push_back(start.position + 1.5 * d * CortAB + 0.5 * AB);
_points.push_back(end.position + 1.5 * d * CortAB);
_points.push_back(end.position + 2.0 * endDirection);
_points.push_back(end.position);
}
glm::dvec3 Bezier2Curve::interpolate(double t) {
return interpolator::piecewiseCubicBezier(t, _points);
}
LinearCurve::LinearCurve(CameraState& start, CameraState& end) {
_points.push_back(start.position);
_points.push_back(end.position);
}
glm::dvec3 LinearCurve::interpolate(double t) {
return ghoul::interpolateLinear(t, _points[0], _points[1]);
}
Linear2Curve::Linear2Curve(CameraState& start, CameraState& end) {
// START:
glm::dvec3 startNodePos = sceneGraphNode(start.referenceNode)->worldPosition();
glm::dvec3 startDirection = start.position - startNodePos;
// END:
glm::dvec3 endNodePos = sceneGraphNode(end.referenceNode)->worldPosition();
glm::dvec3 endDirection = end.position - endNodePos;
// MIDDLE:
glm::dvec3 AB = endNodePos - startNodePos;
glm::dvec3 C = normalize(startDirection + endDirection);
glm::dvec3 CparAB = glm::dot(C, normalize(AB))* normalize(AB);
glm::dvec3 CortAB = normalize(C - CparAB);
double d = length(AB);
_points.push_back(start.position);
_points.push_back(start.position + 2.0 * d * CortAB + 0.5 * AB); //TODO: use scale instead of 2.0
_points.push_back(end.position);
}
glm::dvec3 Linear2Curve::interpolate(double t) {
return interpolator::piecewiseLinear(t, _points);
}
PathSegment::PathSegment(
CameraState start, CameraState end, double startTime, CurveType type)
: _start(start), _end(end), _startTime(startTime), _curveType(type)
@@ -46,17 +133,18 @@ PathSegment::PathSegment(
// TODO: compute duration based on method later
_duration = 5;
switch(_curveType) {
switch(type) {
case Bezier:
generateBezier();
_curve = std::make_shared<BezierCurve>(start, end);
break;
case Bezier2:
generateBezier2();
_curve = std::make_shared<Bezier2Curve>(start, end);
break;
case Linear:
_curve = std::make_shared<LinearCurve>(start, end);
break;
case Linear2:
generateLinear2();
_curve = std::make_shared<Linear2Curve>(start, end);
break;
default:
LERROR(fmt::format("Cannot create curve of type {}. Type does not exist!", _curveType));
@@ -81,24 +169,7 @@ const double PathSegment::startTime() const { return _startTime; }
const glm::vec3 PathSegment::getPositionAt(double t) const {
t = easingfunctions::cubicEaseInOut(t);
switch(_curveType) {
case Bezier:
return interpolator::cubicBezier(t,
_controlPoints[0], _controlPoints[1], _controlPoints[2], _controlPoints[3]);
break;
case Bezier2:
return interpolator::piecewiseCubicBezier(t, _controlPoints);
break;
case Linear:
return ghoul::interpolateLinear(t, _start.position, _end.position);
break;
case Linear2:
return interpolator::piecewiseLinear(t, _controlPoints);
break;
default:
LERROR(fmt::format("Cannot get position for curve type {}. Type does not exist!", _curveType));
}
return _curve.get()->interpolate(t);
}
const glm::dquat PathSegment::getRotationAt(double t) const {
@@ -134,66 +205,4 @@ const glm::dquat PathSegment::getLookAtRotation(
return glm::normalize(glm::inverse(glm::quat_cast(lookAtMat)));
}
// A single bezier segment with four control points
void PathSegment::generateBezier() {
glm::dvec3 startNodePos = sceneGraphNode(_start.referenceNode)->worldPosition();
glm::dvec3 endNodePos = sceneGraphNode(_end.referenceNode)->worldPosition();
// vectors pointing away from target nodes
glm::dvec3 startDirection =_start.position - startNodePos;
glm::dvec3 endDirection = _end.position - endNodePos;
_controlPoints.push_back(_start.position);
_controlPoints.push_back(_start.position + 10.0 * startDirection);
_controlPoints.push_back(_end.position + 10.0 * endDirection);
_controlPoints.push_back(_end.position);
}
void PathSegment::generateBezier2() {
// START:
glm::dvec3 startNodePos = sceneGraphNode(_start.referenceNode)->worldPosition();
glm::dvec3 startDirection = _start.position - startNodePos;
// END:
glm::dvec3 endNodePos = sceneGraphNode(_end.referenceNode)->worldPosition();
glm::dvec3 endDirection = _end.position - endNodePos;
// MIDDLE: one knot and two control points parallell to target nodes
glm::dvec3 AB = endNodePos - startNodePos;
glm::dvec3 C = normalize(startDirection + endDirection);
glm::dvec3 CparAB = glm::dot(C, normalize(AB))* normalize(AB);
glm::dvec3 CortAB = normalize(C - CparAB);
double d = length(AB);
// TODO: set points that actually look good
_controlPoints.push_back(_start.position);
_controlPoints.push_back(_start.position + 2.0 * startDirection);
_controlPoints.push_back(_start.position + 1.5 * d * CortAB);
_controlPoints.push_back(_start.position + 1.5 * d * CortAB + 0.5 * AB);
_controlPoints.push_back(_end.position + 1.5 * d * CortAB);
_controlPoints.push_back(_end.position + 2.0 * endDirection);
_controlPoints.push_back(_end.position);
}
void PathSegment::generateLinear2() {
// START:
glm::dvec3 startNodePos = sceneGraphNode(_start.referenceNode)->worldPosition();
glm::dvec3 startDirection = _start.position - startNodePos;
// END:
glm::dvec3 endNodePos = sceneGraphNode(_end.referenceNode)->worldPosition();
glm::dvec3 endDirection = _end.position - endNodePos;
// MIDDLE:
glm::dvec3 AB = endNodePos - startNodePos;
glm::dvec3 C = normalize(startDirection + endDirection);
glm::dvec3 CparAB = glm::dot(C, normalize(AB))* normalize(AB);
glm::dvec3 CortAB = normalize(C - CparAB);
double d = length(AB);
_controlPoints.push_back(_start.position);
_controlPoints.push_back(_start.position + 2.0 * d * CortAB + 0.5 * AB); //TODO: use scale instead of 2.0
_controlPoints.push_back(_end.position);
}
} // namespace openspace::autonavigation
+39 -7
View File
@@ -43,9 +43,44 @@ enum CurveType {
Linear2
};
// TODO: move to their own file
class PathCurve {
public:
virtual ~PathCurve() = 0;
virtual glm::dvec3 interpolate(double t) = 0;
protected:
// the points used for creating the curve (e.g. control points of a Bezier curve)
std::vector<glm::dvec3> _points;
};
class BezierCurve : public PathCurve {
public :
BezierCurve(CameraState& start, CameraState& end);
glm::dvec3 interpolate(double t);
};
class Bezier2Curve : public PathCurve {
public:
Bezier2Curve(CameraState& start, CameraState& end);
glm::dvec3 interpolate(double t);
};
class LinearCurve : public PathCurve {
public:
LinearCurve(CameraState& start, CameraState& end);
glm::dvec3 interpolate(double t);
};
class Linear2Curve : public PathCurve {
public:
Linear2Curve(CameraState& start, CameraState& end);
glm::dvec3 interpolate(double t);
};
class PathSegment {
public:
PathSegment(CameraState start, CameraState end, double startTime, CurveType type = Bezier);
PathSegment(CameraState start, CameraState end, double startTime, CurveType type = Linear2);
~PathSegment() = default;
// Mutators
void setStart(CameraState cs);
@@ -62,16 +97,13 @@ public:
const glm::dquat getLookAtRotation(double t, glm::dvec3 currentPos, glm::dvec3 up) const;
private:
void generateBezier();
void generateBezier2();
void generateLinear2();
CameraState _start;
CameraState _end;
double _duration;
double _startTime;
CurveType _curveType;
std::vector<glm::dvec3> _controlPoints;
CurveType _curveType; // Ideally, we don't want to need to save this
std::shared_ptr<PathCurve> _curve; // OBS! Does it make more sense to use unique_ptr? However, then PathSegments cannot be copied.
};
} // namespace openspace::autonavigation