Strokes


A stroke, in Quartz 2D parlance, is nothing more than a line that the computer traces along a path. The library will draw the line with a fixed width with the center of the line lies directly atop the path. Apart from the width of the stroke, there are a number of other parameters that affect the way the computer draws the stroke. Figure 7.2 illustrates the anatomy of a stroke and presents several of these drawing parameters.

Figure 7.2. The Anatomy of a Stroke


The white line down the center of Figure 7.2 would not actually be drawn by Quartz. In the figure, it represents the stroked path, in this case two straight line segments. The gray area is the stroke itself and represents what the computer would draw when stroking this path. Notice that the width of the stroke, called the line width, extends to either side of the path. The part of the stroke stretching beyond the end of the path is called the end cap. This particular stroke uses round end caps. The point where the two segments of our path meet is called the join between the two segments. When stroking a path, you have some choices about the way the computer draws the joins. The stroke in figure 7.2 is "chopped off" because this stroke is using a join style called a bevel join.

Your application has control over all these features of a stroke and more. In the Core Graphics API the line parameters are part of the graphics state of the context, which means that you can save and restore them on the graphics state stack. For the Cocoa drawing APIs, the line parameters are stored as part of the NSBezierPath object. Before discussing the methods that apply a stroke to a path, first examine the parameters that your application can use to change the way that stroke looks.

Line Width

The simplest stroke parameter is the line width (a.k.a. stroke width). As seen in Figure 7.2 this is the total width of the line. Half of the stroke width will lie on either side of the path that you are stroking. Line widths are floating point valued and specified in Points. When working with bitmaps, Quartz 2D allows you to specify widths that are less than one pixel after they are transformed to device space. The computer uses antialiasing technologies to render these ultra-thin lines. Figure 7.3 shows the effect of changing the line width for a simple path.

Figure 7.3. Effect of the Line Width Parameter


To change the line width you can use the CGContextSetLineWidth method of a CGContext or the setLineWidth: parameter of an NSBezierPath.

In PostScript, if you set the line width to 0 it is a request to the graphics device to use a one pixel wide line regardless of how large a pixel might be. Quartz does not follow this convention. Quartz will not render lines with a line width of 0.


Changing the line width of the a stroke can affect the other parameters that go into stroking a path. For example, the end caps for the stroke will change to match the width of the stroke. The line width also can have an effect on the length of the miters applied at sharp corners of the path (see the section on the Miter Limit that follows for more details).

The default line width for a newly created CGContext is 1 Point. Without any intervention on the part of your application, the default line width for a newly created NSBezierPath is also 1, but you can change that default by calling the NSBezierPath class method setDefaultLineWidth:

End Caps

End caps allow you to change the way the start and end of strokes are drawn. Quartz 2D supports three different end cap styles. These are illustrated in Figure 7.4.

Figure 7.4. End Caps


All of the strokes in Figure 7.4 are the same length. The strokes with square and round end caps extend beyond the length of the path by a small amount.

To change the cap style in the current graphics state, you use the context method CGContextSetLineCap with any of the three constantskCGLineCapButt, kCGLineCapRound, and kCGLineCapSquare. If you want to change the cap style used when stroking an NSBezierPath, you can use the method setLineCapStyle: with the similar cap constants NSButtLineCapStyle, NSRoundLineCapStyle, or NSSquareLineCapStyle.

By default a CGContext will use butt end caps on any paths you stroke. The NSBezierPath class interface provides the method setDefaultLineCapStyle: to allow applications to change the default cap style for newly created NSBezierPaths.

Line Joins

Changing line joins changes the way that the computer draws the joints between curve segments of the path. The system supports three different line join styles, which are illustrated in Figure 7.5.

Figure 7.5. Line Joins


The method of the CGContext that changes the line join is simply, CGContextSetLineJoin. Just as there are constants for the line caps, there are constants for each of the line joins. They are kCGLineJoinMiter, kCGLineJoinRound, and kCGLineJoinBevel. The similar method that changes the line join style of an NSBezierPath is setLineJoinStyle:. The Cocoa API defines the same constants as NSMiterLineJoinStyle, NSRoundLineJoinStyle, and NSBevelLineJoinStyle.

The Miter Limit

The miter join extends the two outside edges of the strokes until they meet. When the angle between two edges is large, the miter doesn't extend very far beyond the place where the two segments meet. If the two segments meet at a very shallow angle, however, the miter might extend quite some distance from the join point. To avoid this issue, your application can limit the length of the miter by changing a parameter known as the miter limit.

Before discussing exactly what the miter limit means, first look at the effect of adjusting the miter limit. When the angle of a stroke generates a miter join that "exceeds" the miter limit, the computer substitutes a bevel join in its place. Figure 7.6 shows the same angled path drawn with two different miter limits to illustrate this point.

Figure 7.6. The Effect of Changing the Miter Limit for Acute Joins


The paths in Figure 7.6 are composed of two line segments that meet at a 30° angle. When the computer draws the path on the left side of the figure, the miter limit was set to a value of 10. The length of the miter does not exceed the miter limit, so the join is drawn as a miter. For the right side of the figure, we changed the miter limit to 3. In this case, the same 30° line join exceeds the miter limit. The computer draws this join as a beveled join instead.

You've already seen that the miter value for a join is related to the angle at which the two segments meet. The miter join is also affected by the line width of the path that you are stroking. Figure 7.7 shows how you can determine the miter value for a particular join.

Figure 7.7. Miter Value for a Join


As shown in the figure, the miter value for a join is the ratio of the miter length (measured from the inner corner of the join to the outer corner) and the line width of the path. If the miter value of the join exceeds the miter limit, then the computer will substitute a bevel join for the miter.

To change the miter limit of the current context, you can use the routine CGContextSetMiterLimit. If you want to change the miter limit used when drawing an NSBezierPath, you can call its setMiterLimit: method.

Line Dash

Quartz 2D is not limited to drawing only solid lines only. You also can ask the computer to draw a dashed lined. To Quartz, a dashed line is a pattern of line segment lengths. To create this dash pattern, you supply the library with an array of floating point values. The first value tells the computer how long the first segment of the dash should be. The second value gives the length of the gap in the line before the next segment begins. The third value in the array, if specified, gives the length of the next drawn segment (and the fourth value would be the length of the next gap). When the computer reaches the end of the array, it simply repeats the pattern starting over again at the first array entry. Figure 7.8 demonstrates a number of dashed lines with their corresponding value arrays.

Figure 7.8. Some Dashed Lines and their Pattern Arrays


In addition to a pattern array, a dash also has what is called a "phase" setting. The phase tells Quartz how many points into the pattern array the path should start. For example, if the dash pattern were [1, 3, 1, 4] and the dash phase were set to 4.5, the computer would start the dashed line half-way through the second array entry. It would begin the line with a gap 1.5 points long, then a 1 point stroked segment, and a 4 point gap before starting over at the 1 point stroked segment at the start of the pattern.

Dashes can be applied to any stroke, and the dashes themselves are affected by the cap settings of the current context. For example, if you select rounded end caps, each drawn dash segment will receive a round cap as well. Figure 7.9 illustrates the same dash pattern with different end caps selected.

Figure 7.9. Dashed Lines with End Caps


Just as the caps extend a stroke beyond its starting and ending points, the end caps on a dashed lines extend the drawn segments by just a bit. You may need to take this into account when designing a pattern for your dashed lines. The last line in Figure 7.10 shows an interesting application of the end caps applied to dashes. The dashed segments in this line are very short (1/10 Point) so that the end caps dominate the drawn segment of the dash. The end result is a dotted rather than dashed line.

Figure 7.10. Effect of Changing Flatness When Stroking a Path


To change the dash settings on a CGContext, you use the routine CGContextSetLineDash. The line dash is part of the graphics state and can be saved and restored with the rest of the graphics state settings. Like most other settings, the dash pattern is an attribute of an NSBezierPath. If you are working through Cocoa, you can change the dash attributes of a path using the setLineDash:count:phase: method.

Flatness

The flatness of a path is a parameter that controls a rather technical detail of the way the computer draws bezier paths. To draw a path, the computer breaks the curves in the path down into short line segments and draws the shapes using those short segments that approximate the curve. The flatness value is a measure of how closely this approximate curve must match the actual curve itself.

If the computer has a lower flatness setting, it uses shorter line segments and takes more segments to draw the curve. In this case the resulting shape will very closely match the curve. With larger flatness settings, the computer draws the path using longer segments. In general, that means it will have to draw fewer segments, but the shape will not follow the curve as closely. Figure 7.10 illustrates the effect of changing the flatness before drawing a path.

The figure shows the letter G from the Palatino font drawn with three different flatness settings. Notice the way the smoothness of the curve is affected by each flatness setting.

Flatness is a device-dependent setting. Changing the flatness on one device is not guaranteed to give you the same results if you use the same setting on a different device. Because of this, you should rarely rely on changes in the flatness setting for any particular effect. By the same token, however, changing the flatness value usually means that the computer has to work with fewer segments when drawing paths. If you are drawing paths where you can sacrifice a little visual accuracy for some added drawing speed, you may get a performance boost by raising the flatness.




Quartz 2D Graphics for Mac OS X Developers
Quartz 2D Graphics for Mac OS X Developers
ISBN: 0321336631
EAN: 2147483647
Year: 2006
Pages: 100

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net