将CGPathRef拆分为多个路径

时间:2017-07-16 16:39:30

标签: ios objective-c cgpath

我试图通过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。

1 个答案:

答案 0 :(得分: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);

这种方式很有用。一个问题是我没有得到正确的曲线,因此产生的路径不像它们应该的那样平滑。如果我解决它,我会更新。

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

enter image description here

更新:我发现每个点(元素 - >点)都包含正确绘制点的剩余数据(x和y)。例如:

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);
}

这将正确绘制每个字形。