Files
test/testTransform/_transform.h
2012-12-06 21:43:03 +04:00

1409 lines
35 KiB
C++

/*
* SYNOPSYS CONFIDENTIAL - This is an unpublished, proprietary work of Synopsys,
* Inc., and is fully protected under copyright and trade secret laws. You may
* not view, use, disclose, copy, or distribute this file or any information
* contained herein except pursuant to a valid written license from Synopsys.
*/
#ifndef TRANSFORM_H_
#define TRANSFORM_H_
// _MSC_VER >= 1400 means we deal with VC8 or higher.
#if defined( _MSC_VER )
/*warning C4290: C++ exception specification ignored except to indicate a function is not __declspec(nothrow)*/
#pragma warning( disable: 4290 )
#endif
#include <math.h>
#include <string>
#include <stdio.h>
#include "base/port.h"
#include "base/constants.h"
#include "base/except.h"
#include "base/rectangle.h"
#include "base/round.h"
/*!
* round() is only defined in XOPEN_EXTENDED.
* Define it for platforms which do not implement the latter.
*/
#ifndef __USE_XOPEN_EXTENDED
namespace
{
double round(double x)
{
return floor(x + 0.5);
}
}
#endif
//
/// The transform.h file contains the different transform types.
//
/*!
* Usage of transforms:
* Transforms are applied to row vectors from the right as shown below:
* OV = IV * T
* Here, OV and IV are the output and input row vectors and T is the transform.
*
* Multiplying transforms:
* Suppose we have a chain of transforms.
* OV = IV * T1 * T2
* OV = IV * T
* Thus, T can be computed as follows:
* Transform T;
* T1.mult(T2, T);
*
* A general 2-D transform can be viewed in matrix form as follows:
* |a11 a12 0|
* |a21 a22 0|
* | tx ty 1|
* A general transform can be viewed as a sequence of 3 steps:
* 1- Scaling with value (Sx, Sy) (i.e. x' = Sx*x, y' = Sy*y).
* 2- rotating with angle A.
* 3- translating with value (tx, ty).
* In other words, the 2-D transform is the multiplication of the 3 transforms
* as follows:
* |Sx 0 0| | cos(A) sin(A) 0| | 1 0 0|
* |0 Sy 0|*|-sin(A) cos(A) 0|*| 0 1 0|
* |0 0 1| | 0 0 1| |tx ty 1|
*
* Using resolution transforms:
* In order to mimic applying resolution transforms to each cell individually,
* a resolution change operation is applied before anything. Suppose we call
* the resolution change transform RES. Also suppose the transform from the
* cell to the screen is TS. Thus:
* OV = IV * RES * TS.
* In order to change the resolution of a layout, we need to insert the
* resolution transform RES in the chain. Hence:
* 1- Create a resolution transform RES(xScale, yScale, true).
* 2- Assuming T is the total transform, T can be computed as follows:
* RES.mult(TS, T).
*/
namespace base
{
//
/// Enum for types of transforms.
//
enum transformType
{
//
/// ScaleOffsetTransform type.
//
ScaleOffsetTransformType = 0,
//
/// GeneralTransform type.
//
GeneralTransformType,
//
/// StdTransform type.
//
StdTransformType,
//
/// StdTransformWithMag type.
//
StdTransformWithMagType,
//
/// StdTransformWithMag type.
//
ScaleTransformType,
//
/// Resolution type.
//
ResolutionTransformType,
//
/// Always keep this entry as the last enum value.
//
transformTypeMAX
}; // enum transformType
//
/// Inverses of the standard orientations.
//
extern const stdOrientEnum inverseStdOrient[stdOrientMAX];
//
/// Coefficient matrices for the standard orientations.
//
extern const signed char stdOrientCoeffMatrix[stdOrientMAX][2][2];
//
/// Matrix holding standard orientations resulting from multiplying
/// different standard orientations.
//
extern const stdOrientEnum multStdOrientMatrix[stdOrientMAX][stdOrientMAX];
class transform;
//
/// Type definition for determining inverse of various transform types.
//
typedef transform (*pGetInverseFun)(const transform &);
//
/// Table of inverse determining functions by transform type.
//
extern pGetInverseFun getInverseFnTbl[transformTypeMAX];
typedef void (*pMultFun)( const transform & T1,
const transform & T2,
transform & outT );
extern pMultFun multFnTbl[transformTypeMAX*transformTypeMAX];
typedef pod::point<short> (*pModifyFunDblToShort)(const transform &, pod::point<double>);
typedef pod::point<short> (*pModifyFunLongToShort)(const transform &, pod::point<long>);
typedef pod::point<short> (*pModifyFunIntToShort)(const transform &, pod::point<int>);
typedef pod::point<int> (*pModifyFunDblToInt)(const transform &, pod::point<double>);
typedef pod::point<double> (*pModifyFunDblToDbl)(const transform &, pod::point<double>);
typedef pod::point<int> (*pModifyFunLongToInt)(const transform &, pod::point<long>);
typedef pod::point<int> (*pModifyFunIntToInt)(const transform &, pod::point<int>);
typedef pod::point<long> (*pModifyFunLongToLong)(const transform &, pod::point<long>);
//
/// Type definition for for transforming a rectangle of type double to
/// another rectangle of type double.
//
typedef pod::rectangle<double> (*pModifyRectFunDblToDbl)(const transform &, const pod::rectangle<double> &);
//
/// Type definition for for transforming a rectangle of type long to
/// another rectangle of type long.
//
typedef pod::rectangle<long> (*pModifyRectFunLongToLong)(const transform &, const pod::rectangle<long> &);
//
/// Type definition for for transforming a rectangle of type int to
/// another rectangle of type int.
//
typedef pod::rectangle<int> (*pModifyRectFunIntToInt)(const transform &, const pod::rectangle<int> &);
extern pModifyFunDblToShort modifyDblToShortFunTbl[transformTypeMAX];
extern pModifyFunLongToShort modifyLongToShortFunTbl[transformTypeMAX];
extern pModifyFunIntToShort modifyIntToShortFunTbl[transformTypeMAX];
extern pModifyFunDblToInt modifyDblToIntFunTbl[transformTypeMAX];
extern pModifyFunDblToDbl modifyDblToDblFunTbl[transformTypeMAX];
extern pModifyFunLongToInt modifyLongToIntFunTbl[transformTypeMAX];
extern pModifyFunIntToInt modifyIntToIntFunTbl[transformTypeMAX];
extern pModifyFunLongToLong modifyLongToLongFunTbl[transformTypeMAX];
extern pModifyRectFunLongToLong modifyRectLongToLongFunTbl[transformTypeMAX];
extern pModifyRectFunDblToDbl modifyRectDblToDblFunTbl[transformTypeMAX];
extern pModifyRectFunIntToInt modifyRectIntToIntFunTbl[transformTypeMAX];
//
/// The main transformation class.
//
class GXX_VISIBLE transform
{
// Data
protected:
//
/// 2X2 coefficient submatrix.
/// a11 would be used for Sx for scale and offset transforms.
/// It would also be used for resolution change for resolution
/// transforms.
/// Also, a11 would be used for magnification in the case of
/// standard transforms with magnification.
/// a22 would be used for Sy for scale and offset transforms.
/// It would also be used for resolution change for resolution
/// transforms.
//
double a11, a12, a21, a22;
//
// Offset for the transform.
//
pod::point<double> offset;
//
/// Pointer to next transform in chain. This is used by
/// resolution transforms.
//
transform *next;
//
/// Orientation field.
//
base::stdOrient orient;
//
/// Type of transform.
//
unsigned int type : 4;
// Typedefs
protected:
typedef pod::point<short> (*pModifyFunDblToShort)(
const transform &T,
pod::point<double> xy );
typedef pod::point<short> (*pModifyFunIntToShort)(
const transform &T,
pod::point<int> xy );
typedef pod::point<short> (*pModifyFunLongToShort)(
const transform &T,
pod::point<long> xy );
typedef pod::point<int> (*pModifyFunDblToInt)(
const transform &T,
pod::point<double> xy );
typedef pod::point<int> (*pModifyFunIntToInt)(
const transform &T,
pod::point<int> xy );
typedef pod::point<int> (*pModifyFunLongToInt)(
const transform &T,
pod::point<long> xy );
typedef pod::point<long> (*pModifyFunDblToLong)(
const transform &T,
pod::point<double> xy );
typedef pod::point<long> (*pModifyFunIntToLong)(
const transform &T,
pod::point<int> xy );
typedef pod::point<long> (*pModifyFunLongToLong)(
const transform &T,
pod::point<long> xy );
typedef pod::point<double> (*pModifyFunDblToDbl)(
const transform &T,
pod::point<double> xy );
typedef pod::point<double> (*pModifyFunIntToDbl)(
const transform &T,
pod::point<int> xy );
typedef pod::point<double> (*pModifyFunLongToDbl)(
const transform &T,
pod::point<long> xy );
private:
//
/// Get the inverse of a scale offset transform.
//
static transform getInverseScaleOffset(const transform & T);
//
/// Get the inverse of a general transform.
//
static transform getInverseGeneral(const transform & T );
//
/// Get the inverse of a standard transform.
//
static transform getInverseStd(const transform & T);
//
/// Get the inverse of a standard transform with mag.
//
static transform getInverseStdWithMag(const transform & T);
//
/// Get the inverse of a scale transform.
//
static transform getInverseScale(const transform & T);
//
// Get the inverse of a resolution transform.
//
static transform getInverseResolution(const transform & T);
//
/// Multiply two scale transforms.
//
static void multScaleXScale(const transform &T1,
const transform &T2,
transform &outT);
//
/// Multiply a scale transform with a resolution transform.
//
static void multScaleXResolution( const transform &T1,
const transform &T2,
transform &outT);
//
//
/// Multiply two scale offset transforms.
//
static void multScaleOffsetXScaleOffset(const transform &T1,
const transform &T2, transform &outT);
//
/// Multiply a scale offset transform with a general transform.
//
static void multScaleOffsetXGeneral(const transform &T1,
const transform &T2, transform &outT);
//
/// Multiply a scale offset transform with a standard transform.
//
static void multScaleOffsetXStd( const transform &T1,
const transform &T2,
transform &outT);
//
/// Multiply a scale offset transform with a standard transform
/// with magnification.
//
static void multScaleOffsetXStdWithMag( const transform &T1,
const transform &T2,
transform &outT);
//
/// Multiply a scale offset transform with a resolution transform.
//
static void multScaleOffsetXResolution(const transform &T1,
const transform &T2, transform &outT);
//
/// Multiply a general transform with a scale offset transform.
//
static void multGeneralXScaleOffset(const transform &T1,
const transform &T2, transform &outT);
//
/// Multiply two general transforms.
//
static void multGeneralXGeneral(const transform &T1,
const transform &T2, transform &outT);
//
/// Multiply a general transform with a standard transform.
//
static void multGeneralXStd(const transform &T1,
const transform &T2, transform &outT);
//
/// Multiply a general transform with a standard transform
/// with magnification.
//
static void multGeneralXStdWithMag(const transform &T1,
const transform &T2, transform &outT);
//
/// Multiply a general transform with a resolution transform.
//
static void multGeneralXResolution(const transform &T1,
const transform &T2, transform &outT);
//
/// Multiply a standard transform with a scale and offset transform.
//
static void multStdXScaleOffset(const transform &T1,
const transform &T2, transform &outT);
//
/// Multiply a standard transform with a general transform.
//
static void multStdXGeneral(const transform &T1,
const transform &T2, transform &outT);
//
/// Multiply two standard transforms.
//
static void multStdXStd(const transform &T1,
const transform &T2, transform &outT);
//
/// Multiply a standard transform with a standard transform
/// with magnification.
//
static void multStdXStdWithMag(const transform &T1,
const transform &T2, transform &outT);
//
/// Multiply a standard transform with a resolution transform.
//
static void multStdXResolution(const transform &T1,
const transform &T2, transform &outT);
//
/// Multiply a standard transform with magnification with a
/// scale and offset transform.
//
static void multStdWithMagXScaleOffset(const transform &T1,
const transform &T2, transform &outT);
//
/// Multiply a standard transform with magnification with
/// a general transform.
//
static void multStdWithMagXGeneral(const transform &T1,
const transform &T2, transform &outT);
//
/// Multiply a standard transform with magnification with
/// a standard transform.
//
static void multStdWithMagXStd(const transform &T1,
const transform &T2, transform &outT);
//
/// Multiply two standard transforms with magnification.
//
static void multStdWithMagXStdWithMag(const transform &T1,
const transform &T2, transform &outT);
//
/// Multiply a standard transform with magnification with a
/// resolution transform.
//
static void multStdWithMagXResolution(const transform &T1,
const transform &T2, transform &outT);
//
/// Multiply a resolution transform with any transform.
//
static void multResolutionXAny(const transform &T1,
const transform &T2, transform &outT);
// Construction
public:
//
/// Initialize the function tables.
//
static void initFnTables();
//
/// Default constuctor.
//
transform()
:
a11(1.0),
a12(0.0),
a21(0.0),
a22(1.0),
offset(0.0,0.0),
next(NULL),
orient(R0),
type(StdTransformType)
{}
//
/// Constructor for a scale offset transform.
//
transform(
double offsetX,
double offsetY,
double scaleX,
double scaleY
)
:
a11(scaleX),
a12(0.0),
a21(0.0),
a22(scaleY),
offset(offsetX,offsetY),
next(NULL),
type(ScaleOffsetTransformType)
{
double xAbs(offsetX > 0.0 ? offsetX : -offsetX);
double yAbs(offsetY > 0.0 ? offsetY : -offsetY);
if (xAbs < absTolerance && yAbs < absTolerance)
type = ScaleTransformType;
}
//
/// Constructor for a general transform.
//
transform(
double offsetX,
double offsetY,
double coeff11,
double coeff12,
double coeff21,
double coeff22
)
:
a11(coeff11),
a12(coeff12),
a21(coeff21),
a22(coeff22),
offset(offsetX,offsetY),
next(NULL),
type(GeneralTransformType)
{};
//
/// Constructor for a rotate transform.
/// @param inCx X coordinate of the center of rotation.
/// @param inCy Y coordinate of the center of rotation.
/// @param angle rotation angle in degrees.
//
transform(
double inCx,
double inCy,
double angle
)
:
a11(cos(degreesToRadians(angle))),
a12(sin(degreesToRadians(angle))),
a21(-a12),
a22(a11),
offset(inCy * a12 - inCx * a11 + inCx,
- inCy * a11 - inCx * a12 + inCy),
next(NULL),
type(GeneralTransformType)
{}
//
/// Constructor for a standard transform.
//
transform(
double offsetX,
double offsetY,
stdOrientEnum inOrient = R0
)
:
a11(1.0),
a12(0.0),
a21(0.0),
a22(1.0),
offset(offsetX,offsetY),
next(NULL),
orient(inOrient),
type(StdTransformType)
{}
//
/// Constructor for a standard transform with magnification.
//
transform(
double offsetX,
double offsetY,
stdOrientEnum inOrient,
double inMag)
:
a11(inMag),
a12(0.0),
a21(0.0),
a22(inMag),
offset(offsetX,offsetY),
next(NULL),
orient(inOrient),
type(StdTransformWithMagType)
{}
//
/// Advanced constructor for typical references.
/// @param offsetX X value of translation offset.
/// @param offsetY Y value of translation offset.
/// @param inXFlip boolean reflecting the presence of an X flip.
/// @param inAngle rotation angle in degrees.
/// @param inMag magnification.
//
transform(
double offsetX,
double offsetY,
bool inXFlip,
double inAngle,
double inMag)
:
offset(offsetX,offsetY),
next(NULL)
{
stdOrient newOrient(inXFlip, inAngle);
if (newOrient.getOri() != UnknownStdOrient)
{
orient = newOrient;
if (inMag > 1.0 + relTolerance ||
inMag < 1.0 - relTolerance)
{
a11 = inMag;
a12 = 0.0;
a21 = 0.0;
a22 = inMag;
type = StdTransformWithMagType;
}
else
{
a11 = 1.0;
a12 = 0.0;
a21 = 0.0;
a22 = 1.0;
type = StdTransformType;
}
}
else
{
type = GeneralTransformType;
register double multiplier = 1.0;
if (inXFlip == true)
multiplier = -1.0;
register double newAngle = degreesToRadians(normalizeAngle(inAngle));
register double cosine = cos(newAngle);
register double sine = sin(newAngle);
a11 = inMag * cosine;
a12 = inMag * sine;
a21 = -inMag * multiplier * sine;
a22 = inMag * multiplier * cosine;
}
}
//
/// Scale or resolution transform.
/// @param xScale X value of the scale factor.
/// @param yScale Y value of the scale factor.
/// @param rouding A true value means it is a resolution transform.
/// A false value will result in a standard scale transform.
//
transform(
double xScale,
double yScale,
bool rounding)
:
a11(xScale),
a12(0.0),
a21(0.0),
a22(yScale),
offset(0.0, 0.0),
next(NULL),
orient(R0),
type(ScaleTransformType)
{
if (rounding) {
// If both scales are whole numbers, it is
// a scale transform.
// If either scale is not close enough to an whole
// number, it is a resolution transform.
double rVal(base::round(xScale));
double diff(xScale - rVal);
diff = diff > 0.0 ? diff : -diff;
if (diff > absTolerance)
type = ResolutionTransformType;
else {
rVal = base::round(yScale);
diff = yScale - rVal;
diff = diff > 0.0 ? diff : -diff;
if (diff > absTolerance)
type = ResolutionTransformType;
}
}
}
//
/// Copy constructor
//
transform(const transform & inT)
{
type = inT.type;
orient = inT.orient;
offset = inT.offset;
a11 = inT.a11;
a12 = inT.a12;
a21 = inT.a21;
a22 = inT.a22;
if ( inT.next )
next = new transform(*inT.next);
else
next = 0;
}
//
/// Assignment operator
//
transform & operator = (const transform &inT)
{
type = inT.type;
orient = inT.orient;
offset = inT.offset;
a11 = inT.a11;
a12 = inT.a12;
a21 = inT.a21;
a22 = inT.a22;
if (inT.next)
{
if (next)
*next = *(inT.next);
else
next = new transform(*(inT.next));
}
else
{
delete next;
next = NULL;
}
return *this;
}
//
/// Destructor
//
~transform()
{
if (next)
delete next;
}
public:
//
/// Equal operator
//
bool operator == (const transform &inT)
{
if ((inT.type == type) &&
(inT.orient.getOri() == orient.getOri()) &&
(inT.a11 == a11) &&
(inT.a12 == a12) &&
(inT.a21 == a21) &&
(inT.a22 == a22) &&
(inT.offset == offset))
{
if ( !next )
return (!inT.next);
else if ( inT.next )
return (*next == *(inT.next));
else
return false;
}
return false;
}
//
/// Non equal operator
//
bool operator != (const transform &inT)
{
return !(*this == inT);
}
//
/// Test whether this is an identity transform.
//
bool isIdentityTransform() const
throw (except::outOfRange)
{
const double onePlusTolerance = 1.0 + relTolerance;
const double oneMinusTolerance = 1.0 - relTolerance;
//
// See if the offsets are beyond the origin.
//
if (offset.X() > absTolerance || offset.X() < -absTolerance ||
offset.Y() > absTolerance || offset.Y() < -absTolerance)
return false;
//
// Check by transform type.
//
switch((transformType) type)
{
case StdTransformWithMagType:
if (a11 > onePlusTolerance || a11 < oneMinusTolerance)
return false;
case StdTransformType:
if (orient.getOri() != R0)
return false;
break;
case GeneralTransformType:
if ( a12 > absTolerance ||
a12 < -absTolerance ||
a21 > absTolerance ||
a21 < -absTolerance)
return false;
case ScaleOffsetTransformType:
case ScaleTransformType:
if ( a11 > onePlusTolerance ||
a11 < oneMinusTolerance ||
a22 > onePlusTolerance ||
a22 < oneMinusTolerance)
return false;
break;
case ResolutionTransformType:
return false;
break;
default:
throw except::outOfRange("base::transform:isIdentityTransform: Unknown type.");
}
return true;
}
//
/// Returns the type of the transform.
//
transformType getType() const
{
return (transformType) type;
}
//
/// Returns the type of the transform chain.
//
transformType getTypeOfChain() const
{
const transform *t = this;
while (t->getNext() != NULL)
t = t->getNext();
return (transformType) t->type;
}
//
/// Returns the offset point of the transform.
//
pod::point<double> getOffset() const
{
return offset;
}
//
/// Returns the offset point of the transform taking into account also resolution.
//
pod::point<double> getOffsetRes() const
{
if ( getType() != ResolutionTransformType )
return offset;
else
{
pod::point<double> zero( 0., 0.);
pod::point<double> off;
modify( zero, off );
return off;
}
}
//
/// Set the offset of the transform.
//
void setOffset( pod::point<double> off )
{
offset = off;
}
stdOrient getOrient() const
{
return orient;
}
pod::point<double> getDiagonal() const
{
return pod::point<double>(a11,a22);
}
pod::point<double> getRow1() const
{
return pod::point<double>(a11,a12);
}
pod::point<double> getRow2() const
{
return pod::point<double>(a21,a22);
}
pod::point<double> getCol1() const
{
return pod::point<double>(a11,a21);
}
pod::point<double> getCol2() const
{
return pod::point<double>(a12,a22);
}
//
/// Return the magnitude of the vector (1,0).
//
double getXVectorMag() const
{
if ( a21 == 0.0 )
return ::fabs(a11);
else if ( a11 == 0.0 )
return ::fabs(a21);
else
return ::sqrt(a11*a11 + a21*a21);
}
//
/// A special function to return the X scale factor. This
/// is a nonnegative value that reflects the scaling effect
/// in the X direction.
//
double getXScale() const
{
if (type != ResolutionTransformType)
return getXVectorMag();
else
return getXVectorMag() * (next ? next->getXScale() : 1.0);
}
//
/// Returns the a11 entry of the matrix. If the matrix is a scaling
/// one, then this returns the X-scale factor.
/// The result is not correct for all types of transforms.
//
double get11() const
{
return a11;
}
//
/// Return the a12 entry of the matrix.
/// The result is only valid for general transforms.
/// The result is not correct for all types of transforms.
//
double get12() const
{
return a12;
}
//
/// Return the a21 entry of the matrix.
/// The result is only valid for general transforms.
/// The result is not correct for all types of transforms.
//
double get21() const
{
return a21;
}
//
/// Returns the a22 entry of the matrix. If the matrix is a scaling
/// one, then this returns the Y-scale factor.
/// The result is not correct for all types of transforms.
//
double get22() const
{
return a22;
}
//
/// Return the next field.
//
const transform *getNext() const
{
return next;
}
//
/// Return the next field.
//
transform *getNext()
{
return next;
}
//
/// get angle, isXFlip and mag from transformation
//
const void getAngleFlipMag( double& angle, bool& isXFlip, double& mag) const;
// Complex functions.
public:
//
/// Multiply with another transform.
//
void mult(const transform &T2, transform &outT) const
{
(*(multFnTbl[(type*transformTypeMAX)+T2.type]))(*this,T2,outT);
}
transform operator *(const transform & T) const
{
transform out;
mult(T,out);
return out;
}
//
/// Scale the transform by the given scalar.
//
transform & operator *= (const double d)
{
if (type != ResolutionTransformType) {
transform tmp(d, d, false);
transform out;
mult(tmp, out);
*this = out;
} else {
if (next)
*next *= d;
else
next = new transform(d, d, false);
}
return *this;
}
//
/// Return the inverse transform of the transform.
//
transform getInverse() const
{
return (*(getInverseFnTbl[type]))(*this);
}
#if 1
//
/// Do nothing method for syntactic completeness.
//
pod::point<int> modifyDblToInt(pod::point<int>) const
{ return pod::point<int>(); }
pod::point<int> modifyDblToInt(pod::point<long>) const
{ return pod::point<int>(); }
pod::point<short> modifyDblToShort(pod::point<int>) const
{ return pod::point<short>(); }
pod::point<short> modifyDblToShort(pod::point<long>) const
{ return pod::point<short>(); }
pod::point<double> modifyDblToDbl(pod::point<int>) const
{ return pod::point<double>(); }
pod::point<int> modifyIntToInt(pod::point<double>) const
{ return pod::point<int>(); }
pod::point<int> modifyIntToInt(pod::point<long>) const
{ return pod::point<int>(); }
pod::point<short> modifyIntToShort(pod::point<double>) const
{ return pod::point<short>(); }
pod::point<short> modifyIntToShort(pod::point<long>) const
{ return pod::point<short>(); }
pod::point<short> modifyLongToShort(pod::point<int>) const
{ return pod::point<short>(); }
pod::point<short> modifyLongToShort(pod::point<double>) const
{ return pod::point<short>(); }
pod::point<int> modifyLongToInt(pod::point<int>) const
{ return pod::point<int>(); }
pod::point<int> modifyLongToInt(pod::point<double>) const
{ return pod::point<int>(); }
////////////////////////////////////////////////////////////////
//
/// Modify a single point.
//
pod::point<short> modifyDblToShort(pod::point<double> p) const
{
return (*(modifyDblToShortFunTbl[type]))(*this, p);
}
pod::point<int> modifyDblToInt(pod::point<double> p) const
{
return (*(modifyDblToIntFunTbl[type]))(*this, p);
}
//
/// Transform doubles to doubles.
//
pod::point<double> modifyDblToDbl(pod::point<double> p) const
{
return (*(modifyDblToDblFunTbl[type]))(*this, p);
}
pod::point<double> modify(pod::point<double> p) const
{
return (*(modifyDblToDblFunTbl[type]))(*this, p);
}
#ifdef WIN32
// pod::point<i64> modify(pod::point<i64> p) const
// {
// return (*(modifyLongToLongFunTbl[type]))(*this, p);
// }
#endif
template<class C>
pod::rectangle<C> modify(pod::rectangle<C> p) const
{
return pod::rectangle<C>( 0, 0, 0, 0 );
}
pod::point<int> modifyIntToInt(pod::point<int> p) const
{
return (*(modifyIntToIntFunTbl[type]))(*this, p);
}
pod::point<int> modify(pod::point<int> p) const
{
return (*(modifyIntToIntFunTbl[type]))(*this, p);
}
pod::point<short> modifyIntToShort(pod::point<int> p) const
{
return (*(modifyIntToShortFunTbl[type]))(*this, p);
}
pod::point<short> modifyLongToShort(pod::point<long> p) const
{
return (*(modifyLongToShortFunTbl[type]))(*this, p);
}
//
/// Transform longs to ints.
//
pod::point<int> modifyLongToInt(pod::point<long> p) const
{
return (*(modifyLongToIntFunTbl[type]))(*this, p);
}
//
/// Transform longs to longs.
//
pod::point<long> modifyLongToLong(pod::point<long> p) const
{
return (*(modifyLongToLongFunTbl[type]))(*this, p);
}
pod::point<long> modify(pod::point<long> p) const
{
return (*(modifyLongToLongFunTbl[type]))(*this, p);
}
#endif
//
//
//
#if 1
pod::rectangle<double> operator()(const pod::rectangle<double> & r) const
{
return (*(modifyRectDblToDblFunTbl[type]))(*this, r);
}
pod::rectangle<long> operator()(const pod::rectangle<long> & r) const
{
return (*(modifyRectLongToLongFunTbl[type]))(*this, r);
}
pod::rectangle<int> operator()(const pod::rectangle<int> & r) const
{
return (*(modifyRectIntToIntFunTbl[type]))(*this, r);
}
pod::point<double> operator()(const pod::point<double> & p) const
{
return (*(modifyDblToDblFunTbl[type]))(*this, p);
}
pod::point<long> operator()(const pod::point<long> & p) const
{
return (*(modifyLongToLongFunTbl[type]))(*this, p);
}
pod::point<int> operator()(const pod::point<int> & p) const
{
return (*(modifyIntToIntFunTbl[type]))(*this, p);
}
#endif
//
/// This is a convinient function converting coordinate types without loss of precision.
//
/*!
We try to not loss precision and use available functionality
provided by transform maximally. This function does what
all modifyXxxxToYyyyy does and is very helpful in generic programming.
*/
template <class iC, class oC>
void modify( const pod::point<iC>& rSrc, pod::point<oC>& rDest ) const;
//
/// This is pod::rectangle version of above function.
//
template <class iC, class oC>
void modify( const pod::rectangle<iC>& rSrc, pod::rectangle<oC>& rDest ) const;
//
/// Transform given bbox.
//
/*!
While we transform bbox, the usual approach of transforming
lower left and upper right is not satisfactory. In case of
rotations we need to transform and merge all four vertices
of bbox to get one of bbox rectangles of a shape which bbox we
want to transform. The bbox transformed this way will not be the
smallest bbox of the shape, yet at least this will be a bbox.
While if we use usual approach, then we will get (in case of rotation)
a rectangle that is not nessecarily a bbox of original shape.
The function also optimizes cases when transform has
only orthogonal transforms.
*/
template <class iC, class oC>
void modifyBBox( const pod::rectangle<iC>& rSrc, pod::rectangle<oC>& rDest ) const;
//
/// Convert a transform type to a string.
//
operator std::string() const;
friend std::ostream & operator << (std::ostream & os, const transform & t);
//
/// Print a transform, mainly for debug purpose.
//
void print(FILE *outStream, const char *linePrefix) const;
}; // class transform
namespace transformTest
{
/// API test getAngelFlipmag
bool testGetAngleFlipMag();
};
/*!
* Simple resolution chain implementation.
* Objects of this class can receive the resolution portion of transform
* objects and apply them to double precision points.
*/
class resolutionChain
{
private:
int chainSize;
pod::point<double> *chain;
//
/// Get the resolution chain from a transform object.
//
void getResFromTransform(const transform &trn)
{
chainSize = 0;
chain = NULL;
//
// Calculate the resolution chain size.
//
const transform *t = &trn;
while (t && t->getType() == ResolutionTransformType)
{
chainSize++;
t = t->getNext();
}
if (chainSize == 0)
return;
//
// Initialize the resolutions.
//
chain = new pod::point<double>[chainSize];
t = &trn;
for (int i = 0; i < chainSize; i++)
{
chain[i] = t->getDiagonal();
t = t->getNext();
}
}
public:
//
/// Default do-nothing constructor.
//
resolutionChain() :
chainSize(0), chain(NULL)
{}
//
/// Construct the resolution chain of a transform object.
//
resolutionChain(const transform &trn) :
chainSize(0), chain(NULL)
{
getResFromTransform(trn);
}
//
/// Assign to this the resolution chain of a transform object.
//
resolutionChain &operator = (const transform &trn)
{
if (chain)
delete[] chain;
getResFromTransform(trn);
return *this;
}
//
/// Destroy the chain.
//
~resolutionChain()
{
if (chain)
delete[] chain;
}
//
/// Check if this is the resolution chain of trn.
//
bool isResChainOf(const transform &trn) const
{
const transform *t = &trn;
for (int i = 0; i < chainSize; i++)
{
if (!t || t->getType() != ResolutionTransformType)
return false;
if (chain[i] != t->getDiagonal())
return false;
t = t->getNext();
}
if (t && t->getType() == ResolutionTransformType)
return false;
return true;
}
//
/// Apply the chain to the point p. Round after each
/// resolution change if needed.
//
pod::point<double> apply(pod::point<double> p, bool round = true) const
{
pod::point<double> r = p;
for (int i = 0; i < chainSize; i++)
{
r = r % chain[i];
if (round)
r = pod::point<double>(::round(r.getX()),
::round(r.getY()));
}
return r;
}
};
/*!
* Simple transformation class.
* This class does not allow resolution change transformations - they
* should be modeled by resolutionChain instead. Objects of this class
* consist of a 2x2 matrix and an offset and can be applied to double
* precision points.
*/
class simpleTransform
{
private:
pod::point<double> col1;
pod::point<double> col2;
pod::point<double> offset;
public:
//
/// Default identity transformation constructor.
//
simpleTransform() :
col1(1, 0), col2(0, 1), offset(0, 0)
{}
//
/// Construct a transformation from a transform object
/// skipping the resolution chain.
//
simpleTransform(const transform &trn) :
col1(1, 0), col2(0, 1), offset(0, 0)
{
//
// Skip the resolution part
//
const transform *t = &trn;
while (t && t->getType() == base::ResolutionTransformType)
t = t->getNext();
//
// If there is anything left, dig out the parameters from t.
//
if (t)
{
if (t->getType() != ScaleTransformType)
offset = t->getOffset();
switch (t->getType())
{
case base::ScaleTransformType:
case base::ScaleOffsetTransformType:
col1 = pod::point<double>(t->get11(), 0.0);
col2 = pod::point<double>(0.0, t->get22());
break;
case base::GeneralTransformType:
col1 = t->getCol1();
col2 = t->getCol2();
break;
case base::StdTransformType:
case base::StdTransformWithMagType:
if (t->getOrient().getOri() == R90)
{
col1 = pod::point<double>(0.0, -1.0);
col2 = pod::point<double>(1.0, 0.0);
}
if (t->getOrient().getOri() == R180)
{
col1 = pod::point<double>(-1.0, 0.0);
col2 = pod::point<double>(0.0, -1.0);
}
if (t->getOrient().getOri() == R270)
{
col1 = pod::point<double>(0.0, 1.0);
col2 = pod::point<double>(-1.0, 0.0);
}
if (t->getOrient().getOri() == XFlipR0)
{
col1 = pod::point<double>(1.0, 0.0);
col2 = pod::point<double>(0.0, -1.0);
}
if (t->getOrient().getOri() == XFlipR90)
{
col1 = pod::point<double>(0.0, 1.0);
col2 = pod::point<double>(1.0, 0.0);
}
if (t->getOrient().getOri() == XFlipR180)
{
col1 = pod::point<double>(-1.0, 0.0);
col2 = pod::point<double>(0.0, 1.0);
}
if (t->getOrient().getOri() == XFlipR270)
{
col1 = pod::point<double>(0.0, -1.0);
col2 = pod::point<double>(-1.0, 0.0);
}
if (t->getType() == StdTransformWithMagType)
{
col1 *= t->get11();
col2 *= t->get11();
}
break;
default:
break;
}
}
}
//
/// Apply the transformation to a double precision point.
//
pod::point<double> apply(pod::point<double> p) const
{
return pod::point<double>(p * col1, p * col2) + offset;
}
};
} // namespace base
#endif // TRANSFORM_H_