“可变比例”映射模式


Windows提供了两种映射模式MM_ISOTROPIC 和 MM_ANISOTROPIC,允许自由改变它们的比例因子、坐标原

点、X轴和Y轴的正方向。

在MM_ISOTROPIC 映射模式下,纵横比总是 1:1 ,无论比例因子如何变化,圆总是圆;

在MM_ANISOTROPIC 映射模式下,X 和 Y 的比例因子可以独立地变化,就是说用它们各自的一个逻辑单位换算

成现实世界中的物理单位大小(如 像素,英寸,厘米,毫米),得到的结果可能是不同的;所以,圆可以被拉扁成椭圆。

 

例1:

void CTestView::OnDraw(CDC* pDC)
{
 CRect rectClient;
 GetClientRect(&rectClient);
 pDC->SetMapMode(MM_ANISOTROPIC);
 pDC->SetWindowExt(1000,1000);         
 pDC->SetViewportExt(rectClient.right, -rectClient.bottom);
 pDC->SetViewportOrg(rectClient.right / 2, rectClient.bottom / 2); pDC->Ellipse(CRect(-500, -500, 500, 500));
}SetWindowExt(1000,1000); // 设置窗口大小为 1000个逻辑单位宽,1000个逻辑单位高
SetViewportExt(rectClient.right, -rectClient.bottom); // 设置窗口大小为 right 像素宽,bottom像素高
SetViewportOrg(rectClient.right/2, rectClient.bottom/2); // 将坐标原点设在窗口中心

可以看出窗口的大小使用了两种单位来表示,一种是逻辑单位,一种是设备单位(这里是像素)。

X轴上 1000 个逻辑单位 =  right 像素,既 1个逻辑单位 = right / 1000 像素;这就是所谓的比例因子了,这里

X比例因子 = right / 1000

Y比例因子 = bottom / 1000

( 注:本例中right、bottom是变量,就是窗口的实际大小,是随着用户的调整动态改变的;当然也可以把它设成固

定的数值,不过如果是这样,图形的大小不会随着窗口大小的变化而变化,总是固的大小。)

无论窗口的实际大小如何改变,X轴上 1000个逻辑单位总是等于窗口的宽, Y轴上1000个逻辑单位总是等于窗口

的高这就是为什么上例中椭圆总是能撑满窗口的原因。

 

SetViewportExt函数中,两个参数的正负决定了X,Y轴的正方向;如上例中X轴右递增,Y轴下递减。

上例画出的图形:

android 映射gson 混淆 安卓映射模式_图形

如果试着把参数 -rectClient.bottom 改成正的 rectClient.bottom ,这样就变成 X轴右递增,Y轴下递增。

再运行程序发现所画出的图形和上图是一样的。 这是因为在这两种情况下 CRect(-500, -500, 500, 500) 里的一对

坐标值 (-500, -500) (500, 500) 恰好表示了矩形中不同对角线上的两个点。原例子中(-500, -500) 位于左下角而

(500, 500) 位于右上角; 第二种情况下,(-500, -500)  位于左上角而 (500, 500) 位于右下角。

 

例2:

void CTestView::OnDraw(CDC* pDC)
{
 CRect rectClient;
 GetClientRect(&rectClient);
 pDC->SetMapMode(MM_ANISOTROPIC);
 pDC->SetWindowExt(1000,1000);         
 pDC->SetViewportExt(rectClient.right, -rectClient.bottom); pDC->Ellipse(CRect(-500, -500, 500, 500));
}

在这个例子中我们把设置窗口原点的这一句去掉了 SetViewportOrg(rectClient.right/2, rectClient.bottom/2);

现在画出的图形变成了:

android 映射gson 混淆 安卓映射模式_windows_02

我们看到图形只画出了 1/4 ,这是因为现在的坐标原点位于窗口的左上角了。现在X和Y轴上的两个坐标值

(-500, -500)、(500, 500)  与原先相比表达了不同的含义,因为整个坐标系已经移位。

 

我们把最后一个函数改成:

pDC->Ellipse(CRect(0, 0, 1000, -1000)); // (0,0) 左上角; (1000,-1000) 右下角


 
编译运行,发现画出的图形与例1是样的。

 

现在继续修改代码,让Y 坐标轴下递增:

void CTestView::OnDraw(CDC* pDC)
{
 CRect rectClient;
 GetClientRect(&rectClient);
 pDC->SetMapMode(MM_ANISOTROPIC);
 pDC->SetWindowExt(1000,1000);         
 pDC->SetViewportExt(rectClient.right, rectClient.bottom); // 第二个参数由负改成正 pDC->Ellipse(CRect(0, 0, 1000, 1000));  
}

再次编译运行,发现还是一模一样!

另外,其中一句代码改成 pDC->SetViewportExt(rectClient.Width(), rectClient.Height()); 也是可以的。

 

From MSDN:

RECT 结构:

typedef struct tagRECT {
   LONG left;
   LONG top;
   LONG right;
   LONG bottom;
} RECT;

RECT 结构定义了一个矩形的左上角坐标和右下角坐标

成员变量:

left

矩形左上角的X坐标

top

矩形左上角的Y坐标

right

矩形右下角的X坐标

bottom

矩形右下角的Y坐标

 

 

class CRect : public tagRECT
{
public:// Constructors
 ...
// Attributes (in addition to RECT members)
 
 int Width() const; // retrieves the width
 
 int Height() const; // returns the height
 
 CSize Size() const; // returns the size
 
 ...
 
};CRect::Width 
int Width( ) const;

返回值:

矩形CRect的宽度

描述:

通过计算 right - left 得到矩形CRect的宽度;结果可能为负值。

注意:

矩形必须是经过规格化的,不然此函数可能会失败。你可以在调用此函数之前先调用 NormalizeRect 函数来规格化矩形。

 

CRect::Height
int Height( ) const;

返回值:

矩形CRect的高度

描述:

通过计算 bottom - top 得到矩形CRect的高度;结果可能为负值。

注意:

矩形必须是经过规格化的,不然此函数可能会失败。你可以在调用此函数之前先调用 NormalizeRect 函数来规格化矩形。