GDI Mapping Modes Explained
Date:
8 May 1997
Author:
Rich
Goldstein, MD
(
mailto:goldstei@interport.net
goldstei@interport.net
)
Overview
Each device context
(DC, represented by TDC and derivatives in OWL) has the ability
to maintain a coordinate system separate and distinct from the
device it represents. So while the display may be a 640x480 or
800x600 or whatever pixels in dimension, we can tell the DC that
the coordinate space uses some other units.
The result is the
existence of 2 coordinate systems: the
DEVICE
coordinate system, and the
LOGICAL
coordinate
system.
In general,
DEVICE
coordinates are established by the device or it's related
drivers. So for the monitor, the display driver determines the
DEVICE
coordinates (0,0 in the top left, width,height in pixels in the
lower right). These are rarely if ever changed programmatically
(the exceptions, of course, include changing screen or printer
resolution, or paper orientation, etc.).
The
LOGICAL
coordinates relate to the device context (DC) and are established
by the mapping mode, viewport origin and extents, and window
origin and extents. All DC related functions accept
LOGICAL
coordinates, unless explicitly stated (e.g. DPtoLP, which
converts
DEVICE
coordinates to
LOGICAL
coordinates).
The system maps
your
LOGICAL
coordinates to the
DEVICE
coordinates using the viewport/window origins and extents.
So WHAT ARE THEY,
ALREADY???
Origins
OK, let's start
with the window, which is expressed in
LOGICAL
coordinates.
SetWindowOrg()
tells the DC the
LOGICAL
point that maps to the
DEVICE
point (0,0). So if you call
SetWindowOrg(100,100)
for a window, the
LOGICAL
point (100,100) occurs
in the top left corner. (Hold on, this was the easy one...)
SetViewportOrg()
tells the DC which
DEVICE
coordinate maps to
LOGICAL
point (0,0). So calling
SetViewportOrg()
with half the width and height of your window (in pixels), for
example, sets the
LOGICAL
point (0,0) to the
center of the window.
SetWindowOrg()
and
SetViewportOrg()
can be called on
any Mapping Mode. They serve to offset the origin of one system
within the other. They have no effect on the relative distances
specified by the two coordinate systems.
Advanced
Note:
Believe
it or not, there are some (though few) reasons to use
BOTH SetWindowOrg() and SetViewportOrg(). OWL's TScroller
provides one such opportunity. In AutoOrg mode, the
TScroller calls SetViewportOrg in it's BeginView member
function, which is called before Paint is called. If your
LOGICAL
coordinate system uses an origin
other that the top-left of the window, you can call
SetWindowOrg in the Paint method to choose some other
origin. Because both functions can be used safely
together, you can let TScroller adjust the Viewport
origin to facilitate scrolling, and you can adjust the
Window origin to facilitate alternative coordinate
systems.
Mapping Modes
There are several
mapping modes, some of which are constrained to a fixed
relationship between
DEVICE
and
LOGICAL
coordinate systems. Here is the list:
Name/Constant
Constrained?
Logical
Unit
MM_TEXT
(default)
Yes
Pixel
MM_LOENGLISH
Yes
0.01
inch
MM_HIENGLISH
Yes
0.001
inch
MM_LOMETRIC
Yes
0.1
mm
MM_HIMETRIC
Yes
0.01
mm
MM_TWIPS
Yes
1/20
of a point, or 1/1440 of an inch
MM_ISOTROPIC
No
User
Defined
MM_ANISOTROPIC
No
User
Defined
For the 'constrained' modes, all
you are allowed is to change the origin of the logical system
using either
SetWindowOrg
or
SetViewportOrg
.
This means that if I set the
mapping mode to
MM_LOENGLISH
, the point (0,0)
and (0,100) are 1 inch apart (1 Logical inch, defined by the
device capabilities, see
GetDeviceCaps()
)
Extents
Extents are a little trickier,
because how they are interpreted depends on the mapping mode.
They are only appropriate for the non-constrained modes,
MM_ISOTROPIC
and
MM_ANISOTROPIC
.
The difference between these two
modes is that
MM_ISOTROPIC
takes the parameters
you pass to
SetViewportExt
and
SetWindowExt
as 'suggestions' (
#suggestion
see below
) and adjusts the extents so the the x and
y axis coordinates represent the same distance on the device.
This way, a
LOGICAL
unit in the x direction is
the same length (in terms of the output) as a
LOGICAL
unit in the y direction (this is not intuitive... some printers
may have different resolutions in the two axes... this mode
ensures that the
LOGICAL
units are equivalent in
space).
MM_ANISOTROPIC
differs in that the parameters passed to
SetViewportExt
and
SetWindowExt
are taken literally.
Windows make no adjustment. Therefore, you can have very
different coordinate systems in the two axes.
SetWindowExt
and
SetViewportExt
are used as a team.
These two functions set some internal members in the DC, which
are used to map points between coordinate systems. As such, each
is essentially meaningless taken alone.
SetWindowExt
tells the DC that a rectangle with the
LOGICAL
width and height passed in, has the
DEVICE
width
and height passed in via
SetViewportExt
.
Confused yet?
Let's say that I call
SetViewportExt
for a display device with the parameters 100,50. Taken alone,
that's rather meaningless. Now I call
SetWindowExt
with parameters 100,100. This means that for each
LOGICAL
unit in the x direction, I will move 1
DEVICE
unit. On the other hand, for each
LOGICAL
unit I
move in the y direction, I move 1/2 a unit in the
DEVICE
coordinate.
These functions can also be
called with negative numbers. When the sign of the parameters to
SetWindowExt
and
SetViewportExt
a different, the
direction of the axes changes. So that the positive y direction
can be up,
instead of the
usual default of down, if I call:
SetWindowExt(1,-1);
SetViewportExt(1,1);
One LOGICAL x unit translates to
1
DEVICE
x unit, but 1
LOGICAL
y unit translates to 1
DEVICE
y unit, in the
opposite direction.
Basically, here is the formula
used (by Windows) to convert
LOGICAL
points to
DEVICE
points:
where x
D
= the
DEVICE
coordinate
and x
L
= the
LOGICAL
coordinate
x
D
= (x
L
- xWindowOrg)*(xViewportExt/xWindowExt) +
xViewportOrg
If that makes anything clearer.
How Windows handles extents for
MM_ISOTROPIC
Assuming that
SetWindowExt
is called BEFORE
SetViewportExt
(recommended), how the adjustments are made depends on the actual
physical dimensions of the extents passed to
SetViewportExt
.
Since device coordinates are not necessarily in equal units in
the two axes, they are probably adjusted internally according to
LOGPIXELSX/LOGPIXELSY.
If the physical dimensions of the
Viewport Extents are wider than they are tall, the x extent is
adjusted so that it's
LOGICAL
units are equal to
the
LOGICAL
units for the y axis (as defined by
the y parameters passed to
SetWindowExt
/
SetViewportExt
).
If the physical dimensions of the
Viewport Extents are taller than they are wide, the y extent is
adjusted.
Contents of this
page Copyright ? 1997, Rich Goldstein, MD. All Rights Reserved.
support.html
back
