Program Listing for File interpolation_1d.h

Return to documentation for file (/tmp/ws/src/marti_common/swri_math_util/include/swri_math_util/interpolation_1d.h)

// *****************************************************************************
//
// Copyright (c) 2015, Southwest Research Institute® (SwRI®)
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//     * Neither the name of Southwest Research Institute® (SwRI®) nor the
//       names of its contributors may be used to endorse or promote products
//       derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// *****************************************************************************
#ifndef MATH_UTIL_INTERPOLATION_1D_H_
#define MATH_UTIL_INTERPOLATION_1D_H_

#include <string>
#include <vector>

#include <rclcpp/rclcpp.hpp>

namespace swri_math_util
{
  class Interpolation1D
  {
  public:
    enum InterpolationType
    {
      ZERO_ORDER_HOLD,
      LINEAR
    };

    Interpolation1D(rclcpp::Node& node);

    bool appendPoint(double x, double y);

    size_t numPoints() const;

    std::pair<double, double> getPoint(size_t index) const;

    void removePoint(size_t index);

    void clear();

    InterpolationType interpolationType();

    std::string interpolationTypeString() const;

    void setInterpolationType(InterpolationType type);

    bool readFromParameter(const std::string& param_name);

    double minX() const;

    double maxX() const;

    double eval(double x) const;

  private:
    rclcpp::Node& node_;
    InterpolationType interp_type_;
    std::vector<double> x_;
    std::vector<double> y_;
  };

  inline
  double Interpolation1D::eval(double x) const
  {
    if (x_.size() == 0)
    {
      // If we have no points, we just return a sensible default value.
      return 0.0;
    }
    else if (x_.size() == 1)
    {
      // If we have a single point, we can't do any interpolation so we
      // just return the single output value.
      return y_[0];
    }
    else if (x <= x_.front())
    {
      // Clamp the output to the first output if we are below the
      // domain.
      return y_.front();
    }
    else if (x >= x_.back())
    {
      // Clamp the output to the last output if we are above the domain.
      return y_.back();
    }

    // If we pass the general special cases, we have at least two points
    // that bound the evaluation point.  First, we find the index of the
    // point below the evaluation point, and then perform the
    // interpolation.

    // We are searching for the interval where x_i <= x <= x_{i+1}.  The
    // first interval has index 0, the last has index x_.size()-2.
    size_t i_min = 0;
    size_t i_max = x_.size() - 2;
    size_t i_mid = 0;

    while (i_min <= i_max)
    {
      i_mid = i_min + (i_max - i_min) / 2;

      if (x_[i_mid] <= x && x_[i_mid + 1] >= x)
      {
        // This is the interval that contains our point, so stop searching.
        break;
      }
      else if (x < x_[i_mid])
      {
        // The desired interval must be below this one.
        i_max = i_mid - 1;
      }
      else
      {
        i_min = i_mid + 1;
      }
    }
    // The desired interval is at i_mid.

    if (interp_type_ == ZERO_ORDER_HOLD)
    {
      return y_[i_mid];
    }
    else if (interp_type_ == LINEAR)
    {
      size_t i0 = i_mid;
      size_t i1 = i_mid + 1;
      double s = (x - x_[i0]) / (x_[i1] - x_[i0]);
      return (1.0 - s) * y_[i0] + s * y_[i1];
    }
    else
    {
      // We should always have a valid interpolation type, but just in
      // case we print out an error and use a zero order hold.
      RCLCPP_ERROR(node_.get_logger(), "Invalid interpolation type: %d", interp_type_);
      return y_[i_mid];
    }
  }
}  // namespace swri_math_util
#endif  // MATH_UTIL_INTERPOLATION_1D_H_