Wednesday, December 8, 2010

Objective C Geometry overview


CGPoint and CGRect are definitely one of the first names everyone learns when starting to deal with Objective C, and more specific when dealing with the iPhone. As you probably already know these are the structures describing a point(coordinates x and y) and a rectangle (point of top left corner and its size)
The CGGeometry however provides much more useful structures and functions beyond these two and a programmer who wants to go beyond copy/paste programming should definitely have a deeper look into CGGeometry to be able to produce cleaner and more powerful code.

A quick example

There are two given rects (usually the frames of uiview instances on the screen). The task is to find out if one of the rects is fully contained inside the second rectangle. If one spends couple of minutes, he quite easily comes with some code like the following:
CGRect rect1 = CGRectMake(10, 10, 200, 200);
CGRect rect2 = CGRectMake(15, 20, 27, 85);
 
if ( rect1.origin.x < rect2.origin.x &&
    rect1.origin.x+rect1.size.width > rect2.origin.x+rect2.size.width &&
  rect1.origin.y < rect2.origin.y &&
   rect1.origin.y+rect1.size.height > rect2.origin.y+rect2.size.height
 ) {
 NSLog(@"rect1 contains rect2");
}
BAD CODE
Now this code might look quite ok, and you can be proud you figured out how to check if one rectangle contains another, but this code is wrong because:
  1. Nobody would like to debug it when you have several if statements like this one
  2. You are always prone to making a mistake even if it doesn’t look so hard to define the conditions
  3. You are not being a team player, your team mates won’t like to work on your code, and you will be puzzled by theirs
Here is the correct version of the code sample above:
if (CGRectContainsRect(rect1, rect2)) {
 NSLog(@"rect1 contains rect2");
}

CGGeometry overview

As it became obvious from the little example above it is important to know the tools which are available. The geometry function set is not so big, but it really adds value and readableness to one’s code.

Test for membership

In other words if something is inside something else. You have to do this task repetitively if you are programming even a simple game app.
bool CGRectContainsRect(CGRect rect1, CGRect rect2)
Checks if rect2 is contained in rect1
bool CGRectContainsPoint(CGRect rect, CGPoint point)
Checks if point is contained in rect

Useful rectangle functions

CGGeometry provides a set of handy functions to process rectangles- this adds the neccessary abstraction level to your code, so you don’t need to work with coordinated, but rather directly with rectangles.
CGRect CGRectOffset(CGRect rect, CGFloat dx, CGFloat dy)
Moves the given rectangle by the given x and y offset and returns a new CGRect structure.
CGRect CGRectUnion(CGRect r1, CGRect r2)
Returns the (smallest) rectangle that contains both rect1 and rect2.
CGRect CGRectIntersection(CGRect r1, CGRect r2)
Returns a rectangle which is the intersections of the 2 given rectangles.
CGRect CGRectIntegral(CGRect rect)
Gets the rect coordinates and size and rounds them down. I.e. if you have a rect with width: 23.4 and 31.1 the result will have width: 23 and height: 31. Handy to apply on rects which are result of some calculations which might produce floats.
bool CGRectIntersectsRect(CGRect rect1, CGRect rect2)
Checks if the two given rectangles intersect … This is the one you’ll be using a lot if you a programming games for the iPhone.

Comparing CGGeometry structures

Yet another set of functions to add abstraction to code which is supposed to deal with coordinates and sizes.
bool CGPointEqualToPoint(CGPoint point1, CGPoint point2)
Comparest the two given points
bool CGRectEqualToRect(CGRect rect1, CGRect rect2)
Compares the two given rects.
bool CGSizeEqualToSize(CGSize size1, CGSize size2)
Compares the two given size structures. Nota Bene! To myself (having a math background) this function is rather controversial. From geometry point of view, two rects have the same size when they contain the same amount of metric units; for example a room of 2 by 3 meteres has the same size as a room of 1 by 6 meters. On the other hand CGSizeEqualToSize rather just compares the width and height components separately and not really the size of the rect. The following example shows the 2 defined rects are not equal in size:
CGSize s1 = CGSizeMake(20, 30);
 CGSize s2 = CGSizeMake(30, 20);
 if ( CGSizeEqualToSize(s1,s2) ) {
  NSLog(@"the 2 sizes are equal");
 } else {
  NSLog(@"the 2 size are NOT equal");
 }

Get minimal, maximal and middle coordinates

Very very handy functions to get the most left x coordinate or the middle x coordinate and so forth of given rects.
CGFloat CGRectGetMinX(CGRect rect)
CGFloat CGRectGetMidX(CGRect rect)
CGFloat CGRectGetMaxX(CGRect rect)
 
CGFloat CGRectGetMinY(CGRect rect)
CGFloat CGRectGetMidY(CGRect rect)
CGFloat CGRectGetMaxY(CGRect rect)

Geometry wrap up

Well I hope this article was useful. That’s a wrap up for the geometry on the iPhone, if you try to use more of these handy functions your code will definitely be more readable, understandable, interchangable and you will definitely have what to brag about to your copy/paste programmer friends. There are always more interesting stuff in CGGeometry.h so if I intrigued you, feel free to dig in the headers.
Image: http://www.sxc.hu/profile/nkzs
 
If you liked this article please share it with your friends or colleagues; there's also a low traffic RSS feed to give you heads up when there's a new post in Touch Code Magazine.

No comments:

Post a Comment

Followers