123 if (
X.size() != Y.size()) {
124 std::cerr <<
"Error in function " << __FUNCTION__
125 <<
": Vectors X (of size " <<
X.size()
126 <<
") and Y (of size " << Y.size()
127 <<
") are not the same size. Returning an empty array..." << std::endl;
137 if (std::holds_alternative<typename Types::Natural>(
type)) {
139 }
else if (std::holds_alternative<typename Types::NotAKnot>(
type)) {
144 }
else if (std::holds_alternative<typename Types::ParabolicEnds>(
type)) {
149 }
else if (
const auto* c = std::get_if<typename Types::Clamped>(&
type)) {
151 }
else if (
const auto* fs = std::get_if<typename Types::FixedSecond>(&
type)) {
153 }
else if (
const auto* ft = std::get_if<typename Types::FixedThird>(&
type)) {
155 }
else if (std::holds_alternative<typename Types::NotAKnotStart>(
type)) {
160 }
else if (std::holds_alternative<typename Types::NotAKnotEnd>(
type)) {
165 }
else if (std::holds_alternative<typename Types::SemiNotAKnot>(
type)) {
172 Container<Number>
coeffs(4 * (n - 1));
176 SizeT i1 = 0, i2 = n - 1;
180 if (std::holds_alternative<typename Types::Periodic>(
type)) {
185 Container<Number> C(n);
187 C[0] = 3 * (dY[0]/dX[0] - dY[1]/dX[1]) / (dX[0] + dX[1]);
191 Container<Number> diag(n - 1), right(n - 1);
192 for (
SizeT i = 0; i < n - 2; ++i) {
193 diag[i] = 2 * (dX[i] + dX[i+1]);
194 right[i] = 3 * (dY[i+1]/dX[i+1] - dY[i]/dX[i]);
196 diag[n-2] = 2 * (dX[n-2] + dX[0]);
197 right[n-2] = 3 * (dY[0]/dX[0] - dY[n-2]/dX[n-2]);
199 Container<Number> last_row(n - 2), last_col(n - 2);
200 last_row[0] = last_col[0] = dX[0];
201 for (
SizeT i = 1; i < n - 3; ++i) {
202 last_row[i] = last_col[i] = 0;
204 last_row[n-3] = last_col[n-3] = dX[n-2];
206 for (
SizeT i = 0; i < n - 3; ++i) {
207 const auto m1 = dX[i+1] / diag[i];
208 diag[i+1] -= m1 * dX[i+1];
209 last_col[i+1] -= m1 * last_col[i];
210 right[i+1] -= m1 * right[i];
211 const auto m2 = last_row[i] / diag[i];
212 last_row[i+1] -= m2 * dX[i+1];
213 diag[n-2] -= m2 * last_col[i];
214 right[n-2] -= m2 * right[i];
216 diag[n-2] -= last_row[n-3] / diag[n-3] * last_col[n-3];
217 right[n-2] -= last_row[n-3] / diag[n-3] * right[n-3];
219 C[n-1] = right[n-2] / diag[n-2];
220 C[n-2] = (right[n-3] - last_col[n-3] * C[n-1]) / diag[n-3];
221 for (
SizeT i = n - 3; i >= 1; --i) {
222 C[i] = (right[i-1] - dX[i]*C[i+1] - last_col[i-1]*C[n-1]) / diag[i-1];
227 for (
SizeT i = 0, index = 0; i < n - 1; ++i) {
228 coeffs[index++] = (C[i+1] - C[i]) / (3*dX[i]);
230 coeffs[index++] = dY[i]/dX[i] - dX[i] * ((2*C[i] + C[i+1]) / 3);
233 }
else if (
auto* custom = std::get_if<typename Types::Custom>(&
type)) {
235 if (std::holds_alternative<typename Conditions::NotAKnot>(custom->cond1)
236 && std::holds_alternative<typename Conditions::NotAKnot>(custom->cond2)
242 for (
const auto* cond : {&custom->cond1, &custom->cond2}) {
243 if (
const auto* c = std::get_if<typename Conditions::Clamped>(cond)) {
244 if (c->point_idx < 0 || c->point_idx >= n) {
245 std::cerr <<
"Error in function " << __FUNCTION__
246 <<
": point index for condition 'Clamped' is out of bounds: "
247 <<
"expected to be non-negative and less than " << n <<
", but got " << c->point_idx
248 <<
". Returning an empty array..." << std::endl;
251 }
else if (
const auto* fs = std::get_if<typename Conditions::FixedSecond>(cond)) {
252 if (fs->point_idx < 0 || fs->point_idx >= n) {
253 std::cerr <<
"Error in function " << __FUNCTION__
254 <<
": point index for condition 'FixedSecond' is out of bounds: "
255 <<
"expected to be non-negative and less than " << n <<
", but got " << fs->point_idx
256 <<
". Returning an empty array..." << std::endl;
259 }
else if (
const auto* ft = std::get_if<typename Conditions::FixedThird>(cond)) {
260 if (ft->segment_idx < 0 || ft->segment_idx >= n - 1) {
261 std::cerr <<
"Error in function " << __FUNCTION__
262 <<
": segment index for condition 'FixedThird' is out of bounds: "
263 <<
"expected to be non-negative and less than " << n - 1 <<
", but got " << ft->segment_idx
264 <<
". Returning an empty array..." << std::endl;
267 }
else if (
const auto* nak = std::get_if<typename Conditions::NotAKnot>(cond)) {
268 if (nak->point_idx < 1 || nak->point_idx >= n - 1) {
269 std::cerr <<
"Error in function " << __FUNCTION__
270 <<
": point index for condition 'NotAKnot' is out of bounds: "
271 <<
"expected to be positive and less than " << n - 1 <<
", but got " << nak->point_idx
272 <<
". Returning an empty array..." << std::endl;
276 std::cerr <<
"Error in function " << __FUNCTION__ <<
": Unknown condition of 'Custom' type. This should not have happened. "
277 <<
"Please report this to the developers. Returning an empty array..." << std::endl;
283 if (
const auto c1 = std::get_if<typename Conditions::Clamped>(&custom->cond1),
284 c2 = std::get_if<typename Conditions::Clamped>(&custom->cond2);
286 if (c1->point_idx == c2->point_idx) {
287 const auto df = (c1->df + c2->df) / 2;
288 if (c1->point_idx < n / 2) {
294 }
else if (
const auto fs1 = std::get_if<typename Conditions::FixedSecond>(&custom->cond1),
295 fs2 = std::get_if<typename Conditions::FixedSecond>(&custom->cond2);
297 if (fs1->point_idx == fs2->point_idx) {
298 const auto d2f = (fs1->d2f + fs2->d2f) / 2;
299 if (fs1->point_idx < n / 2) {
305 }
else if (
const auto ft1 = std::get_if<typename Conditions::FixedThird>(&custom->cond1),
306 ft2 = std::get_if<typename Conditions::FixedThird>(&custom->cond2);
308 if (ft1->segment_idx == ft2->segment_idx) {
310 const auto i = ft1->segment_idx;
311 const auto c = -dX[i] * (ft1->d3f + ft2->d3f) / 8;
312 coeffs[4*i] = -2*c / (3*dX[i]);
314 coeffs[4*i+2] = dY[i]/dX[i] - dX[i] * c / 3;
318 goto post_main_block;
320 const auto d3f = (ft1->d3f + ft2->d3f) / 2;
321 if (ft1->segment_idx < n / 2) {
328 }
else if (
const auto nak1 = std::get_if<typename Conditions::NotAKnot>(&custom->cond1),
329 nak2 = std::get_if<typename Conditions::NotAKnot>(&custom->cond2);
331 if (nak1->point_idx == nak2->point_idx) {
332 if (nak1->point_idx < n / 2) {
340 const auto set_segment_indices = [&]() {
354 set_segment_indices();
357 std::swap(custom->cond1, custom->cond2);
358 set_segment_indices();
367 = std::holds_alternative<typename Conditions::Clamped>(custom->cond1)
368 ? std::get_if<typename Conditions::Clamped>(&custom->cond1)
369 : std::get_if<typename
Conditions::Clamped>(&custom->cond2);
371 = std::holds_alternative<typename Conditions::FixedSecond>(custom->cond1)
372 ? std::get_if<typename Conditions::FixedSecond>(&custom->cond1)
373 : std::get_if<typename
Conditions::FixedSecond>(&custom->cond2);
376 coeffs[4*(i-1)] = (fs->d2f/2 - c->df/dX[i-1] + dY[i-1]/dX[i-1]/dX[i-1]) / dX[i-1];
377 coeffs[4*(i-1)+1] = 3*c->df/dX[i-1] - 3*dY[i-1]/dX[i-1]/dX[i-1] - fs->d2f;
378 coeffs[4*(i-1)+2] = 3*dY[i-1]/dX[i-1] + fs->d2f*dX[i-1]/2 - 2*c->df;
379 coeffs[4*(i-1)+3] = Y[i-1];
383 coeffs[4*i] = (dY[i]/dX[i]/dX[i] - c->df/dX[i] - fs->d2f/2) / dX[i];
384 coeffs[4*i+1] = fs->d2f/2;
389 goto post_main_block;
393 const auto m = i2 - i1 + 1;
396 Container<Number> lower(m), diag(m), upper(m), right(m);
397 for (
SizeT i = i1 + 1; i < i1 + m - 1; ++i) {
398 const auto j = i - i1;
400 diag[j] = 2 * (dX[i-1] + dX[i]);
402 right[j] = 3 * (dY[i]/dX[i] - dY[i-1]/dX[i-1]);
412 right[0] = 3 * (dY[i1]/dX[i1] - c.df);
417 right[0] = fs.d2f / 2;
422 right[0] = -dX[i1] * ft.d3f / 2;
425 diag[0] = dX[i1] - dX[i1+1];
426 upper[0] = 2*dX[i1] + dX[i1+1];
427 right[0] = dX[i1] / (dX[i1]+dX[i1+1]) * 3 * (dY[i1+1]/dX[i1+1] - dY[i1]/dX[i1]);
432 lower[m-1] = dX[i1+m-2];
433 diag[m-1] = 2*dX[i1+m-2];
434 right[m-1] = 3 * (c.df - dY[i1+m-2]/dX[i1+m-2]);
439 right[m-1] = fs.d2f / 2;
444 right[m-1] = dX[i1+m-2] * ft.d3f / 2;
447 lower[m-1] = 2*dX[i1+m-2] + dX[i1+m-3];
448 diag[m-1] = dX[i1+m-2] - dX[i1+m-3];
449 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]);
454 std::move(lower), std::move(diag), std::move(upper), std::move(right));
456 for (
SizeT i = 0, index = 4 * i1; i < m - 1; ++i) {
457 const auto j = i + i1;
458 coeffs[index++] = (C[i+1] - C[i]) / (3*dX[j]);
460 coeffs[index++] = dY[j]/dX[j] - dX[j] * ((2*C[i] + C[i+1]) / 3);
465 if (
const auto* ft = std::get_if<typename Conditions::FixedThird>(&custom->cond1)) {
466 coeffs[4*i1] = ft->d3f / 6;
468 if (
const auto* ft = std::get_if<typename Conditions::FixedThird>(&custom->cond2)) {
469 coeffs[4*(i2-1)] = ft->d3f / 6;
472 std::cerr <<
"Error in function " << __FUNCTION__ <<
": Unknown type. This should not have happened. "
473 <<
"Please report this to the developers. Returning an empty array..." << std::endl;
478 for (
SizeT iter = 0; iter < i1; ++iter) {
479 const auto i = i1 - 1 - iter;
480 coeffs[4*i] = (
coeffs[4*(i+1)+1] -
coeffs[4*(i+1)+2]/dX[i] + dY[i]/dX[i]/dX[i]) / dX[i];
486 for (
SizeT i = i2; i < n - 1; ++i) {