2015-10-14 8 views
0

Core Graphics имеет две функции: CGPathCreateCopyByDashingPath() и CGPathCreateCopyByStrokingPath(), которые оба берут CGPath, которые вы хотите погладить и преобразовать в эквивалентную заливку. Мне нужно сделать это, чтобы я мог, например, погладить линию с градиентом: вызовите CGPathCreateCopyByStrokingPath(), загрузите путь в CGContext, вызовите CGContextClip(), а затем нарисуйте градиент.Как объединить CGPathCreateCopyByDashingPath() и CGPathCreateCopyByStrokingPath(), чтобы погладить пунктирный CGPath на OS X?

Однако CGPathCreateCopyByStrokingPath() принимает параметры линейного поглаживания, такие как линейная крышка, соединение линии и т. Д., В то время как CGPathCreateCopyByDashingPath() нет. Я хотел бы иметь возможность тире с пользовательской линией cap/join.

В частности, обе функции имеет следующую в их документации:

Новый путь создается так, чтобы заполняя новый путь рисует те же пиксели, как поглаживание исходного пути с заданными параметрами тира.

Новый путь создан таким образом, что , заполняющий новый путь рисует те же пиксели, что и поглаживание исходного пути.

Emphasis mine. Так что я беру из этого, так это то, что как только вы вызываете любую функцию, вы получаете новый путь, состоящий из строк, которые связывают запрошенный штрих. Поэтому, если я позвоню ByDashing, а затем ByStroking, первый создаст путь, состоящий из кучки маленьких прямоугольников, а затем второй сделает прямоугольники, которые образуют линии периметра этих маленьких прямоугольников, чего я не хочу. (Я могу проверить это и опубликовать фотографии позже.)

Все, что я видел, указывает на то, что Core Graphics может делать это напрямую с помощью CGContext; например, книга «Программирование с кварцем» показывает круглые и квадратные листы в своём личном примере. Есть ли причина, по которой я не могу сделать это с помощью автономного 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

Вы всегда можете подать Радар (отчет об ошибке) с Apple, чтобы запросить изменение документации: http://radar.apple.com/ –

1

Я не уверен, в чем проблема, действительно. У вас есть путь для начала; назовем это A. Вы вызываете CGPathCreateCopyByDashingPath(), чтобы создать новый путь от A, который вам нужен; назовем это B. B не имеет на нем определенных строк/объединений строк, поскольку это не свойство пути, а свойства, используемые при поглаживании пути. (Представьте, что вы создаете пунктирный путь, рисуя сегменты линии от точки к точке, нигде в этом описании пути нет понятия шапки или объединений, только начальные и конечные точки для каждого сегмента.) Затем возьмите B и вызовите CGPathCreateCopyByStrokingPath() на нем получите C, заполняемый путь для хода B с использованием конкретных характеристик ширины полосы/кепки/соединения. Наконец, заполните C, используя заливку градиента. Не работает ли это? Похоже, вы знаете обо всех компонентах, которые вам нужны для решения вашей проблемы, поэтому я не уверен, где проблема на самом деле; вы можете уточнить?

+0

Проблема заключается в том, что в документации для ByDashing говорится: «Новый путь создан так, что ** заполнение нового пути ** рисует те же пиксели, что и поглаживание исходного пути с указанными параметрами штриховки». Акцент мой. Если документация не соответствует действительности, вызов ByDrawing, за которым следует ByStroking, приведет к созданию пучка маленьких прямоугольников или эллипсов, где раньше были тире. Вероятно, я должен написать тестовый файл и визуализировать эффект, если это объяснение непонятно, но я добавлю это к вопросу в то же время. – andlabs

+1

А, я вижу вашу точку зрения. Если это действительно то, что делает ByDashing, то это похоже на плохую конструкцию - оно объединило то, что 'ByDashing' * должно * делать с тем, что делает ByStroking'. Несчастная. Да, если вы проверите это, пожалуйста, опубликуйте результаты здесь, мне было бы интересно узнать. Если документ правильный, то я бы подал на Apple ошибку, требуя, чтобы новый API не был сломан. – bhaller

+0

O ... kay Кажется, я не могу установить установки инсульта на пунктирной линии, используя функции CGContext 10.10. Совершенно странно. Я задаюсь вопросом, было ли средство удалено прямо, потому что в книге «Программирование с помощью кварца» сказано, что я должен уметь ... – andlabs

 Смежные вопросы

  • Нет связанных вопросов^_^