Aron C
Aron C

Reputation: 838

iOS: CoreGraphics - Clipping an Arc with CGContextClip and lineCap = .Round

I have an arc, which I have drawn as follows:

    func drawBackgroundMask(context: CGContextRef,
                        center: CGPoint,
                        radius: CGFloat,
                        lineWidth: CGFloat,
                        startAngle: CGFloat,
                        endAngle: CGFloat) {
    let adjustedRadius: CGFloat = radius - (lineWidth/2) - 0

    CGContextSetLineWidth(context, lineWidth)
    CGContextSetLineCap(context, .Round)

    CGContextAddArc(context,
                    center.x,
                    center.y,
                    adjustedRadius,
                    startAngle,
                    endAngle,
                    0)

    //CGContextClosePath(context)
    //CGContextClip(context)
    CGContextStrokePath(context)

}

With the above lines commented out, I can create the following:

black arc

However, if I attempt to use the drawn shape as a mask by uncommenting-out the two lines of code above and then painting the background a solid, I get a different result:

    func drawBackgroundMask(context: CGContextRef,
                        center: CGPoint,
                        radius: CGFloat,
                        lineWidth: CGFloat,
                        startAngle: CGFloat,
                        endAngle: CGFloat) {
    let adjustedRadius: CGFloat = radius - (lineWidth/2) - 0

    CGContextSetLineWidth(context, lineWidth)
    CGContextSetLineCap(context, .Round)

    CGContextAddArc(context,
                    center.x,
                    center.y,
                    adjustedRadius,
                    startAngle,
                    endAngle,
                    0)

    CGContextClosePath(context)
    CGContextClip(context)
    CGContextStrokePath(context)

    CGContextSetRGBFillColor(context, 100.0/255.0, 100.0/255.0, 100.0/255.0, 1.0);
    CGContextFillRect(context, rect);
}

as mask

Can anyone explain to me why using the drawn arc as a clipping mask is causing it to be treated differently than it is drawn? Also, can anyone show me the correct way to create a mask in the shape of an arc with rounded ends? This problem is part of a larger control that I am working on where I must clip another arc with the shape of the arc show.

Upvotes: 3

Views: 1274

Answers (1)

Kurt Revis
Kurt Revis

Reputation: 27984

In your second example, the clip only takes the path of the arc into account. The various stroke parameters like line width, cap, etc. are only used when you actually stroke the path, which you aren't doing.

First you set up a path in the CGContext, then you clip it. The path in the context is consumed afterwards. As the documentation says:

After determining the new clipping path, the function resets the context’s current path to an empty path.

So when you call CGContextStrokePath, it has no effect, because at that time the current path in the CGContext is empty.

It sounds like you want to use CGContextReplacePathWithStrokedPath before you clip. The documentation even mentions this exact use case:

For example, you can clip to the stroked version of a path by calling this function followed by a call to the function CGContextClip.

func drawBackgroundMask(context: CGContextRef,
                    center: CGPoint,
                    radius: CGFloat,
                    lineWidth: CGFloat,
                    startAngle: CGFloat,
                    endAngle: CGFloat) {
    let adjustedRadius: CGFloat = radius - (lineWidth/2) - 0

    CGContextSetLineWidth(context, lineWidth)
    CGContextSetLineCap(context, .Round)

    CGContextAddArc(context,
                    center.x,
                    center.y,
                    adjustedRadius,
                    startAngle,
                    endAngle,
                    0)

    CGContextReplacePathWithStrokedPath(context)
    CGContextClip(context)

    CGContextSetRGBFillColor(context, 100.0/255.0, 100.0/255.0, 100.0/255.0, 1.0);
    CGContextFillRect(context, rect);
}

Upvotes: 5

Related Questions