// Copyright (c) 2009  INRIA Sophia-Antipolis (France).
// All rights reserved.
//
// This file is part of CGAL (www.cgal.org)
//
// $URL: https://github.com/CGAL/cgal/blob/v6.1/Filtered_kernel/include/CGAL/Filtered_kernel/internal/Static_filters/Compare_weighted_squared_radius_3.h $
// $Id: include/CGAL/Filtered_kernel/internal/Static_filters/Compare_weighted_squared_radius_3.h b26b07a1242 $
// SPDX-License-Identifier: LGPL-3.0-or-later OR LicenseRef-Commercial
//
// 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/Filtered_kernel/internal/Static_filters/Static_filter_error.h>
#include <CGAL/Filtered_kernel/internal/Static_filters/tools.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::Comparison_result                 Comparison_result;
    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:
    using Base::operator();

    Comparison_result 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);

      double px, py, pz, pw, qx, qy, qz, qw, rx, ry, rz, rw, sx, sy, sz, sw, alpha;
      init_double(px, py, pz, pw, qx, qy, qz, qw, (FT*)(0));
      init_double(rx, ry, rz, rw, sx, sy, sz, sw, alpha, (FT*)(0));

      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 = CGAL::abs(qpy);

        double aqpx = CGAL::abs(qpx);

        double arpx = CGAL::abs(rpx);
        double arpy = CGAL::abs(rpy);
        double arpz = CGAL::abs(rpz);

        double aspx = CGAL::abs(spx);
        double aspy = CGAL::abs(spy);
        double aspz = CGAL::abs(spz);

        double apw_rw = CGAL::abs(pw_rw);
        double apw_sw = CGAL::abs(pw_sw);

        double aalpha_pw = CGAL::abs(alpha_pw);

        if( max4 < arpy ) max4 = arpy;
        if( max4 < aspy ) max4 = aspy;
        double max2 = max4;
        if( max2 < aqpx ) max2 = aqpx;
        if( max2 < arpx ) max2 = arpx;
        if( max2 < aspx ) max2 = aspx;
        double max1 = max2;
        double max3 = max4;
        double max5 = CGAL::abs(qpz);
        if( max5 < arpz ) max5 = arpz;
        if( max5 < aspz ) max5 = aspz;
        if( max3 < max5 )      max3 = max5;
        if( max1 < max3 )      max1 = max3;
        if( max1 < max4 )      max1 = max4;
        if( max1 < max5 )      max1 = max5;
        double max6 = CGAL::abs(pw_qw);
        if( max6 < apw_rw ) max6 = apw_rw;
        if( max6 < apw_sw ) max6 = apw_sw;
        double max7 = max6;
        if( max7 < aalpha_pw ) max7 = aalpha_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);
    }

    Comparison_result
    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);

      double px, py, pz, pw, qx, qy, qz, qw, rx, ry, rz, rw, alpha;
      init_double(px, py, pz, pw, qx, qy, qz, qw, rx, ry, rz, rw, alpha, (FT*)(0));
      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 = CGAL::abs(qpx);

        double aqpy = CGAL::abs(qpy);
        double aqpz = CGAL::abs(qpz);

        double arpx = CGAL::abs(rpx);
        double arpy = CGAL::abs(rpy);
        double arpz = CGAL::abs(rpz);

        double apw_rw = CGAL::abs(pw_rw);

        double aalpha_pw = CGAL::abs(alpha_pw);

        if( max2 < aqpy )  max2 = aqpy;
        if( max2 < arpx )  max2 = arpx;
        if( max2 < arpy )  max2 = arpy;
        double max1 = max2;
        if( max1 < aqpz )  max1 = aqpz;
        if( max1 < arpz )  max1 = arpz;
        double max3 = CGAL::abs(pw_qw);
        if( max3 < apw_rw ) max3 = apw_rw;
        double max4 = max3;
        if( max4 < aalpha_pw ) max4 = aalpha_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);
    }

    Comparison_result
    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);

      double px, py, pz, pw, qx, qy, qz, qw, alpha;
      init_double(px, py, pz, pw, qx, qy, qz, qw, alpha, (FT*)(0));
      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 = CGAL::abs(qpx);

        double aqpy = CGAL::abs(qpy);
        double aqpz = CGAL::abs(qpz);
        double aalpha_pw = CGAL::abs(alpha_pw);

        if( max1 < aqpy ) max1 = aqpy;
        if( max1 < aqpz ) max1 = aqpz;
        double max2;
        double max3 = CGAL::abs(pw_qw);
        max2 = max3;
        if( max2 < aalpha_pw ) max2 = aalpha_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

