Apple Developer Connection
Member Login Log In | Not a Member? Contact ADC

< Previous PageNext Page > Hide TOC

Drawing Fundamental Shapes

For many types of content, path-based drawing has several advantages over image-based drawing:

The following sections provide information about the primitive shapes you can draw using paths. You can combine one or more of these shapes to create a more complex path and then stroke or fill the path as described in “Drawing the Shapes in a Path.” For some shapes, there may be more than one way to add the shape to a path, or there may be alternate ways to draw the shape immediately. Wherever possible, the benefits and disadvantages of each technique are listed to help you decide which technique is most appropriate in specific situations.

In this section:

Adding Points
Adding Lines and Polygons
Adding Rectangles
Adding Rounded Rectangles
Adding Ovals and Circles
Adding Arcs
Adding Bezier Curves
Adding Text
Drawing the Shapes in a Path


Adding Points

An NSPoint structure by itself represents a location on the screen; it has no weight and cannot be drawn as such. To draw the equivalent of a point on the screen, you would need to create a small rectangle at the desired location, as shown in Listing 5-8.

Listing 5-8  Drawing a point

void DrawPoint(NSPoint aPoint)
{
    NSRect aRect = NSMakeRect(aPoint.x, aPoint.y, 1.0, 1.0);
 
    NSRectFill(aRect);
}

Of course, a more common use for points is to specify the position of other shapes. Many shapes require you to specify the current point before actually creating the shape. You set the current point using the moveToPoint: or relativeMoveToPoint: methods. Some shapes, like rectangles and ovals, already contain location information and do not require a separate call to moveToPoint:.

Important:  You must specify a starting point before drawing individual line, arc, curve, and glyph paths. If you do not, NSBezierPath raises an exception.

Adding Lines and Polygons

Cocoa provides a couple of options for adding lines to a path, with each technique offering different tradeoffs between efficiency and correctness. You can draw lines in the following ways:

Polygons are composed of multiple connected lines and should be created using an NSBezierPath object. The simplest way to create a four-sided nonrectangular shape, like a parallelogram, rhombus, or trapezoid, is using line segments. You could also create these shapes using transforms, but calculating the correct skew factors would require a lot more work.

Listing 5-9 shows code to draw a parallelogram using NSBezierPath. The method in this example inscribes the parallelogram inside the specified rectangle. The withShift parameter specifies the horizontal shift applied to the top left and bottom right corners of the rectangular area.

Listing 5-9  Using lines to draw a polygon

void DrawParallelogramInRect(NSRect rect, float withShift)
{
    NSBezierPath* thePath = [NSBezierPath bezierPath];
 
    [thePath moveToPoint:rect.origin];
    [thePath lineToPoint:NSMakePoint(rect.origin.x - withShift,  rect.origin.y)];
    [thePath lineToPoint:NSMakePoint(NSMaxX(rect), NSMaxY(rect))];
    [thePath lineToPoint:NSMakePoint(rect.origin.x + withShift,  NSMaxY(rect))];
    [thePath closePath];
 
    [thePath stroke];
}

Adding Rectangles

Because rectangles are used frequently, there are several options for drawing them.

Listing 5-10 shows a simple function that fills and strokes the same rectangle using two different techniques. The current fill and stroke colors are used when drawing the rectangle, along with the default compositing operation. In both cases, the rectangles are drawn immediately; there is no need to send a separate fill or stroke message.

Listing 5-10  Drawing a rectangle

void DrawRectangle(NSRect aRect)
{
    NSRectFill(aRect);
    [NSBezierPath strokeRect:aRect];
}

Adding Rounded Rectangles

In Mac OS X v10.5 and later, the NSBezierPath class includes the following methods for creating rounded-rectangles:

These methods create rectangles whose corners are curved according to the specified radius values. The radii describe the width and height of the oval to use at each corner of the rectangle. Figure 5-8 shows how this inscribed oval is used to define the path of the rectangle’s corner segments.


Figure 5-8  Inscribing the corner of a rounded rectangle

Inscribing the corner of a rounded rectangle

Listing 5-11 shows a code snippet that creates and draws a path with a rounded rectangle.

Listing 5-11  Drawing a rounded rectangle

void DrawRoundedRect(NSRect rect, CGFloat x, CGFloat y)
{
    NSBezierPath* thePath = [NSBezierPath bezierPath];
 
    [thePath appendBezierPathWithRoundedRect:rect xRadius:x yRadius:y];
    [thePath stroke];
}

Adding Ovals and Circles

To draw ovals and circles, use the following methods of NSBezierPath:

Both methods inscribe an oval inside the rectangle you specify. You must then fill or stroke the path object to draw the oval in the current context. The following example creates an oval from the specified rectangle and strokes its path.

void DrawOvalInRect(NSRect ovalRect)
{
    NSBezierPath* thePath = [NSBezierPath bezierPath];
 
    [thePath appendBezierPathWithOvalInRect:ovalRect];
    [thePath stroke];
}

You could also create an oval using arcs, but doing so would duplicate what the preceding methods do internally and would be a little slower. The only reason to add individual arcs is to create a partial (nonclosed) oval path. For more information, see “Adding Arcs.”

Adding Arcs

To draw arcs, use the following methods of NSBezierPath:

The appendBezierPathWithArcFromPoint:toPoint:radius: method creates arcs by inscribing them in an angle formed by the current point and the two points passed to the method. Inscribing a circle in this manner can result in an arc that does not intersect any of the points used to specify it. It can also result in the creation of an unwanted line from the current point to the starting point of the arc.

Figure 5-9 shows three different arcs and the control points used to create them. For the two arcs created using appendBezierPathWithArcFromPoint:toPoint:radius:, the current point must be set before calling the method. In both examples, the point is set to (30, 30). Because the radius of the second arc is shorter, and the starting point of the arc is not the same as the current point, a line is drawn from the current point to the starting point.


Figure 5-9  Creating arcs

Creating arcs

Listing 5-12 shows the code snippets you would use to create each of the arcs from Figure 5-9. (Although the figure shows the arcs individually, executing the following code would render the arcs on top of each other. )

Listing 5-12  Creating three arcs

NSBezierPath*   arcPath1 = [NSBezierPath bezierPath];
NSBezierPath*   arcPath2 = [NSBezierPath bezierPath];
 
[[NSColor blackColor] setStroke];
 
// Create the first arc
[arcPath1 moveToPoint:NSMakePoint(30,30)];
[arcPath1 appendBezierPathWithArcFromPoint:NSMakePoint(0,30)  toPoint:NSMakePoint(0,60) radius:30];
[arcPath1 stroke];
 
// Create the second arc.
[arcPath2 moveToPoint:NSMakePoint(30,30)];
[arcPath2 appendBezierPathWithArcFromPoint:NSMakePoint(30,40)  toPoint:NSMakePoint(70,30) radius:20];
[arcPath2 stroke];
 
// Clear the old arc and do not set an initial point, which prevents a
// line being drawn from the current point to the start of the arc.
[arcPath2 removeAllPoints];
[arcPath2 appendBezierPathWithArcWithCenter:NSMakePoint(30,30) radius:30  startAngle:45 endAngle:135];
[arcPath2 stroke];

Adding Bezier Curves

To draw Bezier curves, you must use the curveToPoint:controlPoint1:controlPoint2: method of NSBezierPath. This method supports the creation of a cubic curve from the current point to the destination point you specify when calling the method. The controlPoint1 parameter determines the curvature starting from the current point, and controlPoint2 determines the curvature of the destination point, as shown in Figure 5-1.


Figure 5-10  Cubic Bezier curve

Cubic Bezier curve

Adding Text

Because NSBezierPath only supports path-based content, you cannot add text characters directly to a path; instead, you must add glyphs. A glyph is the visual representation of a character (or partial character) in a particular font. For glyphs in an outline font, this visual representation is stored as a set of mathematical paths that can be added to an NSBezierPath object.

Note: Using NSBezierPath is not the most efficient way to render text, but can be used in situations where you need the path information associated with the text.

To obtain a set of glyphs, you can use the Cocoa text system or the NSFont class. Getting glyphs from the Cocoa text system is usually easier because you can get glyphs for an arbitrary string of characters, whereas using NSFont requires you to know the names of individual glyphs. To get glyphs from the Cocoa text system, you must do the following:

  1. Create the text system objects needed to manage text layout. For a tutorial on how to do this, see Assembling the Text System by Hand in Text System Overview.

  2. Use the glyphAtIndex: or getGlyphs:range: method of NSLayoutManager to retrieve the desired glyphs.

  3. Add the glyphs to your NSBezierPath object using one of the following methods:

When added to your NSBezierPath object, glyphs are converted to a series of path elements. These path elements simply specify lines and curves and do not retain any information about the characters themselves. You can manipulate paths containing glyphs just like you would any other path by changing the points of a path element or by modifying the path attributes.

Drawing the Shapes in a Path

There are two options for drawing the contents of a path: you can stroke the path or fill it. Stroking a path renders an outline of the path’s shape using the current stroke color and path attributes. Filling the path renders the area encompassed by the path using the current fill color and winding rule.

Figure 5-11 shows the same path from Figure 5-1 but with the contents filled and a different stroke width applied.


Figure 5-11  Stroking and filling a path.

Stroking and filling a path.



< Previous PageNext Page > Hide TOC


Last updated: 2007-10-31




Did this document help you?
Yes: Tell us what works for you.

It’s good, but: Report typos, inaccuracies, and so forth.

It wasn’t helpful: Tell us what would have helped.
Get information on Apple products.
Visit the Apple Store online or at retail locations.
1-800-MY-APPLE

Copyright © 2007 Apple Inc.
All rights reserved. | Terms of use | Privacy Notice