spline.cpp
Go to the documentation of this file.
1 /*
2  * spline.cpp
3  *
4  * The original version of this file can be found at with:
5  * https://github.com/joshhooker/CubicSplineClass
6  *
7  * This file has MIT license.
8  *
9  * Actual version is modified to adapt to Fields2Cover requirements.
10  *
11  * ---------------------------------------------------------------------
12  * Copyright (c) 2017 Joshua Hooker
13  *
14  * Permission is hereby granted, free of charge, to any person obtaining
15  * a copy of this software and associated documentation files (the "Software"),
16  * to deal in the Software without restriction, including without limitation
17  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
18  * and/or sell copies of the Software, and to permit persons to whom the
19  * Software is furnished to do so, subject to the following conditions:
20  *
21  * The above copyright notice and this permission notice shall be included
22  * in all copies or substantial portions of the Software.
23  *
24  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
25  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
26  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
27  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
28  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
29  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
30  * DEALINGS IN THE SOFTWARE.
31  * ---------------------------------------------------------------------
32  *
33  */
34 
35 #include <cmath>
36 #include <vector>
37 #include <stdexcept>
38 #include <string>
40 
41 
42 namespace f2c {
43 
44 CubicSpline::CubicSpline() = default;
45 
47  const std::vector<double> &x, const std::vector<double> &y,
48  bool monotonic) {
49  check_error(x.size() == y.size(),
50  "In CubicSpline initialization, x vector size != y vector size\n");
51  check_error(x.size() > 1,
52  "In CubicSpline initialization, array size must be larger than 1\n");
53  size_ = x.size();
54  x_vec_ = x;
55  y_vec_ = y;
56  b_vec_.resize(size_);
57  c_vec_.resize(size_);
58  d_vec_.resize(size_);
59 
60  monotonic_ = monotonic;
61 
62  SetSpline();
63 }
64 
65 
66 CubicSpline::~CubicSpline() = default;
67 
69  const std::vector<double> &x, const std::vector<double> &y,
70  bool monotonic) {
71  check_error(x.size() == y.size(),
72  "In CubicSpline SetPoints, x vector size != y vector size\n");
73  check_error(x.size() > 1,
74  "In CubicSpline initialization, array size must be larger than 1\n");
75  size_ = x.size();
76  x_vec_ = x;
77  y_vec_ = y;
78  b_vec_.resize(size_);
79  c_vec_.resize(size_);
80  d_vec_.resize(size_);
81 
82  monotonic_ = monotonic;
83 
84  SetSpline();
85 }
86 
87 
88 double CubicSpline::operator()(double x) const {
89  const auto xs = static_cast<double>(x);
90 
91  int l = 0;
92  int h = size_;
93  while (l < h) {
94  int mid = (l + h) / 2;
95  if (xs <= x_vec_[mid]) {
96  h = mid;
97  } else {
98  l = mid + 1;
99  }
100  }
101 
102  size_t idx = l == 0 ? 0 : l - 1;
103 
104  double xi = xs - x_vec_[idx];
105  double xi2 = xi * xi;
106  double xi3 = xi2 * xi;
107 
108  return y_vec_[idx] + b_vec_[idx] * xi + c_vec_[idx] * xi2 + d_vec_[idx] * xi3;
109 }
110 
112  SetSplineCubic();
113 }
114 
116  std::vector<double> h(size_), alpha(size_), l(size_), z(size_), u(size_);
117 
118  h[0] = x_vec_[1] - x_vec_[0];
119  l[0] = 1.;
120  u[0] = 0.;
121  z[0] = 0.;
122  l[size_ - 1] = 1.;
123  u[size_ - 1] = 0.;
124  c_vec_[size_ - 1] = 0.;
125 
126  for (unsigned int i = 1; i < size_ - 1; i++) {
127  check_error(x_vec_[i + 1] > x_vec_[i],
128  "In CubicSpline SetSpline, x array is not sorted"
129  "from smallest to largest\n");
130  h[i] = x_vec_[i + 1] - x_vec_[i];
131 
132  alpha[i] = 3. / h[i] * (y_vec_[i + 1] - y_vec_[i]) - 3. /
133  h[i - 1] * (y_vec_[i] - y_vec_[i - 1]);
134  l[i] = 2. * (x_vec_[i + 1] - x_vec_[i - 1]) - h[i - 1] * u[i - 1];
135  u[i] = h[i] / l[i];
136  z[i] = (alpha[i] - h[i - 1] * z[i - 1]) / l[i];
137  }
138 
139  for (int i = size_ - 2; i > -1; i--) {
140  c_vec_[i] = z[i] - u[i] * c_vec_[i + 1];
141  b_vec_[i] =
142  (y_vec_[i + 1] - y_vec_[i]) / h[i] - h[i] * (c_vec_[i + 1] +
143  2. * c_vec_[i]) / 3.;
144  d_vec_[i] = (c_vec_[i + 1] - c_vec_[i]) / (3. * h[i]);
145  }
146 
147  // Monotonic correction
148  if (monotonic_) {
149  bool changed = false;
150  for (unsigned int i = 0; i < size_; i++) {
151  int i_low = std::max(static_cast<int>(i - 1), 0);
152  int i_high =
153  std::min(static_cast<int>(i + 1), static_cast<int>(size_) - 1);
154 
155  if (((y_vec_[i_low] <= y_vec_[i]) && (y_vec_[i] <= y_vec_[i_high]) &&
156  b_vec_[i] < 0.0) ||
157  ((y_vec_[i_low] >= y_vec_[i]) && (y_vec_[i] >= y_vec_[i_high]) &&
158  b_vec_[i] > 0.0)) {
159  b_vec_[i] = 0.0;
160  changed = true;
161  }
162 
163  double slope = (y_vec_[i_high] - y_vec_[i]) / h[i];
164  if (slope == 0.0 && (b_vec_[i] != 0.0 || b_vec_[i + 1] != 0.0)) {
165  b_vec_[i] = 0.0;
166  b_vec_[i + 1] = 0.0;
167  changed = true;
168  } else {
169  double r = sqrt(b_vec_[i] * b_vec_[i] + b_vec_[i + 1] * b_vec_[i + 1]) /
170  fabs(slope);
171  if (r > 3.0) {
172  b_vec_[i] *= 3.0 / r;
173  b_vec_[i + 1] *= 3.0 / r;
174  changed = true;
175  }
176  }
177  }
178 
179  if (changed) {
180  for (unsigned int i = 0; i < size_; i++) {
181  double inv_h = 1.0 / h[i];
182  c_vec_[i] = inv_h * (3.0 * inv_h * (y_vec_[i + 1] - y_vec_[i])
183  - 2.0 * b_vec_[i] - b_vec_[i + 1]);
184  d_vec_[i] =
185  inv_h * (inv_h * (b_vec_[i + 1] - b_vec_[i]) - 2.0 * c_vec_[i]) / 3.0;
186  }
187  }
188  }
189 
190  d_vec_[0] = 0.;
191  d_vec_[size_ - 1] = 0.;
192 }
193 
194 
195 void CubicSpline::check_error(bool cond, const std::string& msg) const {
196  if (!cond) {
197  throw std::out_of_range(msg);
198  }
199 }
200 
201 } // namespace f2c
202 
spline.h
f2c::CubicSpline::y_vec_
std::vector< double > y_vec_
Definition: spline.h:60
f2c::CubicSpline::monotonic_
bool monotonic_
Definition: spline.h:63
f2c::CubicSpline::check_error
void check_error(bool cond, const std::string &msg) const
Definition: spline.cpp:195
f2c::CubicSpline::SetSplineCubic
void SetSplineCubic()
Definition: spline.cpp:115
f2c::CubicSpline::CubicSpline
CubicSpline()
f2c::CubicSpline::size_
size_t size_
Definition: spline.h:59
f2c::CubicSpline::c_vec_
std::vector< double > c_vec_
Definition: spline.h:61
f2c::CubicSpline::x_vec_
std::vector< double > x_vec_
Definition: spline.h:60
f2c::CubicSpline::SetPoints
void SetPoints(const std::vector< double > &x, const std::vector< double > &y, bool monotonic=false)
Definition: spline.cpp:68
f2c
Main namespace of the fields2cover library.
Definition: boustrophedon_decomp.h:14
f2c::CubicSpline::b_vec_
std::vector< double > b_vec_
Definition: spline.h:61
f2c::CubicSpline::operator()
double operator()(double x) const
Definition: spline.cpp:88
f2c::CubicSpline::SetSpline
void SetSpline()
Definition: spline.cpp:111
f2c::CubicSpline::d_vec_
std::vector< double > d_vec_
Definition: spline.h:61
f2c::CubicSpline::~CubicSpline
~CubicSpline()


fields2cover
Author(s):
autogenerated on Fri Apr 25 2025 02:18:31