You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
400 lines
9.8 KiB
400 lines
9.8 KiB
/**************************************************************************\
|
|
*
|
|
* Copyright (c) 1998 Microsoft Corporation
|
|
*
|
|
* Module Name:
|
|
*
|
|
* transform.cpp
|
|
*
|
|
* Abstract:
|
|
*
|
|
* Implement functions related to transforms
|
|
* inside the graphics context.
|
|
*
|
|
* Revision History:
|
|
*
|
|
* 12/09/1998 davidx
|
|
* Created it.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
#include "precomp.hpp"
|
|
|
|
|
|
/**************************************************************************\
|
|
*
|
|
* Function Description:
|
|
*
|
|
* Get the inverse of the world to device matrix.
|
|
* We try to keep the world to device matrix invertible all the time,
|
|
* so this should always succeed.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* [OUT] matrix - the device to world transformation matrix
|
|
*
|
|
* Return Value:
|
|
*
|
|
* GpStatus - Ok or failure status
|
|
*
|
|
* Created:
|
|
*
|
|
* 3/8/1999 DCurtis
|
|
*
|
|
\**************************************************************************/
|
|
GpStatus
|
|
GpGraphics::GetDeviceToWorldTransform(GpMatrix * matrix) const
|
|
{
|
|
ASSERT(matrix != NULL);
|
|
|
|
if (!Context->InverseOk)
|
|
{
|
|
Context->DeviceToWorld = Context->WorldToDevice;
|
|
if (Context->DeviceToWorld.Invert() == Ok)
|
|
{
|
|
Context->InverseOk = TRUE;
|
|
goto InverseOk;
|
|
}
|
|
ASSERT(0); // somehow we got a non-invertible matrix
|
|
return GenericError;
|
|
}
|
|
|
|
InverseOk:
|
|
*matrix = Context->DeviceToWorld;
|
|
return Ok;
|
|
}
|
|
|
|
inline REAL myabs(REAL x)
|
|
{
|
|
return (x >= 0.0f) ? x : -x;
|
|
}
|
|
|
|
VOID
|
|
GpGraphics::GetWorldPixelSize(
|
|
REAL & xSize,
|
|
REAL & ySize
|
|
)
|
|
{
|
|
GpMatrix matrix;
|
|
if (this->GetDeviceToWorldTransform(&matrix) == Ok)
|
|
{
|
|
PointF pnt(1.0f,1.0f);
|
|
matrix.VectorTransform(&pnt);
|
|
xSize = myabs(pnt.X);
|
|
ySize = myabs(pnt.Y);
|
|
}
|
|
else
|
|
{
|
|
xSize = 1.0f;
|
|
ySize = 1.0f;
|
|
}
|
|
}
|
|
|
|
GpStatus
|
|
GpGraphics::SetWorldTransform(const GpMatrix& matrix)
|
|
{
|
|
GpStatus status = Ok;
|
|
|
|
// Keep the WorldToPage transform invertible
|
|
if (matrix.IsInvertible())
|
|
{
|
|
if (IsRecording())
|
|
{
|
|
status = Metafile->RecordSetWorldTransform(matrix);
|
|
}
|
|
Context->WorldToPage = matrix;
|
|
Context->InverseOk = FALSE;
|
|
Context->UpdateWorldToDeviceMatrix();
|
|
}
|
|
else
|
|
{
|
|
status = InvalidParameter;
|
|
}
|
|
return status;
|
|
}
|
|
|
|
GpStatus
|
|
GpGraphics::ResetWorldTransform()
|
|
{
|
|
GpStatus status = Ok;
|
|
|
|
if (IsRecording())
|
|
{
|
|
status = Metafile->RecordResetWorldTransform();
|
|
}
|
|
Context->WorldToPage.Reset();
|
|
Context->InverseOk = FALSE;
|
|
Context->UpdateWorldToDeviceMatrix();
|
|
return status;
|
|
}
|
|
|
|
GpStatus
|
|
GpGraphics::MultiplyWorldTransform(const GpMatrix& matrix,
|
|
GpMatrixOrder order)
|
|
{
|
|
GpStatus status = Ok;
|
|
GpMatrix save = Context->WorldToPage;
|
|
|
|
if (order == MatrixOrderPrepend)
|
|
{
|
|
Context->WorldToPage.Prepend(matrix);
|
|
}
|
|
else
|
|
{
|
|
Context->WorldToPage.Append(matrix);
|
|
}
|
|
|
|
// Keep the WorldToPage transform invertible
|
|
if (Context->WorldToPage.IsInvertible())
|
|
{
|
|
if (IsRecording())
|
|
{
|
|
status = Metafile->RecordMultiplyWorldTransform(matrix, order);
|
|
}
|
|
Context->InverseOk = FALSE;
|
|
Context->UpdateWorldToDeviceMatrix();
|
|
}
|
|
else
|
|
{
|
|
Context->WorldToPage = save;
|
|
WARNING(("Matrix is non-invertible"));
|
|
status = InvalidParameter;
|
|
}
|
|
return status;
|
|
}
|
|
|
|
GpStatus
|
|
GpGraphics::TranslateWorldTransform(REAL dx, REAL dy,
|
|
GpMatrixOrder order)
|
|
{
|
|
GpStatus status = Ok;
|
|
|
|
if (IsRecording())
|
|
{
|
|
status = Metafile->RecordTranslateWorldTransform(dx, dy, order);
|
|
}
|
|
Context->WorldToPage.Translate(dx, dy, order);
|
|
Context->InverseOk = FALSE;
|
|
Context->UpdateWorldToDeviceMatrix();
|
|
return status;
|
|
}
|
|
|
|
GpStatus
|
|
GpGraphics::ScaleWorldTransform(REAL sx, REAL sy,
|
|
GpMatrixOrder order)
|
|
{
|
|
GpStatus status = Ok;
|
|
GpMatrix save = Context->WorldToPage;
|
|
|
|
Context->WorldToPage.Scale(sx, sy, order);
|
|
|
|
// Keep the WorldToPage transform invertible
|
|
if (Context->WorldToPage.IsInvertible())
|
|
{
|
|
if (IsRecording())
|
|
{
|
|
status = Metafile->RecordScaleWorldTransform(sx, sy, order);
|
|
}
|
|
Context->InverseOk = FALSE;
|
|
Context->UpdateWorldToDeviceMatrix();
|
|
}
|
|
else
|
|
{
|
|
Context->WorldToPage = save;
|
|
WARNING(("Matrix is non-invertible"));
|
|
status = InvalidParameter;
|
|
}
|
|
return status;
|
|
}
|
|
|
|
GpStatus
|
|
GpGraphics::RotateWorldTransform(REAL angle, GpMatrixOrder order)
|
|
{
|
|
GpStatus status = Ok;
|
|
GpMatrix save = Context->WorldToPage;
|
|
|
|
Context->WorldToPage.Rotate(angle, order);
|
|
|
|
// Keep the WorldToPage transform invertible
|
|
if (Context->WorldToPage.IsInvertible())
|
|
{
|
|
if (IsRecording())
|
|
{
|
|
status = Metafile->RecordRotateWorldTransform(angle, order);
|
|
}
|
|
Context->InverseOk = FALSE;
|
|
Context->UpdateWorldToDeviceMatrix();
|
|
}
|
|
else
|
|
{
|
|
Context->WorldToPage = save;
|
|
WARNING(("Matrix is non-invertible"));
|
|
status = InvalidParameter;
|
|
}
|
|
return status;
|
|
}
|
|
|
|
/**************************************************************************\
|
|
*
|
|
* Function Description:
|
|
*
|
|
* Set the page transformation using the specified units and scale.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* [IN] unit - the type of units to use
|
|
* [IN] scale - any additional scale to use. For example, if you wanted
|
|
* the page to be described in terms of feet, you'd set the
|
|
* units to be inches and set the scale to be 12.
|
|
*
|
|
* Return Value:
|
|
*
|
|
* GpStatus - Ok or failure status
|
|
*
|
|
* Created:
|
|
*
|
|
* 3/8/1999 DCurtis
|
|
*
|
|
\**************************************************************************/
|
|
GpStatus
|
|
GpGraphics::SetPageTransform(
|
|
GpPageUnit unit,
|
|
REAL scale
|
|
)
|
|
{
|
|
GpStatus status = Ok;
|
|
|
|
if ((scale < 0.000000001) || (scale > 1000000000))
|
|
{
|
|
status = InvalidParameter;
|
|
}
|
|
else
|
|
{
|
|
switch (unit)
|
|
{
|
|
case UnitDisplay: // Variable
|
|
case UnitPixel: // Each unit is one device pixel.
|
|
case UnitPoint: // Each unit is a printer's point, or 1/72 inch.
|
|
case UnitInch: // Each unit is 1 inch.
|
|
case UnitDocument: // Each unit is 1/300 inch.
|
|
case UnitMillimeter: // Each unit is 1 millimeter.
|
|
if (IsRecording() &&
|
|
((unit != Context->PageUnit) || (scale != Context->PageScale)))
|
|
{
|
|
status = Metafile->RecordSetPageTransform(unit, scale);
|
|
}
|
|
Context->PageUnit = unit;
|
|
Context->PageScale = scale;
|
|
Context->GetPageMultipliers();
|
|
Context->UpdateWorldToDeviceMatrix();
|
|
break;
|
|
default:
|
|
ASSERT(0);
|
|
status = InvalidParameter;
|
|
break;
|
|
}
|
|
}
|
|
return status;
|
|
}
|
|
|
|
/**************************************************************************\
|
|
*
|
|
* Function Description:
|
|
*
|
|
* Convert the points from one coordinate space to another.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* [IN] source - the coordinate space of the source points
|
|
* [IN] dest - the coordinate space to convert the points to
|
|
* [IN/OUT] points - the points to convert
|
|
* [IN] count - the number of points to convert
|
|
*
|
|
* Return Value:
|
|
*
|
|
* GpStatus - Ok or failure status
|
|
*
|
|
* Created:
|
|
*
|
|
* 3/8/1999 DCurtis
|
|
*
|
|
\**************************************************************************/
|
|
GpStatus
|
|
GpGraphics::TransformPoints(
|
|
GpPointF * points,
|
|
INT count,
|
|
GpCoordinateSpace source,
|
|
GpCoordinateSpace dest
|
|
)
|
|
{
|
|
if (source != dest)
|
|
{
|
|
GpMatrix m;
|
|
GpMatrix * matrix;
|
|
|
|
switch (source)
|
|
{
|
|
case CoordinateSpaceWorld:
|
|
switch (dest)
|
|
{
|
|
case CoordinateSpacePage:
|
|
matrix = &(Context->WorldToPage);
|
|
break;
|
|
|
|
case CoordinateSpaceDevice:
|
|
matrix = &(Context->WorldToDevice);
|
|
break;
|
|
|
|
default:
|
|
return InvalidParameter;
|
|
}
|
|
break;
|
|
|
|
case CoordinateSpacePage:
|
|
matrix = &m;
|
|
switch (dest)
|
|
{
|
|
case CoordinateSpaceWorld:
|
|
m = Context->WorldToPage;
|
|
m.Invert();
|
|
break;
|
|
|
|
case CoordinateSpaceDevice:
|
|
m.Scale(Context->PageMultiplierX, Context->PageMultiplierY);
|
|
break;
|
|
|
|
default:
|
|
return InvalidParameter;
|
|
}
|
|
break;
|
|
|
|
case CoordinateSpaceDevice:
|
|
matrix = &m;
|
|
switch (dest)
|
|
{
|
|
case CoordinateSpaceWorld:
|
|
GetDeviceToWorldTransform(&m);
|
|
break;
|
|
|
|
case CoordinateSpacePage:
|
|
{
|
|
REAL scaleX = 1 / Context->PageMultiplierX;
|
|
REAL scaleY = 1 / Context->PageMultiplierY;
|
|
m.Scale (scaleX, scaleY);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
return InvalidParameter;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
return InvalidParameter;
|
|
}
|
|
matrix->Transform(points, count);
|
|
}
|
|
|
|
return Ok;
|
|
}
|
|
|