Regions in QuickDraw and paths in Quartz are very different abstractions. Regions are pixel based and don’t retain any information about the contours or boundaries of the shapes they represent. Paths are vector-based representations of the contours of shapes, with no concept of pixels. Converting a region into a path may be inefficient, and the contours of the converted path may not look smooth or scale well. Quartz does not provide a function to convert a region into a path. If at all possible, you will want to replace our use of regions with Quartz abstractions rather than perform this type of conversion. However, if you must, it is possible to write a program to perform the conversion yourself.
This section demonstrates how to write code that converts an arbitrary QuickDraw region into a Quartz path by taking a divide-and-conquer approach. The first step is to describe a region in terms of vectors. Rectangles are ideal for this purpose. It turns out that any region can be decomposed into a sequence of rectangles in top-down or left-right order. QuickDraw provides the function QDRegionToRects for exactly this purpose.
On the Quartz side, several functions exist for adding rectangles to graphics paths. The only remaining problem is to convert the rectangles into the floating-point CGRect format used by Quartz, which is easy to do.
The sample code in Listing 2-14 shows how to write two custom functions that work together to perform the conversion. A detailed explanation for each numbered line of code follows the listing.
MyConvertRegionToPath creates a new path, performs the conversion, and returns the path to the caller.
MyRegionToRectsCallback converts a QuickDraw rectangle into a Quartz rectangle and appends it to the new path.
When you use the converted path to draw in a graphics context with a flipped coordinate space, the path will have the same orientation as the region.
Listing 2-14 Routines that convert a QuickDraw region into a Quartz path
OSStatus MyConvertRegionToPath (RgnHandle region, CGPathRef* outPath) |
{ |
RegionToRectsUPP proc = NewRegionToRectsUPP (MyRegionToRectsCallback); |
CGPathRef path = CGPathCreateMutable(); |
OSStatus err = noErr; |
err = QDRegionToRects ( |
region, kQDParseRegionFromTopLeft, proc, (void*)path);// 1 |
if (err == noErr) { |
*outPath = path;// 2 |
} |
else { |
CGPathRelease (path); |
*outPath = NULL; |
} |
DisposeRegionToRectsUPP (proc); |
return err; |
} |
OSStatus MyRegionToRectsCallback ( |
UInt16 message, RgnHandle region, const Rect *rect, void *data) |
{ |
if (message == kQDRegionToRectsMsgParse) |
{ |
Rect qd = *rect; |
CGRect cg = CGRectMake ( |
qd.left, qd.top, qd.right - qd.left, qd.bottom - qd.top);// 3 |
CGPathAddRect ( |
(CGMutablePathRef)data, NULL, cg);// 4 |
} |
return noErr; |
} |
Here’s what the code does:
Converts the region into a path.
Passes the converted path back to the caller.
Converts the QuickDraw rectangle into a Quartz rectangle, using the upper-left point as the origin.
Adds the Quartz rectangle to the path being constructed.
Last updated: 2006-09-05