/* * 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 #include #include #include #include #include #include #include "SSE2_transform.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} }; typedef pod::point (*pModifyFunDblToShort)(const transform &, pod::point); typedef pod::point (*pModifyFunLongToShort)(const transform &, pod::point); typedef pod::point (*pModifyFunIntToShort)(const transform &, pod::point); typedef pod::point (*pModifyFunDblToInt)(const transform &, pod::point); typedef pod::point (*pModifyFunDblToDbl)(const transform &, pod::point); typedef pod::point (*pModifyFunLongToInt)(const transform &, pod::point); typedef pod::point (*pModifyFunIntToInt)(const transform &, pod::point); typedef pod::point (*pModifyFunLongToLong)(const transform &, pod::point); // /// Type definition for for transforming a rectangle of type double to /// another rectangle of type double. // typedef pod::rectangle (*pModifyRectFunDblToDbl)(const transform &, const pod::rectangle &); // /// Type definition for for transforming a rectangle of type long to /// another rectangle of type long. // typedef pod::rectangle (*pModifyRectFunLongToLong)(const transform &, const pod::rectangle &); // /// Type definition for for transforming a rectangle of type int to /// another rectangle of type int. // typedef pod::rectangle (*pModifyRectFunIntToInt)(const transform &, const pod::rectangle &); static pModifyFunDblToShort modifyDblToShortFunTbl[transformTypeMAX]; static pModifyFunLongToShort modifyLongToShortFunTbl[transformTypeMAX]; static pModifyFunIntToShort modifyIntToShortFunTbl[transformTypeMAX]; static pModifyFunDblToInt modifyDblToIntFunTbl[transformTypeMAX]; static pModifyFunDblToDbl modifyDblToDblFunTbl[transformTypeMAX]; static pModifyFunLongToInt modifyLongToIntFunTbl[transformTypeMAX]; static pModifyFunIntToInt modifyIntToIntFunTbl[transformTypeMAX]; static pModifyFunLongToLong modifyLongToLongFunTbl[transformTypeMAX]; static pModifyRectFunLongToLong modifyRectLongToLongFunTbl[transformTypeMAX]; static pModifyRectFunDblToDbl modifyRectDblToDblFunTbl[transformTypeMAX]; static pModifyRectFunIntToInt modifyRectIntToIntFunTbl[transformTypeMAX]; // /// Modify a point using scale transform. // template pod::point GXX_HIDDEN modifyScale( const transform & T, pod::point xy) { pod::point tmp = xy % T.getDiagonal(); return std::tr1::is_floating_point::value ? pod::point((oC)tmp.X(),(oC)tmp.Y()) : pod::point((oC)base::round(tmp.X()),(oC)base::round(tmp.Y())); } // /// Modify a point using scale and offset transform. // template pod::point GXX_HIDDEN modifyScaleOffset( const transform & T, pod::point xy) { pod::point tmp = xy % T.getDiagonal() + T.getOffset(); return std::tr1::is_floating_point::value ? pod::point((oC)tmp.X(),(oC)tmp.Y()) : pod::point((oC)base::round(tmp.X()),(oC)base::round(tmp.Y())); } // /// Modify a point using a general transform. // template pod::point GXX_HIDDEN modifyGeneral( const transform & T, pod::point xy ) { pod::point tmp(T.getCol1()*pod::point(xy),T.getCol2()*pod::point(xy)); tmp += T.getOffset(); return std::tr1::is_floating_point::value ? pod::point((oC)tmp.X(),(oC)tmp.Y()) : pod::point((oC)base::round(tmp.X()),(oC)base::round(tmp.Y())); } template pod::point GXX_HIDDEN modifyStd ( const transform & T, pod::point xy ) { // // Transform the point. // pod::point d = xy * T.getOrient() + T.getOffset(); // // Convert to target coordinate type. // return std::tr1::is_floating_point::value ? pod::point( (oC)(d.getX()), (oC)(d.getY())) : pod::point( (oC)base::round(d.getX()), (oC)base::round(d.getY())); } // /// Modify a point using standard transform with magnification // template pod::point GXX_HIDDEN modifyStdMag( const transform &T, pod::point xy ) { // // Transform the point. // pod::point d = xy * T.getOrient() * T.get11() + T.getOffset(); // // Convert to target coordinate type. // return std::tr1::is_floating_point::value ? pod::point( (oC)(d.getX()), (oC)(d.getY())) : pod::point( (oC)base::round(d.getX()), (oC)base::round(d.getY())); } // /// Modify a point using resolution transform. // template pod::point GXX_HIDDEN modifyResolution( const transform &T, pod::point xy ) { pod::point tmp = xy % T.getDiagonal(); if (T.getNext()) { if (std::tr1::is_double::value) { pod::point tmp2 = pod::point((double)tmp.X(), (double)tmp.Y()); return T.getNext()->modifyDblToDbl(tmp2); } else if (std::tr1::is_long::value) { pod::point tmp2 = pod::point((long)base::round(tmp.X()), (long)base::round(tmp.Y())); return T.getNext()->modifyLongToLong(tmp2); } else if (std::tr1::is_int::value) { pod::point tmp2 = pod::point((long)base::round(tmp.X()), (long)base::round(tmp.Y())); return T.getNext()->modifyLongToInt(tmp2); } else if (std::tr1::is_short::value) { pod::point tmp2 = pod::point((long)base::round(tmp.X()), (long)base::round(tmp.Y())); return T.getNext()->modifyLongToShort(tmp2); } } else return std::tr1::is_floating_point::value ? pod::point((oC)tmp.X(),(oC)tmp.Y()) : pod::point((oC)base::round(tmp.X()), (oC)base::round(tmp.Y())); // Should not get here or something is missing. throw except::programError(); return pod::point((oC)0, (oC)0); } // // Modify a rectangle using scale transform. // template pod::rectangle GXX_HIDDEN modifyScaleRect( const transform & T, const pod::rectangle & r) { pod::rectangle rect(modifyScale(T,r.getLowerLeft()), modifyScale(T,r.getUpperRight())); rect.makeValid(); return rect; } // // Modify a rectangle using scale and offset transform. // template pod::rectangle GXX_HIDDEN modifyScaleOffsetRect( const transform & T, const pod::rectangle & r) { pod::rectangle rect(modifyScaleOffset(T,r.getLowerLeft()), modifyScaleOffset(T,r.getUpperRight())); rect.makeValid(); return rect; } // // Modify a rectangle using a general transform. // template pod::rectangle GXX_HIDDEN modifyGeneralRect( const transform & T, const pod::rectangle & 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 p0 = modifyGeneral(T,r.getLowerLeft()); pod::point p1 = modifyGeneral(T,r.getLowerRight()); pod::point p2 = modifyGeneral(T,r.getUpperRight()); pod::point p3 = modifyGeneral(T,r.getUpperLeft()); pod::rectangle rect; rect.merge(p0); rect.merge(p1); rect.merge(p2); rect.merge(p3); return rect; } template pod::rectangle GXX_HIDDEN modifyStdRect ( const transform & T, const pod::rectangle & r ) { pod::rectangle rect(modifyStd(T,r.getLowerLeft()), modifyStd(T,r.getUpperRight())); rect.makeValid(); return rect; } // // Modify a rectangle using standard transform with magnification. // template pod::rectangle GXX_HIDDEN modifyStdMagRect( const transform &T, const pod::rectangle & r ) { pod::rectangle rect(modifyStdMag(T,r.getLowerLeft()), modifyStdMag(T,r.getUpperRight())); rect.makeValid(); return rect; } // // Modify a rectangle using resolution transform. // template pod::rectangle GXX_HIDDEN modifyResolutionRect( const transform & T, const pod::rectangle & r) { pod::rectangle rect(modifyResolution(T,r.getLowerLeft()), modifyResolution(T,r.getUpperRight())); rect.makeValid(); return rect; } // /// Type definition for determining inverse of various transform types. // typedef transform (*pGetInverseFun)(const transform &); // /// Table of inverse determining functions by transform type. // static pGetInverseFun getInverseFnTbl[transformTypeMAX]; typedef void (*pMultFun)( const transform & T1, const transform & T2, transform & outT ); static pMultFun multFnTbl[transformTypeMAX*transformTypeMAX]; // /// Initialize the function tables. // void transform::initFnTables() { // // double to short // modifyDblToShortFunTbl[ScaleOffsetTransformType] = &modifyScaleOffset; modifyDblToShortFunTbl[GeneralTransformType] = &modifyGeneral; modifyDblToShortFunTbl[StdTransformType] = &modifyStd; modifyDblToShortFunTbl[StdTransformWithMagType] = &modifyStdMag; modifyDblToShortFunTbl[ScaleTransformType] = &modifyScale; modifyDblToShortFunTbl[ResolutionTransformType] = &modifyResolution; // // long to short // modifyLongToShortFunTbl[ScaleOffsetTransformType] = &modifyScaleOffset; modifyLongToShortFunTbl[GeneralTransformType] = &modifyGeneral; modifyLongToShortFunTbl[StdTransformType] = &modifyStd; modifyLongToShortFunTbl[StdTransformWithMagType] = &modifyStdMag; modifyLongToShortFunTbl[ScaleTransformType] = &modifyScale; modifyLongToShortFunTbl[ResolutionTransformType] = &modifyResolution; // // int to short // modifyIntToShortFunTbl[ScaleOffsetTransformType] = &modifyScaleOffset; modifyIntToShortFunTbl[GeneralTransformType] = &modifyGeneral; modifyIntToShortFunTbl[StdTransformType] = &modifyStd; modifyIntToShortFunTbl[StdTransformWithMagType] = &modifyStdMag; modifyIntToShortFunTbl[ScaleTransformType] = &modifyScale; modifyIntToShortFunTbl[ResolutionTransformType] = &modifyResolution; // // double to int // modifyDblToIntFunTbl[ScaleOffsetTransformType] = &modifyScaleOffset; modifyDblToIntFunTbl[GeneralTransformType] = &modifyGeneral; modifyDblToIntFunTbl[StdTransformType] = &modifyStd; modifyDblToIntFunTbl[StdTransformWithMagType] = &modifyStdMag; modifyDblToIntFunTbl[ScaleTransformType] = &modifyScale; modifyDblToIntFunTbl[ResolutionTransformType] = &modifyResolution; // // double to double // modifyDblToDblFunTbl[ScaleOffsetTransformType] = &modifyScaleOffset; modifyDblToDblFunTbl[GeneralTransformType] = &modifyGeneral; modifyDblToDblFunTbl[StdTransformType] = &modifyStd; modifyDblToDblFunTbl[StdTransformWithMagType] = &modifyStdMag; modifyDblToDblFunTbl[ScaleTransformType] = &modifyScale; modifyDblToDblFunTbl[ResolutionTransformType] = &modifyResolution; // // long to int // modifyLongToIntFunTbl[ScaleOffsetTransformType] = &modifyScaleOffset; modifyLongToIntFunTbl[GeneralTransformType] = &modifyGeneral; modifyLongToIntFunTbl[StdTransformType] = &modifyStd; modifyLongToIntFunTbl[StdTransformWithMagType] = &modifyStdMag; modifyLongToIntFunTbl[ScaleTransformType] = &modifyScale; modifyLongToIntFunTbl[ResolutionTransformType] = &modifyResolution; // // int to int // modifyIntToIntFunTbl[ScaleOffsetTransformType] = &modifyScaleOffset; modifyIntToIntFunTbl[GeneralTransformType] = &modifyGeneral; modifyIntToIntFunTbl[StdTransformType] = &modifyStd; modifyIntToIntFunTbl[StdTransformWithMagType] = &modifyStdMag; modifyIntToIntFunTbl[ScaleTransformType] = &modifyScale; modifyIntToIntFunTbl[ResolutionTransformType] = &modifyResolution; // // long to long // modifyLongToLongFunTbl[ScaleOffsetTransformType] = &modifyScaleOffset; modifyLongToLongFunTbl[GeneralTransformType] = &modifyGeneral; modifyLongToLongFunTbl[StdTransformType] = &modifyStd; modifyLongToLongFunTbl[StdTransformWithMagType] = &modifyStdMag; modifyLongToLongFunTbl[ScaleTransformType] = &modifyScale; modifyLongToLongFunTbl[ResolutionTransformType] = &modifyResolution; // /// 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; modifyRectLongToLongFunTbl[GeneralTransformType] = modifyGeneralRect; modifyRectLongToLongFunTbl[StdTransformType] = modifyStdRect; modifyRectLongToLongFunTbl[StdTransformWithMagType] = modifyStdMagRect; modifyRectLongToLongFunTbl[ScaleTransformType] = modifyScaleRect; modifyRectLongToLongFunTbl[ResolutionTransformType] = modifyResolutionRect; modifyRectDblToDblFunTbl[ScaleOffsetTransformType] = modifyScaleOffsetRect; modifyRectDblToDblFunTbl[GeneralTransformType] = modifyGeneralRect; modifyRectDblToDblFunTbl[StdTransformType] = modifyStdRect; modifyRectDblToDblFunTbl[StdTransformWithMagType] = modifyStdMagRect; modifyRectDblToDblFunTbl[ScaleTransformType] = modifyScaleRect; modifyRectDblToDblFunTbl[ResolutionTransformType] = modifyResolutionRect; modifyRectIntToIntFunTbl[ScaleOffsetTransformType] = modifyScaleOffsetRect; modifyRectIntToIntFunTbl[GeneralTransformType] = modifyGeneralRect; modifyRectIntToIntFunTbl[StdTransformType] = modifyStdRect; modifyRectIntToIntFunTbl[StdTransformWithMagType] = modifyStdMagRect; modifyRectIntToIntFunTbl[ScaleTransformType] = modifyScaleRect; modifyRectIntToIntFunTbl[ResolutionTransformType] = modifyResolutionRect; } transform transform::getInverse() const { return (*(getInverseFnTbl[type]))(*this); } void transform::mult(const transform &T2, transform & outT) const { (*(multFnTbl[(type*transformTypeMAX)+T2.type]))(*this,T2,outT); } pod::point transform::modifyDblToShort(pod::point p) const { return (*(modifyDblToShortFunTbl[type]))(*this, p); } pod::point transform::modifyDblToInt(pod::point p) const { return (*(modifyDblToIntFunTbl[type]))(*this, p); } pod::point transform::modifyDblToDbl(pod::point p) const { return (*(modifyDblToDblFunTbl[type]))(*this, p); } pod::point transform::modify(pod::point p) const { return (*(modifyDblToDblFunTbl[type]))(*this, p); } pod::point transform::modifyIntToInt(pod::point p) const { return (*(modifyIntToIntFunTbl[type]))(*this, p); } pod::point transform::modify(pod::point p) const { return (*(modifyIntToIntFunTbl[type]))(*this, p); } pod::point transform::modifyIntToShort(pod::point p) const { return (*(modifyIntToShortFunTbl[type]))(*this, p); } pod::point transform::modifyLongToShort(pod::point p) const { return (*(modifyLongToShortFunTbl[type]))(*this, p); } pod::point transform::modifyLongToInt(pod::point p) const { return (*(modifyLongToIntFunTbl[type]))(*this, p); } pod::point transform::modifyLongToLong(pod::point p) const { return (*(modifyLongToLongFunTbl[type]))(*this, p); } pod::point transform::modify(pod::point p) const { return (*(modifyLongToLongFunTbl[type]))(*this, p); } pod::rectangle transform::operator()(const pod::rectangle & r) const { return (*(modifyRectDblToDblFunTbl[type]))(*this, r); } pod::rectangle transform::operator()(const pod::rectangle & r) const { return (*(modifyRectLongToLongFunTbl[type]))(*this, r); } pod::rectangle transform::operator()(const pod::rectangle & r) const { return (*(modifyRectIntToIntFunTbl[type]))(*this, r); } pod::point transform::operator()(const pod::point & p) const { return (*(modifyDblToDblFunTbl[type]))(*this, p); } pod::point transform::operator()(const pod::point & p) const { return (*(modifyLongToLongFunTbl[type]))(*this, p); } pod::point transform::operator()(const pod::point & p) const { return (*(modifyIntToIntFunTbl[type]))(*this, p); } // 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 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 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(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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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 void transform::modify( const pod::point& rSrc, pod::point& rDest ) const { switch ( type ) { case ScaleOffsetTransformType: rDest = modifyScaleOffset( *this, rSrc ); break; case GeneralTransformType: rDest = modifyGeneral( *this, rSrc ); break; case StdTransformType: rDest = modifyStd( *this, rSrc ); break; case StdTransformWithMagType: rDest = modifyStdMag( *this, rSrc ); break; case ScaleTransformType: rDest = modifyScale( *this, rSrc ); break; case ResolutionTransformType: rDest = modifyResolution( *this, rSrc ); break; default: throw except::outOfRange("base::modify: Unknown type."); } // switch } // /// This is pod::rectangle version of above function. // template void transform::modify( const pod::rectangle& rSrc, pod::rectangle& rDest ) const { switch ( type ) { case ScaleOffsetTransformType: rDest = modifyScaleOffsetRect( *this, rSrc ); break; case GeneralTransformType: rDest = modifyGeneralRect( *this, rSrc ); break; case StdTransformType: rDest = modifyStdRect( *this, rSrc ); break; case StdTransformWithMagType: rDest = modifyStdMagRect( *this, rSrc ); break; case ScaleTransformType: rDest = modifyScaleRect( *this, rSrc ); break; case ResolutionTransformType: rDest = modifyResolutionRect( *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 void transform::modifyBBox( const pod::rectangle& rSrc, pod::rectangle& rDest ) const { // // If we have orthogonal transform? // First check get12 since most of transform will // have no rotation factor. // if ( get12() == 0 || get11() == 0 ) modify( rSrc, rDest ); // // General case. // else { rDest.makeInvalid(); pod::point 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 ); } } /***************************************************************************** * Instantiate template with some arguments. */ template void transform::modify( const pod::point&, pod::point& ) const; template void transform::modify( const pod::point&, pod::point& ) const; template void transform::modify( const pod::point&, pod::point& ) const; template void transform::modify( const pod::point&, pod::point& ) const; template void transform::modify( const pod::point&, pod::point& ) const; template void transform::modify( const pod::point&, pod::point& ) const; template void transform::modify( const pod::point&, pod::point& ) const; template void transform::modify( const pod::point&, pod::point& ) const; template void transform::modify( const pod::point&, pod::point& ) const; template void transform::modify( const pod::rectangle&, pod::rectangle& ) const; template void transform::modify( const pod::rectangle&, pod::rectangle& ) const; template void transform::modify( const pod::rectangle&, pod::rectangle& ) const; template void transform::modify( const pod::rectangle&, pod::rectangle& ) const; template void transform::modify( const pod::rectangle&, pod::rectangle& ) const; template void transform::modify( const pod::rectangle&, pod::rectangle& ) const; template void transform::modify( const pod::rectangle&, pod::rectangle& ) const; template void transform::modify( const pod::rectangle&, pod::rectangle& ) const; template void transform::modify( const pod::rectangle&, pod::rectangle& ) const; template void transform::modifyBBox( const pod::rectangle&, pod::rectangle& ) const; template void transform::modifyBBox( const pod::rectangle&, pod::rectangle& ) const; template void transform::modifyBBox( const pod::rectangle&, pod::rectangle& ) const; template void transform::modifyBBox( const pod::rectangle&, pod::rectangle& ) const; template void transform::modifyBBox( const pod::rectangle&, pod::rectangle& ) const; template void transform::modifyBBox( const pod::rectangle&, pod::rectangle& ) const; template void transform::modifyBBox( const pod::rectangle&, pod::rectangle& ) const; template void transform::modifyBBox( const pod::rectangle&, pod::rectangle& ) const; template void transform::modifyBBox( const pod::rectangle&, pod::rectangle& ) const; 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