CS-460/560, Week 8-B
Spring, 1998
R. Eckert


For DC coordinates up to now we've used the default system "Device
Units." For a video screen these are pixels measured from upper left
corner of screen. For a printer these are printer dots measured from
upper left corner of printed page.

Problem--not all pixels/dots are same size. i.e., a nice picture on a
screen output to a laser printer --> postage stamp! (printer dots
closer together than screen pixels).

Mapping modes--We can create logical system of units for
text/graphics. Windows then maps the output to any real device. E.g.,
if we plot at 100,100 "logical millimeters" Windows will try to figure
out where that lies on your screen. (Not exact, but close). For
printers, will be very close.


MM_TEXT        Pixel                   Right     Down  (Default)
MM_HIENGLISH   .001 inch               Right     Up
MM_LOENGLISH   .01 inch                Right     Up
MM_HIMETRIC    .01 mm                  Right     Up
MM_LOMETRIC    .1 mm                   Right     Up
MM_TWIPS       1/20 point=1/1440 inch  Right     Up
MM_ISOTROPIC   Arbitrary (x==y)          Selectable
MM_ANISOTROPIC Arbitrary (x!=y)          Selectable

Change mapping mode with: SetMapMode(hDC, MODE);

Windows maps logical coordinates to device coordinates (units=pixels,
+x: toward right, +y toward bottom).

MAPPING--Windows converts logical ("window") coordinates to device
("viewport") coordinates using the following:

xV = (xVExt/xWExt) * (xW - xWOrg) + xVOrg
yV = (yVExt/yWext) * (yW - yWOrg) + yVOrg

where point (xW,yW) is transformed to (xV,yV)

(xWOrg,yWOrg) and (xVOrg,yVOrg) are the origins of the window and
viewport, both are (0,0) in the default device context. (xWOrg,yWOrg)
maps to (xVOrg,yVOrg)

Moving Origin--Since all modes have initial origin at (0,0), when we
change modes, the picture may appear to be gone. Could use negative y
values; but better to move origin.

  SetWindowOrgEx(hDC,x,y,NULL); /* mappping mode logical units */
  (For x,y positive, think of this as moving the upper left-hand
  corner of the screen/paper up and right by (x,y) logical units.)

  SetVieportOrgEx(hDC,x,y,NULL); /* device units--pixels */
  (For x,y positive, think of this as moving the lower left-hand
  corner of the logical window down and right by (x,y) device units.)

Both move the coordinate system origin to (x,y), but units of x,y are

Very common: SetWindowOrgEx() to move logical origin to bottom left
corner of client area. Then change mapping mode to draw with logical
coords of the new mapping mode.

Typical sequence to set Mapping Mode to MM_LOENGLISH, move origin to
bottom left corner of client area, and draw--

SIZE size;
hDC = GetDC (hWnd);
GetWindowExtEx (hDC, &size);  /* returns x,y in SIZE structure */
              /* since in MM_TEXT mode, client area size in device units=pixels; */
SetViewportOrgEx (hDC, 0, size.cy));
/* Now can draw using 0.01 inch logical coords. /*
/* Origin is at lower left hand corner of client area. */
ReleaseDC (hDc);


Coordinate axes can have any unit size/orientation

MM_ISOTROPIC-- x and y units must be the same size
MM_ANISOTROPIC-- different x and y units

Can set the X and Y scaling factors with:

SetWindowExtEx (hDC, xWExt, yWExt, NULL);
SetViewportExtEx (hDC, xVExt, yVExt, NULL);

X scaling factor in going from Logical Coordinates to Device
Coordinates = xVExt/xWExt

Y scaling factor = yVExt/yWExt

To reverse either axis, set one of the Ext values to a negative

EXAMPLE 1--Create a coordinate system where each logical unit is two
pixels (twice the default device unit coordinates)--

hDC = GetDC (hWnd);
SetWindowExtEx (hDC, 1, 1, NULL);
SetViewportExtEx (hDC, 2, 2, NULL);

EXAMPLE 2--Create a logical coordinate system w/ y-axis up, each y-
unit = 1/4 pixel; x-axis unchanged--

hDC = GetDC (hWnd);
SetWindowExtEx (hDC, 1, -4, NULL);
SetViewportExtEx (hDC, 1, 1, NULL);

Common use of MM_ANISOTROPIC mode: Create coordinate system where
window's client area has same logical width and height.

EXAMPLE 3--Create a coord system where client area is always 1000
units high and wide, y-axis up--

SIZE size;
hDC = GetDC (hWnd);
GetWindowExtEx (hDC, &size); /* get client area size */
   /* returns size always in default device units--here pixels */
SetWindowExtEx (hDC, 1000, -1000);
SetViewportExtEx (hDC, size.cx, size.cy);

Now, x=1000 will be at the right edge of the client area, y=1000 will
be at the top of the client area, regardless of any resizing done by
the user. (The origin would have to be moved down to the lower left-
hand corner of the client area also.)