The Bounding Box

The Rectangle, Ellipse, RoundRect, Chord, and Pie functions (as well as the Arc line-drawing function) are all similar in that they are built up from a rectangular ”bounding box.“ You define the coordinates of a box that encloses the object—a bounding box—and Windows draws the object within this box.

The simplest filled object is the rectangle:

Rectangle (hdc, xLeft, yTop, xRight, yBottom) ;

The point (xLeft, yTop) is the upper left corner of the rectangle, and (xRight, yBottom) is the lower right corner; both points are expressed in logical units. A figure drawn using the Rectangle function is shown in Figure 12-4. In the MM_TEXT mapping mode, xRight must be greater than xLeft, and yBottom must be greater than yTop. However, in all the other mapping modes (except possibly MM_ISOTROPIC and MM_ANISOTROPIC), the value of yBottom is less than that of yTop because the coordinates on the y-axis increase as you move up.

Programmers who have worked with graphics before are accustomed to the problem of being off by 1 pixel. Some graphics systems draw a figure to encompass the right and bottom coordinates, and some draw figures up to (but not including) the right and bottom coordinates. Windows uses the latter approach, but there's an easier way to think about it.

Consider the function call:

Rectangle (hdc, 1, 1, 5, 4) ;

I mentioned above that Windows draws the figure within a ”bounding box.“ You can think of the display as a grid where each pixel is within a grid cell. The imaginary bounding box is drawn on the grid, and the rectangle is then drawn within this bounding box. Here's how the figure would be drawn in the MM_TEXT mapping mode:

The area separating the rectangle from the top and left of the client area is 1 pixel wide. Windows uses the current brush to color the 2 pixels on the inside of the rectangle.

For all pen styles except PS_INSIDEFRAME, if the pen used to draw the outline is greater than 1 pixel wide, then the pen is centered on the border so that part of the line may be outside the bounding box. For the PS_INSIDEFRAME pen style, the entire line is drawn inside the bounding box.

Once you know how to draw a rectangle, then you also know how to draw an ellipse, because it uses the same parameters:

Ellipse (hdc, xLeft, yTop, xRight, yBottom) ;

A figure drawn using the Ellipse function is shown (with the imaginary bounding box) in Figure 12-5.

Windows does not include ”square“ or ”circle“ functions. In all mapping modes except MM_TEXT and MM_ANISOTROPIC, you can easily draw squares and circles using the Rectangle and Ellipse functions by making the difference between xLeft and xRight the same as the difference between yTop and yBottom. In MM_TEXT, squares and circles are a little more difficult. You have to call GetDeviceCaps with the ASPECTX and ASPECTY indexes and scale the dimensions based on the aspect ratio of the pixels. In MM_ANISOTROPIC, you also have to take into account the ratio of the window and viewport extents.

The function to draw rectangles with rounded corners uses the same bounding box as the Rectangle and Ellipse functions but includes two more parameters:

RoundRect (hdc, xLeft, yTop, xRight, yBottom,

xCornerEllipse, yCornerEllipse) ;

A figure drawn using this function is shown in Figure 12-6.

Windows uses a small ellipse to draw the rounded corners. The width of this ellipse is xCornerEllipse, and the height is yCornerEllipse, with both points expressed in logical units. Imagine Windows splitting this small ellipse into four quadrants and using one quadrant for each of the four corners. The rounding of the corners is more pronounced for larger values of xCornerEllipse and yCornerEllipse. If xCornerEllipse is equal to the difference between xLeft and xRight and yCornerEllipse is equal to the difference between yTop and yBottom, then the RoundRect function will draw an ellipse.

The rounded rectangle shown in Figure 12-6 was drawn using the MM_TEXT mapping mode with the corner ellipse dimensions calculated with these formulas:

xCornerEllipse = (xRight - xLeft) / 4 ;

yCornerEllipse = (yBottom - yTop) / 4 ;

This is an easy approach, but the results admittedly don't look quite right, because the rounding of the corners is more pronounced along the larger rectangle dimension. To

correct this problem, you'll probably want to make xCornerEllipse equal to yCornerEllipse in real dimensions.

The Arc, Chord, and Pie functions all take identical parameters:

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

xStart, yStart, xEnd, yEnd) ;

Chord (hdc, xLeft, yTop, xRight, yBottom,

xStart, yStart, xEnd, yEnd) ;

Pie (hdc, xLeft, yTop, xRight, yBottom,

xStart, yStart, xEnd, yEnd) ;

A line drawn using the Arc function is shown in Figure 12-7; figures drawn using the Chord and Pie functions are shown in Figures 12-8 and 12-9.

Windows uses an imaginary line to connect (xStart, yStart) with the center of the ellipse. At the point at which that line intersects the ellipse, Windows begins drawing an arc in a counterclockwise direction around the circumference of the ellipse. Windows also uses an imaginary line to connect (xEnd, yEnd) with the center of the ellipse. At the point at which that line intersects the ellipse, Windows stops drawing the arc.

For the Arc function, Windows is now finished, because the arc is an elliptical line rather than a filled area. For the Chord function, Windows connects the endpoints of the arc. For the Pie function, Windows connects each endpoint of the arc with the center of the ellipse. The interiors of the chord and pie-wedge figures are filled with the current brush.