25.4 Converting real coordinates to pixel positions
As mentioned before, many of the most interesting kinds of computer graphics are based on equations, drawn from mathematics, and physics. These equations are normally stated in terms of vectors and real numbers. In order to depict images and motions based on mathematics and physics we need to be able to translate back and forth between mathematical cVector
positions and CPoint
pixel locations in an onscreen window.
Windows has some GDI functions of the form SetMapMode
and SetViewport
that are useful in converting between different integer-valued sizes of windows. This is the kind of thing you need to do in, for instance, desktop-publishing when you want to control the physical sizes of printed versions of the images on the screen. But Windows does not have any built-in functions for converting between real numbers and pixels. The author has developed a cRealPixelConverter
class for this purpose. By the way, Java comes with a somewhat similar class called Transformation
built in, though not with all of our special methods supplied. And when you do OpenGL graphics, the transformation from real to pixel coordinates is something that the OpenGL graphics pipeline does for you automatically, with the settings being controlled by your calls to the ::glViewport
method.
Here are the steps for using a cRealPixelConverter. If you want to see the details of the implementation, look in the realpixelconverter.h and realpixelconverter.cpp files.
Declare a cRealPixelConverter
object in a line like
cRealPixelConverter _realpixelconverter Since our View
windows are going to have different sizes, it makes sense to have a dedicated converter for each view.
Tell your cRealPixelConverter
the size of the Real window that you plan to use for the world in which your cVector
values are going to live. This might be done in CPopView::OnCreate, with a line like
_realpixelconverter.setRealWindow(lox, loy, hix, hiy).
Tell your cRealPixelConverter
the size of the pixel window that you are going to be displaying your objects in. We always resize the cRealPixelConverter
's pixel window to match the current size of the onscreen window. This is done by adding a line of code to the view's OnSize
message handler. Your view's OnSize(UINT nType, int cx, int cy)
method gets called (i) at startup, (ii) when you resize the view window by dragging on of its edges, and (iii) when you use the buttons at the View window's upper right-hand corner to minimize, maximize, or return to normal size. The nType
variable tells you if the window's being maximized, minimized, or resized and the cy
and cy
tell you the size of the window's new client area. To tell _realpixelconverter to match its pixel window to the newly resized screen window, we use code like this. Note that we go ahead and call the base class OnSize
function first; in general this is the correct and safe thing to do when you override the handling of a standard message.
void CView::OnSize(UINT nType, int cx, int cy)
{
CView::OnSize(nType, cx, cy);
// TODO: Add your message handler code here
_realpixelconverter.setPixelWindow(cx, cy);
} In the Pop framework, we allow for the different graphics implementations cGraphicsMFC
and cGraphicsOpenGL, both derived from cGraphics. So our CPopView
class has a cGraphics *_pgraphics member, and the actual Pop Framework CPopView::OnSize
method calls _pgraphics->setViewport(cx, cy). A cGraphicsMFC
object has a cRealPixelConverter
member, and the cGraphicsMFC::setViewport
code invokes this member's cRealPixelConverter::setPixelWindow
method.
void CPopView::OnSize(UINT nType, int cx, int cy)
{
CView::OnSize(nType, cx, cy); //Machine code.
_pgraphics->setViewport(cx, cy);
pviewpointcritter()->setAspect((Real)cx/(Real)cy);
//width/height ratio
}
For each object that you want to display, use your cRealPixelConverter's realToPixel
function to convert the real number coordinates of the object into pixel coordinates. In the Pop Framework's graphicsmfc.h there are examples of this in lines like
_realpixelconverter.realToPixel(center.x(), center.y(),
&intx, &inty);
If you need to convert a real number length into a pixel window length use the cRealPixelConverter::realToInt
method.
If you need to turn a window coordinate such as a mouse click location into a real number location, use your cRealPixelConverter::pixelToReal
method. In the Pop Framework's graphicsmfc.h, the cGraphicsMFC::pixelToVector
does this with a line like
_realpixelconverter.pixelToRealintx, inty,
&realx, &realy);
|