Rectangles, Part 1

Geometry is everywhere in modern programming. We have to know how to deal with points, sizes, and rectangles. Back in the old days we’d use NSPoint, NSSize, and NSRect. These types were bitwise-identical with their Core Graphics counterparts (CGPoint, CGSize, and CGRect), but weren’t type miscible, so you had to play games to use use one where another was wanted. With modern flavors of Cocoa, we can use them interchangeably. If you’re looking at a codebase that has both NSBlah and CGBlah for basic geometrical types, rest assured they’re the same at the bit-level.

These structs are pretty straightforward. A point is an x,y location somewhere in space:

CGPoint {
CGFloat x;
CGFloat y;
};

A size is a width and height, unconnected to any point in space:

CGSize {
CGFloat width;
CGFloat height;
};

And a rectangle is an origin point and a width/height:

struct CGRect {
CGPoint origin;
CGSize size;
};

Along with these basic geometrical structures (why are they structs and not objects? check out NS-structs), there’s a bunch of handy utilities available to do some basic operations. If you find yourself tempted to Just Do The Math, consider using one of these functions to make the code a little easier to read later on.

Making Stuff

NS/CGRect, Point, and Size are structures. You can initialize them like any other structure:

These just splat the numerical values into the corresponding place in the structure. Notice the CGRect sample - the first pair of values is the origin, and the second pair is the size. You can leave the braces out and things will work fine, but you might get a compiler warning (-Wmissing-braces) depending on your current warning level. You are fixing your warnings, right?

You do this to make a compile-time array of structures you can then walk through later, perhaps using a technique like table scanning

Rectangle Extents

There’s a number of different ways you can represent a rectangle in numbers. Some libraries, like the original Mac Quickdraw, use four values: left, top, right, and bottom. To find the width and height you do some math. As you saw, Cocoa and Core Graphics use an origin point plus a size for the width and height:â€¨

If you want the edges, you do some math.

Width and height don’t have to be positive, so you can have a rectangle with a negative width or a negative height. This can make some of your rectangle calculations easier, especially if the user is dragging out a rectangle: have the rectangle origin be the initial tap/click point, and set the width and height as the current delta from that point. All of Apple’s code is set up to handle negative widths and heights, but your code or other library code might not be so savvy. In that case, you can standardize a rectangle so that it has positive extents by using CGRectStandardize:

You can also turn any fractional values in the rectangle into integral values by using CGRectIntegral.

Special Cases

There’s two special rectangles, the null and the infinite rectangle. There are constants for these:

const CGRect CGRectInfinite;
const CGRect CGRectNull;

The infinite rect is a really really huge rectangle, going from an extremely negative origin point and having totally gigantic extents. Feel free to log one out to see its content. This is used for describing things that don’t really have defined bounds, such as the core image tiling filter. It’ll happily tile the entire universe if given half a chance.

The null rect is used to represent rectangles that don’t make sense. It’s represented internally with floating-point infinities for the origin and zero extents. Uses for a null rectangle? Say you intersect two rectangles that don’t overlap. The intersection is the empty set, and so you’d get CGRectNull back for that. The null rectangle behaves nicer than the SQL NULL, so a null rect can be compared to itself and return a true value.

You can ask a rectangle if it is empty (zero width or height) by using CGRectIsEmpty, or if it’s infinite or null with CGRectIsNull or CGRectIsInfinite.

Comparisons

Speaking of comparisons, there are functions for seeing if two points, sizes, or rectangles are the same. You’ll want to use these rather than comparing elements piecewise. The functions less typing, plus recall that these data structures are based on CGFloat, which is as the name implies, a floating point value. You shouldn’t compare two floating point values for equality directly, due to potential round-off errors, but instead see if their difference is small enough to be considered insignificant (sometimes called epsilon). That’s annoying, so I just use the conveniences instead:

These return zero if the given structures are not equal, and return one if they do. 1 happens to be equal to YES in Objective-C, which is convenient. As always with BOOL values in Objective-C, be wary of its sharp corners.

Coming Up

That’s the basics of what some of the available functions are for making and interrogating rectangles. Next time we’ll look at some of the interesting manipulations you can do with them.