// Emacs: -*- C++ -*-

/*

// $Log:	Point.h.m4,v $
// Revision 2.8  92/09/02  14:50:44  rjj
// Corrected renameing of min to infimum and max to supremum
// 
// Revision 2.7  92/09/01  20:45:29  rjj
// Added support to ensure float op IntPoint and IntPoint op float yield FloatPoint.
// 
// Revision 2.6  92/08/28  11:55:11  jnw
// Changed relation functions with POINT_TYPE& and float args
// to have POINT_TYPE& and double args to match current .C code
// 
// Revision 2.5  92/08/27  12:11:27  jnw
// Added C style comments around Log Messages to fixx gcc-cpp bug
// 
// Revision 2.4  92/08/23  13:35:47  thoth
// CFrontified
// throw changed to ia_throw.
// didn't hint to inline for loop stuff any more (braindead compiler).
// fixed const pass-by-value problem.
// 
// 

*/

ifdef(`FLOATPOINT', `
#ifndef FloatPoint_h_
#define FloatPoint_h_
')

ifdef(`INTPOINT', `
#ifndef IntPoint_h_
#define IntPoint_h_
')

#pragma interface

#include "ia.h"
ifdef(`FLOATPOINT', `#include "IntPoint.h"')


class POINT_TYPE {
    
  private:  
    unsigned size;
    TYPE *coordinates;
    
  public:
    // Constructors:
    
    POINT_TYPE () {coordinates = 0; size = 0; }
    POINT_TYPE (const POINT_TYPE&);
    POINT_TYPE (TYPE *, unsigned, int =0);
    POINT_TYPE& operator = (const POINT_TYPE&);
    ~POINT_TYPE () { delete[] coordinates; }  // OK even if coordinates NULL.
                                         
    
    POINT_TYPE (TYPE c0) {
	coordinates = new TYPE[size = 1];
	coordinates[0] =  c0;
    }
    
    POINT_TYPE (TYPE c0, TYPE c1) {
	coordinates = new TYPE[size = 2];
	coordinates[0] = c0;
	coordinates[1] = c1;
    }
    
    POINT_TYPE (TYPE c0, TYPE c1, TYPE c2) {
	coordinates = new TYPE[size = 3];
	coordinates[0] = c0;
	coordinates[1] = c1;
	coordinates[2] = c2;
    }
    
    POINT_TYPE (TYPE c0, TYPE c1, TYPE c2, TYPE c3) {
	coordinates = new TYPE[size = 4];
	coordinates[0] = c0;
	coordinates[1] = c1;
	coordinates[2] = c2;
	coordinates[3] = c3;
    }
    
    POINT_TYPE (TYPE c0, TYPE c1, TYPE c2, TYPE c3, TYPE c4) {
	coordinates = new TYPE[size = 5];
	coordinates[0] = c0;
	coordinates[1] = c1;
	coordinates[2] = c2;
	coordinates[3] = c3;
	coordinates[4] = c4;
    }

ifdef(`FLOATPOINT',`    
//  FloatPoint includes IntPoint.h so we can have a constructor
//  from IntPoint to FloatPoint: this gives us all FloatPoint/IntPoint
//  operations for free.

    FloatPoint(const IntPoint &ipt);


//  Ensure that float args yield FloatPoint answers.

    friend FloatPoint    operator +  (const IntPoint&, const TYPE);
    friend FloatPoint    operator -  (const IntPoint&, const TYPE);
    friend FloatPoint    operator *  (const IntPoint&, const TYPE);
    friend FloatPoint    operator /  (const IntPoint&, const TYPE);

    friend FloatPoint    operator +  (const TYPE, const IntPoint&);
    friend FloatPoint    operator -  (const TYPE, const IntPoint&);
    friend FloatPoint    operator *  (const TYPE, const IntPoint&);
    friend FloatPoint    operator /  (const TYPE, const IntPoint&);
')

    unsigned dimensions() const { return size; }
    TYPE& operator[] (unsigned i) { return coordinates[i]; }
    const TYPE operator[] (unsigned i) const { return coordinates[i]; }
    
    friend  POINT_TYPE extend_to_point (TYPE, unsigned);
    
    const  POINT_TYPE&   operator +=  (const POINT_TYPE&);
    const  POINT_TYPE&   operator -=  (const POINT_TYPE&);
    const  POINT_TYPE&   operator *=  (const POINT_TYPE&);
    const  POINT_TYPE&   operator /=  (const POINT_TYPE&);

    const  POINT_TYPE&   operator +=  (TYPE);
    const  POINT_TYPE&   operator -=  (TYPE);
    const  POINT_TYPE&   operator *=  (TYPE);
    const  POINT_TYPE&   operator /=  (TYPE);
    
           POINT_TYPE    operator +  (const POINT_TYPE&) const;
           POINT_TYPE    operator -  (const POINT_TYPE&) const;
           POINT_TYPE    operator *  (const POINT_TYPE&) const;
           POINT_TYPE    operator /  (const POINT_TYPE&) const;

    friend POINT_TYPE    operator +  (const POINT_TYPE&, TYPE);
    friend POINT_TYPE    operator -  (const POINT_TYPE&, TYPE);
    friend POINT_TYPE    operator *  (const POINT_TYPE&, TYPE);
    friend POINT_TYPE    operator /  (const POINT_TYPE&, TYPE);
    
    friend POINT_TYPE    operator +  (TYPE, const POINT_TYPE&);
    friend POINT_TYPE    operator -  (TYPE, const POINT_TYPE&);
    friend POINT_TYPE    operator *  (TYPE, const POINT_TYPE&);
    friend POINT_TYPE    operator /  (TYPE, const POINT_TYPE&);

    const  POINT_TYPE&   operator ++  ();
    const  POINT_TYPE&   operator --  ();

           POINT_TYPE    operator -   () const;
	   

ifdef(`INTPOINT',`
    const  IntPoint&   operator %=  (const IntPoint&);
    const  IntPoint&   operator <<= (const IntPoint&);
    const  IntPoint&   operator >>= (const IntPoint&);
    const  IntPoint&   operator &=  (const IntPoint&);
    const  IntPoint&   operator ^=  (const IntPoint&);
    const  IntPoint&   operator |=  (const IntPoint&);

    const  IntPoint&   operator %=  (unsigned);
    const  IntPoint&   operator <<= (unsigned);
    const  IntPoint&   operator >>= (unsigned);
    const  IntPoint&   operator &=  (unsigned);
    const  IntPoint&   operator ^=  (unsigned);
    const  IntPoint&   operator |=  (unsigned);

           IntPoint    operator %  (const IntPoint&) const;
           IntPoint    operator << (const IntPoint&) const;
           IntPoint    operator >> (const IntPoint&) const;
           IntPoint    operator &  (const IntPoint&) const;
           IntPoint    operator ^  (const IntPoint&) const;
           IntPoint    operator |  (const IntPoint&) const;
           IntPoint    operator ~  () const;

    friend IntPoint    operator %  (const IntPoint&, unsigned);
    friend IntPoint    operator << (const IntPoint&, unsigned);
    friend IntPoint    operator >> (const IntPoint&, unsigned);
    friend IntPoint    operator &  (const IntPoint&, unsigned);
    friend IntPoint    operator ^  (const IntPoint&, unsigned);
    friend IntPoint    operator |  (const IntPoint&, unsigned);

    friend IntPoint    operator %  (int, const IntPoint&);
    friend IntPoint    operator << (int, const IntPoint&);
    friend IntPoint    operator >> (int, const IntPoint&);
    friend IntPoint    operator &  (int, const IntPoint&);
    friend IntPoint    operator ^  (int, const IntPoint&);
    friend IntPoint    operator |  (int, const IntPoint&);
')

                int    operator <   (const POINT_TYPE&) const;
                int    operator <=  (const POINT_TYPE&) const;
                int    operator >   (const POINT_TYPE&) const;
                int    operator >=  (const POINT_TYPE&) const;
                int    operator ==  (const POINT_TYPE&) const;
                int    operator !=  (const POINT_TYPE&) const;

    friend      int    operator <   (const POINT_TYPE&, int);
    friend      int    operator <=  (const POINT_TYPE&, int);
    friend      int    operator >   (const POINT_TYPE&, int);
    friend      int    operator >=  (const POINT_TYPE&, int);
    friend      int    operator ==  (const POINT_TYPE&, int);
    friend      int    operator !=  (const POINT_TYPE&, int);

    friend      int    operator <   (int, const POINT_TYPE&);
    friend      int    operator <=  (int, const POINT_TYPE&);
    friend      int    operator >   (int, const POINT_TYPE&);
    friend      int    operator >=  (int, const POINT_TYPE&);
    friend      int    operator ==  (int, const POINT_TYPE&);
    friend      int    operator !=  (int, const POINT_TYPE&);

    friend      int    operator <   (const POINT_TYPE&, double);
    friend      int    operator <=  (const POINT_TYPE&, double);
    friend      int    operator >   (const POINT_TYPE&, double);
    friend      int    operator >=  (const POINT_TYPE&, double);
    friend      int    operator ==  (const POINT_TYPE&, double);
    friend      int    operator !=  (const POINT_TYPE&, double);

    friend      int    operator <   (double, const POINT_TYPE&);
    friend      int    operator <=  (double, const POINT_TYPE&);
    friend      int    operator >   (double, const POINT_TYPE&);
    friend      int    operator >=  (double, const POINT_TYPE&);
    friend      int    operator ==  (double, const POINT_TYPE&);
    friend      int    operator !=  (double, const POINT_TYPE&);

    // Index-derangement functions.
    
    POINT_TYPE      operator ()  (unsigned) const;
    POINT_TYPE      operator ()  (unsigned, unsigned) const;
    POINT_TYPE      operator ()  (unsigned, unsigned, unsigned) const;
    POINT_TYPE      operator ()  (unsigned, unsigned, unsigned, unsigned) const;
    POINT_TYPE      operator ()  (unsigned, unsigned, unsigned, unsigned, unsigned) const;

    friend ostream& operator << (ostream&, const POINT_TYPE&);

    // Distance measures

    double enorm() const;

    // more construction functions
    
    friend POINT_TYPE    concat   (const POINT_TYPE&, const POINT_TYPE&);
    friend POINT_TYPE    concat   (const POINT_TYPE&, TYPE);
    friend POINT_TYPE    concat   (TYPE, const POINT_TYPE&);

    friend POINT_TYPE    cdr(const POINT_TYPE&, int =1);

    friend int Pointcmp (const POINT_TYPE&, const POINT_TYPE&);

    friend POINT_TYPE	infimum		(const POINT_TYPE&, const POINT_TYPE&);
    friend TYPE		min		(const POINT_TYPE&);
    friend POINT_TYPE	supremum	(const POINT_TYPE&, const POINT_TYPE&);
    friend TYPE		max		(const POINT_TYPE&);

ifdef(`FLOATPOINT',`
    friend FloatPoint aint  (FloatPoint);
    friend FloatPoint anint (FloatPoint);
    friend FloatPoint ceil  (FloatPoint);
    friend FloatPoint floor (FloatPoint);
    friend FloatPoint rint  (FloatPoint);

    friend IntPoint   irint (const FloatPoint&);
    friend IntPoint   nint  (const FloatPoint&);
    friend IntPoint   trunc (const FloatPoint&);
')
};

#endif
