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

1594 lines
52 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.
*/
#include "base/type-traits2.h"
//#include "ssetypes.h"
#include "transform.h"
#include "base/constants.h"
namespace base
{
const stdOrientEnum inverseStdOrient[stdOrientMAX] =
{
R0,
R270,
R180,
R90,
XFlipR0,
XFlipR90,
XFlipR180,
XFlipR270
};
/* In Aix64 platform char is by default unsigned this causes difference in values, ensuring signed char array */
const signed char stdOrientCoeffMatrix[stdOrientMAX][2][2] =
{
//
/// R0: 0 degree rotation with no flip.
/// Coefficients = | 1 0|
/// | 0 1|
//
{{1, 0},
{0, 1}},
//
/// R90: 90 degree rotation with no flip.
/// Coefficients = | 0 1|
/// |-1 0|
//
{{0, 1},
{-1, 0}},
//
/// R180: 180 degree rotation with no flip.
/// Coefficients = |-1 0|
/// | 0 -1|
//
{{-1, 0},
{0, -1}},
//
/// R270: 270 degree rotation with no flip.
/// Coefficients = | 0 -1|
/// | 1 0|
//
{{0, -1},
{1, 0}},
//
/// XFlipR0: X flip followed by 0 degree rotation.
/// Coefficients = | 1 0|
/// | 0 -1|
//
{{1, 0},
{0, -1}},
//
/// X flip followed by 90 degree rotation.
/// Coefficients = | 0 1|
/// | 1 0|
//
{{0, 1},
{1, 0}},
//
/// X flip followed by 180 degree rotation.
/// Coefficients = |-1 0|
/// | 0 1|
//
{{-1, 0},
{0, 1}},
//
/// X flip followed by 270 degree rotation.
/// Coefficients = | 0 -1|
/// |-1 0|
//
{{0, -1},
{-1, 0}}
};
//
/// Matrix for multiplying standard orientations.
//
const stdOrientEnum multStdOrientMatrix[stdOrientMAX][stdOrientMAX] = {
// R0, R90, R180, R270, XFlipR0, XFlipR90, XFlipR180, XFlipR270
/* R0 */ { R0, R90, R180, R270, XFlipR0, XFlipR90, XFlipR180, XFlipR270},
/* R90 */ { R90, R180, R270, R0, XFlipR270, XFlipR0, XFlipR90, XFlipR180},
/* R180 */ { R180, R270, R0, R90, XFlipR180, XFlipR270, XFlipR0, XFlipR90},
/* R270 */ { R270, R0, R90, R180, XFlipR90, XFlipR180, XFlipR270, XFlipR0},
/* XFlipR0 */ { XFlipR0, XFlipR90, XFlipR180, XFlipR270, R0, R90, R180, R270},
/* XFlipR90 */ { XFlipR90, XFlipR180, XFlipR270, XFlipR0, R270, R0, R90, R180},
/* XFlipR180 */ { XFlipR180, XFlipR270, XFlipR0, XFlipR90, R180, R270, R0, R90},
/* XFlipR270 */ { XFlipR270, XFlipR0, XFlipR90, XFlipR180, R90, R180, R270, R0}
};
pModifyFunDblToShort modifyDblToShortFunTbl[transformTypeMAX];
pModifyFunLongToShort modifyLongToShortFunTbl[transformTypeMAX];
pModifyFunIntToShort modifyIntToShortFunTbl[transformTypeMAX];
pModifyFunDblToInt modifyDblToIntFunTbl[transformTypeMAX];
pModifyFunDblToDbl modifyDblToDblFunTbl[transformTypeMAX];
pModifyFunLongToInt modifyLongToIntFunTbl[transformTypeMAX];
pModifyFunIntToInt modifyIntToIntFunTbl[transformTypeMAX];
pModifyFunLongToLong modifyLongToLongFunTbl[transformTypeMAX];
pModifyFunLongLongToLongLong modifyLongLongToLongLongFunTbl[transformTypeMAX];
pModifyRectFunLongToLong modifyRectLongToLongFunTbl[transformTypeMAX];
pModifyRectFunDblToDbl modifyRectDblToDblFunTbl[transformTypeMAX];
pModifyRectFunIntToInt modifyRectIntToIntFunTbl[transformTypeMAX];
//
/// Table of inverse determining functions by transform type.
//
pGetInverseFun getInverseFnTbl[transformTypeMAX];
//
/// Table of multiplication determining functions by transform type.
//
pMultFun multFnTbl[transformTypeMAX*transformTypeMAX];
//
/// Modify a point using scale transform.
//
template <class iC,class oC>
pod::point<oC> GXX_HIDDEN modifyScale(
const transform & T, pod::point<iC> xy)
{
pod::point<double> tmp = xy % T.getDiagonal();
return std::tr1::is_floating_point<oC>::value ?
pod::point<oC>((oC)tmp.X(),(oC)tmp.Y())
:
pod::point<oC>((oC)base::setSaturated<oC>(tmp.X()),(oC)base::setSaturated<oC>(tmp.Y()));
}
//
/// Modify a point using scale and offset transform.
//
template <class iC,class oC>
pod::point<oC> GXX_HIDDEN modifyScaleOffset(
const transform & T, pod::point<iC> xy)
{
pod::point<double> tmp = xy % T.getDiagonal() + T.getOffset();
return std::tr1::is_floating_point<oC>::value ?
pod::point<oC>((oC)tmp.X(),(oC)tmp.Y())
:
pod::point<oC>((oC)base::setSaturated<oC>(tmp.X()),(oC)base::setSaturated<oC>(tmp.Y()));
}
//
/// Modify a point using a general transform.
//
template <class iC, class oC>
pod::point<oC> GXX_HIDDEN modifyGeneral( const transform & T, pod::point<iC> xy )
{
pod::point<double> tmp(T.getCol1()*pod::point<double>(xy),T.getCol2()*pod::point<double>(xy));
tmp += T.getOffset();
return std::tr1::is_floating_point<oC>::value ?
pod::point<oC>((oC)tmp.X(),(oC)tmp.Y())
:
pod::point<oC>((oC)base::setSaturated<oC>(tmp.X()),(oC)base::setSaturated<oC>(tmp.Y()));
}
template <class iC,class oC>
pod::point<oC> GXX_HIDDEN modifyStd ( const transform & T, pod::point<iC> xy )
{
//
// Transform the point.
//
pod::point<double> d = xy * T.getOrient() + T.getOffset();
//
// Convert to target coordinate type.
//
return std::tr1::is_floating_point<oC>::value ?
pod::point<oC>( (oC)(d.getX()), (oC)(d.getY()))
:
pod::point<oC>( (oC)base::setSaturated<oC>(d.getX()), (oC)base::setSaturated<oC>(d.getY()));
}
//
/// Modify a point using standard transform with magnification
//
template <class iC, class oC>
pod::point<oC> GXX_HIDDEN modifyStdMag( const transform &T, pod::point<iC> xy )
{
//
// Transform the point.
//
pod::point<double> d = xy * T.getOrient() * T.get11() + T.getOffset();
//
// Convert to target coordinate type.
//
return std::tr1::is_floating_point<oC>::value ?
pod::point<oC>( (oC)(d.getX()), (oC)(d.getY()))
:
pod::point<oC>( (oC)base::setSaturated<oC>(d.getX()), (oC)base::setSaturated<oC>(d.getY()));
}
//
/// Modify a point using resolution transform.
//
template <class iC, class oC>
pod::point<oC> GXX_HIDDEN modifyResolution( const transform &T, pod::point<iC> xy )
{
pod::point<double> tmp = xy % T.getDiagonal();
if (T.getNext())
{
if ( std::tr1::is_double<oC>::value )
{
pod::point<double> tmp2((double)tmp.X(),
(double)tmp.Y());
return T.getNext()->modifyDblToDbl(tmp2);
}
else if ( std::tr1::is_i64<oC>::value )
{
pod::point<i64> tmp2((i64)base::setSaturated<i64>(tmp.X()),
(i64)base::setSaturated<i64>(tmp.Y()));
return T.getNext()->modifyLongToLong(tmp2);
}
else if ( std::tr1::is_int<oC>::value )
{
pod::point<i64> tmp2((i64)base::setSaturated<i64>(tmp.X()),
(i64)base::setSaturated<i64>(tmp.Y()));
return T.getNext()->modifyLongToInt(tmp2);
}
else if ( std::tr1::is_short<oC>::value )
{
pod::point<i64> tmp2((i64)base::setSaturated<i64>(tmp.X()),
(i64)base::setSaturated<i64>(tmp.Y()));
return T.getNext()->modifyLongToShort(tmp2);
}
}
else
return std::tr1::is_floating_point<oC>::value ?
pod::point<oC>((oC)tmp.X(),(oC)tmp.Y()) :
pod::point<oC>((oC)base::setSaturated<oC>(tmp.X()),
(oC)base::setSaturated<oC>(tmp.Y()));
// Should not get here or something is missing.
throw except::programError();
return pod::point<oC>((oC)0, (oC)0);
}
//
// Modify a rectangle using scale transform.
//
template <class iC,class oC>
pod::rectangle<oC> GXX_HIDDEN modifyScaleRect(
const transform & T,
const pod::rectangle<iC> & r)
{
pod::rectangle<oC> rect(modifyScale<iC,oC>(T,r.getLowerLeft()),
modifyScale<iC,oC>(T,r.getUpperRight()));
rect.makeValid();
return rect;
}
//
// Modify a rectangle using scale and offset transform.
//
template <class iC,class oC>
pod::rectangle<oC> GXX_HIDDEN modifyScaleOffsetRect(
const transform & T,
const pod::rectangle<iC> & r)
{
pod::rectangle<oC> rect(modifyScaleOffset<iC,oC>(T,r.getLowerLeft()),
modifyScaleOffset<iC,oC>(T,r.getUpperRight()));
rect.makeValid();
return rect;
}
//
// Modify a rectangle using a general transform.
//
template <class iC, class oC>
pod::rectangle<oC> GXX_HIDDEN modifyGeneralRect(
const transform & T,
const pod::rectangle<iC> & r )
{
//
// We have to transform all four corner points when using a
// general transform in order to figure out what the new corner
// points will be.
//
pod::point<oC> p0 = modifyGeneral<iC,oC>(T,r.getLowerLeft());
pod::point<oC> p1 = modifyGeneral<iC,oC>(T,r.getLowerRight());
pod::point<oC> p2 = modifyGeneral<iC,oC>(T,r.getUpperRight());
pod::point<oC> p3 = modifyGeneral<iC,oC>(T,r.getUpperLeft());
pod::rectangle<oC> rect;
rect.merge(p0);
rect.merge(p1);
rect.merge(p2);
rect.merge(p3);
return rect;
}
template <class iC,class oC>
pod::rectangle<oC> GXX_HIDDEN modifyStdRect (
const transform & T,
const pod::rectangle<iC> & r )
{
pod::rectangle<oC> rect(modifyStd<iC,oC>(T,r.getLowerLeft()),
modifyStd<iC,oC>(T,r.getUpperRight()));
rect.makeValid();
return rect;
}
//
// Modify a rectangle using standard transform with magnification.
//
template <class iC, class oC>
pod::rectangle<oC> GXX_HIDDEN modifyStdMagRect(
const transform &T,
const pod::rectangle<iC> & r )
{
pod::rectangle<oC> rect(modifyStdMag<iC,oC>(T,r.getLowerLeft()),
modifyStdMag<iC,oC>(T,r.getUpperRight()));
rect.makeValid();
return rect;
}
//
// Modify a rectangle using resolution transform.
//
template <class iC,class oC>
pod::rectangle<oC> GXX_HIDDEN modifyResolutionRect(
const transform & T,
const pod::rectangle<iC> & r)
{
pod::rectangle<oC> rect(modifyResolution<iC,oC>(T,r.getLowerLeft()),
modifyResolution<iC,oC>(T,r.getUpperRight()));
rect.makeValid();
return rect;
}
//
/// Initialize the function tables.
//
void transform::initFnTables()
{
//
// double to short
//
modifyDblToShortFunTbl[ScaleOffsetTransformType] = &modifyScaleOffset<double,short>;
modifyDblToShortFunTbl[GeneralTransformType] = &modifyGeneral<double,short>;
modifyDblToShortFunTbl[StdTransformType] = &modifyStd<double,short>;
modifyDblToShortFunTbl[StdTransformWithMagType] = &modifyStdMag<double,short>;
modifyDblToShortFunTbl[ScaleTransformType] = &modifyScale<double,short>;
modifyDblToShortFunTbl[ResolutionTransformType] = &modifyResolution<double,short>;
//
// i64 to short
//
modifyLongToShortFunTbl[ScaleOffsetTransformType] = &modifyScaleOffset<i64,short>;
modifyLongToShortFunTbl[GeneralTransformType] = &modifyGeneral<i64,short>;
modifyLongToShortFunTbl[StdTransformType] = &modifyStd<i64,short>;
modifyLongToShortFunTbl[StdTransformWithMagType] = &modifyStdMag<i64,short>;
modifyLongToShortFunTbl[ScaleTransformType] = &modifyScale<i64,short>;
modifyLongToShortFunTbl[ResolutionTransformType] = &modifyResolution<i64,short>;
//
// int to short
//
modifyIntToShortFunTbl[ScaleOffsetTransformType] = &modifyScaleOffset<int,short>;
modifyIntToShortFunTbl[GeneralTransformType] = &modifyGeneral<int,short>;
modifyIntToShortFunTbl[StdTransformType] = &modifyStd<int,short>;
modifyIntToShortFunTbl[StdTransformWithMagType] = &modifyStdMag<int,short>;
modifyIntToShortFunTbl[ScaleTransformType] = &modifyScale<int,short>;
modifyIntToShortFunTbl[ResolutionTransformType] = &modifyResolution<int,short>;
//
// double to int
//
modifyDblToIntFunTbl[ScaleOffsetTransformType] = &modifyScaleOffset<double,int>;
modifyDblToIntFunTbl[GeneralTransformType] = &modifyGeneral<double,int>;
modifyDblToIntFunTbl[StdTransformType] = &modifyStd<double,int>;
modifyDblToIntFunTbl[StdTransformWithMagType] = &modifyStdMag<double,int>;
modifyDblToIntFunTbl[ScaleTransformType] = &modifyScale<double,int>;
modifyDblToIntFunTbl[ResolutionTransformType] = &modifyResolution<double,int>;
//
// double to double
//
modifyDblToDblFunTbl[ScaleOffsetTransformType] = &modifyScaleOffset<double,double>;
modifyDblToDblFunTbl[GeneralTransformType] = &modifyGeneral<double,double>;
modifyDblToDblFunTbl[StdTransformType] = &modifyStd<double,double>;
modifyDblToDblFunTbl[StdTransformWithMagType] = &modifyStdMag<double,double>;
modifyDblToDblFunTbl[ScaleTransformType] = &modifyScale<double,double>;
modifyDblToDblFunTbl[ResolutionTransformType] = &modifyResolution<double,double>;
//
// i64 to int
//
modifyLongToIntFunTbl[ScaleOffsetTransformType] = &modifyScaleOffset<i64,int>;
modifyLongToIntFunTbl[GeneralTransformType] = &modifyGeneral<i64,int>;
modifyLongToIntFunTbl[StdTransformType] = &modifyStd<i64,int>;
modifyLongToIntFunTbl[StdTransformWithMagType] = &modifyStdMag<i64,int>;
modifyLongToIntFunTbl[ScaleTransformType] = &modifyScale<i64,int>;
modifyLongToIntFunTbl[ResolutionTransformType] = &modifyResolution<i64,int>;
//
// int to int
//
modifyIntToIntFunTbl[ScaleOffsetTransformType] = &modifyScaleOffset<int,int>;
modifyIntToIntFunTbl[GeneralTransformType] = &modifyGeneral<int,int>;
modifyIntToIntFunTbl[StdTransformType] = &modifyStd<int,int>;
modifyIntToIntFunTbl[StdTransformWithMagType] = &modifyStdMag<int,int>;
modifyIntToIntFunTbl[ScaleTransformType] = &modifyScale<int,int>;
modifyIntToIntFunTbl[ResolutionTransformType] = &modifyResolution<int,int>;
//
// i64 to i64
//
modifyLongToLongFunTbl[ScaleOffsetTransformType] = &modifyScaleOffset<i64,i64>;
modifyLongToLongFunTbl[GeneralTransformType] = &modifyGeneral<i64,i64>;
modifyLongToLongFunTbl[StdTransformType] = &modifyStd<i64,i64>;
modifyLongToLongFunTbl[StdTransformWithMagType] = &modifyStdMag<i64,i64>;
modifyLongToLongFunTbl[ScaleTransformType] = &modifyScale<i64,i64>;
modifyLongToLongFunTbl[ResolutionTransformType] = &modifyResolution<i64,i64>;
//
/// Init get inverse func table.
//
getInverseFnTbl[ScaleOffsetTransformType] = &getInverseScaleOffset;
getInverseFnTbl[GeneralTransformType] = &getInverseGeneral;
getInverseFnTbl[StdTransformType] = &getInverseStd;
getInverseFnTbl[StdTransformWithMagType] = &getInverseStdWithMag;
getInverseFnTbl[ScaleTransformType] = &getInverseScale;
getInverseFnTbl[ResolutionTransformType] = &getInverseResolution;
//
/// Init the multiply func table.
//
multFnTbl[0] = &multScaleOffsetXScaleOffset;
multFnTbl[1] = &multScaleOffsetXGeneral;
multFnTbl[2] = &multScaleOffsetXStd;
multFnTbl[3] = &multScaleOffsetXStdWithMag;
multFnTbl[4] = &multScaleOffsetXScaleOffset;
multFnTbl[5] = &multScaleOffsetXResolution;
multFnTbl[6] = &multGeneralXScaleOffset;
multFnTbl[7] = &multGeneralXGeneral;
multFnTbl[8] = &multGeneralXStd;
multFnTbl[9] = &multGeneralXStdWithMag;
multFnTbl[10] = &multGeneralXScaleOffset;
multFnTbl[11] = &multGeneralXResolution;
multFnTbl[12] = &multStdXScaleOffset;
multFnTbl[13] = &multStdXGeneral;
multFnTbl[14] = &multStdXStd;
multFnTbl[15] = &multStdXStdWithMag;
multFnTbl[16] = &multStdXScaleOffset;
multFnTbl[17] = &multStdXResolution;
multFnTbl[18] = &multStdWithMagXScaleOffset;
multFnTbl[19] = &multStdWithMagXGeneral;
multFnTbl[20] = &multStdWithMagXStd;
multFnTbl[21] = &multStdWithMagXStdWithMag;
multFnTbl[22] = &multStdWithMagXScaleOffset;
multFnTbl[23] = &multStdWithMagXResolution;
multFnTbl[24] = &multScaleOffsetXScaleOffset;
multFnTbl[25] = &multScaleOffsetXGeneral;
multFnTbl[26] = &multScaleOffsetXStd;
multFnTbl[27] = &multScaleOffsetXStdWithMag;
multFnTbl[28] = &multScaleXScale;
multFnTbl[29] = &multScaleXResolution;
multFnTbl[30] = &multResolutionXAny;
multFnTbl[31] = &multResolutionXAny;
multFnTbl[32] = &multResolutionXAny;
multFnTbl[33] = &multResolutionXAny;
multFnTbl[34] = &multResolutionXAny;
multFnTbl[35] = &multResolutionXAny;
//
// Initialize the rectangle modification function tables.
//
modifyRectLongToLongFunTbl[ScaleOffsetTransformType] = modifyScaleOffsetRect<i64,i64>;
modifyRectLongToLongFunTbl[GeneralTransformType] = modifyGeneralRect<i64,i64>;
modifyRectLongToLongFunTbl[StdTransformType] = modifyStdRect<i64,i64>;
modifyRectLongToLongFunTbl[StdTransformWithMagType] = modifyStdMagRect<i64,i64>;
modifyRectLongToLongFunTbl[ScaleTransformType] = modifyScaleRect<i64,i64>;
modifyRectLongToLongFunTbl[ResolutionTransformType] = modifyResolutionRect<i64,i64>;
modifyRectDblToDblFunTbl[ScaleOffsetTransformType] = modifyScaleOffsetRect<double,double>;
modifyRectDblToDblFunTbl[GeneralTransformType] = modifyGeneralRect<double,double>;
modifyRectDblToDblFunTbl[StdTransformType] = modifyStdRect<double,double>;
modifyRectDblToDblFunTbl[StdTransformWithMagType] = modifyStdMagRect<double,double>;
modifyRectDblToDblFunTbl[ScaleTransformType] = modifyScaleRect<double,double>;
modifyRectDblToDblFunTbl[ResolutionTransformType] = modifyResolutionRect<double,double>;
modifyRectIntToIntFunTbl[ScaleOffsetTransformType] = modifyScaleOffsetRect<int,int>;
modifyRectIntToIntFunTbl[GeneralTransformType] = modifyGeneralRect<int,int>;
modifyRectIntToIntFunTbl[StdTransformType] = modifyStdRect<int,int>;
modifyRectIntToIntFunTbl[StdTransformWithMagType] = modifyStdMagRect<int,int>;
modifyRectIntToIntFunTbl[ScaleTransformType] = modifyScaleRect<int,int>;
modifyRectIntToIntFunTbl[ResolutionTransformType] = modifyResolutionRect<int,int>;
}
// Value of standard orientation
const struct { bool xflip; double angle;} stdOrientXFlipAngValues[stdOrientMAX]=
{
{false, 0. }, // RO
{false, 90. }, // R90
{false, 180. }, // R180
{false, 270. }, // R270
{true, 0. }, // XFlipR0
{true, 90. }, //XFlipR90
{true, 180. }, //XFlipR180
{true, 270. } //XFlipR270
};
const void transform::getAngleFlipMag( double& angle, bool& isXFlip, double& mag) const
{
if( type!=GeneralTransformType)
{
//
// standard orientation. Use table
//
int idx= (int) getOrient().getOri();
isXFlip= stdOrientXFlipAngValues[idx].xflip;
angle = stdOrientXFlipAngValues[idx].angle;
mag = a11;
}
else
{
// From constructor
// 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;
//
// How to get angle, inMage and inXFlip from a11, a12, a21, and a22
// Let sumProd = a11* a22 - a12*a21
// = (inMag*consine)(inMag * multiplier * cosine) - (inMag * sine)(-inMag * multiplier * sine)
// = inMag*inMag*multiplier*consine*consine + inMag*inMag*multiplier*sine*sine
// = inMag*inMag*multiplier(consine* consine + sine*sine)
// = inMag*inMag*multiplier
//
// if( sumProd) < 0 ==> inXFlip=true
// inMag= SquareRoot( Abs(sumPro));
// Angle= ArcCosine(a11/inMag)
double sumProd= a11*a22 - a12*a21;
//get inXFlip.
// sumProd= imMag*imMag*multiplier
isXFlip= sumProd < 0;
// get abs(imMag*imMag)
if(sumProd<0)
sumProd= -sumProd;
// get mag
mag= sqrt(sumProd);
// get angle
if(mag> 0)
{
double angleR= acos(a11/mag);
angle=radiansToDegrees(angleR);
// aCos funciton range is 0 to 180.
// We need to decide if angle is between 180 to 360
//
// How to solve it
// Let (Xt, Yt) is the point by applying (1,0) with transformation without xFlip,
// if Yt > 0, then angle is located between 180 and 360
//
// i.e.
// | a11 a12 | x | 1 | = [a11 a21p ] = (Xt, Yt)
// | a21p a22 | | 0 |
// a21= multiplier * a21p = xFlip + angle
// if a21p > 0 angle is located between 180 and 360
//
double a21p= isXFlip? -a21: a21;
if( a21p> 0 )
angle= 360. - angle;
}
else
angle=0;
}// end else
}
transform transform::getInverseScaleOffset(const transform & T)
{
return transform( -T.offset.X()/T.a11,
-T.offset.Y()/T.a22,
1.0/T.a11,
1.0/T.a22);
}
//
/// Get the inverse of a general transform.
//
transform transform::getInverseGeneral(const transform & T )
{
//
// compute the determinant
//
double det = T.a11*T.a22 - T.a12*T.a21;
return transform( (T.offset.Y()*T.a21 - T.offset.X()*T.a22)/det,
(T.offset.X()*T.a12 - T.offset.Y()*T.a11)/det,
T.a22/det,
-T.a12/det,
-T.a21/det,
T.a11/det);
}
//
/// Get the inverse of a standard transform.
//
transform transform::getInverseStd(const transform & T)
{
//
// Transform the offset.
//
pod::point<double> off = - T.offset * stdOrient(inverseStdOrient[T.orient.getOri()]);
//
// Return the inverted standard transform.
//
return transform (off.X(), off.Y(),
inverseStdOrient[T.orient.getOri()]);
}
//
/// Get the inverse of a standard transform with mag.
//
transform transform::getInverseStdWithMag(const transform & T)
{
register double oneOverMag = 1.0/T.a11;
register stdOrientEnum e = inverseStdOrient[T.orient.getOri()];
//
// Transform the offset.
//
pod::point<double> off = - (T.offset * stdOrient(e)) * oneOverMag;
return transform( off.X(),
off.Y(),
e,
oneOverMag );
}
//
/// Get the inverse of a scale transform.
//
transform transform::getInverseScale(const transform & T)
{
return transform( 0.0,
0.0,
1.0/T.a11,
1.0/T.a22);
}
//
// Get the inverse of a resolution transform.
//
transform transform::getInverseResolution(const transform & T)
{
if (T.next) {
transform T1(T.a11, T.a22, false);
transform T2;
T1.mult(*(T.next), T2);
return T2.getInverse();
} else {
return transform(1.0/T.a11, 1.0/T.a22, false);
}
}
//
/// Multiply two scale transforms.
//
void transform::multScaleXScale(const transform &T1,
const transform &T2, transform &outT)
{
outT.type = ScaleTransformType;
outT.a11 = T1.a11*T2.a11;
outT.a22 = T1.a22*T2.a22;
outT.offset = pod::point<double>(0.0, 0.0);
}
//
/// Multiply a scale transform with a resolution transform.
//
void transform::multScaleXResolution(const transform &T1,
const transform &T2, transform &outT)
{
outT.type = ResolutionTransformType;
outT.a11 = T2.a11;
outT.a12 = T2.a12;
outT.a21 = T2.a21;
outT.a22 = T2.a22;
if (T2.next) {
if (!outT.next)
outT.next = new transform;
transform tmp(T1.a11, T1.a22, false);
tmp.mult(*(T2.next), *(outT.next));
} else {
if (outT.next) {
outT.next->type = ScaleTransformType;
outT.next->a11 = T1.a11;
outT.next->a12 = T1.a12;
outT.next->a21 = T1.a21;
outT.next->a22 = T1.a22;
outT.next->offset.setX(0.0);
outT.next->offset.setY(0.0);
} else {
outT.next = new transform(T1.a11, T1.a22, false);
}
}
}
//
//
/// Multiply two scale offset transforms.
//
void transform::multScaleOffsetXScaleOffset(const transform &T1,
const transform &T2, transform &outT)
{
outT.type = ScaleOffsetTransformType;
outT.a11 = T1.a11*T2.a11;
outT.a22 = T1.a22*T2.a22;
outT.offset = pod::point<double>(
T2.a11*T1.offset.X() + T2.offset.X(),
T2.a22*T1.offset.Y() + T2.offset.Y());
}
//
/// Multiply a scale offset transform with a general transform.
//
void transform::multScaleOffsetXGeneral(const transform &T1,
const transform &T2, transform &outT)
{
outT.type = GeneralTransformType;
outT.a11 = T1.a11*T2.a11;
outT.a12 = T1.a11*T2.a12;
outT.a21 = T1.a22*T2.a21;
outT.a22 = T1.a22*T2.a22;
outT.offset = pod::point<double>( T1.offset.X()*T2.a11 + T1.offset.Y()*T2.a21 + T2.offset.X(),
T1.offset.X()*T2.a12 + T1.offset.Y()*T2.a22 + T2.offset.Y());
}
//
/// Multiply a scale offset transform with a standard transform.
//
void transform::multScaleOffsetXStd( const transform &T1,
const transform &T2,
transform &outT)
{
//
// If we have uniform magnification, then we do not have to go to
// a general transform.
//
if ( T1.a11 == T1.a22 )
{
outT.type = StdTransformWithMagType;
outT.orient = T2.orient;
outT.a11 = T1.a11*T2.a11;
}
else
{
outT.type = GeneralTransformType;
outT.a11 = T1.a11*stdOrientCoeffMatrix[T2.orient.getOri()][0][0];
outT.a12 = T1.a11*stdOrientCoeffMatrix[T2.orient.getOri()][0][1];
outT.a21 = T1.a22*stdOrientCoeffMatrix[T2.orient.getOri()][1][0];
outT.a22 = T1.a22*stdOrientCoeffMatrix[T2.orient.getOri()][1][1];
}
outT.offset = pod::point<double>(
T1.offset.X()*stdOrientCoeffMatrix[T2.orient.getOri()][0][0] +
T1.offset.Y()*stdOrientCoeffMatrix[T2.orient.getOri()][1][0],
T1.offset.X()*stdOrientCoeffMatrix[T2.orient.getOri()][0][1] +
T1.offset.Y()*stdOrientCoeffMatrix[T2.orient.getOri()][1][1])
+ T2.offset;
}
//
/// Multiply a scale offset transform with a standard transform
/// with magnification.
//
void transform::multScaleOffsetXStdWithMag( const transform &T1,
const transform &T2,
transform &outT)
{
//
// If we have uniform magnification, then we do not have to go to
// a general transform.
//
if ( T1.a11 == T1.a22 )
{
outT.type = StdTransformWithMagType;
outT.orient = T2.orient;
outT.a11 = T1.a11*T2.a11;
}
else
{
outT.type = GeneralTransformType;
outT.a11 = T1.a11*T2.a11*stdOrientCoeffMatrix[T2.orient.getOri()][0][0];
outT.a12 = T1.a11*T2.a11*stdOrientCoeffMatrix[T2.orient.getOri()][0][1];
outT.a21 = T1.a22*T2.a11*stdOrientCoeffMatrix[T2.orient.getOri()][1][0];
outT.a22 = T1.a22*T2.a11*stdOrientCoeffMatrix[T2.orient.getOri()][1][1];
}
outT.offset = pod::point<double>(
T2.a11*(T1.offset.X()*stdOrientCoeffMatrix[T2.orient.getOri()][0][0] +
T1.offset.Y()*stdOrientCoeffMatrix[T2.orient.getOri()][1][0]),
T2.a11*(T1.offset.X()*stdOrientCoeffMatrix[T2.orient.getOri()][0][1] +
T1.offset.Y()*stdOrientCoeffMatrix[T2.orient.getOri()][1][1]))
+ T2.offset;
}
//
/// Multiply a scale offset transform with a resolution transform.
//
void transform::multScaleOffsetXResolution(const transform &T1,
const transform &T2, transform &outT)
{
outT.type = ResolutionTransformType;
outT.a11 = T2.a11;
outT.a12 = T2.a12;
outT.a21 = T2.a21;
outT.a22 = T2.a22;
if (T2.next) {
if (!outT.next)
outT.next = new transform;
transform tmp(
T1.offset.getX()*T2.a11,
T1.offset.getY()*T2.a22,
T1.a11, T1.a22);
tmp.mult(*(T2.next), *(outT.next));
} else {
if (outT.next) {
outT.next->type = ScaleOffsetTransformType;
outT.next->a11 = T1.a11;
outT.next->a12 = 0.0;
outT.next->a21 = 0.0;
outT.next->a22 = T1.a22;
outT.next->offset.setX(T1.offset.getX()*T2.a11);
outT.next->offset.setY(T1.offset.getY()*T2.a22);
} else {
outT.next = new transform(
T1.offset.getX()*T2.a11,
T1.offset.getY()*T2.a22,
T1.a11, T1.a22);
}
}
}
//
/// Multiply a general transform with a scale offset transform.
//
void transform::multGeneralXScaleOffset(const transform &T1,
const transform &T2, transform &outT)
{
outT.type = GeneralTransformType;
outT.a11 = T1.a11*T2.a11;
outT.a12 = T1.a12*T2.a22;
outT.a21 = T1.a21*T2.a11;
outT.a22 = T1.a22*T2.a22;
outT.offset = pod::point<double>( T1.offset.X()*T2.a11,
T1.offset.Y()*T2.a22)
+ T2.offset;
}
//
/// Multiply two general transforms.
//
void transform::multGeneralXGeneral(const transform &T1,
const transform &T2, transform &outT)
{
outT.type = GeneralTransformType;
outT.a11 = T1.a11*T2.a11 + T1.a12*T2.a21;
outT.a12 = T1.a11*T2.a12 + T1.a12*T2.a22;
outT.a21 = T1.a21*T2.a11 + T1.a22*T2.a21;
outT.a22 = T1.a21*T2.a12 + T1.a22*T2.a22;
outT.offset = pod::point<double>( T1.offset.X()*T2.a11 + T1.offset.Y()*T2.a21,
T1.offset.X()*T2.a12 + T1.offset.Y()*T2.a22)
+ T2.offset;
}
//
/// Multiply a general transform with a standard transform.
//
void transform::multGeneralXStd(const transform &T1,
const transform &T2, transform &outT)
{
outT.type = GeneralTransformType;
outT.a11 = T1.a11*stdOrientCoeffMatrix[T2.orient.getOri()][0][0] +
T1.a12*stdOrientCoeffMatrix[T2.orient.getOri()][1][0];
outT.a12 = T1.a11*stdOrientCoeffMatrix[T2.orient.getOri()][0][1] +
T1.a12*stdOrientCoeffMatrix[T2.orient.getOri()][1][1];
outT.a21 = T1.a21*stdOrientCoeffMatrix[T2.orient.getOri()][0][0] +
T1.a22*stdOrientCoeffMatrix[T2.orient.getOri()][1][0];
outT.a22 = T1.a21*stdOrientCoeffMatrix[T2.orient.getOri()][0][1] +
T1.a22*stdOrientCoeffMatrix[T2.orient.getOri()][1][1];
//
// Transform the offset.
//
outT.offset = T1.offset * T2.orient + T2.offset;
}
//
/// Multiply a general transform with a standard transform
/// with magnification.
//
void transform::multGeneralXStdWithMag(const transform &T1,
const transform &T2, transform &outT)
{
outT.type = GeneralTransformType;
outT.a11 = T2.a11*(T1.a11*stdOrientCoeffMatrix[T2.orient.getOri()][0][0] +
T1.a12*stdOrientCoeffMatrix[T2.orient.getOri()][1][0]);
outT.a12 = T2.a11*(T1.a11*stdOrientCoeffMatrix[T2.orient.getOri()][0][1] +
T1.a12*stdOrientCoeffMatrix[T2.orient.getOri()][1][1]);
outT.a21 = T2.a11*(T1.a21*stdOrientCoeffMatrix[T2.orient.getOri()][0][0] +
T1.a22*stdOrientCoeffMatrix[T2.orient.getOri()][1][0]);
outT.a22 = T2.a11*(T1.a21*stdOrientCoeffMatrix[T2.orient.getOri()][0][1] +
T1.a22*stdOrientCoeffMatrix[T2.orient.getOri()][1][1]);
//
// Transform the offset.
//
outT.offset = (T1.offset * T2.orient) * T2.a11 + T2.offset;
}
//
/// Multiply a general transform with a resolution transform.
//
void transform::multGeneralXResolution(const transform &T1,
const transform &T2, transform &outT)
{
outT.type = ResolutionTransformType;
outT.a11 = T2.a11;
outT.a12 = T2.a12;
outT.a21 = T2.a21;
outT.a22 = T2.a22;
if (T2.next) {
if (!outT.next)
outT.next = new transform;
transform tmp(
T1.offset.getX()*T2.a11,
T1.offset.getY()*T2.a22,
T1.a11, T1.a12, T1.a21, T1.a22);
tmp.mult(*(T2.next), *(outT.next));
} else {
if (outT.next) {
outT.next->type = GeneralTransformType;
outT.next->a11 = T1.a11;
outT.next->a22 = T1.a22;
outT.next->a12 = T1.a12;
outT.next->a21 = T1.a21;
outT.next->offset.setX(T1.offset.getX()*T2.a11);
outT.next->offset.setY(T1.offset.getY()*T2.a22);
} else {
outT.next = new transform(
T1.offset.getX()*T2.a11,
T1.offset.getY()*T2.a22,
T1.a11, T1.a12, T1.a21, T1.a22);
}
}
}
//
/// Multiply a standard transform with a scale and offset transform.
//
void transform::multStdXScaleOffset(const transform &T1,
const transform &T2, transform &outT)
{
outT.type = GeneralTransformType;
outT.a11 = stdOrientCoeffMatrix[T1.orient.getOri()][0][0]*T2.a11;
outT.a12 = stdOrientCoeffMatrix[T1.orient.getOri()][0][1]*T2.a22;
outT.a21 = stdOrientCoeffMatrix[T1.orient.getOri()][1][0]*T2.a11;
outT.a22 = stdOrientCoeffMatrix[T1.orient.getOri()][1][1]*T2.a22;
//
// Transform the offset.
//
outT.offset = pod::point<double>( T1.offset.X()*T2.a11,
T1.offset.Y()*T2.a22)
+ T2.offset;
}
//
/// Multiply a standard transform with a general transform.
//
void transform::multStdXGeneral(const transform &T1,
const transform &T2, transform &outT)
{
outT.type = GeneralTransformType;
outT.a11 = stdOrientCoeffMatrix[T1.orient.getOri()][0][0]*T2.a11 +
stdOrientCoeffMatrix[T1.orient.getOri()][0][1]*T2.a21;
outT.a12 = stdOrientCoeffMatrix[T1.orient.getOri()][0][0]*T2.a12 +
stdOrientCoeffMatrix[T1.orient.getOri()][0][1]*T2.a22;
outT.a21 = stdOrientCoeffMatrix[T1.orient.getOri()][1][0]*T2.a11 +
stdOrientCoeffMatrix[T1.orient.getOri()][1][1]*T2.a21;
outT.a22 = stdOrientCoeffMatrix[T1.orient.getOri()][1][0]*T2.a12 +
stdOrientCoeffMatrix[T1.orient.getOri()][1][1]*T2.a22;
//
// Transform the offset.
//
outT.offset = pod::point<double>( T1.offset.X()*T2.a11 + T1.offset.Y()*T2.a21,
T1.offset.X()*T2.a12 + T1.offset.Y()*T2.a22)
+ T2.offset;
}
//
/// Multiply two standard transforms.
//
void transform::multStdXStd(const transform &T1,
const transform &T2, transform &outT)
{
outT.type = StdTransformType;
outT.orient = multStdOrientMatrix[T1.orient.getOri()][T2.orient.getOri()];
//
// Transform the offset.
//
outT.offset = T1.offset * T2.orient + T2.offset;
}
//
/// Multiply a standard transform with a standard transform
/// with magnification.
//
void transform::multStdXStdWithMag(const transform &T1,
const transform &T2, transform &outT)
{
outT.type = StdTransformWithMagType;
outT.orient = stdOrient(multStdOrientMatrix[T1.orient.getOri()][T2.orient.getOri()]);
outT.a11 = T2.a11;
//
// Transform the offset.
//
outT.offset = T1.offset * T2.orient * T2.a11 + T2.offset;
}
//
/// Multiply a standard transform with a resolution transform.
//
void transform::multStdXResolution(const transform &T1,
const transform &T2, transform &outT)
{
outT.type = ResolutionTransformType;
outT.a11 = T2.a11;
outT.a12 = T2.a12;
outT.a21 = T2.a21;
outT.a22 = T2.a22;
if (T2.next)
{
if (!outT.next)
outT.next = new transform;
transform tmp(
T1.offset.getX()*T2.a11,
T1.offset.getY()*T2.a22,
T1.orient.getOri());
tmp.mult(*(T2.next), *(outT.next));
}
else if (outT.next)
{
outT.next->type = StdTransformType;
outT.next->a11 = T1.a11;
outT.next->a12 = T1.a12;
outT.next->a21 = T1.a21;
outT.next->a22 = T1.a22;
outT.next->offset.setX(T1.offset.getX()*T2.a11);
outT.next->offset.setY(T1.offset.getY()*T2.a22);
outT.next->orient = T1.orient;
}
else
{
outT.next = new transform(
T1.offset.getX()*T2.a11,
T1.offset.getY()*T2.a22,
T1.orient.getOri());
}
}
//
/// Multiply a standard transform with magnification with a
/// scale and offset transform.
//
void transform::multStdWithMagXScaleOffset(const transform &T1,
const transform &T2, transform &outT)
{
outT.type = GeneralTransformType;
outT.a11 = T1.a11*stdOrientCoeffMatrix[T1.orient.getOri()][0][0]*T2.a11;
outT.a12 = T1.a11*stdOrientCoeffMatrix[T1.orient.getOri()][0][1]*T2.a22;
outT.a21 = T1.a11*stdOrientCoeffMatrix[T1.orient.getOri()][1][0]*T2.a11;
outT.a22 = T1.a11*stdOrientCoeffMatrix[T1.orient.getOri()][1][1]*T2.a22;
//
// Transform the offset.
//
outT.offset = pod::point<double>( T1.offset.X()*T2.a11,
T1.offset.Y()*T2.a22)
+ T2.offset;
}
//
/// Multiply a standard transform with magnification with
/// a general transform.
//
void transform::multStdWithMagXGeneral(const transform &T1,
const transform &T2, transform &outT)
{
outT.type = GeneralTransformType;
outT.a11 = T1.a11*( stdOrientCoeffMatrix[T1.orient.getOri()][0][0]*T2.a11 +
stdOrientCoeffMatrix[T1.orient.getOri()][0][1]*T2.a21);
outT.a12 = T1.a11*( stdOrientCoeffMatrix[T1.orient.getOri()][0][0]*T2.a12 +
stdOrientCoeffMatrix[T1.orient.getOri()][0][1]*T2.a22);
outT.a21 = T1.a11*( stdOrientCoeffMatrix[T1.orient.getOri()][1][0]*T2.a11 +
stdOrientCoeffMatrix[T1.orient.getOri()][1][1]*T2.a21);
outT.a22 = T1.a11*( stdOrientCoeffMatrix[T1.orient.getOri()][1][0]*T2.a12 +
stdOrientCoeffMatrix[T1.orient.getOri()][1][1]*T2.a22);
//
// Transfomr the offset.
//
outT.offset = pod::point<double>( T1.offset.X()*T2.a11 + T1.offset.Y()*T2.a21,
T1.offset.X()*T2.a12 + T1.offset.Y()*T2.a22)
+ T2.offset;
}
//
/// Multiply a standard transform with magnification with
/// a standard transform.
//
void transform::multStdWithMagXStd(const transform &T1,
const transform &T2, transform &outT)
{
outT.type = StdTransformWithMagType;
outT.orient = stdOrient(multStdOrientMatrix[T1.orient.getOri()][T2.orient.getOri()]);
outT.a11 = T1.a11;
//
// Transform the offset.
//
outT.offset = T1.offset * T2.orient + T2.offset;
}
//
/// Multiply two standard transforms with magnification.
//
void transform::multStdWithMagXStdWithMag(const transform &T1,
const transform &T2, transform &outT)
{
outT.type = StdTransformWithMagType;
outT.orient = stdOrient(multStdOrientMatrix[T1.orient.getOri()][T2.orient.getOri()]);
outT.a11 = T1.a11*T2.a11;
//
// Transform the offset.
//
outT.offset = T1.offset * T2.orient * T2.a11 + T2.offset;
}
//
/// Multiply a standard transform with magnification with a
/// resolution transform.
//
void transform::multStdWithMagXResolution(const transform &T1,
const transform &T2, transform &outT)
{
outT.type = ResolutionTransformType;
outT.a11 = T2.a11;
outT.a12 = T2.a12;
outT.a21 = T2.a21;
outT.a22 = T2.a22;
if (T2.next) {
if (!outT.next)
outT.next = new transform;
transform tmp(
T1.offset.getX()*T2.a11,
T1.offset.getY()*T2.a22,
T1.orient.getOri(), T1.a11);
tmp.mult(*(T2.next), *(outT.next));
} else {
if (outT.next) {
outT.next->type = StdTransformWithMagType;
outT.next->a11 = T1.a11;
outT.next->a12 = T1.a12;
outT.next->a21 = T1.a21;
outT.next->a22 = T1.a22;
outT.next->offset.setX(T1.offset.getX()*T2.a11);
outT.next->offset.setY(T1.offset.getY()*T2.a22);
outT.next->orient = T1.orient;
} else {
outT.next = new transform(
T1.offset.getX()*T2.a11,
T1.offset.getY()*T2.a22,
T1.orient.getOri(), T1.a11);
}
}
}
//
/// Multiply a resolution transform with any transform.
//
void transform::multResolutionXAny(const transform &T1,
const transform &T2, transform &outT)
{
outT.type = ResolutionTransformType;
outT.a11 = T1.a11;
outT.a12 = T1.a12;
outT.a21 = T1.a21;
outT.a22 = T1.a22;
if(T1.next) {
if (!(outT.next))
outT.next = new transform;
T1.next->mult(T2, *(outT.next));
} else {
outT.next = new transform(T2);
}
}
//
/// 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 transform::modify( const pod::point<iC>& rSrc, pod::point<oC>& rDest ) const
{
switch ( type )
{
case ScaleOffsetTransformType:
rDest = modifyScaleOffset<iC,oC>( *this, rSrc );
break;
case GeneralTransformType:
rDest = modifyGeneral<iC,oC>( *this, rSrc );
break;
case StdTransformType:
rDest = modifyStd<iC,oC>( *this, rSrc );
break;
case StdTransformWithMagType:
rDest = modifyStdMag<iC,oC>( *this, rSrc );
break;
case ScaleTransformType:
rDest = modifyScale<iC,oC>( *this, rSrc );
break;
case ResolutionTransformType:
rDest = modifyResolution<iC,oC>( *this, rSrc );
break;
default:
throw except::outOfRange("base::modify: Unknown type.");
} // switch
}
//
/// This is pod::rectangle version of above function.
//
template <class iC, class oC>
void transform::modify( const pod::rectangle<iC>& rSrc, pod::rectangle<oC>& rDest ) const
{
switch ( type )
{
case ScaleOffsetTransformType:
rDest = modifyScaleOffsetRect<iC,oC>( *this, rSrc );
break;
case GeneralTransformType:
rDest = modifyGeneralRect<iC,oC>( *this, rSrc );
break;
case StdTransformType:
rDest = modifyStdRect<iC,oC>( *this, rSrc );
break;
case StdTransformWithMagType:
rDest = modifyStdMagRect<iC,oC>( *this, rSrc );
break;
case ScaleTransformType:
rDest = modifyScaleRect<iC,oC>( *this, rSrc );
break;
case ResolutionTransformType:
rDest = modifyResolutionRect<iC,oC>( *this, rSrc );
break;
default:
throw except::outOfRange("base::modify: Unknown type.");
} // switch
}
//
/// 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 transform::modifyBBox( const pod::rectangle<iC>& rSrc, pod::rectangle<oC>& rDest ) const
{
//
// If we have orthogonal transform?
// First check get12 since most of transform will
// have no rotation factor.
//
if ( !next && (get12() == 0 || get11() == 0))
modify( rSrc, rDest );
//
// General case.
//
else
{
rDest.makeInvalid();
pod::point<oC> tmp;
modify( rSrc.getLowerLeft(), tmp );
rDest.merge( tmp );
modify( rSrc.getLowerRight(), tmp );
rDest.merge( tmp );
modify( rSrc.getUpperLeft(), tmp );
rDest.merge( tmp );
modify( rSrc.getUpperRight(), tmp );
rDest.merge( tmp );
}
}
//
/// Print a transform, mainly for debug purpose.
//
void transform::print(FILE *outStream, const char *linePrefix) const
{
std::string str = (std::string)(*this);
fprintf(outStream, "%stype = %s.\n", linePrefix,
str.c_str());
if (getType() != ResolutionTransformType &&
getType() != ScaleTransformType) {
fprintf(outStream, "%stx = %f.\n", linePrefix, offset.X());
fprintf(outStream, "%sty = %f.\n", linePrefix, offset.Y());
}
switch(type) {
case ScaleOffsetTransformType:
case ScaleTransformType:
fprintf(outStream, "%sscaleX = %f.\n", linePrefix, a11);
fprintf(outStream, "%sscaleY = %f.\n", linePrefix, a22);
break;
case GeneralTransformType:
fprintf(outStream, "%sa11 = %f.\n", linePrefix, a11);
fprintf(outStream, "%sa12 = %f.\n", linePrefix, a12);
fprintf(outStream, "%sa21 = %f.\n", linePrefix, a21);
fprintf(outStream, "%sa22 = %f.\n", linePrefix, a22);
break;
case StdTransformType:
str = (std::string)orient;
fprintf(outStream, "%sorient = %s.\n", linePrefix, str.c_str());
break;
case StdTransformWithMagType:
str = (std::string)orient;
fprintf(outStream, "%sorient = %s.\n", linePrefix, str.c_str());
fprintf(outStream, "%smag = %f.\n", linePrefix, a11);
break;
case ResolutionTransformType:
fprintf(outStream, "%sscale = %f.\n", linePrefix, a11);
if (next) {
std::string bfr(linePrefix);
bfr += " ";
next->print(outStream, bfr.c_str());
}
break;
default:
throw except::outOfRange("base::transform:print: Unknown type.");
} // switch
}
//
/// Convert a transform type to a string.
//
transform::operator std::string() const
{
switch(type) {
case ScaleOffsetTransformType:
return std::string("ScaleOffsetTransform");
break;
case GeneralTransformType:
return std::string("GeneralTransform");
break;
case StdTransformType:
return std::string("StdTransform");
break;
case StdTransformWithMagType:
return std::string("StdTransformWithMag");
break;
case ScaleTransformType:
return std::string("ScaleTransform");
break;
case ResolutionTransformType:
return std::string("ResolutionTransform");
break;
default:
throw except::outOfRange("base::transformTypeToString: Unknown type.");
} // switch
}
std::ostream & operator << (std::ostream & os, const transform & t)
{
os << "<transform ";
os << "type=\"" << (std::string)t << "\"";
if ( t.type == StdTransformType || t.type == StdTransformWithMagType )
os << " orientation=\"" << (std::string)t.getOrient() << "\"";
os << ">" << std::endl;
os << "<matrix>" << std::endl;
os << t.getRow1();
os << t.getRow2();
os << "</matrix>" << std::endl;
os << "<offset>" << std::endl;
os << t.getOffset();
os << "</offset>" << std::endl;
os << "</transform>" << std::endl;
return os;
}
/*****************************************************************************
* Instantiate template with some arguments.
*/
template void transform::modify<i32,i16>( const pod::point<i32>&, pod::point<i16>& ) const;
template void transform::modify<i64,i16>( const pod::point<i64>&, pod::point<i16>& ) const;
template void transform::modify<dbl,i16>( const pod::point<dbl>&, pod::point<i16>& ) const;
template void transform::modify<i32,i32>( const pod::point<i32>&, pod::point<i32>& ) const;
template void transform::modify<i64,i32>( const pod::point<i64>&, pod::point<i32>& ) const;
template void transform::modify<dbl,i32>( const pod::point<dbl>&, pod::point<i32>& ) const;
template void transform::modify<i32,i64>( const pod::point<i32>&, pod::point<i64>& ) const;
template void transform::modify<i64,i64>( const pod::point<i64>&, pod::point<i64>& ) const;
template void transform::modify<dbl,i64>( const pod::point<dbl>&, pod::point<i64>& ) const;
template void transform::modify<i32,dbl>( const pod::point<i32>&, pod::point<dbl>& ) const;
template void transform::modify<i64,dbl>( const pod::point<i64>&, pod::point<dbl>& ) const;
template void transform::modify<dbl,dbl>( const pod::point<dbl>&, pod::point<dbl>& ) const;
template void transform::modify<i32,i16>( const pod::rectangle<i32>&, pod::rectangle<i16>& ) const;
template void transform::modify<i64,i16>( const pod::rectangle<i64>&, pod::rectangle<i16>& ) const;
template void transform::modify<dbl,i16>( const pod::rectangle<dbl>&, pod::rectangle<i16>& ) const;
template void transform::modify<i32,i32>( const pod::rectangle<i32>&, pod::rectangle<i32>& ) const;
template void transform::modify<i64,i32>( const pod::rectangle<i64>&, pod::rectangle<i32>& ) const;
template void transform::modify<dbl,i32>( const pod::rectangle<dbl>&, pod::rectangle<i32>& ) const;
template void transform::modify<i32,i64>( const pod::rectangle<i32>&, pod::rectangle<i64>& ) const;
template void transform::modify<i64,i64>( const pod::rectangle<i64>&, pod::rectangle<i64>& ) const;
template void transform::modify<dbl,i64>( const pod::rectangle<dbl>&, pod::rectangle<i64>& ) const;
template void transform::modify<i32,dbl>( const pod::rectangle<i32>&, pod::rectangle<dbl>& ) const;
template void transform::modify<i64,dbl>( const pod::rectangle<i64>&, pod::rectangle<dbl>& ) const;
template void transform::modify<dbl,dbl>( const pod::rectangle<dbl>&, pod::rectangle<dbl>& ) const;
template void transform::modifyBBox<i32,i16>( const pod::rectangle<i32>&, pod::rectangle<i16>& ) const;
template void transform::modifyBBox<i64,i16>( const pod::rectangle<i64>&, pod::rectangle<i16>& ) const;
template void transform::modifyBBox<dbl,i16>( const pod::rectangle<dbl>&, pod::rectangle<i16>& ) const;
template void transform::modifyBBox<i32,i32>( const pod::rectangle<i32>&, pod::rectangle<i32>& ) const;
template void transform::modifyBBox<i64,i32>( const pod::rectangle<i64>&, pod::rectangle<i32>& ) const;
template void transform::modifyBBox<dbl,i32>( const pod::rectangle<dbl>&, pod::rectangle<i32>& ) const;
template void transform::modifyBBox<i32,i64>( const pod::rectangle<i32>&, pod::rectangle<i64>& ) const;
template void transform::modifyBBox<i64,i64>( const pod::rectangle<i64>&, pod::rectangle<i64>& ) const;
template void transform::modifyBBox<dbl,i64>( const pod::rectangle<dbl>&, pod::rectangle<i64>& ) const;
template void transform::modifyBBox<i32,dbl>( const pod::rectangle<i32>&, pod::rectangle<dbl>& ) const;
template void transform::modifyBBox<i64,dbl>( const pod::rectangle<i64>&, pod::rectangle<dbl>& ) const;
template void transform::modifyBBox<dbl,dbl>( const pod::rectangle<dbl>&, pod::rectangle<dbl>& ) const;
#if 0
template void transform::modify<int64,i16>( const pod::point<int64>&, pod::point<i16>& ) const;
template void transform::modify<int64,i32>( const pod::point<int64>&, pod::point<i32>& ) const;
template void transform::modify<int64,i64>( const pod::point<int64>&, pod::point<i64>& ) const;
template void transform::modify<int64,dbl>( const pod::point<int64>&, pod::point<dbl>& ) const;
template void transform::modify<i32,int64>( const pod::point<i32>&, pod::point<int64>& ) const;
template void transform::modify<i64,int64>( const pod::point<i64>&, pod::point<int64>& ) const;
template void transform::modify<dbl,int64>( const pod::point<dbl>&, pod::point<int64>& ) const;
template void transform::modify<int64,int64>( const pod::point<int64>&, pod::point<int64>& ) const;
template void transform::modify<int64,i16>( const pod::rectangle<int64>&, pod::rectangle<i16>& ) const;
template void transform::modify<int64,i32>( const pod::rectangle<int64>&, pod::rectangle<i32>& ) const;
template void transform::modify<int64,i64>( const pod::rectangle<int64>&, pod::rectangle<i64>& ) const;
template void transform::modify<int64,dbl>( const pod::rectangle<int64>&, pod::rectangle<dbl>& ) const;
template void transform::modify<i32,int64>( const pod::rectangle<i32>&, pod::rectangle<int64>& ) const;
template void transform::modify<i64,int64>( const pod::rectangle<i64>&, pod::rectangle<int64>& ) const;
template void transform::modify<dbl,int64>( const pod::rectangle<dbl>&, pod::rectangle<int64>& ) const;
template void transform::modify<int64,int64>( const pod::rectangle<int64>&, pod::rectangle<int64>& ) const;
template void transform::modifyBBox<int64,i16>( const pod::rectangle<int64>&, pod::rectangle<i16>& ) const;
template void transform::modifyBBox<int64,i32>( const pod::rectangle<int64>&, pod::rectangle<i32>& ) const;
template void transform::modifyBBox<int64,i64>( const pod::rectangle<int64>&, pod::rectangle<i64>& ) const;
template void transform::modifyBBox<int64,dbl>( const pod::rectangle<int64>&, pod::rectangle<dbl>& ) const;
template void transform::modifyBBox<i32,int64>( const pod::rectangle<i32>&, pod::rectangle<int64>& ) const;
template void transform::modifyBBox<i64,int64>( const pod::rectangle<i64>&, pod::rectangle<int64>& ) const;
template void transform::modifyBBox<dbl,int64>( const pod::rectangle<dbl>&, pod::rectangle<int64>& ) const;
template void transform::modifyBBox<int64,int64>( const pod::rectangle<int64>&, pod::rectangle<int64>& ) const;
#endif
namespace transformTest
{
/// called by testGetAngleFlipMag()
bool testTran_(int idx, const transform& tr, bool xFlip0, double angle0, double mag0)
{
// Get angle/xflip/mag from tr
bool xFlip;
double angle, mag;
tr.getAngleFlipMag( angle,xFlip, mag);
// Compare
bool bFlp= xFlip == xFlip0;
bool bAng=(angle - angle0) < absTolerance &&
(angle0 -angle) < absTolerance ;
bool bMag= (mag - mag0) < absTolerance &&
(mag0 -mag) < absTolerance ;
// Print error message if there is different
if(!bFlp || !bAng || !bMag)
{
printf(" %-2d tr(xFlop=%s)",idx, (xFlip0?"T":"F"));
if(!bFlp)
printf("!= %s", (xFlip?"T":"F"));
printf(" (angle=%10.5f)", angle0) ;
if(!bAng)
printf("!= %10.5f", angle);
printf(" (mag=%5.3f)",mag0);
if(!bMag)
printf("!= %5.3f", mag);
printf("\n");
return false;
}
return true;
}
//
/// Function test getAngelFlipMag()
//
bool testGetAngleFlipMag()
{
struct { bool xFlip; double angle; double mag; } testData[]=
{ // xFlip Angle Max index
{false, 0, 1}, //0 standard Orientation
{false, 90, 1.1}, //1
{false, 180, 1.2}, //2
{false, 270, 1.3}, //3
{true, 0, 1.4}, //4
{true, 90, 1.5}, //5
{true, 180, 1.6}, //6
{true, 270, 1.7}, //7
{false, 23, 1.8}, //8 non-standard Orientation
{true, 23, 1.9}, //9
{false, 92, 2.1}, //10
{true, 92, 2.2}, //11
{false, 192, 2.3}, //12
{true, 192, 2.4}, //13
{false, 272, 2.5}, //14
{true, 272, 2.6} //15
};
const int dataCount=16;
int failCtr=0;
int i=0;
for( ;i < dataCount; i++)
{
// Construct transform
transform tr(0,0,
testData[i].xFlip,
testData[i].angle,
testData[i].mag);
if(! testTran_(i, tr, testData[i].xFlip, testData[i].angle, testData[i].mag))
failCtr++;
}
/// set a11, a12, a21, a22 directly
transform trR0(101,101, 1, 0, 0, 1);
transform trR90(101,101, 0, 1, -1, 0);
transform trR180(101,101, -1,0, 0, -1);
transform trR270(101,101, 0, -1, 1, 0);
transform XtrR0(101,101, 1, 0,0, -1);
transform XtrR90(101,101, 0, 1, 1, 0);
transform XtrR180(101,101, -1,0, 0, 1);
transform XtrR270(101,101, 0, -1, -1, 0);
if(!testTran_(i++, trR0, false, 0, 1)) failCtr++;
if(!testTran_(i++, trR90, false, 90, 1)) failCtr++;
if(!testTran_(i++, trR180, false, 180, 1)) failCtr++;
if(!testTran_(i++, trR270, false, 270, 1)) failCtr++;
if(!testTran_(i++, XtrR0, true, 0, 1)) failCtr++;
if(!testTran_(i++, XtrR90, true, 90, 1)) failCtr++;
if(!testTran_(i++, XtrR180,true, 180, 1)) failCtr++;
if(!testTran_(i++, XtrR270,true, 270, 1)) failCtr++;
// Print summary
printf("transformation::testGetAngleFlipMag() test:%s\n",
(failCtr >0 ? " failed":" passed"));
return failCtr==0;
}
};
}; // namespace base