













GDI Mapping Modes Explained




Date:
8 May 1997

Author: Rich
Goldstein, MD
  ( mailto:goldstei@interport.netgoldstei@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' (
#suggestionsee 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 xD = the DEVICE
coordinate

  and xL = the LOGICAL
coordinate


     xD
= (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.htmlback 


