#include "rationalcubic.h"
#if defined(_MSC_VER)
#define NOMINMAX
#pragma float_control(except, off)
#pragma float_control(precise, off)
#pragma fp_contract(on)
#pragma fenv_access(off)
#endif
#include <algorithm>
#include <cmath>
#include <float.h>
namespace {
const double minimum_rational_cubic_control_parameter_value = -(1 - sqrt(DBL_EPSILON));
const double maximum_rational_cubic_control_parameter_value = 2 / (DBL_EPSILON * DBL_EPSILON);
inline bool is_zero(double x) {
return fabs(x) < DBL_MIN;
}
}
double rational_cubic_interpolation(double x, double x_l, double x_r, double y_l, double y_r, double d_l, double d_r, double r) {
const double h = (x_r - x_l);
if (fabs(h) <= 0)
return 0.5 * (y_l + y_r);
const double t = (x - x_l) / h;
if (!(r >= maximum_rational_cubic_control_parameter_value)) {
const double t = (x - x_l) / h, omt = 1 - t, t2 = t * t, omt2 = omt * omt;
return (y_r * t2 * t + (r * y_r - h * d_r) * t2 * omt + (r * y_l + h * d_l) * t * omt2 + y_l * omt2 * omt) / (1 + (r - 3) * t * omt);
}
return y_r * t + y_l * (1 - t);
}
double rational_cubic_control_parameter_to_fit_second_derivative_at_left_side(double x_l, double x_r, double y_l, double y_r, double d_l, double d_r, double second_derivative_l) {
const double h = (x_r - x_l), numerator = 0.5 * h * second_derivative_l + (d_r - d_l);
if (is_zero(numerator))
return 0;
const double denominator = (y_r - y_l) / h - d_l;
if (is_zero(denominator))
return numerator > 0 ? maximum_rational_cubic_control_parameter_value : minimum_rational_cubic_control_parameter_value;
return numerator / denominator;
}
double rational_cubic_control_parameter_to_fit_second_derivative_at_right_side(double x_l, double x_r, double y_l, double y_r, double d_l, double d_r, double second_derivative_r) {
const double h = (x_r - x_l), numerator = 0.5 * h * second_derivative_r + (d_r - d_l);
if (is_zero(numerator))
return 0;
const double denominator = d_r - (y_r - y_l) / h;
if (is_zero(denominator))
return numerator > 0 ? maximum_rational_cubic_control_parameter_value : minimum_rational_cubic_control_parameter_value;
return numerator / denominator;
}
double minimum_rational_cubic_control_parameter(double d_l, double d_r, double s, bool preferShapePreservationOverSmoothness) {
const bool monotonic = d_l * s >= 0 && d_r * s >= 0, convex = d_l <= s && s <= d_r, concave = d_l >= s && s >= d_r;
if (!monotonic && !convex && !concave) return minimum_rational_cubic_control_parameter_value;
const double d_r_m_d_l = d_r - d_l, d_r_m_s = d_r - s, s_m_d_l = s - d_l;
double r1 = -DBL_MAX, r2 = r1;
if (monotonic) {
if (!is_zero(s)) r1 = (d_r + d_l) / s; else if (preferShapePreservationOverSmoothness) r1 = maximum_rational_cubic_control_parameter_value; }
if (convex || concave) {
if (!(is_zero(s_m_d_l) || is_zero(d_r_m_s))) r2 = std::max(fabs(d_r_m_d_l / d_r_m_s), fabs(d_r_m_d_l / s_m_d_l));
else if (preferShapePreservationOverSmoothness)
r2 = maximum_rational_cubic_control_parameter_value; } else if (monotonic && preferShapePreservationOverSmoothness)
r2 = maximum_rational_cubic_control_parameter_value; return std::max(minimum_rational_cubic_control_parameter_value, std::max(r1, r2));
}
double convex_rational_cubic_control_parameter_to_fit_second_derivative_at_left_side(double x_l, double x_r, double y_l, double y_r, double d_l, double d_r, double second_derivative_l, bool preferShapePreservationOverSmoothness) {
const double r = rational_cubic_control_parameter_to_fit_second_derivative_at_left_side(x_l, x_r, y_l, y_r, d_l, d_r, second_derivative_l);
const double r_min = minimum_rational_cubic_control_parameter(d_l, d_r, (y_r - y_l) / (x_r - x_l), preferShapePreservationOverSmoothness);
return std::max(r, r_min);
}
double convex_rational_cubic_control_parameter_to_fit_second_derivative_at_right_side(double x_l, double x_r, double y_l, double y_r, double d_l, double d_r, double second_derivative_r, bool preferShapePreservationOverSmoothness) {
const double r = rational_cubic_control_parameter_to_fit_second_derivative_at_right_side(x_l, x_r, y_l, y_r, d_l, d_r, second_derivative_r);
const double r_min = minimum_rational_cubic_control_parameter(d_l, d_r, (y_r - y_l) / (x_r - x_l), preferShapePreservationOverSmoothness);
return std::max(r, r_min);
}