//----------------------------------------------------------------------
// File:			ANNx.h
// Programmer: 		Sunil Arya and David Mount
// Description:		Internal include file for ANN
// Last modified:	01/27/10 (Version 1.1.2)
//
//	These declarations are of use in manipulating some of
//	the internal data objects appearing in ANN, but are not
//	needed for applications just using the nearest neighbor
//	search.
//
//	Typical users of ANN should not need to access this file.
//----------------------------------------------------------------------
// Copyright (c) 1997-2010 University of Maryland and Sunil Arya and
// David Mount.  All Rights Reserved.
// 
// This software and related documentation is part of the Approximate
// Nearest Neighbor Library (ANN).  This software is provided under
// the provisions of the Lesser GNU Public License (LGPL).  See the
// file ../ReadMe.txt for further information.
// 
// The University of Maryland (U.M.) and the authors make no
// representations about the suitability or fitness of this software for
// any purpose.  It is provided "as is" without express or implied
// warranty.
//----------------------------------------------------------------------
//	History:
//	Revision 0.1  03/04/98
//	    Initial release
//	Revision 1.0  04/01/05
//	    Changed LO, HI, IN, OUT to ANN_LO, ANN_HI, etc.
//	Revision 1.1.2  01/27/10
//		Fixed minor compilation bugs for new versions of gcc
//----------------------------------------------------------------------

#ifndef ANNx_H
#define ANNx_H

#include <iomanip>				// I/O manipulators
#include <ANN/ANN.h>			// ANN includes

//----------------------------------------------------------------------
//	Global constants and types
//----------------------------------------------------------------------
enum	{ANN_LO=0, ANN_HI=1};	// splitting indices
enum	{ANN_IN=0, ANN_OUT=1};	// shrinking indices
								// what to do in case of Rf_error
enum ANNerr {ANNwarn = 0, ANNabort = 1};

//----------------------------------------------------------------------
//	Maximum number of points to visit
//	We have an option for terminating the search early if the
//	number of points visited exceeds some threshold.  If the
//	threshold is 0 (its default)  this means there is no limit
//	and the algorithm applies its normal termination condition.
//----------------------------------------------------------------------

extern int		ANNmaxPtsVisited;	// maximum number of pts visited
extern int		ANNptsVisited;		// number of pts visited in search

//----------------------------------------------------------------------
//	Global function declarations
//----------------------------------------------------------------------

void annError(					// ANN Rf_error routine
	const char*		msg,		// Rf_error message
	ANNerr			level);		// level of Rf_error

void annPrintPt(				// print a point
	ANNpoint		pt,			// the point
	int				dim,		// the dimension
	std::ostream	&out);		// output stream

//----------------------------------------------------------------------
//	Orthogonal (axis aligned) rectangle
//	Orthogonal rectangles are represented by two points, one
//	for the lower left corner (min coordinates) and the other
//	for the upper right corner (max coordinates).
//
//	The constructor initializes from either a pair of coordinates,
//	pair of points, or another rectangle.  Note that all constructors
//	allocate new point storage. The destructor deallocates this
//	storage.
//
//	BEWARE: Orthogonal rectangles should be passed ONLY BY REFERENCE.
//	(C++'s default copy constructor will not allocate new point
//	storage, then on return the destructor free's storage, and then
//	you get into big trouble in the calling procedure.)
//----------------------------------------------------------------------

class ANNorthRect {
public:
	ANNpoint		lo;			// rectangle lower bounds
	ANNpoint		hi;			// rectangle upper bounds
//
	ANNorthRect(				// basic constructor
	int				dd,			// dimension of space
	ANNcoord		l=0,		// default is empty
	ANNcoord		h=0)
	{  lo = annAllocPt(dd, l);  hi = annAllocPt(dd, h); }

	ANNorthRect(				// (almost a) copy constructor
	int				dd,			// dimension
	const			ANNorthRect &r) // rectangle to copy
	{  lo = annCopyPt(dd, r.lo);  hi = annCopyPt(dd, r.hi);  }

	ANNorthRect(				// construct from points
	int				dd,			// dimension
	ANNpoint		l,			// low point
	ANNpoint		h)			// hight point
	{  lo = annCopyPt(dd, l);  hi = annCopyPt(dd, h);  }

	~ANNorthRect()				// destructor
    {  annDeallocPt(lo);  annDeallocPt(hi);  }

	ANNbool inside(int dim, ANNpoint p);// is point p inside rectangle?
};

void annAssignRect(				// assign one rect to another
	int				dim,		// dimension (both must be same)
	ANNorthRect		&dest,		// destination (modified)
	const ANNorthRect &source);	// source

//----------------------------------------------------------------------
//	Orthogonal (axis aligned) halfspace
//	An orthogonal halfspace is represented by an integer cutting
//	dimension cd, coordinate cutting value, cv, and side, sd, which is
//	either +1 or -1. Our convention is that point q lies in the (closed)
//	halfspace if (q[cd] - cv)*sd >= 0.
//----------------------------------------------------------------------

class ANNorthHalfSpace {
public:
	int				cd;			// cutting dimension
	ANNcoord		cv;			// cutting value
	int				sd;			// which side
//
	ANNorthHalfSpace()			// default constructor
	{  cd = 0; cv = 0;  sd = 0;  }

	ANNorthHalfSpace(			// basic constructor
	int				cdd,		// dimension of space
	ANNcoord		cvv,		// cutting value
	int				sdd)		// side
	{  cd = cdd;  cv = cvv;  sd = sdd;  }

	ANNbool in(ANNpoint q) const	// is q inside halfspace?
	{  return  (ANNbool) ((q[cd] - cv)*sd >= 0);  }

	ANNbool out(ANNpoint q) const	// is q outside halfspace?
	{  return  (ANNbool) ((q[cd] - cv)*sd < 0);  }

	ANNdist dist(ANNpoint q) const	// (squared) distance from q
	{  return  (ANNdist) ANN_POW(q[cd] - cv);  }

	void setLowerBound(int d, ANNpoint p)// set to lower bound at p[i]
	{  cd = d;  cv = p[d];  sd = +1;  }

	void setUpperBound(int d, ANNpoint p)// set to upper bound at p[i]
	{  cd = d;  cv = p[d];  sd = -1;  }

	void project(ANNpoint &q)		// project q (modified) onto halfspace
	{  if (out(q)) q[cd] = cv;  }
};

								// array of halfspaces
typedef ANNorthHalfSpace *ANNorthHSArray;

#endif
