Measuring Coordinates and Areas

 
Chapter 19 - Graphics with GDI+
bySimon Robinsonet al.
Wrox Press 2002
  

In our last example, we 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, and we're at a convenient point in the chapter to go over the main ones. We'll look at the following structs, which are all defined in the System.Drawing namespace:

Struct

Main Public Properties

struct Point

X, Y

struct PointF

 

struct Size

Width, Height

struct SizeF

 

struct Rectangle

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

struct RectangleF

 

Note that many of these objects have a number of other properties, methods , or operator overloads not listed here. In this section we'll just discuss the most important ones.

Point and PointF

We'll look at Point first. 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). In other words, look at this diagram:

click to expand

In order 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 as this is how they are commonly referred to. We could create a Point struct that represents that as follows :

   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 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 explicitly 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 may be wondering what a "unit" is measured in. By default, GDI+ will interpret units as pixels along the screen (or printer, whatever the graphics device is) so 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 will be measured from the top left corner of the client area of the window, as has been the case in our examples up to now. However, that won't always be the case for example, on some occasions you may wish 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 you're talking pixels relative to the top left corner of the client area.

We'll have more to say on this subject later on, after we've examined scrolling, when we mention the three different coordinate systems in use, world, page, and device coordinates.

Size and SizeF

Like Point and PointF , sizes come in two varieties. The Size struct is for when you are using int s; SizeF is available if you need to use float s. Otherwise Size and SizeF are identical. We'll focus on the Size struct here.

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 . We can represent our earlier diagram by:

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

Although strictly speaking, a Size mathematically represents exactly the same thing as a Point; conceptually it is intended to be used in a slightly different way. A Point is used when we are talking about where something is, and a Size is used when we are talking about how big it is. However, because Size and Point are so closely related , there are even supported explicit 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 we 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 we drew the rectangle in a different location, so it's top left coordinate was 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 that's still (50,50).

The addition operator has been overloaded for Point s and Size s, so that it is possible to add a Size to a Point giving another Point :

 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 this output:

click to expand

Notice 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 to give a Point , and you can add two Sizes together, giving another Size . It is not possible, however, to add a Point to another Point . Microsoft decided that adding Point s doesn't conceptually make sense, and so chose not to supply any overload to the + operator that would have allowed that.

You can also explicitly cast a Point to a Size 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 , we'll only consider the Rectangle struct 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 can be thought of as composed of a point, representing the top left corner of the rectangle, and a Size , which represents how large it is. One of its constructors actually takes a Point and a Size as its parameters. We can see this by rewriting our 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 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:

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 will also affect the value of Right .

Region

We'll mention the existence of the System.Drawing.Region class here, though we don't have space to go details in this book. Region represents an area of the screen that has some complex shape. For example the shaded area in the diagram could be represented by Region :

click to expand

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, then it's worth looking up the Region class.

  


Professional C#. 2nd Edition
Performance Consulting: A Practical Guide for HR and Learning Professionals
ISBN: 1576754359
EAN: 2147483647
Year: 2002
Pages: 244

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