1120 lines
28 KiB
C++
1120 lines
28 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/except.h>
|
|
#include <base/constants.h>
|
|
#include <base/round.h>
|
|
#include <base/point.h>
|
|
#include <base/rectangle.h>
|
|
|
|
using namespace base;
|
|
//
|
|
/// 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 test
|
|
{
|
|
//
|
|
/// 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];
|
|
|
|
//
|
|
/// The main transformation class.
|
|
//
|
|
class GXX_VISIBLE transform
|
|
{
|
|
protected:
|
|
//
|
|
/// Type of transform.
|
|
//
|
|
unsigned int type : 4;
|
|
//
|
|
/// Orientation field.
|
|
//
|
|
base::stdOrient orient;
|
|
//
|
|
/// 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;
|
|
|
|
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);
|
|
|
|
public:
|
|
|
|
//
|
|
/// Default constuctor.
|
|
//
|
|
transform()
|
|
:
|
|
type(StdTransformType),
|
|
orient(R0),
|
|
a11(1.0),
|
|
a12(0.0),
|
|
a21(0.0),
|
|
a22(1.0),
|
|
offset(0.0,0.0),
|
|
next(NULL)
|
|
{}
|
|
//
|
|
/// Constructor for a scale offset transform.
|
|
//
|
|
transform(
|
|
double offsetX,
|
|
double offsetY,
|
|
double scaleX,
|
|
double scaleY
|
|
)
|
|
:
|
|
type(ScaleOffsetTransformType),
|
|
a11(scaleX),
|
|
a12(0.0),
|
|
a21(0.0),
|
|
a22(scaleY),
|
|
offset(offsetX,offsetY),
|
|
next(NULL)
|
|
{
|
|
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
|
|
)
|
|
:
|
|
type(GeneralTransformType),
|
|
a11(coeff11),
|
|
a12(coeff12),
|
|
a21(coeff21),
|
|
a22(coeff22),
|
|
offset(offsetX,offsetY),
|
|
next(NULL)
|
|
{};
|
|
//
|
|
/// 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
|
|
)
|
|
:
|
|
type(GeneralTransformType),
|
|
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)
|
|
{}
|
|
//
|
|
/// Constructor for a standard transform.
|
|
//
|
|
transform(
|
|
double offsetX,
|
|
double offsetY,
|
|
stdOrientEnum inOrient = R0
|
|
)
|
|
:
|
|
type(StdTransformType),
|
|
orient(inOrient),
|
|
a11(1.0),
|
|
a12(0.0),
|
|
a21(0.0),
|
|
a22(1.0),
|
|
offset(offsetX,offsetY),
|
|
next(NULL)
|
|
{}
|
|
//
|
|
/// Constructor for a standard transform with magnification.
|
|
//
|
|
transform(
|
|
double offsetX,
|
|
double offsetY,
|
|
stdOrientEnum inOrient,
|
|
double inMag)
|
|
:
|
|
type(StdTransformWithMagType),
|
|
orient(inOrient),
|
|
a11(inMag),
|
|
a12(0.0),
|
|
a21(0.0),
|
|
a22(inMag),
|
|
offset(offsetX,offsetY),
|
|
next(NULL)
|
|
{}
|
|
//
|
|
/// 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)
|
|
:
|
|
type(ScaleTransformType),
|
|
orient(R0),
|
|
a11(xScale),
|
|
a12(0.0),
|
|
a21(0.0),
|
|
a22(yScale),
|
|
offset(0.0, 0.0),
|
|
next(NULL)
|
|
{
|
|
if (rounding) {
|
|
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 = NULL;
|
|
}
|
|
|
|
//
|
|
/// 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)
|
|
if (inT.next)
|
|
return (*next == *(inT.next));
|
|
else
|
|
return false;
|
|
else
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
//
|
|
/// Non equal operator
|
|
//
|
|
bool operator != (const transform &inT)
|
|
{
|
|
return !(*this == inT);
|
|
}
|
|
|
|
//
|
|
/// 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));
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
//
|
|
/// Destructor
|
|
//
|
|
~transform()
|
|
{
|
|
if (next)
|
|
delete next;
|
|
}
|
|
|
|
//
|
|
/// 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;
|
|
}
|
|
//
|
|
/// Initialize the function tables.
|
|
//
|
|
static void initFnTables();
|
|
//
|
|
/// Test whether this is an identity transform.
|
|
//
|
|
bool isIdentityTransform()
|
|
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;
|
|
}
|
|
//
|
|
/// Multiply with another transform.
|
|
//
|
|
void mult(const transform &T2, transform &outT) const;
|
|
transform operator *(const transform & T) const
|
|
{
|
|
transform out;
|
|
mult(T,out);
|
|
return out;
|
|
}
|
|
//
|
|
/// Print a transform, mainly for debug purpose.
|
|
//
|
|
void 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
|
|
}
|
|
//
|
|
/// Return the inverse transform of the transform.
|
|
//
|
|
transform getInverse() const;
|
|
//
|
|
/// Returns the type of the transform.
|
|
//
|
|
transformType getType() const
|
|
{
|
|
return (transformType) 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;
|
|
}
|
|
|
|
//
|
|
/// get angle, isXFlip and mag from transformation
|
|
//
|
|
const void getAngleFlipMag( double& angle, bool& isXFlip, double& mag) const;
|
|
|
|
|
|
//
|
|
/// Modify a single point.
|
|
//
|
|
pod::point<short> modifyDblToShort(pod::point<double>) const;
|
|
pod::point<int> modifyDblToInt(pod::point<double>) const;
|
|
//
|
|
/// Do nothing method for syntactic completeness.
|
|
//
|
|
pod::point<int> modifyDblToInt(pod::point<int>) const
|
|
{ return pod::point<int>(); }
|
|
//
|
|
/// Do nothing method for syntactic completeness.
|
|
//
|
|
pod::point<int> modifyDblToInt(pod::point<long>) const
|
|
{ return pod::point<int>(); }
|
|
//
|
|
/// Do nothing method for syntactic completeness.
|
|
//
|
|
pod::point<short> modifyDblToShort(pod::point<int>) const
|
|
{ return pod::point<short>(); }
|
|
//
|
|
/// Do nothing method for syntactic completeness.
|
|
//
|
|
pod::point<short> modifyDblToShort(pod::point<long>) const
|
|
{ return pod::point<short>(); }
|
|
//
|
|
/// Transform doubles to doubles.
|
|
//
|
|
pod::point<double> modifyDblToDbl(pod::point<double>) const;
|
|
pod::point<double> modify(pod::point<double>) const;
|
|
//
|
|
/// Do nothing method for syntactic completeness.
|
|
//
|
|
pod::point<double> modifyDblToDbl(pod::point<int>) const
|
|
{ return pod::point<double>(); }
|
|
//
|
|
/// Transform ints to ints.
|
|
//
|
|
pod::point<int> modifyIntToInt(pod::point<int>) const;
|
|
pod::point<int> modify(pod::point<int>) const;
|
|
//
|
|
/// Do nothing method for syntactic completeness.
|
|
//
|
|
pod::point<int> modifyIntToInt(pod::point<double>) const
|
|
{ return pod::point<int>(); }
|
|
//
|
|
/// Do nothing method for syntactic completeness.
|
|
//
|
|
pod::point<int> modifyIntToInt(pod::point<long>) const
|
|
{ return pod::point<int>(); }
|
|
|
|
pod::point<short> modifyIntToShort(pod::point<int>) const;
|
|
//
|
|
/// Do nothing method for syntactic completeness.
|
|
//
|
|
pod::point<short> modifyIntToShort(pod::point<double>) const
|
|
{ return pod::point<short>(); }
|
|
//
|
|
/// Do nothing method for syntactic completeness.
|
|
//
|
|
pod::point<short> modifyIntToShort(pod::point<long>) const
|
|
{ return pod::point<short>(); }
|
|
|
|
pod::point<short> modifyLongToShort(pod::point<long>) const;
|
|
//
|
|
/// Do nothing method for syntactic completeness.
|
|
//
|
|
pod::point<short> modifyLongToShort(pod::point<int>) const
|
|
{ return pod::point<short>(); }
|
|
//
|
|
/// Do nothing method for syntactic completeness.
|
|
//
|
|
pod::point<short> modifyLongToShort(pod::point<double>) const
|
|
{ return pod::point<short>(); }
|
|
//
|
|
/// Transform longs to ints.
|
|
//
|
|
pod::point<int> modifyLongToInt(pod::point<long>) const;
|
|
//
|
|
/// Do nothing method for syntactic completeness.
|
|
//
|
|
pod::point<int> modifyLongToInt(pod::point<int>) const
|
|
{ return pod::point<int>(); }
|
|
//
|
|
/// Do nothing method for syntactic completeness.
|
|
//
|
|
pod::point<int> modifyLongToInt(pod::point<double>) const
|
|
{ return pod::point<int>(); }
|
|
//
|
|
/// Transform longs to longs.
|
|
//
|
|
pod::point<long> modifyLongToLong(pod::point<long>) const;
|
|
pod::point<long> modify(pod::point<long>) const;
|
|
//
|
|
//
|
|
//
|
|
pod::rectangle<double> operator()(const pod::rectangle<double> &) const;
|
|
pod::rectangle<long> operator()(const pod::rectangle<long> &) const;
|
|
pod::rectangle<int> operator()(const pod::rectangle<int> &) const;
|
|
pod::point<double> operator()(const pod::point<double> &) const;
|
|
pod::point<long> operator()(const pod::point<long> &) const;
|
|
pod::point<int> operator()(const pod::point<int> &) const;
|
|
|
|
//
|
|
/// 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
|
|
{
|
|
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
|
|
}
|
|
|
|
friend 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;
|
|
}
|
|
|
|
}; // class transform
|
|
|
|
namespace transformTest
|
|
{
|
|
|
|
/// API test getAngelFlipmag
|
|
bool testGetAngleFlipMag();
|
|
};
|
|
|
|
} // namespace base
|
|
|
|
#endif // TRANSFORM_H_
|