Inherits from: NSObject
Conforms to: NSCoding
NSCopying
NSObject (NSObject)
Declared in: AppKit/NSBezierPath.h
An NSBezierPath object allows you to create paths using PostScript-style commands. Paths consist of straight and curved line segments joined together. Paths can form recognizable shapes such as rectangles, ovals, arcs, and glyphs; they can also form complex polygons using either straight or curved line segments. A single path can be closed by connecting its two endpoints or it can be left open.
An NSBezierPath object can contain multiple disconnected paths, whether they are closed or open. Each of these paths is referred to as a subpath of the NSBezierPath object. The subpaths of an NSBezierPath object must be manipulated as a group. The only way to manipulate subpaths individually is to create separate NSBezierPath objects for each.
For a given NSBezierPath object, you can stroke the path's outline or fill the region occupied by the path. You can also use the path as a clipping region for views or other regions. Using methods of NSBezierPath, you can also perform hit detection on the filled or stroked path. Hit detection is needed to implement interactive graphics, as in rubberbanding and dragging operations.
You can create an instance of NSBezierPath using either of the class methods bezierPath or bezierPathWithRect:. ThebezierPath method initializes a new bezier-path object with an empty path while the bezierPathWithRect: method creates a path with the specified rectangle. (You can also allocate memory for a new instance of NSBezierPath and use the default initializer, the init method, to initialize it to an empty path).
To add path information to an NSBezierPath object, you must invoke a sequence of path construction methods such as the moveToPoint:, lineToPoint:, and curveToPoint:controlPoint1:controlPoint2: methods. For example, to create a polygon path, send a moveToPoint: message, followed by a series of lineToPoint: messages, to the NSBezierPath object. When you are done adding points to the path and want to form a closed path, send a closePath message to connect the last point back to the starting point.
The order in which path construction methods are invoked is significant. Line segments connect only if they are defined consecutively and the second segment starts where the first segment ends. A path may be made up of one or more disconnected subpaths, which can themselves be either open or closed. The current point is the last point of the most recently added line segment.
Most construction methods implicitly use the current point as the starting point of the next segment. If you want to create a new subpath, you must explicitly invoke moveToPoint: first. For example, lineToPoint: adds a line segment from the current point to the specified point. Some methods may implicitly invoke moveToPoint:, thereby creating a new subpath automatically. See the method descriptions for more information.
Convenience methods are provided for appending paths and common shapes to an existing path. The new path is usually discontiguous from the receiver's original path, although the appendBezierPathWithPoints:count: method creates a contiguous path from the specified points. .Use the appendBezierPath... methods to append a path to an NSBezierPath object as in this example which uses appendBezierPathWithOvalInRect: to create a circle:
NSRect aRect = NSMakeRect(0.0, 0.0, 50.0, 50.0); aPath = [[NSBezierPath bezierPath] appendBezierPathWithOvalInRect:aRect];
No matter which construction methods you use, all paths are reduced to a sequence of data points and common element types corresponding to the methods moveToPoint:, lineToPoint:, curveToPoint:controlPoint1:controlPoint2:, and closePath. These element types can be specified with the following constants from the enumerated type NSBezierPathElementType:
NSBezierPathElementMoveTo
NSBezierPathElementLineTo
NSBezierPathElementCurveTo
NSBezierPathElementClose
Every element except NSBezierPathElementClose has at least one data point associated with it. The only element that has more than one data point is NSBezierPathElementCurveTo (which maintains additional control points to define the shape of the curve). NSBezierPath defines several methods for obtaining information about the path elements (and their associated points) directly, including pointAtIndex:, elementTypeAtIndex:, and elementTypeAtIndex:associatedPoints: among others. You could use these methods together with the removeLastElement method to break down a path and reconstruct it point by point.
You typically render NSBezierPath objects inside an NSView's drawRect: method (unless you are drawing outside the bounds of an NSView object, as in a rubberbanding operation). At the time the drawRect: method is invoked, the focus is locked on the view and all drawing operations are clipped to that view. Therefore, most of the time you will want to construct paths whose points are specified in the view's coordinate system. You could also construct a path using an arbitrary coordinate system and transform the path to a view's coordinate system using an NSAffineTransform object. An NSAffineTransform object can translate, scale, and rotate paths (see the NSAffineTransform class specification for details).
Before filling or stroking an NSBezierPath object, you should set the graphics attributes to use for the path. You can use the set... methods of NSBezierPath to set such attributes as the line cap style, line join style, line width, miter limit, curve flatness, and halftone phase. Other attributes must be set using the appropriate objects. For example, you set the color in the current graphics context by sending set to an NSColor object.
You can use either the stroke or fill methods to render a path. The stroke method draws a line along the receiver's path using the color, line width, cap and join styles, and curve flatness drawing attributes in the current graphics context. The fill method renders the path by painting the region enclosed by the path and uses the color and curve flatness attributes. The fill method will perform a close operation (invoke closePath) if the path is not already closed. (A subpath is closed if the ending point is connected to the starting point, otherwise the subpath is opened).
As a convenience, some class methods are provided for drawing immediate shapes without the creation of an NSBezierPath object. For example, use the fillRect: and strokeRect: class methods to draw a filled rectangle or outline of a rectangle, and use the strokeLineFromPoint:toPoint: class method to draw a line segment.
Simple paths like an oval or rectangle are easy to fill; however,
there are several ways to fill complex paths that contain intersecting
line segments or that contain a subpath enclosed by another subpath
(i.e., a doughnut shape). You can specify how complex paths are
filled using the setWindingRule: method
and the constants NSWindingRuleNonZero
or NSWindingRuleEvenOdd
.The
rules that govern the effects of each constant are as follows:
Winding Rule | Description |
NSWindingRuleNonZero |
A point is outside if drawing a ray from that point in any direction results in a crossing count of 0, where crossing a left-to-right path adds 1 and crossing a right-to-left path subtracts 1. Otherwise, the point is inside. |
NSWindingRuleEvenOdd |
A point is inside if drawing a ray from that point in any direction and counting the number of path segments that the ray crosses is odd, otherwise the point is outside. Inside points are filled, outside points are not. |
For example, given a path with two nested circles, Figure
0-1 shows the results of using each winding rule. If the winding
rule is NSWindingRuleNonZero
, the direction
of the paths is used to determine whether or not a segment should
be filled. When the two paths are traveling in the same direction,
the entire area of both circles is filled, but when the paths travel
counter to each other the interior circle is left unfilled. When
the winding rule is NSWindingRuleEvenOdd
,
the interior circle is left unfilled regardless of which direction
the paths travel.
Winding rule examples
Hit detection is necessary if you want the user to be able to select your paths or graphical shapes. The Application Kit notifies your application know if the user clicked within the bounds of an NSView object by invoking one of the NSResponder mouse... methods. You use the NSBezierPath isHitByPoint: method to determine if the user clicked a filled path, and the isStrokeHitByPoint: method to determine if the user clicked on a stroked path. The isHitByRect: and isStrokeHitByRect: methods are useful if the user has selected a region (for example, by rubberbanding a rectangle) and you want to determine which paths lie inside that region.
NSBezierPath includes several methods for setting the current drawing style to be used for rendering paths. Most drawing styles are global attributes, set using class methods of NSBezierPath. The one exception to this is the winding rule attribute, which is local to a particular path. The global attributes include path-related attributes such as the line width, miter limit, line join style, line cap style, and curve flatness. For information about setting the winding rule of a path, see "Winding Rules and Filling Paths".
To set other attributes of the path, such as the color, you must use the methods of the appropriate class. For example, to set the color of the path, you would need to create a new instance of NSColor and invoke its set method.
- NSCoding
- - encodeWithCoder:
- - initWithCoder:
- NSCopying
- - copyWithZone:
- Creating an NSBezierPath object
- + bezierPath
- + bezierPathWithRect:
- Contructing paths
- - moveToPoint:
- - lineToPoint:
- - curveToPoint:controlPoint1:controlPoint2:
- - closePath
- - reset
- - relativeMoveToPoint:
- - relativeLineToPoint:
- - relativeCurveToPoint:controlPoint1:controlPoint2:
- Appending paths and some common shapes
- - appendBezierPath:
- - appendBezierPathWithPoints:count:
- - appendBezierPathWithOvalInRect:
- - appendBezierPathWithArcWithCenter:radius:startAngle:endAngle:
- - appendBezierPathWithGlyph:inFont:
- - appendBezierPathWithGlyphs:count:inFont:
- - appendBezierPathWithPackedGlyphs:
- Setting attributes
- - setWindingRule:
- - windingRule
- + setLineCapStyle
- + setLineJoinStyle
- + setLineWidth
- + setMiterLimit:
- + setFlatness:
- + setHalftonePhase:
- Drawing paths
- - stroke
- - fill
- + fillRect:
- + strokeRect:
- + strokeLineFromPoint:toPoint:
- + drawPackedGlyphs:atPoint:
- Clipping paths
- - addClip
- - setClip
- + clipRect:
- Hit detection
- - isHitByPoint:
- - isHitByRect:
- - isHitByPath:
- - isStrokeHitByPoint:
- - isStrokeHitByRect:
- - isStrokeHitByPath:
- Querying paths
- - bounds
- - controlPointBounds
- - currentPoint
- Accessing elements of a path
- - elementCount
- - elementTypeAtIndex:
- - elementTypeAtIndex:associatedPoints:
- - removeLastElement
- - pointCount
- - pointAtIndex:
- - setPointAtIndex:toPoint:
- - pointIndexForPathElementIndex:
- - pathElementIndexForPointIndex:
- Caching paths
- - cachesBezierPath
- - setCachesBezierPath:
+ (NSBezierPath *)bezierPath
+ (NSBezierPath *)bezierPathWithRect:(NSRect)aRect
See Also: + bezierPath, - appendBezierPathWithRect:, + fillRect:, + strokeRect:
+ (void)clipRect:(NSRect)aRect
See Also: - addClip, - setClip
+ (void)drawPackedGlyphs:(const
char *)packedGlyphs atPoint:(NSPoint)aPoint
See Also: - appendBezierPathWithGlyph:inFont:, - appendBezierPathWithGlyphs:count:inFont:, - appendBezierPathWithPackedGlyphs:, - set, - set (NSColor)
+ (void)fillRect:(NSRect)aRect
See Also: - appendBezierPathWithRect:, + bezierPathWithRect:, + strokeRect:, - set, - set (NSColor)
+ (void)setFlatness:(float)flatness
The default flatness value for a graphic context is 1.0. Flatness values that are less than 0.2 or greater than 100 are normalized to those boundaries.
+ (void)setHalftonePhase:(NSPoint)aPoint
This is a device dependent property. The default value is (0, 0).
+ (void)setLineCapStyle:(NSLineCapStyle)lineCap
Line cap styles
See Also: + setLineJoinStyle:, + setLineWidth:
+ (void)setLineJoinStyle:(NSLineJoinStyle)lineJoinStyle
Line join styles
See Also: + setLineCapStyle:, + setLineWidth:, + setMiterLimit:
+ (void)setLineWidth:(float)width
See Also: + setLineCapStyle:, + setLineJoinStyle:
+ (void)setMiterLimit:(float)limit
See Also: + setLineJoinStyle:
+ (void)strokeLineFromPoint:(NSPoint)point1 toPoint:(NSPoint)point2
See Also: - lineToPoint:, - moveToPoint:, + setLineCapStyle:, + setLineWidth:, - stroke
+ (void)strokeRect:(NSRect)aRect
See Also: - appendBezierPathWithRect:, + bezierPathWithRect:, + fillRect:, + setLineJoinStyle:, + setLineWidth:, - set, - set (NSColor)
- (void)addClip
See Also: + clipRect:, - setClip
- (void)appendBezierPath:(NSBezierPath
*)aPath
- (void)appendBezierPathWithArcWithCenter:(NSPoint)center
radius:(float)radius
startAngle:(float)startAngle
endAngle:(float)endAngle
<< This is one of those methods that does not appear to have been implemented. Can someone give me a good description of how this method is going to work? Will the arc begin at the current point or will it be based solely at center? Will center be a relative position from the current point? >>
- (void)appendBezierPathWithGlyph:(NSGlyph)aGlyph inFont:(NSFont
*)fontObj
See Also: - appendBezierPathWithGlyphs:count:inFont:, - appendBezierPathWithPackedGlyphs:, + drawPackedGlyphs:atPoint:
- (void)appendBezierPathWithGlyphs:(NSGlyph
*)glyphs
count:(int)count
inFont:(NSFont *)fontObj
<< Does drawing of the glyph begin at the current point or does the current point simply indicate the glyph's baseline position? >>
See Also: - appendBezierPathWithGlyph:inFont:, - appendBezierPathWithPackedGlyphs:, + drawPackedGlyphs:atPoint:
- (void)appendBezierPathWithOvalInRect:(NSRect)aRect
- (void)appendBezierPathWithPackedGlyphs:(const
char *)packedGlyphs
See Also: + drawPackedGlyphs:atPoint:
- (void)appendBezierPathWithPoints:(NSPoint
*)points count:(int)count
This method does not close the receiver's path. If you wish to create a closed path, you must do so by explicitly invoking the receiver's closePath method.
- (void)appendBezierPathWithRect:(NSRect)aRect
See Also: + bezierPathWithRect:, + fillRect:, + strokeRect:
- (NSRect)bounds
See Also: - controlPointBounds
- (BOOL)cachesBezierPath
See Also: - setCachesBezierPath:
- (void)closePath
See Also: - fill
- (NSRect)controlPointBounds
See Also: - bounds
- (NSPoint)currentPoint
See Also: - closePath, - curveToPoint:controlPoint1:controlPoint2:, - lineToPoint:, - moveToPoint:, - reset
- (void)curveToPoint:(NSPoint)aPoint
controlPoint1:(NSPoint)controlPoint1
controlPoint2:(NSPoint)controlPoint2
See Also: - closePath, - lineToPoint:, - moveToPoint:, - relativeCurveToPoint:controlPoint1:controlPoint2:, + setFlatness:
- (int)elementCount
See Also: - elementTypeAtIndex:, - elementTypeAtIndex:associatedPoints:, - removeLastElement
- (NSBezierPathElementType)elementTypeAtIndex:(int)index
See Also: - elementCount, - elementTypeAtIndex:associatedPoints:, - removeLastElement
- (NSBezierPathElementType)elementTypeAtIndex:(int)index associatedPoints:(NSPoint
*)points
See Also: - elementCount, - elementTypeAtIndex:, - removeLastElement
- (void)fill
See Also: - stroke, - windingRule, - set, - set (NSColor)
- (BOOL)isHitByPath:(NSBezierPath
*)aBezierPath
<< The current method does a comparsion of bounding boxes. Seems to me that intersecting the bounding rectangle is not a terribly accurate measurement of hit detection. Is this going to change in the near future? >>
See Also: - isHitByPoint:, - isHitByRect:, - isStrokeHitByPath:, - bounds
- (BOOL)isHitByPoint:(NSPoint)aPoint
<< The current method does a comparsion of bounding boxes. Seems to me that intersecting the bounding rectangle is not a terribly accurate measurement of hit detection. Is this going to change in the near future? >>
See Also: - isHitByPath:, - isHitByRect:, - isStrokeHitByPoint:, - bounds
- (BOOL)isHitByRect:(NSRect)aRect
<< The current method does a comparsion of bounding boxes. Seems to me that intersecting the bounding rectangle is not a terribly accurate measurement of hit detection. Is this going to change in the near future? >>
See Also: - isHitByPath:, - isHitByPoint:, - isStrokeHitByRect:, - bounds
- (BOOL)isStrokeHitByPath:(NSBezierpath
*)aBezierPath
<< The current method does a comparsion of bounding boxes. Seems to me that intersecting the bounding rectangle is not a terribly accurate measurement of hit detection. Is this going to change in the near future? >>
See Also: - isStrokeHitByPoint:, - isStrokeHitByRect:, - isHitByPath:, - bounds
- (BOOL)isStrokeHitByPoint:(NSPoint)aPoint
<< The current method does a comparsion of bounding boxes. Seems to me that intersecting the bounding rectangle is not a terribly accurate measurement of hit detection. Is this going to change in the near future? >>
See Also: - isStrokeHitByPath:, - isStrokeHitByRect:, - isHitByPoint:, - bounds
- (BOOL)isStrokeHitByRect:(NSRect)aRect
<< The current method does a comparsion of bounding boxes. Seems to me that intersecting the bounding rectangle is not a terribly accurate measurement of hit detection. Is this going to change in the near future? >>
See Also: - isStrokeHitByPath:, - isStrokeHitByPoint:, - isHitByRect:, - bounds
- (void)lineToPoint:(NSPoint)aPoint
See Also: - closePath, - curveToPoint:controlPoint1:controlPoint2:, - moveToPoint:
- (void)moveToPoint:(NSPoint)aPoint
See Also: - closePath, - curveToPoint:controlPoint1:controlPoint2:, - lineToPoint:
- (int)pathElementIndexForPointIndex:(int)index
See Also: - pointAtIndex:, - pointCount, - pointIndexForPathElementIndex:, - setPointAtIndex:toPoint:
- (NSPoint)pointAtIndex:(int)index
See Also: - pathElementIndexForPointIndex:, - pointCount, - pointIndexForPathElementIndex:, - setPointAtIndex:toPoint:
- (int)pointCount
See Also: - pathElementIndexForPointIndex:, - pointAtIndex:, - pointIndexForPathElementIndex:, - setPointAtIndex:toPoint:
- (int)pointIndexForPathElementIndex:(int)index
See Also: - pathElementIndexForPointIndex:, - pointAtIndex:, - pointCount, - setPointAtIndex:toPoint:
- (void)relativeCurveToPoint:(NSPoint)aPoint
controlPoint1:(NSPoint)controlPoint1
controlPoint2:(NSPoint)controlPoint2
See Also: - closePath, - curveToPoint:controlPoint1:controlPoint2:, - relativeLineToPoint:, - relativeMoveToPoint:
- (void)relativeLineToPoint:(NSPoint)aPoint
See Also: - closePath, - lineToPoint:, - relativeLineToPoint:, - relativeMoveToPoint:
- (void)relativeMoveToPoint:(NSPoint)aPoint
See Also: - closePath, - moveToPoint:, - relativeCurveToPoint:controlPoint1:controlPoint2:, - relativeLineToPoint:
- (void)removeLastElement
See Also: - elementCount, - elementTypeAtIndex:, - elementTypeAtIndex:associatedPoints:
- (void)reset
- (void)setCachesBezierPath:(BOOL)flag
See Also: - cachesBezierPath
- (void)setClip
See Also: - addClip, + clipRect:, - saveGraphicsState, - restoreGraphicsState, - saveGraphicsState (NSGraphicsContext)
- (void)setPointAtIndex:(int)index toPoint:(NSPoint)aPoint
See Also: - pathElementIndexForPointIndex:, - pointAtIndex:, - pointCount, - pointIndexForPathElementIndex:
- (void)setWindingRule:(NSWindingRule)aWindingRule
NSWindingRuleNonZero
or NSWindingRuleEvenOdd
.
See "Winding Rules and Filling Paths" for more information on
how winding rules affect the appearance of filled paths.See Also: - fill, - windingRule
- (void)stroke
See Also: - fill, + setLineCapStyle:, + setLineJoinStyle:, - set, - set (NSColor)
- (NSWindingRule)windingRule
NSWindingRuleNonZero
or NSWindingRuleEvenOdd
.
See "Winding Rules and Filling Paths" for more information on
how winding rules affect the appearance of filled paths.See Also: - fill, - setWindingRule: