Search code examples
ioscgpathcgpathref

Opposite of CGPathCreateCopyByStrokingPath?


Are there any core or other framework methods to return a CGPath or collection of some type that represents the Fill portion of a path object?

I am looking for something that would basically do the opposite of CGPathCreateCopyByStrokingPath.

With the help of an article on low-level-text-rendering I was able to come up with a path representing each letter of the alphabet.

The problem is that the path is the outline of the letter and what I would actually like to have is a path that represents only the fill portion of the letter instead of the stroke. For example the letter "A" would just consist of 3 distinct lines.

I am currently trying to work around this problem with class that acts much like an over complicated 16 segment display. Here is some sample code from that effort for anyone who is interested:

const NSUInteger segmentsPerDimension = 4;
const CGFloat oneOverTheNumberOfSegments = 1.0 / segmentsPerDimension;

@implementation PathSegments

- (instancetype)initWithRect:(CGRect)rect {
    self = [super init];
    [self setSegmentBounds:rect];
    _segments = [[NSMutableArray alloc] init];
    ...
    [self addVerticalSegments];
    ...
    return self;
}

- (void)addVerticalSegments {
    for (NSUInteger i = 0; i <= segmentsPerDimension; i++) {
        [self createColumnSegmentsForRow:i];
    }
}

- (void)createColumnSegmentsForRow:(NSUInteger)row {
    for (NSUInteger i = 0; i < segmentsPerDimension; i++) {
        CGFloat x = _segmentBounds.size.width * oneOverTheNumberOfSegments * row;
        CGFloat yEnd = _segmentBounds.size.height * oneOverTheNumberOfSegments * i;
        CGFloat yStart = _segmentBounds.size.height * oneOverTheNumberOfSegments * (i + 1);
        [self addLineSegmentWithXStart:x YStart:yStart XEnd:x YEnd:yEnd];
    }
}
...
@end

Solution

  • I have determined that it does not make sense to return the fill portion of a path. While a path can be defined in such a way to draw a circle, rectangle or custom shape by filling an outline, it would be ambiguous to copy the fill portion to another path because it would simply be the same path you started with.

    A segmented path which is then combined into one full path using GPathAddPath(...) seems to be the way to go on this one. With a series lines and curves you can roll your own letter shapes.

    A snippet based on the assumption you have defined a set of points to use as segments of the path:

    _generatedSegmentPath = CGPathCreateMutable();
    CGMutablePathRef subPath = CGPathCreateMutable();
    
    ...
    
    if (CGPathIsEmpty(subPath)) {
        CGPoint start = [[points objectAtIndex:startIndex] CGPointValue];
        CGPathMoveToPoint(subPath, nil, start.x, start.y);
    }
    
    if (points.count == 2) {
        CGPoint point = [[points objectAtIndex:startIndex + indexChange] CGPointValue];
        CGPathAddLineToPoint(subPath, nil, point.x, point.y);
    }
    else {
        CGPoint controlPoint = [[points objectAtIndex:startIndex + indexChange] CGPointValue];
        CGPoint endPoint = [[points objectAtIndex:startIndex + (2 * indexChange)] CGPointValue];
        CGPathAddQuadCurveToPoint(subPath, nil, controlPoint.x, controlPoint.y, endPoint.x, endPoint.y);
    }
    

    Then to combined the subpaths together:

    CGPathAddPath(_generatedSegmentPath, nil, subPath);