Measuring Coordinates and Areas


In the previous example, you encountered the base struct, Rectangle, which is used to represent the coordinates of a rectangle. GDI+ actually uses several similar structures to represent coordinates or areas. The following table lists the structs that are defined in the System.Drawing namespace.

Open table as spreadsheet

Struct

Main Public Properties

Point

PointF

X, Y

Size

SizeF

Width, Height

Rectangle

RectangleF

Left, Right, Top, Bottom, Width, Height, X, Y, Location, Size

Note that many of these objects have a number of other properties, methods, or operator overloads not listed here. This section just discusses some of the most important ones.

Point and PointF

Point is conceptually the simplest of these structs. Mathematically, it’s completely equivalent to a 2D vector. It contains two public integer properties, which represent how far you move horizontally and vertically from a particular location (perhaps on the screen), as shown in Figure 30-3.

image from book
Figure 30-3

To get from point A to point B, you move 20 units across and 10 units down, marked as x and y on the diagram because this is how they are commonly referred to. The following Point struct represents that line:

  Point ab = new Point(20, 10); Console.WriteLine("Moved {0} across, {1} down", ab.X, ab.Y); 

X and Y are read-write properties, which means that you can also set the values in a Point, like this:

 Point ab = new Point(); ab.X = 20; ab.Y = 10; Console.WriteLine("Moved {0} across, {1} down", ab.X, ab.Y);

Note that although conventionally horizontal and vertical coordinates are referred to as x and y coordinates (lowercase), the corresponding Point properties are X and Y (uppercase) because the usual convention in C# is for public properties to have names that start with an uppercase letter.

PointF is essentially identical to Point, except that X and Y are of type float instead of int. PointF is used when the coordinates are not necessarily integer values. A cast has been defined so that you can implicitly convert from Point to PointF. (Note that because Point and PointF are structs, this cast involves actually making a copy of the data.) There is no corresponding reverse case - to convert from PointF to Point you have to copy the values across, or use one of three conversion methods, Round(), Truncate(), and Ceiling():

  PointF abFloat = new PointF(20.5F, 10.9F); // converting to Point Point ab = new Point(); ab.X = (int)abFloat.X; ab.Y = (int)abFloat.Y; Point ab1 = Point.Round(abFloat); Point ab2 = Point.Truncate(abFloat); Point ab3 = Point.Ceiling(abFloat); // but conversion back to PointF is implicit PointF abFloat2 = ab; 

You might be wondering what a unit is measured in. By default, GDI+ interprets units as pixels along the screen (or printer, whatever the graphics device is); that’s how the Graphics object methods will view any coordinates that they get passed as parameters. For example, the point new Point(20,10) represents 20 pixels across the screen and 10 pixels down. Usually these pixels are measured from the top-left corner of the client area of the window, as has been the case in the examples up to now. However, that won’t always be the case. For example, on some occasions you might want to draw relative to the top-left corner of the whole window (including its border), or even to the top-left corner of the screen. In most cases, however, unless the documentation tells you otherwise, you can assume that you’re talking pixels relative to the top-left corner of the client area.

You learn more on this subject later on, after scrolling is examined, when the three different coordinate systems in use - world, page, and device coordinates - are discussed.

Size and SizeF

Like Point and PointF, sizes come in two varieties. The Size struct is for when you are using int types; SizeF is available if you need to use float types. Otherwise, Size and SizeF are identical. This section focuses on the Size struct.

In many ways, the Size struct is identical to the Point struct. It has two integer properties that represent a distance horizontally and a distance vertically. The main difference is that instead of X and Y, these properties are named Width and Height. You can represent the earlier diagram using this code:

  Size ab = new Size(20,10); Console.WriteLine("Moved {0} across, {1} down", ab.Width, ab.Height); 

Although strictly speaking, Size mathematically represents exactly the same thing as Point; conceptually it is intended to be used in a slightly different way. Point is used when you are talking about where something is, and Size is used when you are talking about how big it is. However, because Size and Point are so closely related, there are even supported conversions between these two:

  Point point = new Point(20, 10); Size size = (Size) point; Point anotherPoint = (Point) size; 

As an example, think about the rectangle you drew earlier, with top-left coordinate (0,0) and size (50,50). The size of this rectangle is (50,50) and might be represented by a Size instance. The bottom-right corner is also at (50,50), but that would be represented by a Point instance. To see the difference, suppose that you draw the rectangle in a different location, so its top-left coordinate is at (10,10):

  dc.DrawRectangle(bluePen, 10,10,50,50); 

Now the bottom-right corner is at coordinate (60,60), but the size is unchanged at (50,50).

The addition operator has been overloaded for Point and Size structs, so that it is possible to add a Size to a Point struct, resulting in another Point struct:

  static void Main(string[] args) {    Point topLeft = new Point(10,10);    Size rectangleSize = new Size(50,50);    Point bottomRight = topLeft + rectangleSize;    Console.WriteLine("topLeft = " + topLeft);    Console.WriteLine("bottomRight = " + bottomRight);    Console.WriteLine("Size = " + rectangleSize); } 

This code, running as a simple console application called PointsAndSizes, produces the output shown in Figure 30-4.

image from book
Figure 30-4

Note that this output also shows how the ToString() method has been overridden in both Point and Size to display the value in {X,Y} format.

It is also possible to subtract a Size from a Point struct to produce a Point struct, and you can add two Size structs together, producing another Size. It is not possible, however, to add a Point struct to another Point. Microsoft decided that adding Point structs doesn’t conceptually make sense, and so chose not supply any overload to the + operator that would have allowed that.

You can also explicitly cast a Point to a Size struct and vice versa:

  Point topLeft = new Point(10,10); Size s1 = (Size)topLeft; Point p1 = (Point)s1; 

With this cast s1.Width is assigned the value of topLeft.X, and s1.Height is assigned the value of topLeft.Y. Hence, s1 contains (10,10). p1 will end up storing the same values as topLeft.

Rectangle and RectangleF

These structures represent a rectangular region (usually of the screen). Just as with Point and Size, only the Rectangle struct is considered here. RectangleF is basically identical except that those of its properties that represent dimensions all use float, whereas those of Rectangle use int.

A Rectangle struct can be thought of as composed of a point, representing the top-left corner of the rectangle, and a Size struct, which represents how large it is. One of its constructors actually takes a Point struct and a Size struct as its parameters. You can see this by rewriting the earlier code from the DrawShapes sample that draws a rectangle:

  Graphics dc = e.Graphics; Pen bluePen = new Pen(Color.Blue, 3); Point topLeft = new Point(0,0); Size howBig = new Size(50,50); Rectangle rectangleArea = new Rectangle(topLeft, howBig); dc.DrawRectangle(bluePen, rectangleArea); 

This code also uses an alternative override of Graphics.DrawRectangle(), which takes a Pen and a Rectangle struct as its parameters.

You can also construct a Rectangle struct by supplying the top-left horizontal coordinate, top-left vertical coordinate, width, and height separately, and in that order, as individual numbers:

  Rectangle rectangleArea = new Rectangle(0, 0, 50, 50) 

Rectangle makes quite a few read-write properties available to set or extract its dimensions in different combinations. See the following table for details.

Open table as spreadsheet

Property

Description

int Left

x-coordinate of left-hand edge

int Right

x-coordinate of right-hand edge

int Top

y-coordinate of top

int Bottom

y-coordinate of bottom

int X

Same as Left

int Y

Same as Top

int Width

Width of rectangle

int Height

Height of rectangle

Point Location

Top-left corner

Size Size

Size of rectangle

Note that these properties are not all independent. For example, setting Width also affects the value of Right.

Region

Region represents an area of the screen that has some complex shape. For example, the shaded area in Figure 30-5 could be represented by Region.

image from book
Figure 30-5

As you can imagine, the process of initializing a Region instance is itself quite complex. Broadly speaking, you can do it by indicating either what component simple shapes make up the region or what path you take as you trace round the edge of the region. If you do need to start working with areas like this, it’s worth looking up the Region class in the SDK documentation.




Professional C# 2005 with .NET 3.0
Professional C# 2005 with .NET 3.0
ISBN: 470124725
EAN: N/A
Year: 2007
Pages: 427

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net