// 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 #ifndef CGAL_FIXED_PRECISION_NT_H #define CGAL_FIXED_PRECISION_NT_H #include #include #include #include #include #include #include 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 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 (D0) 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