cgal/Fixed_precision_nt/include/CGAL/Fixed_precision_nt.h

802 lines
32 KiB
C++

// Copyright (c) 1998 Utrecht University (The Netherlands),
// ETH Zurich (Switzerland), Freie Universitaet Berlin (Germany),
// INRIA Sophia-Antipolis (France), Martin-Luther-University Halle-Wittenberg
// (Germany), Max-Planck-Institute Saarbruecken (Germany), RISC Linz (Austria),
// and Tel-Aviv University (Israel). All rights reserved.
//
// This file is part of CGAL (www.cgal.org); you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public License as
// published by the Free Software Foundation; version 2.1 of the License.
// See the file LICENSE.LGPL distributed with CGAL.
//
// Licensees holding a valid commercial license may use this file in
// accordance with the commercial license agreement provided with the software.
//
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
//
// $URL$
// $Id$
//
//
// Author(s) : Olivier Devillers <Olivivier.Devillers@sophia.inria.fr>
#ifndef CGAL_FIXED_PRECISION_NT_H
#define CGAL_FIXED_PRECISION_NT_H
#include <CGAL/basic.h>
#include <iostream>
#include <CGAL/tags.h>
#include <CGAL/enum.h>
#include <CGAL/assertions.h>
#include <CGAL/double.h>
#include <CGAL/number_utils.h>
CGAL_BEGIN_NAMESPACE
// Fixed_precision_nt implement 24 bits integers using float
// The user has to initiate a multiplicator factor to be applied to
// original data.
// ======================================================================
//--------- static variables declaration and initialization
// ======================================================================
// static marks to decide if perturbation are used
static bool Fixed_incircle_perturb= false;
static bool Fixed_insphere_perturb= false;
////// degree 0 constant
static double Fixed_Or2 = 3.0/9007199254740992.0;
// 3/2^53 semi-static orientation filter
static double Fixed_Ic2 = 3.0/9007199254740992.0;
// 3/2^54 semi-static incircle filter
static double Fixed_Is2 = 6.0 / 18014398509481984.0;
// 6/2^54 semi-static insphere filter
////// degree 1 constant
static double Fixed_B0=0.0;
// precision on coordinates
// assumed to be 1.0 to fix value below
static double Fixed_B24 = 16777216.0;
// 2^24 bound on coordinates
static double Fixed_SNAP = 6755399441055744.0;
// 3 * 2^51 for rounding of coordinates
////// degree 2 constant
static double Fixed_S_2_25= 453347182355485940514816.0;
// 3 * 2^77 split to bit B0^2 * 2^25
////// degree 3 constant
static double Fixed_S_3_25= Fixed_S_2_25;
// 3 * 2^77 split to bit B0^3 * 2^25
static double Fixed_S_3_51= 30423614405477505635920876929024.0;
// 3 * 2^103 split to bit B0^3 * 2^51
static double Fixed_Or1 = 37748736.0;
// 9*2^22 static error for orientation filter
static double Fixed_Bx3 = 0.5;
// 2^(-1) half degree 3 unit for semi-static filter
////// degree 4 constant
static double Fixed_Ic1 = 2533274790395904.0;
// 9*2^48; static error for incircle filter
static double Fixed_Bx4 = 0.5;
// 2^(-1) half degree 4 unit for semi-static filter
////// degree 5 constant
static double Fixed_Is1 = 1416709944860893564108800.0;
// 75*2^74; static error for insphere filter
static double Fixed_Bx5 = 0.5;
// 2^(-1) half degree 5 unit for semi-static filter
class Fixed_precision_nt
{
private:
float _value; // value of the number
// I put this function here so that GCC doesn't complain with -Winline.
void round() {_value = ( _value+ Fixed_SNAP ) - Fixed_SNAP ;}
public:
typedef Tag_false Has_gcd;
typedef Tag_true Has_division;
typedef Tag_false Has_sqrt;
typedef Tag_false Has_exact_ring_operations;
typedef Tag_false Has_exact_division;
typedef Tag_false Has_exact_sqrt;
// constructors
Fixed_precision_nt() {_value=0;}
Fixed_precision_nt(const Fixed_precision_nt&f) {_value=f._value;}
Fixed_precision_nt(double f) {_value=f; round(); }
Fixed_precision_nt(int f) {_value=f; round(); }
//access functions
double to_double() const {return (double)_value;}
float to_float() const {return _value;}
// NT requirements
Fixed_precision_nt operator= (const Fixed_precision_nt&f)
{_value= f._value; return *this;}
Fixed_precision_nt operator+=(const Fixed_precision_nt&f)
{_value+=f._value; return *this;}
Fixed_precision_nt operator-=(const Fixed_precision_nt&f)
{_value-=f._value; return *this;}
Fixed_precision_nt operator*=(const Fixed_precision_nt&f)
{_value*=f._value; return *this;}
Fixed_precision_nt operator/=(const Fixed_precision_nt&f)
{_value/=f._value; return *this;}
// access and parametrization of static members
inline static bool init(float f);
static float unit_value() {return Fixed_B0;}
static float upper_bound(){return Fixed_B24;}
static void perturb_incircle(){Fixed_incircle_perturb=true;}
static void unperturb_incircle(){Fixed_incircle_perturb=false;}
static bool is_perturbed_incircle(){return Fixed_incircle_perturb;}
static void perturb_insphere(){Fixed_insphere_perturb=true;}
static void unperturb_insphere(){Fixed_insphere_perturb=false;}
static bool is_perturbed_insphere(){return Fixed_insphere_perturb;}
};
inline double to_double(Fixed_precision_nt a){ return a.to_double(); }
inline bool is_finite(Fixed_precision_nt) { return true; }
inline bool is_valid(Fixed_precision_nt) { return true; }
inline
std::pair<double,double>
to_interval (Fixed_precision_nt a)
{
double d = a.to_double();
return std::make_pair(d,d);
}
inline Fixed_precision_nt operator- (Fixed_precision_nt a)
{ return Fixed_precision_nt( - (a.to_double()) );}
inline Fixed_precision_nt operator+(Fixed_precision_nt a, Fixed_precision_nt b)
{ return Fixed_precision_nt(a.to_double() + b.to_double() );}
inline Fixed_precision_nt operator-(Fixed_precision_nt a, Fixed_precision_nt b)
{ return Fixed_precision_nt(a.to_double() - b.to_double() );}
inline Fixed_precision_nt operator*(Fixed_precision_nt a, Fixed_precision_nt b)
{ return Fixed_precision_nt(a.to_double() * b.to_double() );}
inline Fixed_precision_nt operator/(Fixed_precision_nt a, Fixed_precision_nt b)
{ return Fixed_precision_nt(a.to_double() / b.to_double() );}
inline bool operator< (Fixed_precision_nt a, Fixed_precision_nt b)
{ return (a.to_double() < b.to_double() );}
inline bool operator<= (Fixed_precision_nt a, Fixed_precision_nt b)
{ return (a.to_double() <= b.to_double() );}
inline bool operator> (Fixed_precision_nt a, Fixed_precision_nt b)
{ return (a.to_double() > b.to_double() );}
inline bool operator>= (Fixed_precision_nt a, Fixed_precision_nt b)
{ return (a.to_double() >= b.to_double() );}
inline bool operator== (Fixed_precision_nt a, Fixed_precision_nt b)
{ return (a.to_double() == b.to_double() );}
inline bool operator!= (Fixed_precision_nt a, Fixed_precision_nt b)
{ return (a.to_double() != b.to_double() );}
inline std::ostream &operator<<(std::ostream &os, const Fixed_precision_nt& a)
{ return os << a.to_double(); }
inline std::istream &operator>>(std::istream &is, Fixed_precision_nt& a)
{ float f; is >>f; a=Fixed_precision_nt(f); return is; }
// ======================================================================
//--------- non official mysterious NT requirement
// ======================================================================
inline io_Operator io_tag(Fixed_precision_nt)
{ return io_Operator(); }
// ======================================================================
//--------- initialize the upper bound on fixed
// ======================================================================
inline bool Fixed_precision_nt::init(float b)
// return true if init succeed false otherwise
// Precondition : b positive
// Precondition : non yet initialized
// parameter b is the upper bound on absolute value on all entries
{
bool result = true;
if (b<=0) b=-b;
if (Fixed_B0!=0) result = false;
float D = ((double) b) * 4503599627370497.0; //2^52 + 1
D = (((double) b)+D )-D ; // get the power of two closer to b
if (D<b) D *=2;
Fixed_B0 = D/Fixed_B24; // B24 = 2^24
Fixed_B24 = D;
Fixed_SNAP *= Fixed_B0;
Fixed_S_2_25*= Fixed_B0*Fixed_B0;
Fixed_S_3_25*= Fixed_B0*Fixed_B0*Fixed_B0;
Fixed_S_3_51*= Fixed_B0*Fixed_B0*Fixed_B0;
Fixed_Or1 *= Fixed_B0*Fixed_B0*Fixed_B0;
Fixed_Bx3 *= Fixed_B0*Fixed_B0*Fixed_B0;
Fixed_Ic1 *= Fixed_B0*Fixed_B0*Fixed_B0*Fixed_B0;
Fixed_Bx4 *= Fixed_B0*Fixed_B0*Fixed_B0*Fixed_B0;
Fixed_Is1 *=
Fixed_B0*Fixed_B0*Fixed_B0*Fixed_B0*Fixed_B0;
Fixed_Bx5 *=
Fixed_B0*Fixed_B0*Fixed_B0*Fixed_B0*Fixed_B0;
return result;
};
// ======================================================================
//--------- splitting numbers for exact computation
// ======================================================================
inline void Fixed_split
(double a, double &a1, double &a0, const double &format)
// split a in two numbers. a=a1+a0, a1 get the most significant digit
// format specify the range of the input, and how to split
// if format is S_i_j it means that a is of degree i
// (in terms of original coordinates) the splitting bit is B0^i*2^j
{ a1 = a+format; a1-= format; a0 = a-a1; }
// ======================================================================
//--------- geometric predicates
// ======================================================================
inline Comparison_result
cmp_dist_to_pointC2(
const Fixed_precision_nt& x0, const Fixed_precision_nt& y0,
const Fixed_precision_nt& x1, const Fixed_precision_nt& y1,
const Fixed_precision_nt& x2, const Fixed_precision_nt& y2)
{
return CGAL_NTS compare(
CGAL_NTS square(x0.to_double()-x1.to_double())
+ CGAL_NTS square(y0.to_double()-y1.to_double()),
CGAL_NTS square(x0.to_double()-x2.to_double())
+ CGAL_NTS square(y0.to_double()-y2.to_double()));
}
inline Orientation orientationC2
(const Fixed_precision_nt& x0, const Fixed_precision_nt& y0,
const Fixed_precision_nt& x1, const Fixed_precision_nt& y1,
const Fixed_precision_nt& x2, const Fixed_precision_nt& y2)
{
/* points are assumed to be distincts */
double det = ( x1.to_double() - x0.to_double())
*( y2.to_double() - y0.to_double())
-( x2.to_double() - x0.to_double())
*( y1.to_double() - y0.to_double());
/* stay inside double precision, thus it is exact */
if (det>0) return LEFT_TURN;
if (det) return RIGHT_TURN;
/* the points are collinear */
return COLLINEAR;
}
inline Oriented_side side_of_oriented_circleC2 (
const Fixed_precision_nt& x0, const Fixed_precision_nt& y0,
const Fixed_precision_nt& x1, const Fixed_precision_nt& y1,
const Fixed_precision_nt& x2, const Fixed_precision_nt& y2,
const Fixed_precision_nt& x3, const Fixed_precision_nt& y3)
// relative position of p3 with respect to circle p0p1p2
// if p0p1p2 is positively oriented,
// positive side is the interior of the circle
{
double X1=x1.to_double()-x0.to_double();
double Y1=y1.to_double()-y0.to_double();
double X2=x2.to_double()-x0.to_double();
double Y2=y2.to_double()-y0.to_double();
double X3=x3.to_double()-x0.to_double();
double Y3=y3.to_double()-y0.to_double();
double R1=X1*X1+Y1*Y1;
double R2=X2*X2+Y2*Y2;
double R3=X3*X3+Y3*Y3;
double M1=X2*Y3-X3*Y2;
double M2=X1*Y3-X3*Y1;
double M3=X1*Y2-X2*Y1;
double det= R1*M1 -R2*M2 +R3*M3;
if (det > Fixed_Ic1) return ON_NEGATIVE_SIDE;
if (det <= -Fixed_Ic1) return ON_POSITIVE_SIDE;
// static filter failed, error is small
{
double error=
CGAL_NTS abs(R1*M1) + CGAL_NTS abs(R2*M2) + CGAL_NTS abs(R3*M3) ;
error *= Fixed_Ic2 ;
if ( error < Fixed_Bx4 ) error = 0.0;
if (det > error) return ON_NEGATIVE_SIDE;
if (det < -error) return ON_POSITIVE_SIDE;
double m1,m2,m3,r1,r2,r3;
if (error!=0) {
// dynamic filter failed, error is very small
Fixed_split(M1,M1,m1,Fixed_S_2_25);
Fixed_split(M2,M2,m2,Fixed_S_2_25);
Fixed_split(M3,M3,m3,Fixed_S_2_25);
// Minor i is Mi+mi
Fixed_split(R1,R1,r1,Fixed_S_2_25);
Fixed_split(R2,R2,r2,Fixed_S_2_25);
Fixed_split(R3,R3,r3,Fixed_S_2_25);
// xi^2+yi^2 is Ri+ri
det = R1*M1 -R2*M2 +R3*M3 ; // most significant
// exact because necessary less than 2^80 and multiple 2^52
det += (R1*m1 + r1*M1) - (R2*m2 + r2*M2) + (R3*m3 + r3*M3) ;
// exact because necessary less than 2^53 and multiple 2^25
det += r1*m1 -r2*m2 +r3*m3 ; // less significant
if (det>0) return ON_NEGATIVE_SIDE;
if (det<0) return ON_POSITIVE_SIDE;
}
//cocircular case
if (! Fixed_incircle_perturb) return ON_ORIENTED_BOUNDARY;
// apply perturbation method
// first order coefficient is obtained replacing x^2+y^2 by xy
R1 = X1*Y1;
R2 = X2*Y2;
R3 = X3*Y3;
det= R1*M1 -R2*M2 +R3*M3;
if (det > Fixed_Ic1) return ON_NEGATIVE_SIDE;
if (det <= -Fixed_Ic1) return ON_POSITIVE_SIDE;
// static filter failed, error is small
error=
(CGAL_NTS abs(R1*M1)+CGAL_NTS abs(R2*M2)+CGAL_NTS abs(R3*M3))
* Fixed_Ic2 ;
if ( error < Fixed_Bx4 ) error = 0.0;
if (det > error) return ON_NEGATIVE_SIDE;
if (det < -error) return ON_POSITIVE_SIDE;
if (error!=0) {
// dynamic filter failed, error is very small
Fixed_split(R1,R1,r1,Fixed_S_2_25);
Fixed_split(R2,R2,r2,Fixed_S_2_25);
Fixed_split(R3,R3,r3,Fixed_S_2_25);
det = R1*M1 -R2*M2 +R3*M3 ;
det += (R1*m1 + r1*M1) - (R2*m2 + r2*M2) + (R3*m3 + r3*M3) ;
det += r1*m1 -r2*m2 +r3*m3 ;
if (det>0) return ON_NEGATIVE_SIDE;
if (det<0) return ON_POSITIVE_SIDE;
}
// first order coefficient is null,
// compute second order coefficient in the pertrubation method
// replace x^2+y^2 by y^2
R1 = Y1*Y1;
R2 = Y2*Y2;
R3 = Y3*Y3;
det= R1*M1 -R2*M2 +R3*M3;
if (det > Fixed_Ic1) return ON_NEGATIVE_SIDE;
if (det <= -Fixed_Ic1) return ON_POSITIVE_SIDE;
// static filter failed, error is small
error=
(CGAL_NTS abs(R1*M1)+CGAL_NTS abs(R2*M2)+CGAL_NTS abs(R3*M3))
* Fixed_Ic2 ;
if ( error < Fixed_Bx4 ) error = 0.0;
if (det > error) return ON_NEGATIVE_SIDE;
if (det < -error) return ON_POSITIVE_SIDE;
if (error!=0) {
// dynamic filter failed, error is very small
Fixed_split(R1,R1,r1,Fixed_S_2_25);
Fixed_split(R2,R2,r2,Fixed_S_2_25);
Fixed_split(R3,R3,r3,Fixed_S_2_25);
det = R1*M1 -R2*M2 +R3*M3 ;
det += (R1*m1 + r1*M1) - (R2*m2 + r2*M2) + (R3*m3 + r3*M3) ;
det += r1*m1 -r2*m2 +r3*m3 ;
if (det>0) return ON_NEGATIVE_SIDE;
if (det<0) return ON_POSITIVE_SIDE;
}
// points are collinear
return ON_ORIENTED_BOUNDARY;
}
}
inline Comparison_result
cmp_dist_to_pointC3(
const Fixed_precision_nt& x0, const Fixed_precision_nt& y0,
const Fixed_precision_nt& z0,
const Fixed_precision_nt& x1, const Fixed_precision_nt& y1,
const Fixed_precision_nt& z1,
const Fixed_precision_nt& x2, const Fixed_precision_nt& y2,
const Fixed_precision_nt& z2)
{
return CGAL_NTS compare(
CGAL_NTS square(x0.to_double()-x1.to_double())
+ CGAL_NTS square(y0.to_double()-y1.to_double())
+ CGAL_NTS square(z0.to_double()-z1.to_double()),
CGAL_NTS square(x0.to_double()-x2.to_double())
+ CGAL_NTS square(y0.to_double()-y2.to_double())
+ CGAL_NTS square(z0.to_double()-z2.to_double()));
}
inline
Orientation orientationC3
( const Fixed_precision_nt& x0, const Fixed_precision_nt& y0,
const Fixed_precision_nt& z0,
const Fixed_precision_nt& x1, const Fixed_precision_nt& y1,
const Fixed_precision_nt& z1,
const Fixed_precision_nt& x2, const Fixed_precision_nt& y2,
const Fixed_precision_nt& z2,
const Fixed_precision_nt& x3, const Fixed_precision_nt& y3,
const Fixed_precision_nt& z3)
{
double X1=x1.to_double() -x0.to_double();
double Y1=y1.to_double() -y0.to_double();
double Z1=z1.to_double() -z0.to_double();
double X2=x2.to_double() -x0.to_double();
double Y2=y2.to_double() -y0.to_double();
double Z2=z2.to_double() -z0.to_double();
double X3=x3.to_double() -x0.to_double();
double Y3=y3.to_double() -y0.to_double();
double Z3=z3.to_double() -z0.to_double();
double M1=Y2*Z3-Y3*Z2;
double M2=Y1*Z3-Y3*Z1;
double M3=Y1*Z2-Y2*Z1;
double det= X1*M1 - X2*M2 + X3*M3 ;
if (det > Fixed_Or1 ) return POSITIVE;
if (det < -Fixed_Or1 ) return NEGATIVE;
/* det is small */
double error=
CGAL_NTS abs(X1*M1) + CGAL_NTS abs(X2*M2) + CGAL_NTS abs(X3*M3);
error *= Fixed_Or2;
if ( error < Fixed_Bx3) error = 0.0;
if (det > error) return POSITIVE;
if (det < -error) return NEGATIVE;
/* det is very small, exact computation must be done */
if (error!=0.0) { // otherwise, exact value 0 already certified
Fixed_split(M1,M1,Z1,Fixed_S_2_25);
Fixed_split(M2,M2,Z2,Fixed_S_2_25);
Fixed_split(M3,M3,Z3,Fixed_S_2_25);
det = X1*M1 - X2*M2 + X3*M3 ;
det += X1*Z1 - X2*Z2 + X3*Z3 ; /* less significant */
if (det>0) return POSITIVE;
if (det<0) return NEGATIVE;
}
/* points are coplanar */
return COPLANAR;
}
inline
Oriented_side side_of_oriented_sphereC3
( const Fixed_precision_nt& x0, const Fixed_precision_nt& y0,
const Fixed_precision_nt& z0,
const Fixed_precision_nt& x1, const Fixed_precision_nt& y1,
const Fixed_precision_nt& z1,
const Fixed_precision_nt& x2, const Fixed_precision_nt& y2,
const Fixed_precision_nt& z2,
const Fixed_precision_nt& x3, const Fixed_precision_nt& y3,
const Fixed_precision_nt& z3,
const Fixed_precision_nt& x4, const Fixed_precision_nt& y4,
const Fixed_precision_nt& z4)
// relative position of p4 with respect to sphere p0p1p2p3
// if p0p1p2p3 is positively oriented,
// positive side is the interior of the sphere
{ double det,error;
// transform in 4x4 determinant
// point p4 is inside sphere through oriented tetra p0p1p2p3
// if the determinant is negative
double X1=x1.to_double() -x0.to_double() ;
double Y1=y1.to_double() -y0.to_double() ;
double Z1=z1.to_double() -z0.to_double() ;
double X2=x2.to_double() -x0.to_double() ; // | X1 X2 X3 X4 |
double Y2=y2.to_double() -y0.to_double() ; // | Y1 Y2 Y3 Y4 |
double Z2=z2.to_double() -z0.to_double() ; // | Z1 Z2 Z3 Z4 |
double X3=x3.to_double() -x0.to_double() ; // | R1 R2 R3 R4 |
double Y3=y3.to_double() -y0.to_double() ;
double Z3=z3.to_double() -z0.to_double() ;
double X4=x4.to_double() -x0.to_double() ;
double Y4=y4.to_double() -y0.to_double() ;
double Z4=z4.to_double() -z0.to_double() ;
double R1= X1*X1+Y1*Y1+Z1*Z1;
double R2= X2*X2+Y2*Y2+Z2*Z2;
double R3= X3*X3+Y3*Y3+Z3*Z3;
double R4= X4*X4+Y4*Y4+Z4*Z4;
// compute 2x2 minors on the two first lines
double M12 = X1 * Y2 - X2 * Y1;
double M23 = X2 * Y3 - X3 * Y2;
double M34 = X3 * Y4 - X4 * Y3;
double M13 = X1 * Y3 - X3 * Y1;
double M14 = X1 * Y4 - X4 * Y1;
double M24 = X2 * Y4 - X4 * Y2;
// compute 3x3 minors on the three first lines
double MM1 = Z2 * M34 - Z3 * M24 + Z4 * M23 ;
double MM2 = Z1 * M34 - Z3 * M14 + Z4 * M13 ;
double MM3 = Z1 * M24 - Z2 * M14 + Z4 * M12 ;
double MM4 = Z1 * M23 - Z2 * M13 + Z3 * M12 ;
// compute determinant
det= (R2 * MM2 - R1 * MM1) + (R4 * MM4 - R3 * MM3) ;
if (det >= Fixed_Is1 ) return ON_NEGATIVE_SIDE;
if (det <= -Fixed_Is1 ) return ON_POSITIVE_SIDE;
// static filter failed, error is small
{
double mm1 =CGAL_NTS abs(Z2*M34) + CGAL_NTS abs(Z3*M24)
+ CGAL_NTS abs(Z4*M23) ;
double mm2 =CGAL_NTS abs(Z1*M34) + CGAL_NTS abs(Z3*M14)
+ CGAL_NTS abs(Z4*M13) ;
double mm3 =CGAL_NTS abs(Z1*M24) + CGAL_NTS abs(Z2*M14)
+ CGAL_NTS abs(Z4*M12) ;
double mm4 =CGAL_NTS abs(Z1*M23) + CGAL_NTS abs(Z2*M13)
+ CGAL_NTS abs(Z3*M12) ;
error= CGAL_NTS abs(R1)*mm1 + CGAL_NTS abs(R2)*mm2
+ CGAL_NTS abs(R3)*mm3 + CGAL_NTS abs(R4)*mm4;
error *= Fixed_Is2;
if ( error < Fixed_Bx5 ) error = 0.0;
if (det > error) return ON_NEGATIVE_SIDE;
if (det < -error) return ON_POSITIVE_SIDE;
if (error!=0) {
// dynamic filter failed, error is very small
double a1,a2,a3,a4;
double b1,b2,b3,b4;
double c1,c2,c3,c4;
double d1,d2,d3,d4;
if (error!=0.0){
// start exact computation
Fixed_split(M12,a2,M12,Fixed_S_2_25);
Fixed_split(M13,a3,M13,Fixed_S_2_25);
Fixed_split(M14,a4,M14,Fixed_S_2_25);
Fixed_split(M23,b3,M23,Fixed_S_2_25);
Fixed_split(M24,b4,M24,Fixed_S_2_25);
Fixed_split(M34,c4,M34,Fixed_S_2_25);
// compute 3x3 minors ci+di is minor i
c1 = Z2 * c4 - Z3 * b4 + Z4 * b3 ; // most significant
c2 = Z1 * c4 - Z3 * a4 + Z4 * a3 ;
c3 = Z1 * b4 - Z2 * a4 + Z4 * a2 ;
c4 = Z1 * b3 - Z2 * a3 + Z3 * a2 ;
d1 = Z2 * M34 - Z3 * M24 + Z4 * M23 ; // less significant
d2 = Z1 * M34 - Z3 * M14 + Z4 * M13 ;
d3 = Z1 * M24 - Z2 * M14 + Z4 * M12 ;
d4 = Z1 * M23 - Z2 * M13 + Z3 * M12 ;
Fixed_split(d1,a1,d1,Fixed_S_3_25);
Fixed_split(d2,a2,d2,Fixed_S_3_25);
Fixed_split(d3,a3,d3,Fixed_S_3_25);
Fixed_split(d4,a4,d4,Fixed_S_3_25);
// now ci+ai+di is minor i
a1 += c1;
a2 += c2;
a3 += c3;
a4 += c4;
// now ai+di is minor i
Fixed_split(a1,c1,a1,Fixed_S_3_51);
Fixed_split(a2,c2,a2,Fixed_S_3_51);
Fixed_split(a3,c3,a3,Fixed_S_3_51);
Fixed_split(a4,c4,a4,Fixed_S_3_51);
// now ci+ai+di is minor i, non overlapping 25 bits for each
Fixed_split(R1,b1,R1,Fixed_S_2_25);
Fixed_split(R2,b2,R2,Fixed_S_2_25);
Fixed_split(R3,b3,R3,Fixed_S_2_25);
Fixed_split(R4,b4,R4,Fixed_S_2_25);
// now bi+Ri is last line, non overlapping 25 bits for each
det = (b2 * c2 - b1 * c1) ; // 1
det += (b4 * c4 - b3 * c3) ; // 1b
det += (b2 * a2 - b1 * a1) + (b4 * a4 - b3 * a3) ; // 2
det += (R2 * c2 - R1 * c1) + (R4 * c4 - R3 * c3) ; // 3
det += (b2 * d2 - b1 * d1) + (b4 * d4 - b3 * d3) ; // 4
det += (R2 * a2 - R1 * a1) + (R4 * a4 - R3 * a3) ; // 5
det += (R2 * d2 - R1 * d1) + (R4 * d4 - R3 * d3) ; // 6
if (det>0) return ON_NEGATIVE_SIDE;
if (det<0) return ON_POSITIVE_SIDE;
}
// points are cospherical
if (! Fixed_insphere_perturb)return ON_ORIENTED_BOUNDARY;
// apply perturbation method
// first order coefficient is obtained replacing x^2+y^2+z^2 by xy
R1 = X1*Y1;
R2 = X2*Y2;
R3 = X3*Y3;
R4 = X4*Y4;
// compute determinant
det= (R2 * MM2 - R1 * MM1) + (R4 * MM4 - R3 * MM3) ;
if (det >= Fixed_Is1 ) return ON_NEGATIVE_SIDE;
if (det <= -Fixed_Is1 ) return ON_POSITIVE_SIDE;
// static filter failed, error is small
error= CGAL_NTS abs(R1)*mm1 + CGAL_NTS abs(R2)*mm2
+ CGAL_NTS abs(R3)*mm3 + CGAL_NTS abs(R4)*mm4;
error *= Fixed_Is2;
if ( error < Fixed_Bx5 ) error = 0.0;
if (det > error) return ON_NEGATIVE_SIDE;
if (det < -error) return ON_POSITIVE_SIDE;
if (error!=0.0){
// dynamic filter failed, error is very small
// start exact computation
Fixed_split(R1,b1,R1,Fixed_S_2_25);
Fixed_split(R2,b2,R2,Fixed_S_2_25);
Fixed_split(R3,b3,R3,Fixed_S_2_25);
Fixed_split(R4,b4,R4,Fixed_S_2_25);
// now bi+Ri is last line, non overlapping 25 bits for each
det = (b2 * c2 - b1 * c1) ; // 1
det += (b4 * c4 - b3 * c3) ; // 1b
det += (b2 * a2 - b1 * a1) + (b4 * a4 - b3 * a3) ; // 2
det += (R2 * c2 - R1 * c1) + (R4 * c4 - R3 * c3) ; // 3
det += (b2 * d2 - b1 * d1) + (b4 * d4 - b3 * d3) ; // 4
det += (R2 * a2 - R1 * a1) + (R4 * a4 - R3 * a3) ; // 5
det += (R2 * d2 - R1 * d1) + (R4 * d4 - R3 * d3) ; // 6
if (det>0) return ON_NEGATIVE_SIDE;
if (det<0) return ON_POSITIVE_SIDE;
}
// first order coefficient is null,
// compute second order coefficient in the pertrubation method
// replace x^2+y^2+z^2 by y^2
R1 = Y1*Y1;
R2 = Y2*Y2;
R3 = Y3*Y3;
R4 = Y4*Y4;
// compute determinant
det= (R2 * MM2 - R1 * MM1) + (R4 * MM4 - R3 * MM3) ;
if (det >= Fixed_Is1 ) return ON_NEGATIVE_SIDE;
if (det <= -Fixed_Is1 ) return ON_POSITIVE_SIDE;
// static filter failed, error is small
error= CGAL_NTS abs(R1)*mm1 + CGAL_NTS abs(R2)*mm2
+ CGAL_NTS abs(R3)*mm3 + CGAL_NTS abs(R4)*mm4;
error *= Fixed_Is2;
if ( error < Fixed_Bx5 ) error = 0.0;
if (det > error) return ON_NEGATIVE_SIDE;
if (det < -error) return ON_POSITIVE_SIDE;
if (error!=0.0){
// dynamic filter failed, error is very small
// start exact computation
Fixed_split(R1,b1,R1,Fixed_S_2_25);
Fixed_split(R2,b2,R2,Fixed_S_2_25);
Fixed_split(R3,b3,R3,Fixed_S_2_25);
Fixed_split(R4,b4,R4,Fixed_S_2_25);
// now bi+Ri is last line, non overlapping 25 bits for each
det = (b2 * c2 - b1 * c1) ; // 1
det += (b4 * c4 - b3 * c3) ; // 1b
det += (b2 * a2 - b1 * a1) + (b4 * a4 - b3 * a3) ; // 2
det += (R2 * c2 - R1 * c1) + (R4 * c4 - R3 * c3) ; // 3
det += (b2 * d2 - b1 * d1) + (b4 * d4 - b3 * d3) ; // 4
det += (R2 * a2 - R1 * a1) + (R4 * a4 - R3 * a3) ; // 5
det += (R2 * d2 - R1 * d1) + (R4 * d4 - R3 * d3) ; // 6
if (det>0) return ON_NEGATIVE_SIDE;
if (det<0) return ON_POSITIVE_SIDE;
}
// 2nd order coefficient is null,
// compute 3rd order coefficient in the pertrubation method
// replace x^2+y^2+z^2 by yz
R1 = Y1*Z1;
R2 = Y2*Z2;
R3 = Y3*Z3;
R4 = Y4*Z4;
// compute determinant
det= (R2 * MM2 - R1 * MM1) + (R4 * MM4 - R3 * MM3) ;
if (det >= Fixed_Is1 ) return ON_NEGATIVE_SIDE;
if (det <= -Fixed_Is1 ) return ON_POSITIVE_SIDE;
// static filter failed, error is small
error= CGAL_NTS abs(R1)*mm1 + CGAL_NTS abs(R2)*mm2
+ CGAL_NTS abs(R3)*mm3 + CGAL_NTS abs(R4)*mm4;
error *= Fixed_Is2;
if ( error < Fixed_Bx5 ) error = 0.0;
if (det > error) return ON_NEGATIVE_SIDE;
if (det < -error) return ON_POSITIVE_SIDE;
if (error!=0.0){
// dynamic filter failed, error is very small
// start exact computation
Fixed_split(R1,b1,R1,Fixed_S_2_25);
Fixed_split(R2,b2,R2,Fixed_S_2_25);
Fixed_split(R3,b3,R3,Fixed_S_2_25);
Fixed_split(R4,b4,R4,Fixed_S_2_25);
// now bi+Ri is last line, non overlapping 25 bits for each
det = (b2 * c2 - b1 * c1) ; // 1
det += (b4 * c4 - b3 * c3) ; // 1b
det += (b2 * a2 - b1 * a1) + (b4 * a4 - b3 * a3) ; // 2
det += (R2 * c2 - R1 * c1) + (R4 * c4 - R3 * c3) ; // 3
det += (b2 * d2 - b1 * d1) + (b4 * d4 - b3 * d3) ; // 4
det += (R2 * a2 - R1 * a1) + (R4 * a4 - R3 * a3) ; // 5
det += (R2 * d2 - R1 * d1) + (R4 * d4 - R3 * d3) ; // 6
if (det>0) return ON_NEGATIVE_SIDE;
if (det<0) return ON_POSITIVE_SIDE;
}
// 3rd order coefficient is null,
// compute 4th order coefficient in the pertrubation method
// replace x^2+y^2+z^2 by xz
R1 = X1*Z1;
R2 = X2*Z2;
R3 = X3*Z3;
R4 = X4*Z4;
// compute determinant
det= (R2 * MM2 - R1 * MM1) + (R4 * MM4 - R3 * MM3) ;
if (det >= Fixed_Is1 ) return ON_NEGATIVE_SIDE;
if (det <= -Fixed_Is1 ) return ON_POSITIVE_SIDE;
// static filter failed, error is small
error= CGAL_NTS abs(R1)*mm1 + CGAL_NTS abs(R2)*mm2
+ CGAL_NTS abs(R3)*mm3 + CGAL_NTS abs(R4)*mm4;
error *= Fixed_Is2;
if ( error < Fixed_Bx5 ) error = 0.0;
if (det > error) return ON_NEGATIVE_SIDE;
if (det < -error) return ON_POSITIVE_SIDE;
if (error!=0.0){
// dynamic filter failed, error is very small
// start exact computation
Fixed_split(R1,b1,R1,Fixed_S_2_25);
Fixed_split(R2,b2,R2,Fixed_S_2_25);
Fixed_split(R3,b3,R3,Fixed_S_2_25);
Fixed_split(R4,b4,R4,Fixed_S_2_25);
// now bi+Ri is last line, non overlapping 25 bits for each
det = (b2 * c2 - b1 * c1) ; // 1
det += (b4 * c4 - b3 * c3) ; // 1b
det += (b2 * a2 - b1 * a1) + (b4 * a4 - b3 * a3) ; // 2
det += (R2 * c2 - R1 * c1) + (R4 * c4 - R3 * c3) ; // 3
det += (b2 * d2 - b1 * d1) + (b4 * d4 - b3 * d3) ; // 4
det += (R2 * a2 - R1 * a1) + (R4 * a4 - R3 * a3) ; // 5
det += (R2 * d2 - R1 * d1) + (R4 * d4 - R3 * d3) ; // 6
if (det>0) return ON_NEGATIVE_SIDE;
if (det<0) return ON_POSITIVE_SIDE;
}
// 4th order coefficient is null,
// compute 5th order coefficient in the pertrubation method
// replace x^2+y^2+z^2 by z^2
R1 = Z1*Z1;
R2 = Z2*Z2;
R3 = Z3*Z3;
R4 = Z4*Z4;
// compute determinant
det= (R2 * MM2 - R1 * MM1) + (R4 * MM4 - R3 * MM3) ;
if (det >= Fixed_Is1 ) return ON_NEGATIVE_SIDE;
if (det <= -Fixed_Is1 ) return ON_POSITIVE_SIDE;
// static filter failed, error is small
error= CGAL_NTS abs(R1)*mm1 + CGAL_NTS abs(R2)*mm2
+ CGAL_NTS abs(R3)*mm3 + CGAL_NTS abs(R4)*mm4;
error *= Fixed_Is2;
if ( error < Fixed_Bx5 ) error = 0.0;
if (det > error) return ON_NEGATIVE_SIDE;
if (det < -error) return ON_POSITIVE_SIDE;
if (error!=0.0){
// dynamic filter failed, error is very small
// start exact computation
Fixed_split(R1,b1,R1,Fixed_S_2_25);
Fixed_split(R2,b2,R2,Fixed_S_2_25);
Fixed_split(R3,b3,R3,Fixed_S_2_25);
Fixed_split(R4,b4,R4,Fixed_S_2_25);
// now bi+Ri is last line, non overlapping 25 bits for each
det = (b2 * c2 - b1 * c1) ; // 1
det += (b4 * c4 - b3 * c3) ; // 1b
det += (b2 * a2 - b1 * a1) + (b4 * a4 - b3 * a3) ; // 2
det += (R2 * c2 - R1 * c1) + (R4 * c4 - R3 * c3) ; // 3
det += (b2 * d2 - b1 * d1) + (b4 * d4 - b3 * d3) ; // 4
det += (R2 * a2 - R1 * a1) + (R4 * a4 - R3 * a3) ; // 5
det += (R2 * d2 - R1 * d1) + (R4 * d4 - R3 * d3) ; // 6
if (det>0) return ON_NEGATIVE_SIDE;
if (det<0) return ON_POSITIVE_SIDE;
}
// 5th order coefficient is null,
// compute 6th order coefficient in the pertrubation method
// replace x^2+y^2+z^2 by x^2
R1 = X1*X1;
R2 = X2*X2;
R3 = X3*X3;
R4 = X4*X4;
// compute determinant
det= (R2 * MM2 - R1 * MM1) + (R4 * MM4 - R3 * MM3) ;
if (det >= Fixed_Is1 ) return ON_NEGATIVE_SIDE;
if (det <= -Fixed_Is1 ) return ON_POSITIVE_SIDE;
// static filter failed, error is small
error= CGAL_NTS abs(R1)*mm1 + CGAL_NTS abs(R2)*mm2
+ CGAL_NTS abs(R3)*mm3 + CGAL_NTS abs(R4)*mm4;
error *= Fixed_Is2;
if ( error < Fixed_Bx5 ) error = 0.0;
if (det > error) return ON_NEGATIVE_SIDE;
if (det < -error) return ON_POSITIVE_SIDE;
if (error!=0.0){
// dynamic filter failed, error is very small
// start exact computation
Fixed_split(R1,b1,R1,Fixed_S_2_25);
Fixed_split(R2,b2,R2,Fixed_S_2_25);
Fixed_split(R3,b3,R3,Fixed_S_2_25);
Fixed_split(R4,b4,R4,Fixed_S_2_25);
// now bi+Ri is last line, non overlapping 25 bits for each
det = (b2 * c2 - b1 * c1) ; // 1
det += (b4 * c4 - b3 * c3) ; // 1b
det += (b2 * a2 - b1 * a1) + (b4 * a4 - b3 * a3) ; // 2
det += (R2 * c2 - R1 * c1) + (R4 * c4 - R3 * c3) ; // 3
det += (b2 * d2 - b1 * d1) + (b4 * d4 - b3 * d3) ; // 4
det += (R2 * a2 - R1 * a1) + (R4 * a4 - R3 * a3) ; // 5
det += (R2 * d2 - R1 * d1) + (R4 * d4 - R3 * d3) ; // 6
if (det>0) return ON_NEGATIVE_SIDE;
if (det<0) return ON_POSITIVE_SIDE;
}
// 6th order coefficient is null,
// points are coplanar
return ON_ORIENTED_BOUNDARY;
}
}
return ON_ORIENTED_BOUNDARY;
// code never goes here, it is just to avoid compilation warning
}
CGAL_END_NAMESPACE
#endif //CGAL_FIXED_PRECISION_NT_H