Programming Examples

Are you a Programmer or Application Developer or a DBA? Take a cup of coffee, sit back and spend few minutes here :)

Custom Mapping Mode in VC++ Via MM_ISOTROPIC

1. Introduction

In the previous MFC Article, we examined how the Mapping Modes works while performing the drawing operation. In this example, we will see how we set the custom mapping modes. Our goal is below:

  1. Set mapping mode so that the horizontal logical unit is 1 Centimeter (cm). Simply, 1 Unit = 1 cm in X axis.

2) Also, 1 Unit = 1 cm in Y Axis.
3) Positive X is towards left.
4) Positive Y is going Upwards.
5) The Drawing origin should be in screen center.

We can achieve the above goal by using the Custom Mapping mode MM_ISOTROPIC.

2. The Custom Mapping Mode

To achieve the above, we need to use the Custom Mapping mode. From the previous article, you may now know that the mapping modes MM_ISOTROPIC, MM_ANISOTROPIC are custom mapping modes. In MM_ISOTROPIC mode, both X and Y-axis represents the same unit of measure. If X-axis represents 1 logical unit as 1 mm, then Y-axis also represents 1 logical unit as 1 mm. In MM_ANISOTROPIC X and Y need not to have equal units. In our example, we are going to use the MM_ISOTROPIC mode.

3. About the Example

Have a look at the below depiction:

Drawing in C.M via Custom Mapping Mode
Drawing in C.M via Custom Mapping Mode

In this example, we are going to draw X Axis and Y Axis and then draw an ellipse. The ellipse will have 8 cm major axis and 4 cm minor axis when measured in the hard copy. So for achieving this drawing, we should set a mapping mode which will see one unit as 1 centimeter. Also, note that we should shift the origin to the center of the screen.

OK. Let us walk through how do we create this example.

4. Coding the Custom Mapping Mode Example

4.1 Set MM_ISOTROPIC Mapping Mode

First we create a MFC Single Document Interface (SDI) application and in the  OnPaint Handler, we will perform the drawing specified above. First, we need to set the mapping mode as ISOTROPIC via the constant MM_ISOTROPIC. In this example we specified the ISOTROPIC mapping mode as both X and Y-axis has the same unit of measure. Recall, our requirement is to have one logical drawing unit as one centimeter. Below is code to set the mapping mode:

4.2 Get Screen Resolution in Logical Unit

After setting the mapping mode, we get the screen resolution in MM by making a call to the  GetDeviceCaps function. We pass HORZSIZE, VERTSIZEto get screen width and height. The size returned in mm is based on the current resolution. Finally, we stored the screen size in mm in the variables width_in_mm and height_in_mm.

The picture shown below tells that the 1 pixel is represented as 0.3525 mm approximately. Note the monitor size may vary and the hard copy print out when measured provides the same unique value.

Screen Resolution and Logical Measure
Screen Resolution and Logical Measure

4.3 Get Screen Resolution in Pixels

Once we have Screen resolution in mm, we need to get the screen resolution in pixels. We use the same GetDeviceCaps function to get the screen resolution in pixels. Note, this time we pass HORZRES & VERTRES to the function. Below is the code:

4.4 Setup Custom Logical Coordinate Units

Before we proceed, have a look at the below picture:

Window and Viewport Extends vs Pixels
Window and Viewport Extends vs Pixels

4.1 Logical Extends and Pixel Mapping

In the above picture, we can see how the Window and View-Port Extends works together. Here, let us assume, the Gray boxes are 1×1 pixels. The Red line shows how the window is divided by logical measure, say, for example, imagine like this, we divide the screen dimension of 7×5 mm as 4 horizontal extends and 3 vertical extends. We can use this same technique in the below-given code.

4.2 Understanding the ViewPort and Window Extends

In the above code we specified unit of measure for both Device & Logical Coordinates.

SetViewportExt function call will set the Device Coordinate System’s unit of measure. Let us say the resolution is 800×600 pixels. The above code divides the screen as 800 horizontal extents and 600 vertical extents. This means each unit represents one pixel; for example, if we say 10 units in device coordinate, then it is 10 pixels. For same 800×600 resolution, the screen size measured was 282×212 mm (Refer Section 4.2). Now, using the SetWindowExt function call, we divided the screen width as 28 extents and screen height as 21 extents. This way, each unit measures 1 cm in the Logical Coordinate System.

OK. What is the value of defining the extents? Let us start with a precise explanation that may help you figure out the coordinate transformation in terms of Pixels versus Logical units. From the above picture, we can see the Device Coordinate System uses the Gray lines (pixels) as Unit of Measure and the Logical Co-ordinate system uses Red lines as a unit of measures. MFC Framework and Win32 APIs use both the coordinate systems. For example, the WM_LBUTTONUP uses the device coordinate system to specify the mouse cursor location in terms of (x, y) pixels. Whereas, the drawing functions exposed by the CDC (Device Context) expects the Logical Coordinate System.

4.3 Coordinate Conversion – Device vs Logical Units

Now, think how a user can draw a 10 cm line by using the mouse. Here, MFC framework demands a coordinate conversion. Your code may go like this:

  1. The mouse events capture the Line start and end.
  2. But drawing functions exposed by the Device Context expects the unit in terms of Logical units. This comes handy when performing the print-out. When user drawn something in MM scale, the printout measures same mm. So we end up converting the Start point &  end points in Device Units (Pixels) into Logical units.
  3. After the conversion, we pass these converted points (Dimensions) to the Line Drawing function.

Now, we know how an application developer Device and Logical units are used. There are two conversions possible:

  • Device Unit to Logical Unit (API: DPtoLP)
  • Logical Unit to Device Unit (API: LPtoLP)

In our previous article we learned that all co-ordinate except MM_ISOTROPIC and MM_ANISOTROPIC have the pre-defined mappings. MM_ISOTROPIC & MM_ANISOTROPIC mapping modes are custom mapping modes and that means we decide our own mapping between Logical and Physical unit. In this example, we are not going to use mouse drawing so the conversion is not required.

4.4 Set MFC Drawing Origin to Screen Center

Next, we shifted the viewport origin towards the center of the screen. Below is the code which uses the SetViewportOrg API:

4.5 Drawing the Ellipse in CM Using Custom Mapping Mode

After shifting the drawing origin to the screen center, we draw the x-axis and y-axis using the MoveTo, LineTofunctions. Note, these functions expect the parameters in Logical Units. Next using the device context we draw an ellipse to the screen. Now all the units stated here are in Centimeter.

Source Code: Download Custom Mapping Mode Example

Categories: MFC

Tags: , , , ,

Do you like this Example? Please comment about it for others!!

This site uses Akismet to reduce spam. Learn how your comment data is processed.