// Copyright (C) 2001-2019 Sam Varner
//
// This file is part of Vamos Automotive Simulator.
//
// Vamos is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Vamos is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Vamos. If not, see <http://www.gnu.org/licenses/>.
#ifndef _SPLINE_H_
#define _SPLINE_H_
#include "Interpolator.hpp"
#include "Three_Vector.hpp"
#include "Two_Vector.hpp"
#include <optional>
#include <vector>
namespace Vamos_Geometry
{
class Spline : public Interpolator
{
public:
Spline();
Spline(double first_slope, double last_slope);
Spline(const std::vector<Two_Vector> &points);
Spline(const std::vector<Two_Vector> &points, double first_slope, double last_slope);
virtual ~Spline() = default;
void set_periodic(double period_end);
double slope(double distance) const;
double second_derivative(double distance) const;
virtual double interpolate(double dist) const override;
virtual Two_Vector normal(double dist) const override;
private:
// Calculate the coefficients for interpolation.
void calculate() const;
void check(double *a, double *b, double *r) const;
// The array of calculated second derivatives.
mutable std::vector<double> m_second_deriv;
// The first derivative of the spline at the first point.
std::optional<double> m_first_slope;
// The first derivative of the spline at the last point.
std::optional<double> m_last_slope;
// The 1st and 2nd derivatives at the interpolated point calculated during the last
// call to interpolate().
mutable double m_slope = 0.0;
mutable double m_second_derivative = 0.0;
bool m_periodic = false;
};
class Parametric_Spline
{
public:
Parametric_Spline();
Parametric_Spline(double first_x_slope, double last_x_slope,
double first_y_slope, double last_y_slope);
// Add a point to the curve.
void load(double parameter, const Two_Vector &point);
void load(double parameter, double x, double y) { load(parameter, Two_Vector(x, y)); }
// Remove all points from the curve.
void clear();
void set_periodic(double period_end);
// Return the point at PARAMETER.
Two_Vector interpolate(double parameter) const;
// Return the number of control points.
size_t size() const;
Two_Vector operator[](size_t i) const;
double parameter(size_t i) const;
private:
Spline m_x;
Spline m_y;
};
class Vector_Spline
{
public:
Vector_Spline();
Vector_Spline(double first_x_slope, double last_x_slope, double first_y_slope,
double last_y_slope, double first_z_slope, double last_z_slope);
// Add a point to the curve.
void load(double parameter, const Vamos_Geometry::Three_Vector &point);
void load(double parameter, double x, double y, double z)
{ load(parameter, Three_Vector(x, y, z)); }
// Remove all points from the curve.
void clear();
void set_periodic(double period_end);
// Return the point at PARAMETER.
Vamos_Geometry::Three_Vector interpolate(double parameter) const;
// Return the number of control points.
size_t size() const;
Vamos_Geometry::Three_Vector operator[](size_t i) const;
double parameter(size_t i) const;
private:
Spline m_x;
Spline m_y;
Spline m_z;
};
} // namespace Vamos_Geometry
#endif