图形基础-映射模式--英文

The MM_ISOTROPIC Mapping Mode

The MM_ISOTROPIC mapping mode is ideal for using arbitrarily scaled axes while preserving equal logical units on the two axes. Rectangles with equal logical widths and heights are displayed as squares, and ellipses with equal logical widths and heights are displayed as circles.

When you first set the mapping mode to MM_ISOTROPIC, Windows uses the same window and viewport extents that it uses with MM_LOMETRIC. (Don't rely on this fact, however.) The difference is that you can now change the extents to suit your preferences by calling SetWindowExtEx and SetViewportExtEx. Windows will then adjust the extents so that the logical units on both axes represent equal physical distances.

Generally, you'll use arguments to SetWindowExtEx with the desired logical size of the logical windows, and arguments to SetViewportExtEx with the actual height and width of the client area. When Windows adjusts these extents, it has to fit the logical window within the physical viewport, which can result in a section of the client area falling outside the logical window. You should call SetWindowExtEx before you call SetViewportExtEx to make the most efficient use of space in the client area.

For example, suppose you want a traditional one-quadrant virtual coordinate system where (0, 0) is at the lower left corner of the client area and the logical width and height ranges from 0 to 32,767. You want the x and y units to have the same physical dimensions. Here's what you need to do:

SetMapMode (hdc, MM_ISOTROPIC) ;
SetWindowExtEx (hdc, 32767, 32767, NULL) ;
SetViewportExtEx (hdc, cxClient, -cyClient, NULL) ;
SetViewportOrgEx (hdc, 0, cyClient, NULL) ;

If you then obtain the window and viewport extents using GetWindowExtEx and GetViewportExtEx, you'll find that they are not the values you specified. Windows has adjusted the extents based on the aspect ratio of the display device so that logical units on the two axes represent the same physical dimensions.

If the client area is wider than it is high (in physical dimensions), Windows adjusts the x extents so that the logical window is narrower than the client-area viewport. The logical window will be positioned at the left of the client area:

Windows 98 will actually not allow you to display anything in the right side of the client area because it is limited to 16-bit signed coordinates. Windows NT uses a full 32-bits for coordinates, and you would be able to display something over in the right side.

If the client area is higher than it is wide (in physical dimensions), Windows adjust the y extents. The logical window will be positioned at the bottom of the client area:

Windows 98 will not allow you to display anything at the top of the client area.

If you prefer that the logical window always be positioned at the left and top of the client area, you can change the code to the following:

SetMapMode (MM_ISOTROPIC) ;
SetWindowExtEx (hdc, 32767, 32767, NULL) ;
SetViewportExtEx (hdc, cxClient, -cyClient, NULL) ;
SetWindowOrgEx (hdc, 0, 32767, NULL) ;

In the SetWindowOrgEx call, we're saying that we want the logical point (0, 32767) to be mapped to the device point (0, 0). Now, if the client area is higher than it is wide, the coordinates are arranged like this:

For a clock program, you might want to use a four-quadrant Cartesian coordinate system with arbitrarily scaled axes in four directions in which the logical point (0, 0) is in the center of the client area. If you want each axis to range from 0 to 1000 (for instance), you use this code:

SetMapMode (hdc, MM_ISOTROPIC) ;
SetWindowExtEx (hdc, 1000, 1000, NULL) ;
SetViewportExtEx (hdc, cxClient / 2, -cyClient / 2, NULL) ;
SetViewportOrgEx (hdc, cxClient / 2, cyClient / 2, NULL) ;

The logical coordinates look like this if the client area is wider than it is high:

The logical coordinates are also centered if the client area is higher than it is wide, as shown below.

Keep in mind that no clipping is implied in window or viewport extents. When calling GDI functions, you are still free to use logical x and y values less than -1000 and greater than +1000. Depending on the shape of the client area, these points might or might not be visible.

With the MM_ISOTROPIC mapping mode, you can make logical units larger than pixels. For instance, suppose you want a mapping mode with the point (0, 0) at the upper left corner of the display and values of y increasing as you move down (like MM_TEXT) but with logical coordinates in sixteenths of an inch. Here's one way to do it:

SetMapMode (hdc, MM_ISOTROPIC) ;
SetWindowExtEx (hdc, 16, 16, NULL) ;
SetViewportExtEx (hdc, GetDeviceCaps (hdc, LOGPIXELSX),
                       GetDeviceCaps (hdc, LOGPIXELSY), NULL) ;

The arguments to the SetWindowExtEx function indicate the number of logical units in one inch. The arguments to the SetViewportExtEx function indicate the number of physical units (pixels) in one inch.

However, this approach would not be consistent with the metric mapping modes in Windows NT. These mapping modes use the pixel size and metric size of the display. To be consistent with the metric mapping modes, you can use this code:

SetMapMode (hdc, MM_ISOTROPIC) ;
SetWindowExtEx (hdc, 160 * GetDeviceCaps (hdc, HORZSIZE) / 254,
                     160 * GetDeviceCaps (hdc, VERTSIZE) / 254, NULL) ;
SetViewportExtEx (hdc, GetDeviceCaps (hdc, HORZRES),
                       GetDeviceCaps (hdc, VERTRES), NULL) ;

In this code, the viewport extents are set to the pixel dimensions of the entire screen. The window extents are set to the assumed dimension of the screen in units of sixteenths of an inch. GetDeviceCaps with the HORZRES and VERTRES indexes return the dimensions of the device in millimeters. If we were working with floating-point numbers, we would convert the millimeters to inches by dividing by 25.4 and then convert inches to sixteenths of an inch by multiplying by 16. However, because we're working with integers, we must multiply by 160 and divide by 254.

Of course, such a coordinate system makes logical units much larger than physical units. Everything you draw on the device will have coordinate values that map to an increment of 1/16 inch. You cannot draw two horizontal lines that are 1/32 inch apart because that would require a fractional logical coordinate.

MM_ANISOTROPIC: Stretching the Image to Fit

When you set the viewport and window extents in the MM_ISOTROPIC mapping mode, Windows adjusts the values so that logical units on the two axes have the same physical dimensions. In the MM_ANISOTROPIC mapping mode, Windows makes no adjustments to the values you set. This means that MM_ANISOTROPIC does not necessarily maintain the correct aspect ratio.

One way you can use MM_ANISOTROPIC is to have arbitrary coordinates for the client area, as we did with MM_ISOTROPIC. This code sets the point (0, 0) at the lower left corner of the client area with the x and y axes ranging from 0 to 32,767:

SetMapMode (hdc, MM_ANISOTROPIC) ;
SetWindowExtEx (hdc, 32767, 32767, NULL) ;
SetViewportExtEx (hdc, cxClient, -cyClient, NULL) ;
SetViewportOrgEx (hdc, 0, cyClient, NULL) ;

With MM_ISOTROPIC, similar code caused part of the client area to be beyond the range of the axes. With MM_ANISOTROPIC, the upper right corner of the client area is always the point (32767, 32767), regardless of its dimensions. If the client area is not square, logical x and y units will have different physical dimensions.

In the previous section on the MM_ISOTROPIC mapping mode, I discussed how you might draw a round clock in the client area where the x and y axes ranged from -1000 to 1000. You can do something similar with MM_ANISOTROPIC:

SetMapMode (hdc, MM_ANISOTROPIC) ;
SetWindowExtEx (hdc, 1000, 1000, NULL) ;
SetViewportExtEx (hdc, cxClient / 2, -cyClient / 2, NULL) ;
SetViewportOrgEx (hdc, cxClient / 2, cyClient / 2, NULL) ;

The difference with MM_ANISOTROPIC is that in general the clock would be drawn as an ellipse rather than a circle.

Another way to use MM_ANISOTROPIC is to set x and y units to fixed but unequal values. For instance, if you have a program that displays only text, you may want to set coarse coordinates based on the height and width of a single character:

SetMapMode (hdc, MM_ANISOTROPIC) ;
SetWindowExtEx (hdc, 1, 1, NULL) ;
SetViewportExtEx (hdc, cxChar, cyChar, NULL) ;

Of course, I've assumed that cxChar and cyChar are the width and height of characters in that font. Now you can specify coordinates in terms of character rows and columns. For instance, the following statement displays text three characters from the left and two character rows from the top of the client area:

TextOut (hdc, 3, 2, TEXT ("Hello"), 5) ;

This might be more appropriate if you're using a fixed-point font, as in the upcoming WHATSIZE program.

When you first set the MM_ANISOTROPIC mapping mode, it always inherits the extents of the previously set mapping mode. This can be very convenient. One way of thinking about MM_ANISTROPIC is that it "unlocks" the extents; that is, it allows you to change the extents of an otherwise fully-constrained mapping mode. For instance, suppose you want to use the MM_LOENGLISH mapping mode because you want logical units to be 0.01 inch. But you don't want the values along the y-axis to increase as you move up the screen—you prefer the MM_TEXT orientation, where y values increase moving down. Here's the code:

SIZE size ;
[other program lines]
SetMapMode (hdc, MM_LOENGLISH) ;
SetMapMode (hdc, MM_ANISOTROPIC) ;
GetViewportExtEx (hdc, &size) ;
SetViewportExtEx (hdc, size.cx, -size.cy, NULL) ;

We first set the mapping mode to MM_LOENGLISH. Then we liberate the extents by setting the mapping mode to MM_ANISOTROPIC. The GetViewportExtEx function obtains the viewport extents in a SIZE structure. Then we call SetViewportExtEx with the extents, except that the y extent is made negative.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值