// Copyright 1999
// 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.

///////////////////////////////////////////////////////////////////////////////

//	Scale2D.h

///////////////////////////////////////////////////////////////////////////////

#ifndef SCALE2D_H_
#define SCALE2D_H_

#include "Scale.h"
#include "Basic2D.h"


// abstract base class for 2D scale operation

class EXPORT Scale2D {
	// no data in this abstract base class
	
public:
	// a 2D scale class must have an operator() that takes Point2D to PointData
	virtual PointData operator() (const Point2D&) const = 0;

	// a scale class must have an inverse function to its operator()
	virtual Point2D Inverse(const PointData&) const = 0;
};


// class to define a linear 2D scale function

class EXPORT LinearScale2D : public Scale2D {
	LinearScale sx;
	LinearScale sy;
	
public:
	// set functions

	// supply factors and offsets

	LinearScale2D& Set(double FactorX, double OffsetX, double FactorY, double OffsetY) {
		sx.Set(FactorX, OffsetX);
		sy.Set(FactorY, OffsetY);

		return *this;
	};
	
	// map Rect2D Bounds to RectData Limits

	LinearScale2D& Set(const Rect2D& Bounds, const RectData& Limits);
	
	// map Rect2D Bounds to RectData Limits
	// require that the x-y scale factors have the same absolute value
	// so that the true geometric shape of objects is maintained

	LinearScale2D& SetTrueShape(const Rect2D& Bounds, const RectData& Limits);
	
	
	// constructors
	
	// default

	LinearScale2D() : sx(), sy() { };
	
	// supply factors and offsets

	LinearScale2D(double FactorX, double OffsetX, double FactorY, double OffsetY)
		: sx(FactorX, OffsetX), sy(FactorY, OffsetY) { };
	
	// map Rect2D Bounds to Rect Limits

	LinearScale2D(const Rect2D& Bounds, const RectData& Limits)
		{ Set(Bounds, Limits); };
	
	
	// scaling transform operator

	PointData operator() (const Point2D& P) const {
		double X;
		double Y;
		
		P.Get(X, Y);
		
		return PointData( sx(X), sy(Y) );
	};


	RectData operator() (const Rect2D& R) const {
		double X1;
		double Y1;
		double X2;
		double Y2;
	
		R.Get(X1, Y1, X2, Y2);

		return RectData( sx(X1), sy(Y1), sx(X2), sy(Y2) );
	};


	// scaling transform operator for polygons uses reference parameters
	// rather than function call operator

	void Apply(const Polygon2D& WorldPoly, PolygonData& PixelPoly) {
		int i;
		int size = WorldPoly.ValidSize();

		PixelPoly.ChangeMemory(size).ValidateAll();

		for (i = 0; i < size; i++)
			PixelPoly.Access(i) = operator() (WorldPoly.Access(i));
	};

	// scaling inverse transform operator

	Point2D Inverse(const PointData& P) const {
		short X;
		short Y;
		
		P.Get(X, Y);
		
		return Point2D( sx.Inverse(X), sy.Inverse(Y) );
	};


	Rect2D Inverse(const RectData& R) {
		short x1;
		short y1;
		short x2;
		short y2;
	
		R.Get(x1, y1, x2, y2);

		double X1 = sx.Inverse(x1);
		double Y1 = sy.Inverse(y1);
		double X2 = sx.Inverse(x2);
		double Y2 = sy.Inverse(y2);
	
		return Rect2D(X1, Y1, X2, Y2);
	};
};
	
#endif // SCALE2D_H_
