divert(-1)
#        Copyright 1993, Center for Computer Vision and Visualization,
#        University of Florida.  All rights reserved.
#

#
# $Log: defines.m4,v $
# Revision 2.15.1.1  1994/12/08  14:34:09  thoth
# All throws are now of class objects.
#

# This is a set of m4 macros and defines for turning Point.C.m4 and Point.h.m4
# into the files IntPoint.{C,h} and FloatPoint.{C,h}.
#
# usage: "/local/gnu/m4 -DFLOATPOINT defines.m4 Point.C.m4 > FloatPoint.C"
#        "/local/gnu/m4 -DINTPOINT defines.m4 Point.h.m4 > IntPoint.h"
# etc.
#
# There are some gotchas using m4, however!  If the program text (or this file)
# uses m4 predefined macro keywords,  they must be quoted -- here's the list:
#
# `builtin'	`changecom'	`changequote'	`debugfile'	`debugmode'	`decr'
# `define'	`defn'		`divert'	`divnum'	`dnl'
# `dumpdef'
# `errprint'	`esyscmd'	`eval'		`file'		`format'	`ifdef'
# `ifelse'	`include'	`incr'		`index'		`indir'		`len'
# `line'	`m4exit'	`m4wrap'	`maketemp'	`patsubst'	`popdef'
# `pushdef'	`regexp'	`shift'		`sinclude'	`substr'	`syscmd'
# `sysval'	`traceoff'	`traceon'	`translit'	`undefine'
# `undivert'
#
# There where two problems I had: variables names `len' and `index'. I 
# changed them rather than quoting them.
#
# Additionally, if a defined macro appears in the program text followed
# by parens, say `POINT_TYPE(...)',  then everything in the parens will 
# disappear. This is the case for all the constructors.  My solution: precede
# the left paren immediately by a space.
#
# It's rather worth the effort to get the code in a form debuggers can read
# it (and that includes you, gentle reader).
#
#						Fischer
divert

ifdef(`INTPOINT', `
define(`POINT_TYPE', `IA_Point<int>')
define(`TYPE', `int')
define(`POINT', `IA_Point')
')

ifdef(`DOUBLEPOINT', `
define(`POINT_TYPE', `IA_Point<double>')
define(`TYPE', `double')
define(`POINT', `IA_Point')

define(`IPOINT', `IA_Point<int>')
')

divert(-1)
#//////////////////////////////////////////////////////////////
#//
#// A R I T H E M I T I C   P O I N T   D E F I N I T I O N S
#//
#//////////////////////////////////////////////////////////////
divert
define(`COMPOUND_ARITH_ASSIGN_POINT', `  
POINT_TYPE& POINT_TYPE::operator $1= (const POINT_TYPE& rhs) {
    if (this->dim() != rhs.dim()) {  
	ia_throw(Point_DimensionMismatch_Exception(__FILE__, __LINE__));  
	return *this;  
    }  
    if (this->dim() == 0) {  
	ia_throw(Point_Uninitialized_Exception(__FILE__, __LINE__));;  
	return *this;  
    }  
#ifdef NO_LOOP_UNROLLING
    for (unsigned i = 0; i < this->dim(); i++)  
	this->coordinates[i] $1= rhs.coordinates[i];  
#else
    switch (this->dim()) {
    case 5: this->coordinates[4] $1= rhs.coordinates[4];  
    case 4: this->coordinates[3] $1= rhs.coordinates[3];  
    case 3: this->coordinates[2] $1= rhs.coordinates[2];  
    case 2: this->coordinates[1] $1= rhs.coordinates[1];  
    case 1: this->coordinates[0] $1= rhs.coordinates[0];  
    case 0: break;
    default:
	    {
		for (unsigned i = 0; i < this->dim(); i++)  
		    coordinates[i] $1= rhs.coordinates[i];  
	    }
    }
#endif
    return *this;  
}')


define(`COMPOUND_ARITH_ASSIGN_NUMBER', `  
POINT_TYPE& POINT_TYPE::operator $1= (TYPE rhs) { 
    if (this->dim() == 0) {  
	ia_throw(Point_Uninitialized_Exception(__FILE__, __LINE__));;  
	return *this;  
    }  
#ifdef NO_LOOP_UNROLLING
    for (unsigned i = 0; i < this->dim(); i++)  
	this->coordinates[i] $1= rhs;  
#else
    switch (this->dim()) {
    case 5: this->coordinates[4] $1= rhs;  
    case 4: this->coordinates[3] $1= rhs;  
    case 3: this->coordinates[2] $1= rhs;  
    case 2: this->coordinates[1] $1= rhs;  
    case 1: this->coordinates[0] $1= rhs;  
    case 0: break;
    default:
	    {
		for (unsigned i = 0; i < this->dim(); i++)  
		    this->coordinates[i] $1= rhs;  
	    }
    }
#endif
    return *this;  
}')

define(`ARITH_POINT_POINT', `
POINT_TYPE POINT_TYPE::operator $1 (const POINT_TYPE& rhs) const  
{ 
   POINT_TYPE result_point = *this;    
   return result_point $1= rhs;  
}')

define(`ARITH_POINT_NUMBER', `
POINT_TYPE POINT_TYPE::operator $1 (TYPE rhs) const
{ 
    POINT_TYPE result_point = *this;
    return result_point $1= rhs; 
}')

define(`ARITH_NUMBER_POINT', `
POINT_TYPE operator $1 (TYPE lhs, const POINT_TYPE& rhs)  
{ 
  POINT_TYPE result_point = extend_to_point (lhs, rhs.dim()); 
  return result_point $1= rhs;  
}')

divert(-1)
//
// IntPoint double ops
//
divert
define(`ARITH_INTPOINT_DOUBLE', `
POINT_TYPE operator $1 (const IPOINT& lhs, TYPE rhs)
{
    POINT_TYPE result_point = lhs;
    return result_point $1= rhs;
}')
 
define(`ARITH_DOUBLE_INTPOINT', `
POINT_TYPE operator $1 (TYPE lhs, const IPOINT& rhs)
{
  POINT_TYPE result_point = rhs;
  return result_point $1= lhs;
}')

divert(-1)
#//////////////////////////////////////////////////////////////
#//
#// L A T T I C E   P O I N T   D E F I N I T I O N S
#//
#//////////////////////////////////////////////////////////////
divert
define(`LATTICE_POINT_POINT', ` 
int POINT_TYPE::operator $1 (const POINT_TYPE& rhs) const  
{  
// this is suspicious -XXX-
    if (this->dim() == 0 || rhs.dim() == 0) {  
	ia_throw(Point_Uninitialized_Exception(__FILE__, __LINE__));;  
	return  0;  
    }	  
    if (this->dim() != rhs.dim())  
	return  0;  

#ifdef NO_LOOP_UNROLLING    
    for (unsigned i = 0; i < this->dim() ; i++)
	if (! (this->coordinates[i] $1 rhs.coordinates[i])) return 0;  
#else
    switch (this->dim()) {
    case 5: if (! (this->coordinates[4] $1 rhs.coordinates[4])) return 0;  
    case 4: if (! (this->coordinates[3] $1 rhs.coordinates[3])) return 0;  
    case 3: if (! (this->coordinates[2] $1 rhs.coordinates[2])) return 0;  
    case 2: if (! (this->coordinates[1] $1 rhs.coordinates[1])) return 0;  
    case 1: if (! (this->coordinates[0] $1 rhs.coordinates[0])) return 0;  
    case 0: break;
    default: 
	    {
		for (unsigned i = 0; i < this->dim() ; i++)   
		    if (! (this->coordinates[i] $1 rhs.coordinates[i]))
			return 0;  
	    }
    }
#endif
    return 1;  
}')


define(`LATTICE_POINT_NUMBER', `
int  POINT_TYPE::operator $1 (TYPE rhs) const
{  
    if (this->dim() == 0) {
	ia_throw(Point_Uninitialized_Exception(__FILE__, __LINE__));;  
	return  0;  
    }	  

#ifdef NO_LOOP_UNROLLING
    for (unsigned int i = 0; i < this->dim(); i++)  
	if (! (this->coordinates[i] $1 rhs)) return  0;  
#else
    switch (this->dim()) {
    case 5: if (! (this->coordinates[4] $1 rhs)) return  0;  
    case 4: if (! (this->coordinates[3] $1 rhs)) return  0;  
    case 3: if (! (this->coordinates[2] $1 rhs)) return  0;  
    case 2: if (! (this->coordinates[1] $1 rhs)) return  0;  
    case 1: if (! (this->coordinates[0] $1 rhs)) return  0;
    case 0: break;
    default:
	    {
		for (unsigned int i = 0; i < this->dim(); i++)  
		    if (! (this->coordinates[i] $1 rhs)) return  0;  
	    }
    }
#endif  
    return  1;  
}')


define(`LATTICE_NUMBER_POINT', ` 
int operator $1 (TYPE lhs, const POINT_TYPE& rhs)  
{  
    if (rhs.dim() == 0) {  
	ia_throw(Point_Uninitialized_Exception(__FILE__, __LINE__));;  
	return  0;  
    }	  

#ifdef NO_LOOP_UNROLLING
    for (unsigned int i = 0; i < rhs.dim(); i++)  
	if (! (lhs $1 rhs.coordinates[i])) return  0;  
#else
    switch (rhs.dim()) {
    case 5: if (! (lhs $1 rhs.coordinates[4])) return  0;  
    case 4: if (! (lhs $1 rhs.coordinates[3])) return  0;  
    case 3: if (! (lhs $1 rhs.coordinates[2])) return  0;  
    case 2: if (! (lhs $1 rhs.coordinates[1])) return  0;  
    case 1: if (! (lhs $1 rhs.coordinates[0])) return  0;
    case 0: break;
    default:
	    {
		for (unsigned int i = 0; i < rhs.dim(); i++)  
		    if (! (lhs $1 rhs.coordinates[i])) return  0;  
	    }
    }
#endif  

    return  1;  
}')


define(`LATTICE_INTPOINT_DOUBLE', ` 
int POINT_TYPE::operator $1  (double rhs) const
{  
    if (this->dim() == 0) {  
	ia_throw(Point_Uninitialized_Exception(__FILE__, __LINE__));;  
	return  0;  
    }	  

#ifdef NO_LOOP_UNROLLING
    for (unsigned int i = 0; i < this->dim(); i++)  
	if (! (this->coordinates[i] $1 rhs)) return  0;  
#else
    switch (this->dim()) {
    case 5: if (! (this->coordinates[4] $1 rhs)) return  0;  
    case 4: if (! (this->coordinates[3] $1 rhs)) return  0;  
    case 3: if (! (this->coordinates[2] $1 rhs)) return  0;  
    case 2: if (! (this->coordinates[1] $1 rhs)) return  0;  
    case 1: if (! (this->coordinates[0] $1 rhs)) return  0;
    case 0: break;
    default:
	    {
		for (unsigned int i = 0; i < this->dim(); i++)  
		    if (! (this->coordinates[i] $1 rhs)) return  0;  
	    }
    }
#endif
    return  1;  
}')


define(`LATTICE_DOUBLE_INTPOINT', `
int operator $1 (double lhs, const POINT_TYPE& rhs)  
{  
    if (rhs.dim() == 0) {  
	ia_throw(Point_Uninitialized_Exception(__FILE__, __LINE__));;  
	return  0;  
    }	  

#ifdef NO_LOOP_UNROLLING
    for (unsigned int i = 0; i < rhs.dim(); i++)  
	if (! (lhs $1 rhs.coordinates[i]))  
	    return  0;  

#else
    switch (rhs.dim()) {
    case 5: if (! (lhs $1 rhs.coordinates[4])) return  0;  
    case 4: if (! (lhs $1 rhs.coordinates[3])) return  0;  
    case 3: if (! (lhs $1 rhs.coordinates[2])) return  0;  
    case 2: if (! (lhs $1 rhs.coordinates[1])) return  0;  
    case 1: if (! (lhs $1 rhs.coordinates[0])) return  0;
    case 0: break;
    default:
	    {
		for (unsigned int i = 0; i < rhs.dim(); i++)  
		    if (! (lhs $1 rhs.coordinates[i])) return  0;  
	    }
    }
#endif    
    return  1;  
}')

divert(-1)
#//////////////////////////////////////////////////////////////
#//
#// B I T W I S E   P O I N T   D E F I N I T I O N S
#//
#//////////////////////////////////////////////////////////////
divert
define(`COMPOUND_BITWISE_ASSIGN_POINT', `  
POINT_TYPE& POINT_TYPE::operator $1= (const POINT_TYPE& rhs) {  
    if (this->dim() != rhs.dim()) {  
	ia_throw(Point_DimensionMismatch_Exception(__FILE__, __LINE__));  
	return *this;  
    }  
    if (this->dim() == 0) {  
	ia_throw(Point_Uninitialized_Exception(__FILE__, __LINE__));;  
	return *this;  
    }  
#ifdef NO_LOOP_UNROLLING
    for (unsigned i = 0; i < this->dim(); i++)  
	this->coordinates[i] $1= rhs.coordinates[i];  
#else
    switch (this->dim()) {
    case 5: this->coordinates[4] $1= rhs.coordinates[4];  
    case 4: this->coordinates[3] $1= rhs.coordinates[3];  
    case 3: this->coordinates[2] $1= rhs.coordinates[2];  
    case 2: this->coordinates[1] $1= rhs.coordinates[1];  
    case 1: this->coordinates[0] $1= rhs.coordinates[0];  
    case 0: break;
    default:
	    {
		for (unsigned i = 0; i < this->dim(); i++)  
		    this->coordinates[i] $1= rhs.coordinates[i];  
	    }
    }
#endif
    return *this;  
}')


define(`COMPOUND_BITWISE_ASSIGN_NUMBER', `  
POINT_TYPE& POINT_TYPE::operator $1= (int rhs) {
    if (this->dim() == 0) {  
	ia_throw(Point_Uninitialized_Exception(__FILE__, __LINE__));;  
	return *this;  
    }  
#ifdef NO_LOOP_UNROLLING
    for (unsigned i = 0; i < this->dim(); i++)  
	this->coordinates[i] $1= rhs;
#else
    switch (this->dim()) {
    case 5: this->coordinates[4] $1= rhs;
    case 4: this->coordinates[3] $1= rhs;
    case 3: this->coordinates[2] $1= rhs;
    case 2: this->coordinates[1] $1= rhs;
    case 1: this->coordinates[0] $1= rhs;
    case 0: break;
    default:
	    {
		for (unsigned i = 0; i < this->dim(); i++)  
		    this->coordinates[i] $1= rhs;
	    }
    }
#endif
    return *this;  
}')


define(`BITWISE_POINT_POINT', `
POINT_TYPE POINT_TYPE::operator $1 (const POINT_TYPE& rhs) const  
{ 
   POINT_TYPE result_point = *this;    
   return result_point $1= rhs;  
}')


define(`BITWISE_POINT_NUMBER', `
POINT_TYPE POINT_TYPE::operator $1 (int rhs) const
{ 
   POINT_TYPE result_point = *this;    
   return result_point $1= rhs;  
}')


define(`BITWISE_NUMBER_POINT', `
POINT_TYPE operator $1 (int lhs, const POINT_TYPE& rhs) {
    POINT_TYPE result_point = extend_to_point (lhs, rhs.dim());  
    return result_point $1= rhs;  
}')

divert(-1)
#//////////////////////////////////////////////////////////////
#//
#// O T H E R   P O I N T   D E F I N I T I O N S
#//
#//////////////////////////////////////////////////////////////
#
#
# The "FRIEND_SELECT_BINARY" macro takes two args, the name, and a logical 
# comparison operation: ie, could use "min" and "<" to construct something
# that returns a point that is the minimum value, elementwise, in two points.
# The "FRIEND_SELECT_UNARY" is similar, but extracts the element in the point
# that satisfies the condition.
divert


define(`FRIEND_SELECT_BINARY',`
// $1 returns an empty POINT_TYPE if passed two empty points.

POINT_TYPE $1 (const POINT_TYPE& lhs, const POINT_TYPE& rhs) 
{ 
    if (lhs.dim() != rhs.dim()) {  
	ia_throw(Point_DimensionMismatch_Exception(__FILE__, __LINE__));  
	return POINT_TYPE ();  
    }  

    POINT_TYPE p = rhs;

#ifdef NO_LOOP_UNROLLING
    for (unsigned i = 0; i < p.dim(); i++) 
	p.coordinates[i]
	    = (lhs.coordinates[i] $2 rhs.coordinates[i])
		?  lhs.coordinates[i] : rhs.coordinates[i];
#else
    switch (p.dim()) {
    case 5: p.coordinates[4] =	
	(lhs.coordinates[4] $2 rhs.coordinates[4])
	    ? lhs.coordinates[4] : rhs.coordinates[4];
    case 4: p.coordinates[3] = 
	(lhs.coordinates[3] $2 rhs.coordinates[3])
	    ? lhs.coordinates[3] : rhs.coordinates[3];
    case 3: p.coordinates[2] = 
	(lhs.coordinates[2] $2 rhs.coordinates[2])
	    ? lhs.coordinates[2] : rhs.coordinates[2];
    case 2: p.coordinates[1] = 
	(lhs.coordinates[1] $2 rhs.coordinates[1])
	    ? lhs.coordinates[1] : rhs.coordinates[1];
    case 1: p.coordinates[0] = 
	(lhs.coordinates[0] $2 rhs.coordinates[0])
	    ? lhs.coordinates[0] : rhs.coordinates[0];
    case 0: break;
    default:
	    {
		for (unsigned i = 0; i < p.dim(); i++) 
		    p.coordinates[i]
			= (lhs.coordinates[i] $2 rhs.coordinates[i])
			    ?  lhs.coordinates[i] : rhs.coordinates[i];
	    }
    }
#endif    
    return p; 
}')

define(`FRIEND_SELECT_UNARY',`
TYPE $1 (const POINT_TYPE& point)
{

    if (point.dim() == 0) {  
	ia_throw(Point_Uninitialized_Exception(__FILE__, __LINE__));;  
	return 0;
    }

    TYPE result = point.coordinates[0];

#ifdef NO_LOOP_UNROLLING
    for (unsigned i = 1; i < point.dim(); i++) 
	result =  (point.coordinates[i] $2 result)
			? point.coordinates[i] : result;
#else
    switch (point.dim()) {
    case 5: result = (point.coordinates[4] $2 result)
			? point.coordinates[4] : result;
    case 4: result = (point.coordinates[3] $2 result)
			? point.coordinates[3] : result;
    case 3: result = (point.coordinates[2] $2 result)
			? point.coordinates[2] : result;
    case 2: result = (point.coordinates[1] $2 result)
			? point.coordinates[1] : result;
    case 1: break;
    default:
	    {
		for (unsigned i = 1; i < point.dim(); i++) 
		    result =  (point.coordinates[i] $2 result)
				? point.coordinates[i] : result;
	    }
    }
#endif
    return result; 
}')


define(`ROUNDING_DOUBLE_TO_DOUBLE',`
POINT_TYPE $1 (POINT_TYPE p) 
{ 
#ifdef NO_LOOP_UNROLLING
    for (unsigned i = 0; i < p.dim(); i++) 
	p.coordinates[i] = $1(p.coordinates[i]); 
#else
    switch (p.dim()) {
    case 5: p.coordinates[4] = $1(p.coordinates[4]);
    case 4: p.coordinates[3] = $1(p.coordinates[3]);
    case 3: p.coordinates[2] = $1(p.coordinates[2]);
    case 2: p.coordinates[1] = $1(p.coordinates[1]);
    case 1: p.coordinates[0] = $1(p.coordinates[0]);
    case 0: break;
    default:
	    {
		for (unsigned i = 0; i < p.dim(); i++) 
		    p.coordinates[i] = $1(p.coordinates[i]);
	    }
    }
#endif
    return p; 
}')

define(`ROUNDING_DOUBLE_TO_INT',`
IPOINT $1 (const POINT_TYPE& p) 
{ 
    int	*iptr;
    iptr = new int[p.dim()];	    

#ifdef NO_LOOP_UNROLLING
    for (unsigned i = 0; i < p.dim(); i++) 
	iptr[i] = $1(p.coordinates[i]);    
#else
    switch (p.dim()) {
    case 5: iptr[4] = $1(p.coordinates[4]);
    case 4: iptr[3] = $1(p.coordinates[3]);
    case 3: iptr[2] = $1(p.coordinates[2]);
    case 2: iptr[1] = $1(p.coordinates[1]);
    case 1: iptr[0] = $1(p.coordinates[0]);
    case 0: break;
    default:
	    {
		for (unsigned i = 0; i < p.dim(); i++) 
		    iptr[i] = $1 (p.coordinates[i]);
	    }
    }
#endif    
    return IPOINT (iptr, p.dim(), 1);

}')
