2015-10-14 25 views
0

核心图形有两个功能,CGPathCreateCopyByDashingPath()CGPathCreateCopyByStrokingPath(),这两个函数都需要一个CGPath,您想要笔划并将其转换为其等效填充。我需要这样做,例如,我可以用渐变描边线条:调用CGPathCreateCopyByStrokingPath(),将路径加载到CGContext中,调用CGContextClip(),然后绘制渐变。如何将CGPathCreateCopyByDashingPath()和CGPathCreateCopyByStrokingPath()组合起来在OS X上描画虚线的CGPath?

但是,CGPathCreateCopyByStrokingPath()接受线条线条,线条连接等线条线条参数,而CGPathCreateCopyByDashingPath()没有。我希望能够用自定义线帽/连接冲刺。

特别地,这两个函数具有在他们的单证以下:创建

新路径,使得加注新路径绘制像素相同的像素与指定的破折号参数抚摸原始路径。

创建新路径以便填充新路径绘制与抚摸原始路径相同的像素。

强调我的。所以我从中得出的结论是,一旦你调用了任何一个函数,你就会得到一个由包含所请求的笔划的行组成的新路径。所以,如果我打电话ByDashing,然后ByStroking,第一个将创建一个由一串小矩形组成的路径,然后第二个将形成矩形形成这些小矩形的周长线,这不是我想要的。 (我可以测试这个,并在稍后张贴图片。)

我见过的一切指向Core Graphics可以直接使用CGContext来做到这一点;例如,“Programming with Quartz”书籍在其潇洒的例子中显示了圆形和方形的线条上限。有没有任何理由我不能用独立的CGPath做到这一点?

我错过了什么吗?或者我只是坚持这一点?

这是用于OS X,不适用于iOS。

谢谢。

回答

1

原来的文档CGPathCreateCopyByDashingPath()是错误的。

眼下,它说

创建新的路径,以便加注新路径得出相同的像素与指定的仪表参数抚摸着原始路径。

这意味着它会产生具有默认笔画参数的合成路径。但它不!相反,你会得到一个新的路径,这个路径就是现有的由破折号参数分解的路径。您需要拨打CGPathCreateCopyByStrokingPath()才能生成填写路径。

以下程序有三个部分。首先通过使用CGContext函数而不是CGPath函数来显示路径应该看起来像什么。其次,它只绘制CGPathCreateCopyByDashingPath()。请注意,如何抚摸路径不会产生破折号曾经是一堆盒子,而是一堆破折号。如果仔细观察,你会发现线条连接处的蓝色小病。最后,它调用CGPathCreateCopyByDashingPath(),然后是CGPathCreateCopyByStrokingPath(),你会看到填充产生正确的输出。再次

Screenshot

谢谢,bhaller!我不确定文件的变更内容,或者如何请求这样的变更。

// 15 october 2015 
#import <Cocoa/Cocoa.h> 

@interface dashStrokeView : NSView 
@end 

void putstr(CGContextRef c, const char *str, double x, double y) 
{ 
    NSFont *sysfont; 
    CFStringRef string; 
    CTFontRef font; 
    CFStringRef keys[1]; 
    CFTypeRef values[1]; 
    CFDictionaryRef attrs; 
    CFAttributedStringRef attrstr; 
    CTLineRef line; 

    sysfont = [NSFont systemFontOfSize:[NSFont systemFontSizeForControlSize:NSRegularControlSize]]; 
    font = (CTFontRef) sysfont;  // toll-free bridge 

    string = CFStringCreateWithCString(kCFAllocatorDefault, 
     str, kCFStringEncodingUTF8); 
    keys[0] = kCTFontAttributeName; 
    values[0] = font; 
    attrs = CFDictionaryCreate(kCFAllocatorDefault, 
     keys, values, 
     1, 
     &kCFTypeDictionaryKeyCallBacks, 
     &kCFTypeDictionaryValueCallBacks); 
    attrstr = CFAttributedStringCreate(kCFAllocatorDefault, string, attrs); 

    line = CTLineCreateWithAttributedString(attrstr); 
    CGContextSetTextPosition(c, x, y); 
    CTLineDraw(line, c); 

    CFRelease(line); 
    CFRelease(attrstr); 
    CFRelease(attrs); 
    CFRelease(string); 
} 

@implementation dashStrokeView 

- (void)drawRect:(NSRect)r 
{ 
    CGContextRef c; 
    CGFloat lengths[2] = { 10, 13 }; 
    CGMutablePathRef buildpath; 
    CGPathRef copy, copy2; 

    c = (CGContextRef) [[NSGraphicsContext currentContext] graphicsPort]; 

    CGContextSaveGState(c); 

    putstr(c, "Dash + Stroke With CGContext Functions", 10, 10); 
    CGContextMoveToPoint(c, 50, 50); 
    CGContextAddLineToPoint(c, 100, 30); 
    CGContextAddLineToPoint(c, 150, 70); 
    CGContextAddLineToPoint(c, 200, 50); 
    CGContextSetLineWidth(c, 10); 
    CGContextSetLineJoin(c, kCGLineJoinBevel); 
    CGContextSetLineCap(c, kCGLineCapRound); 
    CGContextSetLineDash(c, 0, lengths, 2); 
    CGContextSetRGBStrokeColor(c, 0, 0, 0, 1); 
    CGContextStrokePath(c); 
    // and reset 
    CGContextSetLineWidth(c, 1); 
    CGContextSetLineJoin(c, kCGLineJoinMiter); 
    CGContextSetLineCap(c, kCGLineCapButt); 
    CGContextSetLineDash(c, 0, NULL, 0); 

    CGContextTranslateCTM(c, 0, 100); 
    putstr(c, "Dash With CGPath Functions", 10, 10); 
    buildpath = CGPathCreateMutable(); 
    CGPathMoveToPoint(buildpath, NULL, 50, 50); 
    CGPathAddLineToPoint(buildpath, NULL, 100, 30); 
    CGPathAddLineToPoint(buildpath, NULL, 150, 70); 
    CGPathAddLineToPoint(buildpath, NULL, 200, 50); 
    copy = CGPathCreateCopyByDashingPath(buildpath, NULL, 0, lengths, 2); 
    CGContextAddPath(c, copy); 
    CGContextStrokePath(c); 
    CGContextAddPath(c, copy); 
    CGContextSetRGBFillColor(c, 0, 0.25, 0.5, 1); 
    CGContextFillPath(c); 
    CGPathRelease(copy); 
    CGPathRelease((CGPathRef) buildpath); 

    CGContextTranslateCTM(c, 0, 100); 
    putstr(c, "Dash + Stroke With CGPath Functions", 10, 10); 
    buildpath = CGPathCreateMutable(); 
    CGPathMoveToPoint(buildpath, NULL, 50, 50); 
    CGPathAddLineToPoint(buildpath, NULL, 100, 30); 
    CGPathAddLineToPoint(buildpath, NULL, 150, 70); 
    CGPathAddLineToPoint(buildpath, NULL, 200, 50); 
    copy = CGPathCreateCopyByDashingPath(buildpath, NULL, 0, lengths, 2); 
    copy2 = CGPathCreateCopyByStrokingPath(copy, NULL, 10, kCGLineCapRound, kCGLineJoinBevel, 10); 
    CGContextAddPath(c, copy2); 
    CGContextSetRGBFillColor(c, 0, 0.25, 0.5, 1); 
    CGContextFillPath(c); 
    CGContextAddPath(c, copy2); 
    CGContextStrokePath(c); 
    CGPathRelease(copy2); 
    CGPathRelease(copy); 
    CGPathRelease((CGPathRef) buildpath); 

    CGContextRestoreGState(c); 
} 

- (BOOL)isFlipped 
{ 
    return YES; 
} 

@end 

@interface appDelegate : NSObject<NSApplicationDelegate> 
@end 

@implementation appDelegate 

- (void)applicationDidFinishLaunching:(NSNotification *)note 
{ 
    NSWindow *mainwin; 
    NSView *contentView; 
    dashStrokeView *view; 
    NSDictionary *views; 
    NSArray *constraints; 

    mainwin = [[NSWindow alloc] initWithContentRect: NSMakeRect(0, 0, 320, 360) 
     styleMask:(NSTitledWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask | NSResizableWindowMask) 
     backing:NSBackingStoreBuffered 
     defer:YES]; 
    [mainwin setTitle:@"Dash/Stroke Example"]; 
    contentView = [mainwin contentView]; 

    view = [[dashStrokeView alloc] initWithFrame:NSZeroRect]; 
    [view setTranslatesAutoresizingMaskIntoConstraints:NO]; 
    [contentView addSubview:view]; 

    views = NSDictionaryOfVariableBindings(view); 
    constraints = [NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[view]-|" 
     options:0 
     metrics:nil 
     views:views]; 
    [contentView addConstraints:constraints]; 
    constraints = [NSLayoutConstraint constraintsWithVisualFormat:@"V:|-[view]-|" 
     options:0 
     metrics:nil 
     views:views]; 
    [contentView addConstraints:constraints]; 

    [mainwin cascadeTopLeftFromPoint:NSMakePoint(20, 20)]; 
    [mainwin makeKeyAndOrderFront:nil]; 
} 

- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)app 
{ 
    return YES; 
} 

@end 

int main(void) 
{ 
    NSApplication *app; 

    app = [NSApplication sharedApplication]; 
    [app setActivationPolicy:NSApplicationActivationPolicyRegular]; 
    [app setDelegate:[appDelegate new]]; 
    [app run]; 
    return 0; 
} 
+1

您可以随时向苹果公司提交雷达(错误报告)以请求文档更改:http://radar.apple.com/ –

1

我不确定问题是什么,真的。你有一条开始的道路;我们称之为A。您拨打CGPathCreateCopyByDashingPath()A开辟一条您想要的崭新路线;我们称之为BB没有设置特定的行上限/连接,因为它不是路径的属性,而是在抚摸路径时使用的属性。 (想象一下,通过从点到点绘制线段来手工绘制虚线路径;在路径描述中没有任何概念的顶点或连接,只是每个段的起点和终点。)然后取B并调用CGPathCreateCopyByStrokingPath()就可以了获得C,使用特定线宽/帽/连接特征的B中风的可填充路径。最后,使用渐变填充填充C。这不行吗?好像你知道你需要解决你的问题的所有组件,所以我不确定问题实际在哪里。你能澄清吗?

+0

问题是,ByDashing的文档显示“新路径已创建,因此**填充新路径**会绘制与使用指定的破折号参数描绘原始路径相同的像素。”强调我的。除非文档是错误的,否则调用ByDrawing和ByStroking将产生一堆小矩形或椭圆,其中破折号曾经是。如果这个解释不清楚,我可能应该编写一个测试用例并将其效果可视化,但是我将在此期间将其添加到问题中。 – andlabs

+1

啊,我明白你的意思了。如果那真的是'ByDashing'所做的,那么这看起来是一个糟糕的设计 - 它已经将ByDashing应该做的和ByStroking做了什么。不幸的。是的,如果您对此进行测试,请在此处发布结果,我很想知道。如果文档是正确的,那么我会在Apple上提出一个问题,要求提供一个没有损坏的新API。 – bhaller

+0

O ... kay我似乎无法使用10.10上的CGContext函数在虚线上设置笔触设置。完全奇怪。我想知道这个设施是否被彻底清除,因为Quartz编程书上说我应该可以...... – andlabs