124 if (
X.size() != Y.size()) {
125 std::cerr <<
"Error in function " << __FUNCTION__
126 <<
": Vectors X (of size " <<
X.size()
127 <<
") and Y (of size " << Y.size()
128 <<
") are not the same size. Returning an empty array..." << std::endl;
138 if (std::holds_alternative<typename Types::Natural>(
type)) {
140 }
else if (std::holds_alternative<typename Types::NotAKnot>(
type)) {
145 }
else if (std::holds_alternative<typename Types::ParabolicEnds>(
type)) {
150 }
else if (
const auto* c = std::get_if<typename Types::Clamped>(&
type)) {
152 }
else if (
const auto* fs = std::get_if<typename Types::FixedSecond>(&
type)) {
154 }
else if (
const auto* ft = std::get_if<typename Types::FixedThird>(&
type)) {
156 }
else if (std::holds_alternative<typename Types::NotAKnotStart>(
type)) {
161 }
else if (std::holds_alternative<typename Types::NotAKnotEnd>(
type)) {
166 }
else if (std::holds_alternative<typename Types::SemiNotAKnot>(
type)) {
173 Container<Number>
coeffs(4 * (n - 1));
177 SizeT i1 = 0, i2 = n - 1;
181 if (std::holds_alternative<typename Types::Periodic>(
type)) {
186 Container<Number> C(n);
188 C[0] = 3 * (dY[0]/dX[0] - dY[1]/dX[1]) / (dX[0] + dX[1]);
192 Container<Number> diag(n - 1), right(n - 1);
193 for (
SizeT i = 0; i < n - 2; ++i) {
194 diag[i] = 2 * (dX[i] + dX[i+1]);
195 right[i] = 3 * (dY[i+1]/dX[i+1] - dY[i]/dX[i]);
197 diag[n-2] = 2 * (dX[n-2] + dX[0]);
198 right[n-2] = 3 * (dY[0]/dX[0] - dY[n-2]/dX[n-2]);
200 Container<Number> last_row(n - 2), last_col(n - 2);
201 last_row[0] = last_col[0] = dX[0];
202 for (
SizeT i = 1; i < n - 3; ++i) {
203 last_row[i] = last_col[i] = 0;
205 last_row[n-3] = last_col[n-3] = dX[n-2];
207 for (
SizeT i = 0; i < n - 3; ++i) {
208 const auto m1 = dX[i+1] / diag[i];
209 diag[i+1] -= m1 * dX[i+1];
210 last_col[i+1] -= m1 * last_col[i];
211 right[i+1] -= m1 * right[i];
212 const auto m2 = last_row[i] / diag[i];
213 last_row[i+1] -= m2 * dX[i+1];
214 diag[n-2] -= m2 * last_col[i];
215 right[n-2] -= m2 * right[i];
217 diag[n-2] -= last_row[n-3] / diag[n-3] * last_col[n-3];
218 right[n-2] -= last_row[n-3] / diag[n-3] * right[n-3];
220 C[n-1] = right[n-2] / diag[n-2];
221 C[n-2] = (right[n-3] - last_col[n-3] * C[n-1]) / diag[n-3];
222 for (
SizeT i = n - 3; i >= 1; --i) {
223 C[i] = (right[i-1] - dX[i]*C[i+1] - last_col[i-1]*C[n-1]) / diag[i-1];
228 for (
SizeT i = 0, index = 0; i < n - 1; ++i) {
229 coeffs[index++] = (C[i+1] - C[i]) / (3*dX[i]);
231 coeffs[index++] = dY[i]/dX[i] - dX[i] * ((2*C[i] + C[i+1]) / 3);
234 }
else if (
auto* custom = std::get_if<typename Types::Custom>(&
type)) {
236 if (std::holds_alternative<typename Conditions::NotAKnot>(custom->cond1)
237 && std::holds_alternative<typename Conditions::NotAKnot>(custom->cond2)
243 for (
const auto* cond : {&custom->cond1, &custom->cond2}) {
244 if (
const auto* c = std::get_if<typename Conditions::Clamped>(cond)) {
245 if (c->point_idx < 0 || c->point_idx >= n) {
246 std::cerr <<
"Error in function " << __FUNCTION__
247 <<
": point index for condition 'Clamped' is out of bounds: "
248 <<
"expected to be non-negative and less than " << n <<
", but got " << c->point_idx
249 <<
". Returning an empty array..." << std::endl;
252 }
else if (
const auto* fs = std::get_if<typename Conditions::FixedSecond>(cond)) {
253 if (fs->point_idx < 0 || fs->point_idx >= n) {
254 std::cerr <<
"Error in function " << __FUNCTION__
255 <<
": point index for condition 'FixedSecond' is out of bounds: "
256 <<
"expected to be non-negative and less than " << n <<
", but got " << fs->point_idx
257 <<
". Returning an empty array..." << std::endl;
260 }
else if (
const auto* ft = std::get_if<typename Conditions::FixedThird>(cond)) {
261 if (ft->segment_idx < 0 || ft->segment_idx >= n - 1) {
262 std::cerr <<
"Error in function " << __FUNCTION__
263 <<
": segment index for condition 'FixedThird' is out of bounds: "
264 <<
"expected to be non-negative and less than " << n - 1 <<
", but got " << ft->segment_idx
265 <<
". Returning an empty array..." << std::endl;
268 }
else if (
const auto* nak = std::get_if<typename Conditions::NotAKnot>(cond)) {
269 if (nak->point_idx < 1 || nak->point_idx >= n - 1) {
270 std::cerr <<
"Error in function " << __FUNCTION__
271 <<
": point index for condition 'NotAKnot' is out of bounds: "
272 <<
"expected to be positive and less than " << n - 1 <<
", but got " << nak->point_idx
273 <<
". Returning an empty array..." << std::endl;
277 std::cerr <<
"Error in function " << __FUNCTION__ <<
": Unknown condition of 'Custom' type. This should not have happened. "
278 <<
"Please report this to the developers. Returning an empty array..." << std::endl;
284 if (
const auto c1 = std::get_if<typename Conditions::Clamped>(&custom->cond1),
285 c2 = std::get_if<typename Conditions::Clamped>(&custom->cond2);
287 if (c1->point_idx == c2->point_idx) {
288 const auto df = (c1->df + c2->df) / 2;
289 if (c1->point_idx < n / 2) {
295 }
else if (
const auto fs1 = std::get_if<typename Conditions::FixedSecond>(&custom->cond1),
296 fs2 = std::get_if<typename Conditions::FixedSecond>(&custom->cond2);
298 if (fs1->point_idx == fs2->point_idx) {
299 const auto d2f = (fs1->d2f + fs2->d2f) / 2;
300 if (fs1->point_idx < n / 2) {
306 }
else if (
const auto ft1 = std::get_if<typename Conditions::FixedThird>(&custom->cond1),
307 ft2 = std::get_if<typename Conditions::FixedThird>(&custom->cond2);
309 if (ft1->segment_idx == ft2->segment_idx) {
311 const auto i = ft1->segment_idx;
312 const auto c = -dX[i] * (ft1->d3f + ft2->d3f) / 8;
313 coeffs[4*i] = -2*c / (3*dX[i]);
315 coeffs[4*i+2] = dY[i]/dX[i] - dX[i] * c / 3;
319 goto post_main_block;
321 const auto d3f = (ft1->d3f + ft2->d3f) / 2;
322 if (ft1->segment_idx < n / 2) {
329 }
else if (
const auto nak1 = std::get_if<typename Conditions::NotAKnot>(&custom->cond1),
330 nak2 = std::get_if<typename Conditions::NotAKnot>(&custom->cond2);
332 if (nak1->point_idx == nak2->point_idx) {
333 if (nak1->point_idx < n / 2) {
341 const auto set_segment_indices = [&]() {
355 set_segment_indices();
358 std::swap(custom->cond1, custom->cond2);
359 set_segment_indices();
368 = std::holds_alternative<typename Conditions::Clamped>(custom->cond1)
369 ? std::get_if<typename Conditions::Clamped>(&custom->cond1)
370 : std::get_if<typename
Conditions::Clamped>(&custom->cond2);
372 = std::holds_alternative<typename Conditions::FixedSecond>(custom->cond1)
373 ? std::get_if<typename Conditions::FixedSecond>(&custom->cond1)
374 : std::get_if<typename
Conditions::FixedSecond>(&custom->cond2);
377 coeffs[4*(i-1)] = (fs->d2f/2 - c->df/dX[i-1] + dY[i-1]/dX[i-1]/dX[i-1]) / dX[i-1];
378 coeffs[4*(i-1)+1] = 3*c->df/dX[i-1] - 3*dY[i-1]/dX[i-1]/dX[i-1] - fs->d2f;
379 coeffs[4*(i-1)+2] = 3*dY[i-1]/dX[i-1] + fs->d2f*dX[i-1]/2 - 2*c->df;
380 coeffs[4*(i-1)+3] = Y[i-1];
384 coeffs[4*i] = (dY[i]/dX[i]/dX[i] - c->df/dX[i] - fs->d2f/2) / dX[i];
385 coeffs[4*i+1] = fs->d2f/2;
390 goto post_main_block;
394 const auto m = i2 - i1 + 1;
397 Container<Number> lower(m), diag(m), upper(m), right(m);
398 for (
SizeT i = i1 + 1; i < i1 + m - 1; ++i) {
399 const auto j = i - i1;
401 diag[j] = 2 * (dX[i-1] + dX[i]);
403 right[j] = 3 * (dY[i]/dX[i] - dY[i-1]/dX[i-1]);
413 right[0] = 3 * (dY[i1]/dX[i1] - c.df);
418 right[0] = fs.d2f / 2;
423 right[0] = -dX[i1] * ft.d3f / 2;
426 diag[0] = dX[i1] - dX[i1+1];
427 upper[0] = 2*dX[i1] + dX[i1+1];
428 right[0] = dX[i1] / (dX[i1]+dX[i1+1]) * 3 * (dY[i1+1]/dX[i1+1] - dY[i1]/dX[i1]);
433 lower[m-1] = dX[i1+m-2];
434 diag[m-1] = 2*dX[i1+m-2];
435 right[m-1] = 3 * (c.df - dY[i1+m-2]/dX[i1+m-2]);
440 right[m-1] = fs.d2f / 2;
445 right[m-1] = dX[i1+m-2] * ft.d3f / 2;
448 lower[m-1] = 2*dX[i1+m-2] + dX[i1+m-3];
449 diag[m-1] = dX[i1+m-2] - dX[i1+m-3];
450 right[m-1] = dX[i1+m-2] / (dX[i1+m-2]+dX[i1+m-3]) * 3 * (dY[i1+m-2]/dX[i1+m-2] - dY[i1+m-3]/dX[i1+m-3]);
455 std::move(lower), std::move(diag), std::move(upper), std::move(right));
457 for (
SizeT i = 0, index = 4 * i1; i < m - 1; ++i) {
458 const auto j = i + i1;
459 coeffs[index++] = (C[i+1] - C[i]) / (3*dX[j]);
461 coeffs[index++] = dY[j]/dX[j] - dX[j] * ((2*C[i] + C[i+1]) / 3);
466 if (
const auto* ft = std::get_if<typename Conditions::FixedThird>(&custom->cond1)) {
467 coeffs[4*i1] = ft->d3f / 6;
469 if (
const auto* ft = std::get_if<typename Conditions::FixedThird>(&custom->cond2)) {
470 coeffs[4*(i2-1)] = ft->d3f / 6;
473 std::cerr <<
"Error in function " << __FUNCTION__ <<
": Unknown type. This should not have happened. "
474 <<
"Please report this to the developers. Returning an empty array..." << std::endl;
479 for (
SizeT iter = 0; iter < i1; ++iter) {
480 const auto i = i1 - 1 - iter;
481 coeffs[4*i] = (
coeffs[4*(i+1)+1] -
coeffs[4*(i+1)+2]/dX[i] + dY[i]/dX[i]/dX[i]) / dX[i];
487 for (
SizeT i = i2; i < n - 1; ++i) {