
// ---------------------------------------------------------
//
//  interval_base.h
//  Tyson Brochu 2011
//
//  Interface definition for Interval types.
//
// ---------------------------------------------------------

#ifndef TUNICATE_INTERVAL_BASE_H
#define TUNICATE_INTERVAL_BASE_H

#include "vec.h"
namespace CCD
{
class IntervalBase
{
   
public:
   
   inline virtual ~IntervalBase() {}

   virtual double stored_left() const = 0;
   virtual double stored_right() const = 0;

   inline virtual Vec2d get_actual_interval() const;
   inline virtual Vec2d get_internal_representation() const;
      
   inline virtual bool contains_zero() const;
   inline virtual bool indefinite_sign() const;
   inline virtual bool is_certainly_negative( ) const;   
   inline virtual bool is_certainly_positive( ) const;
   inline virtual bool is_certainly_zero( ) const;
   
   inline virtual bool certainly_opposite_sign( const IntervalBase& other ) const;
   
   inline virtual bool same_sign( const IntervalBase& other ) const;
   
   inline virtual double estimate() const;
      
};


// ----------------------------------------

inline Vec2d IntervalBase::get_actual_interval() const
{
   return Vec2d( -stored_left(), stored_right() );
}

// ----------------------------------------

inline Vec2d IntervalBase::get_internal_representation() const
{
   return Vec2d( stored_left(), stored_right() );
}


// ----------------------------------------

inline bool IntervalBase::contains_zero() const
{
   // true if a <= 0 && b >= 0
   // remember v[0] == -a
   
   return ( stored_left() >= 0 && stored_right() >= 0 );
}

// ----------------------------------------
// TODO: This is equivalent to contains_zero(), should be removed

inline bool IntervalBase::indefinite_sign() const
{
   return ( stored_left() >= 0 && stored_right() >= 0 );
}

// ----------------------------------------

inline bool IntervalBase::is_certainly_negative( ) const
{
   return ( stored_right() < 0 );
}

// ----------------------------------------

inline bool IntervalBase::is_certainly_positive( ) const
{
   return ( stored_left() < 0 );
}

// ----------------------------------------

inline bool IntervalBase::is_certainly_zero( ) const
{
   return ( stored_left() == 0 && stored_right() == 0 );
}

// ----------------------------------------

inline bool IntervalBase::certainly_opposite_sign( const IntervalBase& other ) const
{
   return ( ( this->is_certainly_negative() && other.is_certainly_positive() ) ||
           ( this->is_certainly_positive() && other.is_certainly_negative() ) );     
}

// ----------------------------------------

inline bool IntervalBase::same_sign( const IntervalBase& other ) const
{
   return ( this->contains_zero() ||
           other.contains_zero() ||
           ( this->is_certainly_negative() && other.is_certainly_negative() ) || 
           ( this->is_certainly_positive() && other.is_certainly_positive() ) );
}


// ----------------------------------------

inline double IntervalBase::estimate() const
{
   double est = 0.5 * (-stored_left() + stored_right());
   
   if ( est == 0 && !is_certainly_zero() )
   {
      // don't return zero as an estimate if the interval is not identically zero.
      est = 1e-20;
   }
   
   return est;
}

// ----------------------------------------

inline bool certainly_opposite_sign( const IntervalBase& a, const IntervalBase& b ) 
{
   return a.certainly_opposite_sign( b );
}

// ----------------------------------------

inline bool same_sign( const IntervalBase& a, const IntervalBase& b )
{  
   return a.same_sign(b);
}
}

#endif

