|
|
/******************************Module*Header*******************************\
* Module Name: xformobj.hxx * * * * User objects for transforms. * * * * Created: 13-Sep-1990 14:45:27 * * Author: Wendy Wu [wendywu] * * * * Copyright (c) 1990-1999 Microsoft Corporation * \**************************************************************************/
// These constants are used in the XFORMOBJ constructor.
#define COORD_METAFILE 1
#define COORD_WORLD 2
#define COORD_PAGE 3
#define COORD_DEVICE 4
#define WORLD_TO_DEVICE ((COORD_WORLD << 8) + COORD_DEVICE)
#define DEVICE_TO_WORLD ((COORD_DEVICE << 8) + COORD_WORLD)
// The exponents of all the coefficients for the various transforms must be
// within the following ranges:
//
// Metafile --
// |--> -47 <= e <= 48
// World --
// |--> -47 <= e <= 48
// Page --
// |--> -31 <= e <= 31
// Device --
//
// This will guarantee us a METAFILE_TO_DEVICE transform with
//
// -126 <= exponents <= 127
//
// for all the coefficients. The ranges are set so that transform coefficients
// can fit nicely in the IEEE single precision floating point format which has
// 8-bit exponent field that can hold values from -126 to 127. Note that when
// the transforms have reached the limits the calculations of inverse transforms
// might cause overflow.
// The max and min values for metafile and world transforms.
#define MAX_METAFILE_XFORM_EXP 52
#define MIN_METAFILE_XFORM_EXP -43
#define MAX_WORLD_XFORM_EXP MAX_METAFILE_XFORM_EXP
#define MIN_WORLD_XFORM_EXP MIN_METAFILE_XFORM_EXP
#define MAX_METAFILE_XFORM 1024*1024*1024*1024*1024*4 // 2^52
#define MIN_METAFILE_XFORM 1/(1024*1024*1024*1024*8) // 2^(-43)
#define MAX_WORLD_XFORM MAX_METAFILE_XFORM
#define MIN_WORLD_XFORM MIN_METAFILE_XFORM
// flag values for matrix.flAccel
#define XFORM_SCALE 1 // off-diagonal are 0
#define XFORM_UNITY 2 // diagonal are 1s, off-diagonal are 0
// will be set only if XFORM_SCALE is set
#define XFORM_Y_NEG 4 // M22 is negative. Will be set only if
// XFORM_SCALE|XFORM_UNITY are set
#define XFORM_FORMAT_LTOFX 8 // transform from LONG to FIX format
#define XFORM_FORMAT_FXTOL 16 // transform from FIX to LONG format
#define XFORM_FORMAT_LTOL 32 // transform from LONG to LONG format
#define XFORM_NO_TRANSLATION 64 // no translations
// These constants are used in the XFORMOBJ constructor.
#define IDENTITY 1
#define DONT_COMPUTE_FLAGS 0
#define COMPUTE_FLAGS 1
#define XFORM_FORMAT (XFORM_FORMAT_LTOFX|XFORM_FORMAT_FXTOL|XFORM_FORMAT_LTOL)
#define BLTOFXOK(x) (((x) < 0x07FFFFFF) && ((x) > -0x07FFFFFF))
extern "C" { BOOL bCvtPts(PMATRIX pmx, PPOINTL pSrc, PPOINTL pDest, SIZE_T cPts); BOOL bCvtPts1(PMATRIX pmx, PPOINTL pptl, SIZE_T cPts); BOOL bCvtVts(PMATRIX pmx, PVECTORL pSrc, PVECTORL pDest, SIZE_T cPts); BOOL bCvtVts_FlToFl(PMATRIX pmx, PVECTORFL pSrc, PVECTORFL pDest, SIZE_T cPts); };
extern MATRIX gmxIdentity_LToFx; extern MATRIX gmxIdentity_LToL; extern MATRIX gmxIdentity_FxToL;
VOID vConvertXformToMatrix(CONST XFORML *pxf, PMATRIX pmx);
#if DBG
extern int giXformLevel; #define XFORMPRINT(l,s,a) {if (giXformLevel >= l) DbgPrint(s,a);}
#else
#define XFORMPRINT(l,s,a)
#endif
/******************************Class***************************************\
* class EXFORMOBJ * * * * User object that lets clients interact with transforms. * * * * History: * * 12-Nov-1990 -by- Wendy Wu [wendywu] * * Wrote it. * \**************************************************************************/
class EXFORMOBJ { public: MATRIX *pmx; // pointer to the matrix
ULONG ulMode; BOOL bMirrored; public:
// Constructor
EXFORMOBJ() { pmx = (PMATRIX)NULL; bMirrored = FALSE; }
// Constructor - Make the given matrix a transform.
EXFORMOBJ(MATRIX& mx) { pmx = &mx; bMirrored = FALSE; }
// Initialize the the xform
VOID vInit(MATRIX *pmx_, FLONG fl = DONT_COMPUTE_FLAGS) { pmx = pmx_;
if (fl & COMPUTE_FLAGS) // compute accelerator flags
{ vComputeAccelFlags(fl & XFORM_FORMAT); } else if (fl & XFORM_FORMAT) { pmx->flAccel = fl; } }
// Constructor - Make a transform object given the pointer to the matrix.
EXFORMOBJ(MATRIX *pmx_, FLONG fl) { pmx = pmx_; bMirrored = FALSE;
if (fl & COMPUTE_FLAGS) // compute accelerator flags
{ vComputeAccelFlags(fl & XFORM_FORMAT); } else if (fl & XFORM_FORMAT) { pmx->flAccel = fl; } }
// Constructor - Get a transform matrix based on the request type. The only
// legitimate type for now is IDENTITY.
EXFORMOBJ(ULONG iXform, ULONG iFormat = XFORM_FORMAT_LTOFX);
#ifdef _DCOBJ_
// Constructor - Get a transform from a DC.
EXFORMOBJ(XDCOBJ& dco, ULONG iXform) {vQuickInit(dco,iXform);}
VOID vQuickInit(XDCOBJ& dco, ULONG iXform) { ulMode = (ULONG)dco.pdc->iGraphicsMode(); bMirrored = MIRRORED_DC(dco.pdc);
if (!dco.pdc->bDirtyXform() && (iXform == WORLD_TO_DEVICE)) { pmx = &dco.pdc->mxWorldToDevice(); } else { vInit(dco,iXform); } }
VOID vInit(XDCOBJ &dco, ULONG iXform); VOID vInitPageToDevice(XDCOBJ &dco, PMATRIX pmx_); #endif
// vComputeWtoDAccelFlags - Compute accelerator flags for the world
// to device xform.
VOID vComputeWtoDAccelFlags() { pmx->flAccel = XFORM_FORMAT_LTOFX; // clear the flag
// set translation flag
if ((pmx->fxDx == 0) && (pmx->fxDy == 0)) pmx->flAccel |= XFORM_NO_TRANSLATION;
if (pmx->efM12.bIsZero() && pmx->efM21.bIsZero()) { // off diagonal elements are zeros
pmx->flAccel |= XFORM_SCALE;
if (pmx->efM11.bIs16() && pmx->efM22.bIs16()) pmx->flAccel |= XFORM_UNITY; } }
// Destructor - Don't need to free anything.
~EXFORMOBJ() {}
// bValid - Validator.
BOOL bValid() { return(pmx != (PMATRIX)NULL); }
// vComputeAccelFlags - Compute accelerator flags for a given transform matrix.
VOID vComputeAccelFlags(FLONG flFormat = XFORM_FORMAT_LTOFX);
// efM11 - Get/set coefficients of the given matrix.
EFLOAT& efM11() {return(pmx->efM11);} EFLOAT& efM22() {return(pmx->efM22);} EFLOAT& efM12() {return(pmx->efM12);} EFLOAT& efM21() {return(pmx->efM21);} FIX fxDx() {return(pmx->fxDx);} FIX fxDy() {return(pmx->fxDy);}
VOID vSetElementsLToL ( EFLOAT ef11, EFLOAT ef12, EFLOAT ef21, EFLOAT ef22 ) { pmx->efM11 = ef11; pmx->efM12 = ef12; pmx->efM21 = ef21; pmx->efM22 = ef22; }
VOID vSetElementsLToFx ( FLOATL l_e11, FLOATL l_e12, FLOATL l_e21, FLOATL l_e22 ) { pmx->efM11 = l_e11; pmx->efM12 = l_e12; pmx->efM21 = l_e21; pmx->efM22 = l_e22;
// Elements in a transform of LTOFX format must be scaled by 16.
pmx->efM11.vTimes16(); pmx->efM12.vTimes16(); pmx->efM21.vTimes16(); pmx->efM22.vTimes16(); }
// flAccel - Get the accelerator flag of a given matrix.
FLONG flAccel() { return(pmx->flAccel); } FLONG flAccel(FLONG fl) { return(pmx->flAccel = fl); }
// bEqual - See if two transforms are identical.
BOOL bEqual(EXFORMOBJ& xo);
// bEqualExceptTranslations - See if two transforms are identical in M11, M12,
// M21, and M22.
BOOL bEqualExceptTranslations(PMATRIX pmx_); BOOL bEqualExceptTranslations(EXFORMOBJ& xo) { return(bEqualExceptTranslations(xo.pmx)); }
// bScale -- See if a the off-diangonal elements of a transform are 0.
BOOL bScale() { return(pmx->flAccel & XFORM_SCALE); }
// bRotation -- See if there is rotation.
BOOL bRotation() { return(!bScale()); }
// bRotationOrMirroring -- See if there is a rotation or mirroring (negative
// diagonal element(s) with 0 off-diagonal elements)
BOOL bRotationOrMirroring() { return (bRotation() || ( !bMirrored && ((pmx->efM11.bIsNegative()) || (pmx->efM22.bIsNegative())) )); }
// bNoTranslation -- See if a transform has translation components.
BOOL bNoTranslation() { return(pmx->flAccel & XFORM_NO_TRANSLATION); }
// bIdentity - See if a given transform is an identity transform.
BOOL bIdentity() { return((pmx->flAccel & (XFORM_SCALE | XFORM_UNITY | XFORM_NO_TRANSLATION)) == (XFORM_SCALE | XFORM_UNITY | XFORM_NO_TRANSLATION)); }
// bTranslationsOnly - no rotations and scaling, translations may possibly
// be zero
BOOL bTranslationsOnly () { return (pmx->flAccel & XFORM_UNITY); }
// bConformal -- Does the transform preserve angles?
// looks at the 2 X 2 transform only
BOOL bConformal() { EFLOAT ef;
ef = pmx->efM21; ef.vNegate(); return (pmx->efM11 == pmx->efM22 && pmx->efM12 == ef); }
// bXform - Apply the transform to various objects. Return FALSE on
// overflow.
// Transform a list of points.
BOOL bXform(PPOINTL pptlSrc,PPOINTL pptlDst,SIZE_T cPts); BOOL bXform(PPOINTL pSrc, PPOINTFIX pDest, SIZE_T cPts); BOOL bXform(PPOINTFIX pSrc, PPOINTL pDest, SIZE_T cPts); BOOL bXformRound(PPOINTL pSrc, PPOINTFIX pDest, SIZE_T cPts);
// Transform a list of points in place.
BOOL bXform(PPOINTL pptl, SIZE_T cPts) { return(bIdentity() || bCvtPts1(pmx, pptl, cPts)); }
BOOL bXform(EPOINTL& eptl) { return(bXform((PPOINTL) &eptl, 1)); }
BOOL bXform(ERECTL& ercl) { BOOL bRet; bRet = bXform((PPOINTL) &ercl, 2); // If it a mirrored DC then shift the rect one pixel to the right
// This will give the effect of including the right edge of the rect and exclude the left edge.
if (bMirrored) { ++ercl.left; ++ercl.right; } return (bRet); }
// Transform a list of vectors.
BOOL bXform(PVECTORFL pvtflSrc, PVECTORFL pvtflDst,SIZE_T cVts); BOOL bXform(PVECTORL pSrc, PVECTORFX pDest, SIZE_T cVts); BOOL bXform(PVECTORL pSrc, PVECTORL pDest, SIZE_T cVts); BOOL bXform(PVECTORFX pSrc, PVECTORL pDest, SIZE_T cVts); BOOL bXformRound(PVECTORL pSrc, PVECTORFX pDest, SIZE_T cVts);
// Transform a list of vectors in place.
BOOL bXform(PVECTORFL pvtfl, SIZE_T cVts) { BOOL bReturn = TRUE;
if (!bTranslationsOnly()) bReturn = bXform(pvtfl, pvtfl, cVts);
return(bReturn); }
BOOL bXform(EVECTORFL& evtfl) { return(bXform((PVECTORFL) &evtfl, 1)); }
BOOL bXform(EVECTORL& evtl) { BOOL bReturn = TRUE;
if (!bTranslationsOnly()) bReturn = bXform((PVECTORL)&evtl, (PVECTORL)&evtl, 1);
return(bReturn); }
// bMultiply - Multiply two XFORMs together and store the result in the
// XFORMOBJ.
BOOL bMultiply(PMATRIX pmxLeft, PMATRIX pmxRight, FLONG fl = DONT_COMPUTE_FLAGS); BOOL bMultiply(EXFORMOBJ& exoLeft, EXFORMOBJ& exoRight, FLONG fl = DONT_COMPUTE_FLAGS) { return(bMultiply(exoLeft.pmx, exoRight.pmx, fl)); }
// bMultToWorld - Multiply the world transform with a given matrix. The
// result is stored in the passed in matrix. This is so
// that the resultant matrix can be range-checked later on
// before the WORLD_TO_PAGE xform is changed.
// The order of the multiplication is based on imode.
// If imode == MWT_LEFTMULTIPLY, the given matrix is applied
// to the left of the multiplication. It's applied to the
// right otherwise.
BOOL bMultToWorld(MATRIX *pmx_, ULONG imode) { MATRIX mx = *pmx_; EXFORMOBJ xo(pmx_, DONT_COMPUTE_FLAGS);
if (imode == MWT_LEFTMULTIPLY) return(xo.bMultiply(&mx, pmx)); else return(xo.bMultiply(pmx, &mx)); }
// vRemoveTranslation - Remove the translation coefficients from a matrix.
VOID vRemoveTranslation();
// vGetCoefficient - Get the coefficients of a transform matrix. This is
// used to convert our internal matrix structure into
// the GDI/DDI transform format.
VOID vGetCoefficient(PFLOATOBJ_XFORM pxf);
// vGetCoefficient - Get the coefficients of a transform matrix. This is
// used to convert our internal matrix structure into
// the GDI/DDI transform format.
VOID vGetCoefficient(XFORML *pxf);
// vGetCoefficient - Get the coefficients of a transform matrix. This is
// used to convert our internal matrix structure into
// the IFI transform format.
VOID vGetCoefficient(PFD_XFORM pxf);
// vSetScaling - Set the scaling factors for a given matrix.
VOID vSetScaling(EFLOAT efM11, EFLOAT efM22, FLONG fl = DONT_COMPUTE_FLAGS) { ASSERTGDI(pmx->efM12.bIsZero(), "vSetScaling error: M12 not zero"); ASSERTGDI(pmx->efM21.bIsZero(), "vSetScaling error: M21 not zero");
pmx->efM11 = efM11; pmx->efM22 = efM22;
if (fl & COMPUTE_FLAGS) vComputeAccelFlags(fl & XFORM_FORMAT); }
// vSetTranslations - Set the translations for a given matrix.
VOID vSetTranslations(EFLOAT efDx, EFLOAT efDy) { FIX fxDx, fxDy;
pmx->efDx = efDx; pmx->efDy = efDy;
#if DBG
if (!efDx.bEfToL(fxDx)) WARNING("vSetTranslations:dx overflowed\n"); if (!efDy.bEfToL(fxDy)) WARNING("vSetTranslations:dy overflowed\n"); #else
efDx.bEfToL(fxDx); efDy.bEfToL(fxDy); #endif
pmx->fxDx = fxDx; pmx->fxDy = fxDy;
if ((fxDx == 0) && (fxDy == 0)) pmx->flAccel |= XFORM_NO_TRANSLATION; else pmx->flAccel &= ~(XFORM_NO_TRANSLATION); }
// vSet - Set the coefficients for a given matrix.
// This is used to set WorldToPage transform.
VOID vSet(MATRIX *pmx_, FLONG fl = DONT_COMPUTE_FLAGS) { *pmx = *pmx_;
if (fl & COMPUTE_FLAGS) vComputeAccelFlags(fl & XFORM_FORMAT); }
// vCopy -- Copy a transform obj to another.
VOID vCopy(EXFORMOBJ& xoSrc);
// vOrder -- Order a rectangle based on the PAGE_TO_DEVICE transform.
// The rectangle will be well ordered after the PAGE_TO_DEVICE
// transform is applied.
VOID vOrder(RECTL &rcl);
// bInverse -- Calculate the inverse of a passed in xform/matrix and store
// the result in the XFORMOBJ. The source and destination
// matrices CANNOT be the same one.
BOOL bInverse(MATRIX& mxSrc); BOOL bInverse(EXFORMOBJ& xo) { return(bInverse(*(xo.pmx))); }
// bComputeUnits -- Calculates a simplified transform for vectors parallel
// to the given angle.
BOOL bComputeUnits(LONG lAngle,POINTFL *ppte,EFLOAT *pefWD,EFLOAT *pefDW);
// fxFastX -- Does a quick scaling transform on x.
FIX fxFastX(LONG ll) {return((FIX) lCvt(pmx->efM11,ll) + pmx->fxDx);}
// fxFastY -- Does a quick scaling transform on y.
FIX fxFastY(LONG ll) {return((FIX) lCvt(pmx->efM22,ll) + pmx->fxDy);} };
typedef EXFORMOBJ *PEXFORMOBJ;
|