3

A dashed line

I'm using this code to stroke a NSBezierPath with a wide, dashed, black line.

(c and strForBezier are defined somewhere else)

NSGlyph glyph;
for(n = 0; n < len; n++) {
    glyph = [font glyphWithName: [strForBezier substringWithRange:NSMakeRange(n, 1)]];
    [path appendBezierPathWithGlyph: glyph inFont: font];
}

CGFloat pattern2[4]; pattern2[0]=5*c; pattern2[1]=2*c; pattern2[2]=2*c; pattern2[3]=2*c;
[path setLineDash:pattern2 count:4 phase:0];

[path setLineWidth:c];
[path stroke];
[[NSColor blueColor] set ];
[path fill];

How can I get the black NSBezierPath ? I'm making the assumption that a NSBezierPath is built and filled to stroke the initial curve.

alecail
  • 3,993
  • 4
  • 33
  • 52

1 Answers1

3

You can create a path by dashing and stroking an existing path, but that requires to use CGPathRef instead of NSBezierPath.

CGMutablePathRef path0 = CGPathCreateMutable();
CGAffineTransform transform = CGAffineTransformMakeTranslation(20, 20);
// initial position is {20, 20}

CGGlyph glyph;
for(n = 0; n < len; n++)
{
    glyph = [font glyphWithName: [strForBezier substringWithRange:NSMakeRange(n, 1)]];
    CGPathRef glyphPath = CTFontCreatePathForGlyph((__bridge CTFontRef) font, glyph, NULL);
    CGPathAddPath(path0, &transform, glyphPath);
    CGPathRelease(glyphPath);

    // append the glyph advance to the transform
    CGSize advance;
    CTFontGetAdvancesForGlyphs((__bridge CTFontRef) font, kCTFontDefaultOrientation, &glyph, &advance, 1);
    transform.tx += advance.width;
    transform.ty += advance.height;
}

CGFloat pattern2[4]; pattern2[0]=5*c; pattern2[1]=2*c; pattern2[2]=2*c; pattern2[3]=2*c;
CGPathRef path1 = CGPathCreateCopyByDashingPath(path0, NULL, 0, pattern2, 4);
CGPathRef path2 = CGPathCreateCopyByStrokingPath(path1, NULL, c, kCGLineCapButt, kCGLineJoinMiter, CGFLOAT_MAX);

CGContextRef context = [NSGraphicsContext currentContext].graphicsPort;
CGContextAddPath(context, path2);
CGContextDrawPath(context, kCGPathFill);

CGPathRelease(path0);
CGPathRelease(path1);
CGPathRelease(path2);

If you're not comfortable with CGPathRef, you may create a NSBezierPath then convert it to a CGPathRef using the method described in Apple documentation Building a CGPathRef From a NSBezierPath Object (the reverse is also possible).

Nicolas Bachschmidt
  • 6,475
  • 2
  • 26
  • 36
  • The code makes sense, but I can't compile it on my system (OS X 10.7); I have 1/`Use of undeclared identifier 'kCTFontOrientationDefault'; did you mean 'kCTFontOptionsDefault'?` 2/`Incompatible pointer types passing 'NSGlyph *' (aka 'unsigned int *') to parameter of type 'const CGGlyph *' (aka 'const unsigned short *')`. – alecail Jul 09 '12 at 22:54
  • I fixed the pointer type issue by using CGGlyph instead of NSGlyph (although they store the same value, they don't have the same size). `kCTFontOrientationDefault` should be declared. You may need to include the `` header. – Nicolas Bachschmidt Jul 10 '12 at 12:36
  • `kCTFontOrientationDefault` is not defined. The correct name is: `kCTFontDefaultOrientation`. – alecail Jul 10 '12 at 13:03
  • My bad. You're right: `kCTFontDefaultOrientation` is the correct name and `kCTFontOrientationDefault` ins't declared yet. – Nicolas Bachschmidt Jul 10 '12 at 13:20