// Copyright 2000
// College of Computer Science
// Northeastern University Boston MA 02115

// This software may be used for educational purposes as long as this copyright
// notice is retained at the top of all files

// Should this software be modified, the words "Modified from Original" must be
// included as a comment below this notice

// All publication rights are retained.  This software or its documentation may
// not be published in any media either in whole or in part.

///////////////////////////////////////////////////////////////////////////////

// GeoTypes.h

//          PointData       definition
//          NativePointData definition
//
//          RectData        definition
//          NativeRectData  definition
//
//			SizeData		definition
//
//			PolygonData		definition

///////////////////////////////////////////////////////////////////////////////

#ifndef GEOTYPES_H_
#define GEOTYPES_H_

#include "MathUtil.h"
#include "ArrayT.h"


///////////////////////////////////////////////////////////////////////////////

// NativePointData = typedef for native point structure
// NativeRectData  = typedef for native rect  structure


#if defined(CORE_PLATFORM_WIN32)

typedef POINT NativePointData;
typedef RECT  NativeRectData;

#endif // end Win32 specific


#if defined(CORE_PLATFORM_MACOS)

typedef Point NativePointData
typedef Rect  NativeRectData

#endif // end MacOS specific


///////////////////////////////////////////////////////////////////////////////

// forward declarations from GeoTypes.h

class EXPORT PointData;
class EXPORT RectData;
class EXPORT SizeData;

// forward declarations from Basic2D.h

class EXPORT Point2D;
class EXPORT Rect2D;

///////////////////////////////////////////////////////////////////////////////

// point class
// will define vector arithmetic on point class

class EXPORT PointData {
	friend class RectData;
	friend class SizeData;

	friend class Point2D;
	friend class Rect2D;

	// system independent point information: x, y
	// system  dependent  point information: NativePointData


#if defined(CORE_PLATFORM_WIN32)

	union {
		NativePointData NativePoint;	// Win32 point structure

		struct {
			short x;
			short padding1;				// added to force 32 bit alignment
			short y;
			short padding2;				// added to force 32 bit alignment
		};
	};

#endif // end Win32 specific


#if defined(CORE_PLATFORM_MACOS)

	// Note that the MacOS geometric structures put y before x

	union {
		NativePointData NativePoint;	// MacOS point structure

		struct {
			short y;
			short x;
		};		
	};

#endif // end MacOS specific


public:

	// Set functions

	PointData& Set(short X, short Y) {
		x = X;
		y = Y;

#if defined(CORE_PLATFORM_WIN32)

		// since this function is called by a constructor force padding to zero here

		padding1 = 0;
		padding2 = 0;

#endif // end Win32 specific

		return *this;

	};


	// default Set

	PointData& Set() { return Set(0, 0); };


	// Set x coordinate only

	PointData& SetX(short X) {
		x = X;
		return *this;
	};


	// Set y coordinate only

	PointData& SetY(short Y) {
		y = Y;
		return *this;
	};


	// Get functions

	void Get(short& X, short& Y) const {
		X = x;
		Y = y;
	};


	void Get(long& X, long& Y) const {
		X = x;
		Y = y;
	};


	void Get(int& X, int& Y) const {
		X = x;
		Y = y;
	};


	// set and get with PointData information

	PointData& Set(const PointData& point) {
		NativePoint = point.NativePoint;

		return *this;
	};


	void Get(PointData& point) const { point.NativePoint = NativePoint; };


	// set and get with NativePointData information

	PointData& Set(const NativePointData& point) {
		NativePoint = point;

#if defined(CORE_PLATFORM_WIN32)

		// since this function is called by a constructor force padding to zero here

		padding1 = 0;
		padding2 = 0;

#endif // end Win32 specific

		return *this;
	};


	void Get(NativePointData & point) const { point = NativePoint; };


	// constructors

	// default initialization: 0, 0

	PointData() { Set(0, 0); };


	// explicit initialization

	PointData(short X, short Y) { Set(X, Y); };


	// copy constructor from PointData

	PointData(const PointData& point) { Set(point); };


	// copy constructor from NativePointData

	PointData(const NativePointData& point) { Set(point); };


	// operator= for PointData

	PointData& operator= (const PointData& point) { return Set(point); };


	// operator= for NativePointData

	PointData& operator= (const NativePointData& point) { return Set(point); };


	// explicit conversion to NativePointData

	NativePointData Native() const { return NativePoint; };


	// destructor

	~PointData() { };


	// vector operators


	// operator+		P + Q

	friend PointData operator+ (const PointData& P, const PointData& Q)
		{ return PointData(P.x + Q.x, P.y + Q.y); };


	// operator+=		this point += P

	PointData& operator+= (const PointData& P) {
		x += P.x;
		y += P.y;

		return *this;
	};


	// operator-		P - Q

	friend PointData operator- (const PointData& P, const PointData& Q)
		{ return PointData(P.x - Q.x, P.y - Q.y); };


	// operator-=		this point -= P

	PointData& operator-= (const PointData& P) {
		x -= P.x;
		y -= P.y;

		return *this;
	};


	// operator*		s * P for short s

	friend PointData operator* (short s, const PointData& P)
		{ return PointData(s * P.x, s * P.y); };


	// operator*		P * s for short s

	friend PointData operator* (const PointData& P, short s)
		{ return PointData(P.x * s, P.y * s); };


	// operator*=		this point *= s for short s

	PointData& operator*= (short s) {
		x *= s;
		y *= s;

		return *this;
	};


	// operator/		P / s for short s
	//
	// if s == 0 then throw a string exception

	friend PointData operator/ (const PointData& P, short s) {
		if (s == 0)
			throw string("Division by zero");

		return PointData(P.x / s, P.y / s);
	};


	// operator/=		this point /= s for short s
	//
	// if s == 0 then throw a string exception

	PointData& operator/= (short s) {
		if (s == 0)
			throw string("Division by zero");

		x /= s;
		y /= s;

		return *this;
	};


	// operator%		P % s for short s
	//
	// if s == 0 then throw a string exception

	friend PointData operator% (const PointData& P, short s) {
		if (s == 0)
			throw string("Division by zero");

		return PointData(P.x % s, P.y % s);
	};


	// operator%=		this point %= s for short s
	//
	// if s == 0 then throw a string exception

	PointData& operator%= (short s) {
		if (s == 0)
			throw string("Division by zero");

		x %= s;
		y %= s;

		return *this;
	};


	// zero test

	friend bool IsZero(const PointData& P)
		{ return (P.x == 0) && (P.y == 0); };


	// operator==

	friend bool operator== (const PointData& P, const PointData& Q)
		{ return IsZero(P - Q); };


	// operator!=

	friend bool operator!= (const PointData& P, const PointData& Q)
		{ return ! IsZero(P - Q); };


	// geometric operations


	// offset point by dx and dy

	PointData& Offset(short dx, short dy) {
		x += dx;
		y += dy;

		return *this;
	};


	// offset point by point P
	// same as this point += P

	PointData& Offset(const PointData& P) {
		x += P.x;
		y += P.y;

		return *this;
	};


	// the following vector math functions return double
	// DotProduct could return short but might overflow

	friend double DotProduct (const PointData& P, const PointData& Q) {
		double px = P.x;
		double py = P.y;
		double qx = Q.x;
		double qy = Q.y;

		return px * qx + py * qy;
	};


	friend double Length (const PointData& P)
		{ return sqrt(DotProduct(P, P)); };


	friend double Distance (const PointData& P, const PointData& Q)
		{ return Length(P - Q); };


	friend double AngleInRadians (const PointData& P, const PointData& Q);


	friend double AngleInDegrees (const PointData& P, const PointData& Q)
		{ return radians_to_degrees * AngleInRadians(P, Q); };


	// IOTools member functions

	// New data is always stored in object
	// When appropriate, object is also returned by reference

	PointData& Request(						// respond-or-default
		const string&		prompt,			// prompt to user
		const PointData&	answer			// default answer
	);


	PointData& Request(						// mandatory response
		const string&		prompt			// prompt to user
	);


	bool Reading(							// respond-or-decline
		const string&		prompt			// prompt to user
	);
	
	
	// member functions for conversion of string to PointData

	// at the start position string should contain 2 short values: x y
	// optionally x y may be separated by commas as in: x, y
	
	PointData& FromString(
		const string&	source,			// string to read
		int				start,			// start position to read
		int&			next,			// next  position to read
		int&			error			// string IO error code
	);


	PointData& FromString(
		const char*		start,			// start position to read
		const char*&	next,			// next  position to read
		int&			error			// string IO error code
	);


	// member function for conversion of PointData to string

	// wide format: x, y using a field width of 6 each
	// otherwise:   x, y using minimal space 
	
	string ToString(bool wide = false) const;
	

	// see below for regular PointData functions that parallel procedural IOTools

}; // class PointData

///////////////////////////////////////////////////////////////////////////////

// rect class

class EXPORT RectData {
	friend class PointData;
	friend class SizeData;

	friend class Point2D;
	friend class Rect2D;

	// system independent rect information: x1, y1, x2, y2
	// system  dependent  rect information: NativeRectData


#if defined(CORE_PLATFORM_WIN32)

	union {
		NativeRectData NativeRect;		// Win32 rect structure

		struct {
			short x1;
			short padding1;				// added to force 32 bit alignment
			short y1;
			short padding2;				// added to force 32 bit alignment
			short x2;
			short padding3;				// added to force 32 bit alignment
			short y2;
			short padding4;				// added to force 32 bit alignment
		};
	};

#endif // end Win32 specific


#if defined(CORE_PLATFORM_MACOS)

	// Note that the MacOS geometric structures put y before x

	union {
		NativeRectData NativeRect;		// MacOS rect structure

		struct {
			short y1;
			short x1;
			short y2;
			short x2;
		};		
	};

#endif // end MacOS specific


public:

	// Set functions

	RectData& Set(short X1, short Y1, short X2, short Y2) {
		x1 = X1;
		y1 = Y1;
		x2 = X2;
		y2 = Y2;

#if defined(CORE_PLATFORM_WIN32)

		// since this function is called by a constructor force padding to zero here

		padding1 = 0;
		padding2 = 0;
		padding3 = 0;
		padding4 = 0;

#endif // end Win32 specific

		return *this;

	};


	// default Set

	RectData& Set() { return Set(0, 0, 0, 0); };


	// Get functions

	void Get(short& X1, short& Y1, short& X2, short& Y2) const {
		X1 = x1;
		Y1 = y1;
		X2 = x2;
		Y2 = y2;
	};


	void Get(long& X1, long& Y1, long& X2, long& Y2) const {
		X1 = x1;
		Y1 = y1;
		X2 = x2;
		Y2 = y2;
	};


	void Get(int& X1, int& Y1, int& X2, int& Y2) const {
		X1 = x1;
		Y1 = y1;
		X2 = x2;
		Y2 = y2;
	};


	// set and get with RectData information

	RectData& Set(const RectData& rect) {
		NativeRect = rect.NativeRect;

		return *this;
	};


	void Get(RectData& rect) const { rect.NativeRect = NativeRect; };


	// set and get with NativeRectData information

	RectData& Set(const NativeRectData& rect) {
		NativeRect = rect;

#if defined(CORE_PLATFORM_WIN32)

		// since this function is called by a constructor force padding to zero here

		padding1 = 0;
		padding2 = 0;
		padding3 = 0;
		padding4 = 0;

#endif // end Win32 specific

		return *this;
	};


	void Get(NativeRectData& rect) const {
		rect = NativeRect;
	};


	// set and get with pair of points
	// use the fact that RectData is a friend of PointData

	RectData& Set(const PointData& P, const PointData& Q) {
		return Set(P.x, P.y, Q.x, Q.y);
	};


	void Get (PointData& P, PointData& Q) const {
		Get(P.x, P.y, Q.x, Q.y);
	};


	// constructors

	// default initialization: 0, 0, 0, 0

	RectData() { Set(0, 0, 0, 0); };


	// explicit initializations

	RectData(short X1, short Y1, short X2, short Y2) { Set(X1, Y1, X2, Y2); };


	RectData(const PointData& P, const PointData& Q) { Set(P, Q); };


	// copy constructor from RectData

	RectData(const RectData& rect) { Set(rect); };


	// copy constructor from NativeRectData

	RectData(const NativeRectData& rect) { Set(rect); };


	// operator= for RectData

	RectData& operator= (const RectData& rect) { return Set(rect); };


	// operator= for NativeRectData

	RectData& operator= (const NativeRectData& rect) { return Set(rect); };


	// explicit conversion to NativeRectData

	NativeRectData Native() const { return NativeRect; };


	// destructor

	~RectData() { };


	// geometric operations


	// test if rect is empty

	friend bool IsEmpty (const RectData& R)
		{ return (R.x1 == R.x2) || (R.y1 == R.y2); };


	// offset rect by dx and dy

	RectData& Offset(short dx, short dy) {
		x1 += dx;
		y1 += dy;
		x2 += dx;
		y2 += dy;

		return *this;
	};


	// offset rect by point P

	RectData& Offset(const PointData& P) {
		x1 += P.x;
		y1 += P.y;
		x2 += P.x;
		y2 += P.y;

		return *this;
	};


	// expand rect by dx and dy

	RectData& Expand(short dx, short dy) {
		x1 -= dx;
		y1 -= dy;
		x2 += dx;
		y2 += dy;

		return *this;
	};


	// shrink rect by dx and dy

	RectData& Shrink(short dx, short dy) { return Expand(-dx, -dy); };


	// inset is a synonym for shrink

	RectData& Inset(short dx, short dy)  { return Expand(-dx, -dy); };


	// order the rect coordinates
	// guarantees x1 <= x2 and y1 <= y2

	RectData& Order() {
		SortPair(x1, x2);
		SortPair(y1, y2);

		return *this;
	};


	// grow rect to include point x, y

	RectData& Grow(short x, short y) {
		ExpandInterval(x1, x2, x);
		ExpandInterval(y1, y2, y);

		return *this;
	};


	// grow rect to include point P

	RectData& Grow(const PointData& P) { return Grow(P.x, P.y); };


	// test if point x, y is in rect

	bool PointInRect(short x, short y) const {
		return IsBetween(x1, x2, x) && IsBetween(y1, y2, y);
	};


	// test if point P is in rect

	bool PointInRect(const PointData& P) const {
		return PointInRect(P.x, P.y);
	};


	// union = smallest rect containing R and S

	friend RectData Union (RectData R, RectData S) {
		// compute union

		R.Order();
		S.Order();

		short x1 = Minimum(R.x1, S.x1);
		short y1 = Minimum(R.y1, S.y1);
		short x2 = Maximum(R.x2, S.x2);
		short y2 = Maximum(R.y2, S.y2);

		return RectData(x1, y1, x2, y2);
	};


	// intersection = rect formed by set intersection of R and S

	friend RectData Intersection (RectData R, RectData S) {
		// compute intersection

		R.Order();
		S.Order();

		short x1 = Maximum(R.x1, S.x1);
		short y1 = Maximum(R.y1, S.y1);
		short x2 = Minimum(R.x2, S.x2);
		short y2 = Minimum(R.y2, S.y2);

		// empty intersection adjustments

		if (x1 > x2)
			x1 = x2 = (x1 + x2) / 2;	// make rect trivial in x-direction

		if (y1 > y2)
			y1 = y2 = (y1 + y2) / 2;	// make rect trivial in y-direction

		return RectData(x1, y1, x2, y2);
	};


	// IOTools member functions

	// New data is always stored in object
	// When appropriate, object is also returned by reference

	RectData& Request(						// respond-or-default
		const string&		prompt,			// prompt to user
		const RectData&		answer			// default answer
	);


	RectData& Request(						// mandatory response
		const string&		prompt			// prompt to user
	);


	bool Reading(							// respond-or-decline
		const string&		prompt			// prompt to user
	);
	
	
	// member functions for conversion of string to RectData

	// at the start position string should contain 4 short values: x1 y1 x2 y2
	// optionally x1 y1 x2 y2 may be separated by commas as in: x1, y1, x2, y2
	
	RectData& FromString(
		const string&	source,			// string to read
		int				start,			// start position to read
		int&			next,			// next  position to read
		int&			error			// string IO error code
	);


	RectData& FromString(
		const char*		start,			// start position to read
		const char*&	next,			// next  position to read
		int&			error			// string IO error code
	);


	// member functions for conversion of RectData to string

	// wide format: x1, y1, x2, y2 using a field width of 6 each
	// otherwise:   x1, y1, x2, y2 using minimal space 

	string ToString(bool wide = false) const;
	

	// see below for regular RectData functions that parallel procedural IOTools

}; // class RectData

///////////////////////////////////////////////////////////////////////////////

// size data class
//
// contains 4 data fields: xsize, ysize, minimumsize, defaultsize
// will guarantee:
//     0 <= minimumsize <= xsize, ysize, defaultsize
//
// algorithmic steps for data modification
//
// 1: replace each item by its absolute value
// 2: if defaultsize is less than minimumsize then make
//       defaultsize = minimumsize
// 3: if either size is less than minimumsize then adjust the size by
//       if size == 0 then size = defaultsize else size = minimumsize
//
// in particular if minimum is strictly positive then
//        choose size = 0 to force size = default
//        cooose size = 1 to force size = minimum


class EXPORT SizeData {

	short xsize;
	short ysize;
	short minimumsize;
	short defaultsize;

	SizeData& Modify() {
		if (xsize < 0) xsize = -xsize;
		if (ysize < 0) ysize = -ysize;
		if (minimumsize < 0) minimumsize = -minimumsize;
		if (defaultsize < 0) defaultsize = -defaultsize;

		if (defaultsize < minimumsize) defaultsize = minimumsize;

		if (xsize < minimumsize) {
			if (xsize == 0)
				xsize = defaultsize;
			else
				xsize = minimumsize;
		}

		if (ysize < minimumsize) {
			if (ysize == 0)
				ysize = defaultsize;
			else
				ysize = minimumsize;
		}

		return *this;
	};

public:

	// Set xsize and ysize

	SizeData& Set(short X, short Y) {
		xsize = X;
		ysize = Y;

		return Modify();
	};


	// Get xsize and ysize

	void Get(short& X, short& Y) const {
		X = xsize;
		Y = ysize;
	};


	void Get(long& X, long& Y) const {
		X = xsize;
		Y = ysize;
	};


	void Get(int& X, int& Y) const {
		X = xsize;
		Y = ysize;
	};


	// Set minimumsize and defaultsize

	SizeData& SetMinAndDef(short Min, short Def) {
		minimumsize = Min;
		defaultsize = Def;

		return Modify();
	};


	// Get minimumsize and defaultsize

	void GetMinAndDef(short& Min, short& Def) const {
		Min = minimumsize;
		Def = defaultsize;
	};


	// Set using RectData to compute width and height
	// automatically resets minimumsize and defaultsize to 0

	SizeData& SetViaRect(const RectData& R) {
		minimumsize = 0;
		defaultsize = 0;

		return Set(R.x1 - R.x2, R.y1 - R.y2);
	};


	// default constructor

	SizeData() : 
		xsize(0), ysize(0), minimumsize(0), defaultsize(0) { };


	// constructor with xsize, ysize

	SizeData(short X, short Y) :
		xsize(X), ysize(Y), minimumsize(0), defaultsize(0)
			{ Modify(); };


	// constructor with xsize, ysize, minimumsize, defaultsize

	SizeData(short X, short Y, short Min, short Def) :
		xsize(X), ysize(Y), minimumsize(Min), defaultsize(Min)
			{ Modify(); };

	// constructor using RectData to compute width and height
	// sets minimumsize and defaultsize to 0

	SizeData(const RectData& R) { SetViaRect(R); };


	// destructor

	~SizeData() { };


	// Call the MathUtil function EqualizeSize on xsize and ysize
	//    Makes xsize and ysize equal to the smaller value
	//    unless one or both of them are zero

	SizeData& EqualizeSize() { 
		::EqualizeSize(xsize, ysize);
		
		return *this;
	};

}; // class SizeData

///////////////////////////////////////////////////////////////////////////////

// required declaration of Array<PointData>
// to satisfy Visual C++ DLL rules

#if defined(CORE_PLATFORM_WIN32)
#pragma warning(disable: 4231)
#endif	// end WIN32 specific

TEMPLATE_PREFIX template class EXPORT Array<PointData>;

///////////////////////////////////////////////////////////////////////////////

// PolygonData class is a public extension of Array<PointData>

class EXPORT PolygonData : public Array<PointData> {

public:

	PolygonData(int size = 1) : Array<PointData>(size) { };


	~PolygonData() { };

	
	// Append and Remove using PointData

	bool Append(const PointData& P) {
		return Array<PointData>::Append(P);
	}
	
	
	bool Remove(PointData& P) {
		return Array<PointData>::Remove(P);
	}
	
	
	// Append and Remove using x, y data

	bool Append(short x, short y) {
		PointData P(x, y);

		return Array<PointData>::Append(P);
	};


	bool Remove(short& x, short& y) {
		PointData P;

		if (Array<PointData>::Remove(P)) {
			P.Get(x, y);
			return true;
		}
		else
			return false;
	};


	// ClearPolygon makes all data invalid

	PolygonData& ClearPolygon() {
		Array<PointData>::ValidateNone();
		return *this;
	};


	// ClosePolygon appends a point at the end equal to the first point
	// Does nothing if polygon is empty

	PolygonData& ClosePolygon() {
		if (ValidSize() > 0) {
			short x, y;
			Access(0).Get(x, y);

			Append(x, y);
		}

		return *this;
	};


	// vector operators
	// only +=, -=, *=, /=, %= are supported ... these modify the polygon


	// operator+=		add P to all points in polygon

	PolygonData& operator+= (const PointData& P) {
		int i;
		int size = ValidSize();

		for (i = 0; i < size; i++)
			Access(i) += P;

		return *this;
	};


	// operator-=		subtract P from all points in polygon

	PolygonData& operator-= (const PointData& P) {
		int i;
		int size = ValidSize();

		for (i = 0; i < size; i++)
			Access(i) -= P;

		return *this;
	};


	// operator*=		this point *= s for short s

	PolygonData& operator*= (short s) {
		int i;
		int size = ValidSize();

		for (i = 0; i < size; i++)
			Access(i) *= s;

		return *this;
	};


	// operator/=		this point /= s for short s
	//
	// if s == 0 then throw a string exception

	PolygonData& operator/= (short s) {
		if (s == 0)
			throw string("Division by zero");

		int i;
		int size = ValidSize();

		for (i = 0; i < size; i++)
			Access(i) /= s;

		return *this;
	};


	// operator%=		this point %= s for short s
	//
	// if s == 0 then throw a string exception

	PolygonData& operator%= (short s) {
		if (s == 0)
			throw string("Division by zero");

		int i;
		int size = ValidSize();

		for (i = 0; i < size; i++)
			Access(i) %= s;

		return *this;
	};


	// geometric operations


	// offset point by point P
	// same as this point += P

	PolygonData& Offset(const PointData& P) {
		return (*this += P);
	};


	// offset point by dx and dy

	PolygonData& Offset(short dx, short dy) {
		PointData P(dx, dy);
		return (*this += P);
	};

}; // PolygonData

///////////////////////////////////////////////////////////////////////////////

// The following inline functions implement the procedural interface
// for PointData and RectData objects.


inline void SetPoint(PointData& P, short x, short y)
	{ P.Set(x, y); }


inline void GetPoint(const PointData& P, short& x, short& y)
	{ P.Get(x, y); }


inline void GetPoint(const PointData& P, long& x, long& y)
	{ P.Get(x, y); }


inline void GetPoint(const PointData& P, int& x, int& y)
	{ P.Get(x, y); }


inline PointData MakePoint(short x, short y)
	{ return PointData(x, y); }


inline void OffsetPoint(PointData& P, short dx, short dy)
	{ P.Offset(dx, dy); }


inline void OffsetPoint(PointData& P, const PointData& Q)
	{ P.Offset(Q); }


inline void SetRect(RectData& R, short x1, short y1, short x2, short y2)
	{ R.Set(x1, y1, x2, y2); }


inline void SetRect(RectData& R, const PointData& P, const PointData& Q)
	{ R.Set(P, Q); }


inline void GetRect(const RectData& R, short& x1, short& y1, short& x2, short& y2)
	{ R.Get(x1, y1, x2, y2); }


inline void GetRect(const RectData& R, long& x1, long& y1, long& x2, long& y2)
	{ R.Get(x1, y1, x2, y2); }


inline void GetRect(const RectData& R, int& x1, int& y1, int& x2, int& y2)
	{ R.Get(x1, y1, x2, y2); }


inline void GetRect(const RectData& R, PointData& P, PointData& Q)
	{ R.Get(P, Q); };


inline RectData MakeRect(short x1, short y1, short x2, short y2)
	{ return RectData(x1, y1, x2, y2); }


inline RectData MakeRect(const PointData& P, const PointData& Q)
	{ return RectData(P, Q); }


inline void OffsetRect(RectData& R, short dx, short dy)
	{ R.Offset(dx, dy); }


inline void OffsetRect(RectData& R, const PointData& P)
	{ R.Offset(P); }


inline void ExpandRect(RectData& R, short dx, short dy)
	{ R.Expand(dx, dy); }


inline void ShrinkRect(RectData& R, short dx, short dy)
	{ R.Shrink(dx, dy); }


inline void InsetRect(RectData& R, short dx, short dy)
	{ R.Inset(dx, dy); }


inline void OrderRect(RectData& R)
	{ R.Order(); }


inline void GrowRect(RectData& R, short x, short y)
	{ R.Grow(x, y); }


inline void GrowRect(RectData& R, const PointData& P)
	{ R.Grow(P); }


inline bool PointInRect(const RectData& R, short x, short y)
	{ return R.PointInRect(x, y); }


inline bool PointInRect(const RectData& R, const PointData& P)
	{ return R.PointInRect(P); }


// This set of functions is patterned after procedural IOTools


inline PointData RequestPoint(			// respond-or-default
	const string&		prompt,			// prompt to user
	const PointData&	answer			// default answer
) {
	PointData response;

	return response.Request(prompt, answer);
}
	
	
inline PointData RequestPoint(			// mandatory response
	const string&		prompt			// prompt to user
) {
	PointData response;

	return response.Request(prompt);
}
	
	
inline bool ReadingPoint(				// respond-or-decline
	const string&		prompt,			// prompt to user
	PointData&			answer			// user answer if provided
) {
	return answer.Reading(prompt);
}
	
	
inline PointData StringToPoint(
	const string&	source,			// string to read
	int				start,			// start position to read
	int&			next,			// next  position to read
	int&			error			// string IO error code
) {
	PointData response;

	return response.FromString(source, start, next, error);
}
	
	
inline PointData StringToPoint(
	const char*		start,			// start position to read
	const char*&	next,			// next  position to read
	int&			error			// string IO error code
) {
	PointData response;

	return response.FromString(start, next, error);
}
	
	
inline ostream& operator<< (ostream& os, const PointData& data) {
	os << data.ToString(true);
	return os;
}


inline RectData RequestRect(			// respond-or-default
	const string&		prompt,			// prompt to user
	const RectData&		answer			// default answer
) {
	RectData response;

	return response.Request(prompt, answer);
}
	
	
inline RectData RequestRect(			// mandatory response
	const string&		prompt			// prompt to user
) {
	RectData response;

	return response.Request(prompt);
}
	
	
inline bool ReadingRect(				// respond-or-decline
	const string&		prompt,			// prompt to user
	RectData&			answer			// user answer if provided
) {
	return answer.Reading(prompt);
}
	
	
inline RectData StringToRect(
	const string&	source,			// string to read
	int				start,			// start position to read
	int&			next,			// next  position to read
	int&			error			// string IO error code
) {
	RectData response;

	return response.FromString(source, start, next, error);
}
	
	
inline RectData StringToRect(
	const char*		start,			// start position to read
	const char*&	next,			// next  position to read
	int&			error			// string IO error code
) {
	RectData response;

	return response.FromString(start, next, error);
}
	
	
inline ostream& operator<< (ostream& os, const RectData& data) {
	os << data.ToString(true);
	return os;
}


#endif  // GEOTYPES_H_