// Copyright (c) 2009  INRIA Sophia-Antipolis (France).
// All rights reserved.
//
// This file is part of CGAL (www.cgal.org); you may redistribute it under
// the terms of the Q Public License version 1.0.
// See the file LICENSE.QPL 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: svn+ssh://scm.gforge.inria.fr/svn/cgal/branches/CGAL-3.6-branch/Triangulation_3/include/CGAL/internal/Static_filters/Compare_weighted_squared_radius_3.h $
// $Id: Compare_weighted_squared_radius_3.h 52628 2009-10-20 08:59:26Z lrineau $
//
// Author(s)     : Sebastien Loriot
// This predicates was generated using the fpg tool written by Andreas Meyer.
//

#ifndef CGAL_INTERNAL_STATIC_FILTERS_COMPARE_WEIGHTED_SQUARED_RADIUS_3_H
#define CGAL_INTERNAL_STATIC_FILTERS_COMPARE_WEIGHTED_SQUARED_RADIUS_3_H

#include <CGAL/Profile_counter.h>
#include <CGAL/internal/Static_filters/Static_filter_error.h>
#include <cmath>


namespace CGAL { namespace internal { namespace Static_filters_predicates {
  
  
  template <typename K_base>
  class Compare_weighted_squared_radius_3:
    public K_base::Compare_weighted_squared_radius_3
  {
    typedef typename K_base::Weighted_point_3 Weighted_point_3;
    typedef typename K_base::FT FT;
    typedef typename K_base::Compare_weighted_squared_radius_3 Base;
  public:
    typedef typename Base::result_type result_type;
  
    #ifndef CGAL_CFG_MATCHING_BUG_6
    using Base::operator();
    #else 
    result_type
    operator()(const Weighted_point_3& p, const FT& w) const
    { 
      return Base::operator()(p,w);
    }
    #endif
    
    
    result_type operator() (
        const Weighted_point_3& p, 
        const Weighted_point_3& q, 
        const Weighted_point_3& r, 
        const Weighted_point_3& s,
        const FT& w
    ) const {

      CGAL_BRANCH_PROFILER_3("semi-static failures/attempts/calls to   : Compare_weighted_squared_radius_3 with 4 wpoints", tmp);
      using std::fabs;
      
      double px, py, pz, pw, qx, qy, qz, qw, rx, ry, rz, rw, sx, sy, sz, sw, alpha;
      if( fit_in_double(p.x(), px) && fit_in_double(p.y(), py)      &&
          fit_in_double(p.z(), pz) && fit_in_double(p.weight(), pw) && 
          fit_in_double(q.x(), qx) && fit_in_double(q.y(), qy)      &&
          fit_in_double(q.z(), qz) && fit_in_double(q.weight(), qw) &&
          fit_in_double(r.x(), rx) && fit_in_double(r.y(), ry)      &&
          fit_in_double(r.z(), rz) && fit_in_double(r.weight(), rw) &&
          fit_in_double(s.x(), sx) && fit_in_double(s.y(), sy)      &&
          fit_in_double(s.z(), sz) && fit_in_double(s.weight(), sw) && 
          fit_in_double(w, alpha)
        )
      {
        CGAL_BRANCH_PROFILER_BRANCH_1(tmp);
        
        double qpx = (qx - px);
        double qpy = (qy - py);
        double qpz = (qz - pz);
        double pw_qw = (pw - qw);
        double qp2 = (((CGAL::square( qpx ) + CGAL::square( qpy )) + CGAL::square( qpz )) + pw_qw);
        double rpx = (rx - px);
        double rpy = (ry - py);
        double rpz = (rz - pz);
        double pw_rw = (pw - rw);
        double rp2 = (((CGAL::square( rpx ) + CGAL::square( rpy )) + CGAL::square( rpz )) + pw_rw);
        double spx = (sx - px);
        double spy = (sy - py);
        double spz = (sz - pz);
        double pw_sw = (pw - sw);
        double sp2 = (((CGAL::square( spx ) + CGAL::square( spy )) + CGAL::square( spz )) + pw_sw);
        double num_x = CGAL::determinant( qpy, qpz, qp2, rpy, rpz, rp2, spy, spz, sp2 );
        double num_y = CGAL::determinant( qpx, qpz, qp2, rpx, rpz, rp2, spx, spz, sp2 );
        double num_z = CGAL::determinant( qpx, qpy, qp2, rpx, rpy, rp2, spx, spy, sp2 );
        double den = CGAL::determinant( qpx, qpy, qpz, rpx, rpy, rpz, spx, spy, spz );
        double alpha_pw = (alpha + pw);
        CGAL::Sign int_tmp_result;
        double eps;
        double double_tmp_result = (((alpha_pw * 4.00000000000000000000e+00) * CGAL::square( den )) - ((CGAL::square( num_x ) + CGAL::square( num_y )) + CGAL::square( num_z )));
        double max4 = fabs(qpy);
        if( (max4 < fabs(rpy)) ) max4 = fabs(rpy);
        if( (max4 < fabs(spy)) ) max4 = fabs(spy); 
        double max2 = max4;
        if( (max2 < fabs(qpx)) ) max2 = fabs(qpx); 
        if( (max2 < fabs(rpx)) ) max2 = fabs(rpx); 
        if( (max2 < fabs(spx)) ) max2 = fabs(spx); 
        double max1 = max2;
        double max3 = max4;
        double max5 = fabs(qpz);
        if( (max5 < fabs(rpz)) ) max5 = fabs(rpz);  
        if( (max5 < fabs(spz)) ) max5 = fabs(spz);  
        if( (max3 < max5) )      max3 = max5;       
        if( (max1 < max3) )      max1 = max3;       
        if( (max1 < max4) )      max1 = max4;       
        if( (max1 < max5) )      max1 = max5;      
        double max6 = fabs(pw_qw);
        if( (max6 < fabs(pw_rw)) ) max6 = fabs(pw_rw);
        if( (max6 < fabs(pw_sw)) ) max6 = fabs(pw_sw);
        double max7 = max6;
        if( (max7 < fabs(alpha_pw)) ) max7 = fabs(alpha_pw); 
        double lower_bound_1;
        double upper_bound_1;
        lower_bound_1 = max1;
        upper_bound_1 = max1;
        if( (max2 < lower_bound_1) ) lower_bound_1 = max2;
        if( (max3 < lower_bound_1) ) lower_bound_1 = max3;
        if( (max4 < lower_bound_1) ) lower_bound_1 = max4;
        if( (max5 < lower_bound_1) ) lower_bound_1 = max5;
        double lower_bound_2;
        double upper_bound_2;
        lower_bound_2 = max6;
        upper_bound_2 = max6;
        if( (max7 < lower_bound_2) ) lower_bound_2 = max7;
        else 
        {
            if( (max7 > upper_bound_2) ) upper_bound_2 = max7;
        } 
        if( ((lower_bound_1 < 8.99995159231796093217e-38) || (lower_bound_2 < 8.09991286640666077573e-75)) )
        {
          CGAL_BRANCH_PROFILER_BRANCH_2(tmp);
          return Base::operator()(p,q,r,s,w);
        } 
        else 
        {
            if( ((upper_bound_1 > 2.59614842926741294957e+33) || (upper_bound_2 > 6.73998666678765545893e+66)) )
            {
              CGAL_BRANCH_PROFILER_BRANCH_2(tmp);
              return Base::operator()(p,q,r,s,w);
            } 
            eps = (5.16919651938288206243e-12 * (((((max2 * max3) * max1) * max1) * CGAL::max BOOST_PREVENT_MACRO_SUBSTITUTION ( max7, (max1 * max1) )) * CGAL::max BOOST_PREVENT_MACRO_SUBSTITUTION ( CGAL::max BOOST_PREVENT_MACRO_SUBSTITUTION ( max6, (max4 * max5) ), (max1 * max1) )));
            if( (double_tmp_result > eps) )
            {
                int_tmp_result = CGAL::NEGATIVE;
            } 
            else 
            {
                if( (double_tmp_result < -eps) )
                {
                    int_tmp_result = CGAL::POSITIVE;
                } 
                else 
                {
                  CGAL_BRANCH_PROFILER_BRANCH_2(tmp);
                  return Base::operator()(p,q,r,s,w);
                } 
            } 
        } 
        return int_tmp_result;
      }
      else
        return Base::operator()(p,q,r,s,w);
    }

    result_type
    operator() (
      const Weighted_point_3& p, 
      const Weighted_point_3& q , 
      const Weighted_point_3& r,
      const FT& w
    ) const {
      
      CGAL_BRANCH_PROFILER_3("semi-static failures/attempts/calls to   : Compare_weighted_squared_radius_3 with 3 wpoints", tmp);
      using std::fabs;
      
      double px, py, pz, pw, qx, qy, qz, qw, rx, ry, rz, rw, alpha;
      if( fit_in_double(p.x(), px) && fit_in_double(p.y(), py)      &&
          fit_in_double(p.z(), pz) && fit_in_double(p.weight(), pw) && 
          fit_in_double(q.x(), qx) && fit_in_double(q.y(), qy)      &&
          fit_in_double(q.z(), qz) && fit_in_double(q.weight(), qw) &&
          fit_in_double(r.x(), rx) && fit_in_double(r.y(), ry)      &&
          fit_in_double(r.z(), rz) && fit_in_double(r.weight(), rw) &&
          fit_in_double(w, alpha)
        )
      {
        CGAL_BRANCH_PROFILER_BRANCH_1(tmp);
        
        double qpx = (qx - px);
        double qpy = (qy - py);
        double qpz = (qz - pz);
        double pw_qw = (pw - qw);
        double qp2 = (((CGAL::square( qpx ) + CGAL::square( qpy )) + CGAL::square( qpz )) + pw_qw);
        double rpx = (rx - px);
        double rpy = (ry - py);
        double rpz = (rz - pz);
        double pw_rw = (pw - rw);
        double rp2 = (((CGAL::square( rpx ) + CGAL::square( rpy )) + CGAL::square( rpz )) + pw_rw);
        double sx = ((qpy * rpz) - (qpz * rpy));
        double sy = ((qpz * rpx) - (qpx * rpz));
        double sz = ((qpx * rpy) - (qpy * rpx));
        double num_x = ((qp2 * CGAL::determinant( rpy, rpz, sy, sz )) - (rp2 * CGAL::determinant( qpy, qpz, sy, sz )));
        double num_y = ((qp2 * CGAL::determinant( rpx, rpz, sx, sz )) - (rp2 * CGAL::determinant( qpx, qpz, sx, sz )));
        double num_z = ((qp2 * CGAL::determinant( rpx, rpy, sx, sy )) - (rp2 * CGAL::determinant( qpx, qpy, sx, sy )));
        double den = CGAL::determinant( qpx, qpy, qpz, rpx, rpy, rpz, sx, sy, sz );
        double alpha_pw = (alpha + pw);
        CGAL::Sign int_tmp_result;
        double eps;
        double double_tmp_result = ((alpha_pw * CGAL::square( den )) - (2.50000000000000000000e-01 * ((CGAL::square( num_x ) + CGAL::square( num_y )) + CGAL::square( num_z ))));
        double max2 = fabs(qpx);
        if( (max2 < fabs(qpy)) )  max2 = fabs(qpy);
        if( (max2 < fabs(rpx)) )  max2 = fabs(rpx);
        if( (max2 < fabs(rpy)) )  max2 = fabs(rpy);
        double max1 = max2;
        if( (max1 < fabs(qpz)) )  max1 = fabs(qpz);
        if( (max1 < fabs(rpz)) )  max1 = fabs(rpz);
        double max3 = fabs(pw_qw);
        if( (max3 < fabs(pw_rw)) ) max3 = fabs(pw_rw);
        double max4 = max3;
        if( (max4 < fabs(alpha_pw)) ) max4 = fabs(alpha_pw);
        double lower_bound_1;
        double upper_bound_1;
        lower_bound_1 = max1;
        upper_bound_1 = max1;
        if( (max2 < lower_bound_1) ) lower_bound_1 = max2;
        double lower_bound_2;
        double upper_bound_2;
        lower_bound_2 = max3;
        upper_bound_2 = max3;
        if( (max4 < lower_bound_2) )  lower_bound_2 = max4;
        else 
        {
          if( (max4 > upper_bound_2) ) upper_bound_2 = max4;
        } 
        if( ((lower_bound_1 < 2.13354839219409151500e-30) || (lower_bound_2 < 4.55202874183399304187e-60)) )
        {
          CGAL_BRANCH_PROFILER_BRANCH_2(tmp);
          return Base::operator()(p,q,r,w);
        } 
        else 
        {
            if( ((upper_bound_1 > 1.23794003928538000002e+27) || (upper_bound_2 > 1.53249554086588817779e+54)) )
            {
              CGAL_BRANCH_PROFILER_BRANCH_2(tmp);
              return Base::operator()(p,q,r,w);
            } 
            eps = (1.13846439714120896721e-11 * (((((((max1 * max2) * max1) * max1) * max1) * max1) * CGAL::max BOOST_PREVENT_MACRO_SUBSTITUTION ( max4, (max1 * max1) )) * CGAL::max BOOST_PREVENT_MACRO_SUBSTITUTION ( max3, (max1 * max1) )));
            if( (double_tmp_result > eps) )
            {
                int_tmp_result = CGAL::NEGATIVE;
            } 
            else 
            {
                if( (double_tmp_result < -eps) )
                {
                    int_tmp_result = CGAL::POSITIVE;
                } 
                else 
                {
                  CGAL_BRANCH_PROFILER_BRANCH_2(tmp);
                  return Base::operator()(p,q,r,w);
                } 
            } 
        } 
        return int_tmp_result;
      }
      else
        return Base::operator()(p,q,r,w);
    }

    result_type
    operator() (
      const Weighted_point_3& p, 
      const Weighted_point_3& q,
      const FT& w
    ) const {
      
      CGAL_BRANCH_PROFILER_3("semi-static failures/attempts/calls to   : Compare_weighted_squared_radius_3 with 2 wpoints", tmp);
      using std::fabs;
      
      double px, py, pz, pw, qx, qy, qz, qw, alpha;
      if( fit_in_double(p.x(), px) && fit_in_double(p.y(), py)      &&
          fit_in_double(p.z(), pz) && fit_in_double(p.weight(), pw) && 
          fit_in_double(q.x(), qx) && fit_in_double(q.y(), qy)      &&
          fit_in_double(q.z(), qz) && fit_in_double(q.weight(), qw) &&
          fit_in_double(w, alpha)
        )
      {
        CGAL_BRANCH_PROFILER_BRANCH_1(tmp);
        
        double qpx = (qx - px);
        double qpy = (qy - py);
        double qpz = (qz - pz);
        double qp2 = ((CGAL::square( qpx ) + CGAL::square( qpy )) + CGAL::square( qpz ));
        double alpha_pw = (alpha + pw);
        double pw_qw = (pw - qw);
        CGAL::Sign int_tmp_result;
        double eps;
        double double_tmp_result = (((4.00000000000000000000e+00 * qp2) * alpha_pw) - CGAL::square( (qp2 + pw_qw) ));
        double max1 = fabs(qpx);
        if( (max1 < fabs(qpy)) ) max1 = fabs(qpy);
        if( (max1 < fabs(qpz)) ) max1 = fabs(qpz);
        double max2;
        double max3 = fabs(pw_qw);
        max2 = max3;
        if( (max2 < fabs(alpha_pw)) ) max2 = fabs(alpha_pw);
        double lower_bound_2;
        double upper_bound_2;
        lower_bound_2 = max2;
        upper_bound_2 = max2;
        if( (max3 < lower_bound_2) ) lower_bound_2 = max3;
        if( ((max1 < 3.12497063152273477754e-74) || (lower_bound_2 < 9.76544144787960039738e-148)) ){
          CGAL_BRANCH_PROFILER_BRANCH_2(tmp);
          return Base::operator()(p,q,w);
        }
        else 
        {
            if( ((max1 > 6.42775217703595896130e+60) || (upper_bound_2 > 4.13159980493905099125e+121)) )
            {
              CGAL_BRANCH_PROFILER_BRANCH_2(tmp);
              return Base::operator()(p,q,w);
            } 
            eps = (2.33324675561911025753e-14 * (CGAL::max BOOST_PREVENT_MACRO_SUBSTITUTION ( max2, (max1 * max1) ) * CGAL::max BOOST_PREVENT_MACRO_SUBSTITUTION ( max3, (max1 * max1) )));
            if( (double_tmp_result > eps) )
            {
                int_tmp_result = CGAL::NEGATIVE;
            } 
            else 
            {
                if( (double_tmp_result < -eps) )
                {
                    int_tmp_result = CGAL::POSITIVE;
                } 
                else 
                {
                  CGAL_BRANCH_PROFILER_BRANCH_2(tmp);
                  return Base::operator()(p,q,w);
                } 
            } 
        } 
        return int_tmp_result;        
      }
      else
        return Base::operator()(p,q,w);
    }
    
  };
  
  
} } }//namespace CGAL::internal::Static_filters_predicates


#endif //CGAL_INTERNAL_STATIC_FILTERS_COMPARE_WEIGHTED_SQUARED_RADIUS_3_H

