【问题标题】:Split a CGPathRef into multiple paths将 CGPathRef 拆分为多个路径
【发布时间】:2017-07-16 16:39:30
【问题描述】:

我试图通过 CGPathRefs 将文本分成所有不同的部分。例如,L 有一条路径并且 ?有两个(点和其余部分)。

目前,我可以将每个字母作为路径但是在“?”的示例中路径同时包含点和其余部分。我想把它们分开,但我似乎无法让它工作。

为了将文本划分为路径,我使用了堆栈溢出的一些答案,它运行良好,这是我将每个字母作为路径的部分。在这里,我还通过“CGPathApply”函数运行它来查看每个单独的点

CGPathRef letter = CTFontCreatePathForGlyph(runFont, glyph, NULL);
NSMutableArray *pathElements = [NSMutableArray array];
CGPathApply(letter, (__bridge void * _Nullable)(pathElements), getPointsFromBezier);

然后我会像这样查看getPointsFromBezier 中的每个点:

void getPointsFromBezier(void *info, const CGPathElement *element){
    CGPoint *p = element->points;
    NSString *name;
    switch (element->type) {
        case kCGPathElementMoveToPoint: name = @"kCGPathElementMoveToPoint"; break;
        case kCGPathElementAddLineToPoint: name = @"kCGPathElementAddLineToPoint"; break;
        case kCGPathElementAddQuadCurveToPoint: name = @"kCGPathElementAddQuadCurveToPoint"; break;
        case kCGPathElementAddCurveToPoint: name = @"kCGPathElementAddCurveToPoint"; break;
        case kCGPathElementCloseSubpath: name = @"kCGPathElementCloseSubpath"; break;
        default: name = @"default"; break;
    }
    NSLog(@"Type: %@ || Point: %@", name, NSStringFromCGPoint(*p));
}

这给了我这样的输出:

Type: kCGPathElementMoveToPoint || Point: {11.75, 0}
Type: kCGPathElementAddLineToPoint || Point: {11.75, 9.729}
Type: kCGPathElementAddQuadCurveToPoint || Point: {11.75, 11.26}
..
..
Type: kCGPathElementAddQuadCurveToPoint || Point: {13.00, 10.52}
Type: kCGPathElementAddLineToPoint || Point: {13.00, 0}
Type: kCGPathElementCloseSubpath || Point: {13.00, 0}
Type: kCGPathElementMoveToPoint || Point: {12.75, 18.75}
Type: kCGPathElementAddQuadCurveToPoint || Point: {11.5, 18.94}
Type: kCGPathElementAddLineToPoint || Point: {11.5, 19.95}
Type: kCGPathElementAddQuadCurveToPoint || Point: {11.5, 20.41}
..
..
Type: kCGPathElementAddQuadCurveToPoint || Point: {12.75, 18.169}
Type: kCGPathElementCloseSubpath || Point: {12.75, 18.169}

我在这里输入的字符是ก็,我们可以清楚地看到它在输出中有两个不同的路径(即两个kCGPathElementMoveToPoint和两个kCGPathElementCloseSubpath)。

我不确定如何正确或很好地从中创建两个单独的 CGPathRef。

【问题讨论】:

    标签: ios objective-c cgpath


    【解决方案1】:

    其实,在写这个问题的时候,我差点就解决了。

    我创建一个静态可变 CGPath,然后在通过 CGPathApply 调用的函数中添加点。像这样:

    static CGMutablePathRef path;
    
    void getPointsFromBezier(void *info, const CGPathElement *element){
        CGPoint *p = element->points;
    
        if ( element->type == kCGPathElementMoveToPoint ){
            path = CGPathCreateMutable();
            CGPathMoveToPoint(path, nil, p->x, p->y);
        }
        else if ( element->type == kCGPathElementAddLineToPoint ){
            CGPathAddLineToPoint(path, nil, p->x, p->y);
        }
        else if ( element->type == kCGPathElementAddQuadCurveToPoint ){
            CGPathAddQuadCurveToPoint(path, nil, p->x, p->y, p->x, p->y);
        }
        else if ( element->type == kCGPathElementAddCurveToPoint ){
            // ...
        }
        else if ( element->type == kCGPathElementCloseSubpath ){
            CGPathCloseSubpath(path);
            [((__bridge NSMutableArray*)info) addObject:(__bridge id _Nonnull)(path)];
            path = nil;
            CGPathRelease(path);
        }
    }
    

    然后我简单地遍历原始方法中的每个路径并绘制它们而不是原始的“字母”CGPath。

    CGPathRef letter = CTFontCreatePathForGlyph(runFont, glyph, NULL);
    NSMutableArray *pathElements = [NSMutableArray array];
    CGPathApply(letter, (__bridge void * _Nullable)(pathElements), getPointsFromBezier);
    
    for (id e in pathElements) {
        CGContextSaveGState(ctx);
        CGContextTranslateCTM(ctx,position.x,0 - 40 + CGRectGetMidY(rect) - self.font.descender + position.y);
        CGContextScaleCTM(ctx, 1, -1);
        CGContextAddPath(ctx, (CGPathRef)e);
        [[self r] setFill];
        CGContextFillPath(ctx);
        CGContextRestoreGState(ctx);
    }
    
    CGPathRelease(letter);
    

    这有点用。一个问题是我没有得到正确的曲线,因此生成的路径并不像应有的那样平滑。解决了我会更新的。

    这是目前的结果,您可以看到与底部的原始图像相比,图像有点块状。但是,它们有两种不同的颜色,这是最初要解决的问题。

    UPDATE:我发现每个点(element->points)都包含剩余的数据(x 和 y's)以正确绘制点。例如:

    if ( element->type == kCGPathElementAddQuadCurveToPoint ){
        CGPoint *p0 = &points[0]; // Control points for bezier path
        CGPoint *p1 = &points[1]; // Actual points
        CGPathAddQuadCurveToPoint(path,
                                  nil,
                                  p0->x,
                                  p0->y,
                                  p1->x,
                                  p1->y);
    }
    

    这将正确绘制每个字形。

    【讨论】:

      猜你喜欢
      • 2020-08-04
      • 2015-01-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-05-23
      • 2018-03-05
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多