CubicSpline.cpp 2.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283
  1. #include "CubicSpline.h"
  2. #include <cmath>
  3. CubicSpline::CubicSpline(const std::vector<std::pair<float, float> >& dataPoints, bool useSlopes, bool minSlopes) :
  4. useSlopes{ useSlopes }
  5. {
  6. if (dataPoints.size() < 2) {
  7. return;
  8. }
  9. points.push_back({ dataPoints[0].first, dataPoints[0].second,
  10. (dataPoints[1].second - dataPoints[0].second) /
  11. (dataPoints[1].first - dataPoints[0].first) });
  12. for (size_t i = 1; i < dataPoints.size() - 1; i++) {
  13. auto& dp1 = dataPoints[i - 1];
  14. auto& dp2 = dataPoints[i];
  15. auto& dp3 = dataPoints[i + 1];
  16. float w1 = dp2.first - dp1.first;
  17. float w2 = dp3.first - dp2.first;
  18. float h1 = dp2.second - dp1.second;
  19. float h2 = dp3.second - dp2.second;
  20. float s1 = h1 / w1;
  21. float s2 = h2 / w2;
  22. float slope;
  23. if (minSlopes) {
  24. if (fabs(s1) > fabs(s2))
  25. slope = s2;
  26. else
  27. slope = s1;
  28. } else
  29. slope = (s1 + s2) / 2;
  30. points.push_back({ dp2.first, dp2.second, slope });
  31. }
  32. points.push_back({ dataPoints[dataPoints.size() - 1].first, dataPoints[dataPoints.size() - 1].second,
  33. (dataPoints[dataPoints.size() - 2].second - dataPoints[dataPoints.size() - 1].second) /
  34. (dataPoints[dataPoints.size() - 2].first - dataPoints[dataPoints.size() - 1].first) });
  35. }
  36. float CubicSpline::interpolateAt(float x)
  37. {
  38. const static auto h00 = [] (float t) { return (1 + 2 * t) * (1 - t) * (1 - t); };
  39. const static auto h01 = [] (float t) { return t * t * (3 - 2 * t); };
  40. const static auto h10 = [] (float t) { return t * (1 - t) * (1 - t); };
  41. const static auto h11 = [] (float t) { return t * t * (t - 1); };
  42. if (points.empty()) {
  43. return 0.0f;
  44. }
  45. if(std::get<0>(points[0]) > x) {
  46. return std::get<1>(points[0]);
  47. }
  48. for (auto it = points.begin(); it != points.end() && (it + 1) != points.end(); ++it) {
  49. auto& left = *it;
  50. auto& right = *(it + 1);
  51. float xleft = std::get<0>(left);
  52. float xright = std::get<0>(right);
  53. if (xleft <= x && xright >= x) {
  54. float w = (xright - xleft);
  55. float t = (x - xleft) / w;
  56. float yleft = std::get<1>(left);
  57. float yright = std::get<1>(right);
  58. float sleft = std::get<2>(left);
  59. float sright = std::get<2>(right);
  60. float inter = h00(t) * yleft +
  61. h01(t) * yright;
  62. if (useSlopes)
  63. inter += h10(t) * w * sleft +
  64. h11(t) * w * sright;
  65. return inter;
  66. }
  67. }
  68. return std::get<1>(points[points.size() - 1]);
  69. }