Wednesday, June 5, 2013

UIBezierPath usesEvenOddFillRule example in Objective C (iOS).


UIBezierPath usesEvenOddFillRule

A Boolean indicating whether the even-odd winding rule is in use for drawing paths.

@property(nonatomic) BOOL usesEvenOddFillRule

Discussion of [UIBezierPath usesEvenOddFillRule]
If YES, the path is filled using the even-odd rule. If NO, it is filled using the non-zero rule. Both rules are algorithms to determine which areas of a path to fill with the current fill color. A ray is drawn from a point inside a given region to a point anywhere outside the path’s bounds. The total number of crossed path lines (including implicit path lines) and the direction of each path line are then interpreted as follows:[UIBezierPath usesEvenOddFillRule]

For the even-odd rule, if the total number of path crossings is odd, the point is considered to be inside the path and the corresponding region is filled. If the number of crossings is even, the point is considered to be outside the path and the region is not filled.
For the non-zero rule, the crossing of a left-to-right path counts as +1 and the crossing of a right-to-left path counts as -1. If the sum of the crossings is nonzero, the point is considered to be inside the path and the corresponding region is filled. If the sum is 0, the point is outside the path and the region is not filled.[UIBezierPath usesEvenOddFillRule]
The default value of this property is NO. For more information about winding rules and how they are applied to subpaths, see Quartz 2D Programming Guide.

UIBezierPath usesEvenOddFillRule example.
The even-odd rule is simply this:

As you progress in a straight line across the canvas containing the path, count the number of times you cross the path. If you have crossed an odd number of times, you are "inside" the path. If you have crossed an even number of times, you are outside the path.
UIBezierPath *clipPath = [UIBezierPath bezierPathWithRect:CGRectInfinite];
[clipPath appendPath:smallMaskPath];
clipPath.usesEvenOddFillRule = YES;

CGContextSaveGState(UIGraphicsGetCurrentContext()); {
    [clipPath addClip];
    [[UIColor orangeColor] setFill];
    [bigMaskPath fill];
} CGContextRestoreGState(UIGraphicsGetCurrentContext());

Example of [UIBezierPath usesEvenOddFillRule].
CGRect outerRect = {0, 0, 200, 200};
CGRect innerRect  = CGRectInset(outerRect,  30, 30);

UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:outerRect cornerRadius:10];

[path appendPath:[UIBezierPath bezierPathWithRoundedRect:innerRect cornerRadius:5]];
path.usesEvenOddFillRule = YES;

[[UIColor orangeColor] set];
[path fill];

UIBezierPath usesEvenOddFillRule example.
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    CGPoint curPoint = [[touches anyObject] locationInView:self];
    for (int i = 0; i < [pathInfo count]; i++){
        NSArray *row = [[NSArray alloc] initWithArray:[pathInfo objectAtIndex:i]];
        UIBezierPath *path = [row objectAtIndex:0];

        NSLog(@"Path %@", path);
        if (strokedPathContainsPoint(path.CGPath, NULL, 10.0f, kCGLineCapRound,
            kCGLineJoinRound, 0, curPoint, path.usesEvenOddFillRule))
        {
            NSLog(@"YES");
        } else {
            NSLog(@"NO");
        }
    }
}

End of UIBezierPath usesEvenOddFillRule example article.