dust3d/thirdparty/cgal/CGAL-5.1/include/CGAL/Kernel/Conic_misc.h

157 lines
4.1 KiB
C++

// Copyright (c) 2000,2001
// Utrecht University (The Netherlands),
// ETH Zurich (Switzerland),
// INRIA Sophia-Antipolis (France),
// Max-Planck-Institute Saarbruecken (Germany),
// and Tel-Aviv University (Israel). All rights reserved.
//
// This file is part of CGAL (www.cgal.org)
//
// $URL: https://github.com/CGAL/cgal/blob/v5.1/Kernel_23/include/CGAL/Kernel/Conic_misc.h $
// $Id: Conic_misc.h 0779373 2020-03-26T13:31:46+01:00 Sébastien Loriot
// SPDX-License-Identifier: LGPL-3.0-or-later OR LicenseRef-Commercial
//
//
// Author(s) : Bernd Gaertner, Sven Schoenherr <sven@inf.ethz.ch>
#ifndef CGAL_CONIC_MISC_H
#define CGAL_CONIC_MISC_H
#include <cmath>
#include <CGAL/number_utils.h>
#include <CGAL/kernel_assertions.h>
#include <boost/math/special_functions/cbrt.hpp>
namespace CGAL {
template < class R>
class Conic_2;
enum Conic_type
{
HYPERBOLA = -1,
PARABOLA,
ELLIPSE
};
typedef CGAL::Bounded_side Convex_side;
const Convex_side ON_CONVEX_SIDE = CGAL::ON_BOUNDED_SIDE;
const Convex_side ON_NONCONVEX_SIDE = CGAL::ON_UNBOUNDED_SIDE;
template < class NT >
NT best_value (NT *values, int nr_values,
NT a2, NT a1, NT a0,
NT b3, NT b2, NT b1, NT b0)
{
bool det_positive = false;
NT d, q, max_det = 0, det, best = -1;
for (int i=0; i<nr_values; ++i) {
NT x = values[i];
d = (a2*x+a1)*x+a0;
q = ((b3*x+b2)*x+b1)*x+b0;
det = d*d*d/(q*q);
// if q==0, this root value doesn't qualify for the
// best value. Under roundoff errors, q might be very
// small but nonzero, so that the value is erroneously
// being considered; however, d should be very small
// in this case as well, so that det won't compete
// for max_det below.
if (CGAL_NTS is_positive(det) && !CGAL_NTS is_zero(q))
if (!det_positive || (det > max_det)) {
max_det = det;
best = x;
det_positive = true;
}
}
CGAL_kernel_precondition (det_positive);
return best;
}
template < class NT >
int solve_cubic (NT c3, NT c2, NT c1, NT c0,
NT& r1, NT& r2, NT& r3)
{
if (c3 == 0.0) {
// quadratic equation
if (c2 == 0) {
// linear equation
CGAL_kernel_precondition (c1 != 0);
r1 = -c0/c1;
return 1;
}
NT D = c1*c1-4*c2*c0;
if (D < 0.0)
// only complex roots
return 0;
if (D == 0.0) {
// one real root
r1 = -c1/(2.0*c2);
return 1;
}
// two real roots
r1 = (-c1 + CGAL_NTS sqrt(D))/(2.0*c2);
r2 = (-c1 - CGAL_NTS sqrt(D))/(2.0*c2);
return 2;
}
// cubic equation
// define the gamma_i
NT g2 = c2/c3,
g1 = c1/c3,
g0 = c0/c3;
// define a, b
NT a = g1 - g2*g2/3.0,
b = 2.0*g2*g2*g2/27.0 - g1*g2/3.0 + g0;
if (a == 0) {
// one real root
r1 = boost::math::cbrt(-b) - g2 / 3.0;
// r1 = std::exp(std::log(-b) / 3.0) - g2 / 3.0;
return 1;
}
// define D
NT D = a*a*a/27.0 + b*b/4.0;
if (D >= 0.0) {
// real case
NT u = boost::math::cbrt(-b / 2.0 + CGAL_NTS sqrt(D)),
// NT u = std::exp(std::log(-b/2.0 + CGAL_NTS sqrt(D)) / 3.0),
alpha = 1.0 - a/(3.0*u*u);
if (D == 0) {
// two distinct real roots
r1 = u*alpha - g2/3.0;
r2 = -0.5*alpha*u - g2/3.0;
return 2;
}
// one real root
r1 = u*alpha - g2/3.0;
return 1;
}
// complex case
NT r_prime = CGAL_NTS sqrt(-a/3),
phi_prime = acos (-b/(2.0*r_prime*r_prime*r_prime))/3.0,
u_R = r_prime * cos (phi_prime),
u_I = r_prime * sin (phi_prime);
// three distinct real roots
r1 = 2.0*u_R - g2/3.0;
r2 = -u_R + u_I*std::sqrt(3.0) - g2/3.0;
r3 = -u_R - u_I*std::sqrt(3.0) - g2/3.0;
return 3;
}
} //namespace CGAL
#endif // CGAL_CONIC_MISC_H
// ===== EOF ==================================================================