DRAWING LINES

After drawing points, the next step up is drawing lines. Windows can draw straight lines and elliptical lines. An elliptical line is a curved line on the circumference of an ellipse. The three functions that draw lines are LineTo (straight lines), PolyLine (series of connected lines), and Arc (elliptical lines). Five attributes of the device context affect the appearance of lines that you draw using these functions: current pen position (for LineTo only), pen, background mode (for nonsolid pens), background color (for the OPAQUE background mode), and drawing mode.

The LineTo function is one of the few GDI functions that does not include the full dimensions of the object to be drawn. Instead, LineTo draws a line from the current pen position defined in the device context up to (but not including) the logical point specified in the LineTo function. In the default device context, the current pen position is initially set at the logical point (0, 0). If you call LineTo without first setting the current pen position (or the viewport or window origin), it draws a line starting at the upper left corner of the client area.

To draw a line from the logical point (xStart, yStart) to the logical point (xEnd, yEnd), you first must use MoveTo to set the current pen position to the point (xStart, yStart):

MoveTo (hdc, xStart, yStart) ;

MoveTo doesn't draw anything. It simply changes the current pen position. You can then use LineTo to draw the line:

LineTo (hdc, xEnd, yEnd) ;

This draws the line up to (but not including) the point (xEnd, yEnd). Following the LineTo call, the current pen position is set to (xEnd, yEnd).

LineTo is the only Windows function that uses the current pen position. MoveTo and LineTo are the only functions that change it. You can obtain the current pen position by calling:

dwPoint = GetCurrentPosition (hdc) ;

The dwPoint return value is an unsigned long (or doubleword) that contains the x- coordinate in the low word and the y-coordinate in the high word. You can use the LOWORD and HIWORD macros to extract the two coordinates, or you can convert the value of dwPoint to a POINT structure using the MAKEPOINT macro:

point = MAKEPOINT (dwPoint) ;

The following code draws a grid in the client area of a window, spacing the lines 1 inch apart starting from the upper left corner. The variable hwnd is assumed to be a handle to the window, hdc is a handle to the device context, rect is a structure of type RECT, and x and y are short integers:

SetMapMode (hdc, MM_LOENGLISH) ;

GetClientRect (hwnd, &rect) ;

DPtoLP (hdc, (LPPOINT) &rect, 2) ;

for (x = 0 ; x < rect.right ; x += 100)

{

MoveTo (hdc, x, 0) ;

LineTo (hdc, x, rect.bottom) ;

}

for (y = 0 ; y > rect.bottom ; y -= 100)

{

MoveTo (hdc, 0, y) ;

LineTo (hdc, rect.right, y) ;

}

The dimensions of the client area are saved in the RECT structure called rect and converted to logical points with DPtoLP. After the DPtoLP conversion, rect.right is the width of the client area in units of 0.01 inch, and rect.bottom is the negative height of the client area. Notice that y is decremented rather than incremented in the second for loop because the MM_LOENGLISH mapping mode uses decreasing values of y as you move down the display.

Although it may seem like a nuisance to be forced to use two functions to draw a single line, the current pen position attribute comes in handy when you want to draw a series of connected lines. For instance, you might want to define an array of 5 points (10 values) that draw the outline of a rectangle:

POINT pt [5] = { 100, 100, 200, 100, 200, 200,

100, 200, 100, 100 } ;

Notice that the last point is the same as the first. Now you need only use MoveTo for the first point and LineTo for the successive points:

MoveTo (hdc, pt[0].x, pt[0].y) ;

for (i = 1 ; i < 5 ; i++)

LineTo (hdc, pt[i].x, pt[i].y) ;

Because LineTo draws from the current point up to (but not including) the point in the LineTo function, no coordinate gets written twice by this code. While overwriting points is not a problem with a display, it might not look good on a plotter or with some drawing modes (to be covered shortly).

When you have an array of points that you want connected with lines, you can draw the lines more easily using the PolyLine function. This statement draws the same rectangle as in the code shown above:

PolyLine (hdc, &pt, 5) ;

The last parameter is the number of points. We could also have represented this value by (sizeofpt / sizeof (POINT)). PolyLine has the same effect as an initial MoveTo function followed by multiple LineTo functions. However, PolyLine doesn't use or change the current pen position.

The Arc function is a little more complex. Here's the general syntax:

Arc (hdc, xLeft, yTop, xRight, yBottom,

xStart, yStart, xEnd, yEnd) ;

The Arc function draws a line on the circumference of an ellipse that is bounded by a rectangle with the upper left corner at (xLeft, yTop) and the lower right corner at (xRight, yBottom). The arc starts at the intersection of the ellipse and the line connecting (xStart, yStart) with the center of the ellipse. The arc is drawn counterclockwise around the circumference of the ellipse and ends at the intersection of the ellipse and the line connecting point (xEnd, yEnd) with the center of the ellipse. If you're having trouble visualizing this, don't worry about it: I'll discuss the Arc function in much more detail after we've covered rectangles and ellipses.