Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

iOS - Clipping union of two paths using UIBezierPath appendPath

I'm attempting the create a clipping path in the shape of a plus sign, so that subsequent paths that I draw into the same context have this portion removed. I create the clipping path using two rectangle paths overlaid on each other.

This is what I'd like the final drawing to look like when I subsequently draw a circle:

      xXX|   |XXx
   XXXX|   |XXXX
 XXXXX|   |XXXXX
 ———      ———
 ———      ———
 XXXXX|   |XXXXX
   XXXX|   |XXXX
      xXX|   |XXx

However, it actually looks like this:

      xXX|   |XXx
   XXXX|   |XXXX
 XXXXX|   |XXXXX
 ——— XX———
 ——— XX———
 XXXXX|   |XXXXX
   XXXX|   |XXXX
      xXX|   |XXx

If I read this behaviour correctly, the intersection of the two rectangle paths is not forming part of the clipping mask.

It seems (not surprisingly) that appendPath does not create a single unified path from my two rectangle paths in this case - I'm assuming that there is nothing I can do about this. Furthermore, Core Graphics doesn't seem to have any functions relating to path unions etc.

Does anyone have any idea what I can do? I've included the relevant code snippet.

Drawing the plus sign using one path isn't a solution, as I want to add other overlapping paths to my clipping mask.

        CGContextSaveGState(context);

        // create clipping path
        UIBezierPath *clippingPath = [UIBezierPath bezierPath];
        clippingPath = [UIBezierPath bezierPathWithRect:CGRectMake(centrePoint.x - 2.0f, 0.0f, 4.0f, self.sizeY)];
        [clippingPath appendPath:[UIBezierPath bezierPathWithRect:CGRectMake(0.0f, centrePoint.y - 2.0f, self.sizeX, 4.0f)]];

        // use the clipping path to create a hole in the context
        CGContextAddPath(context, clippingPath.CGPath);
        CGRect boundingRect = CGContextGetClipBoundingBox(context);
        CGContextAddRect(context, boundingRect);
        CGContextEOClip(context);

        // draw the icon shape (clipped portion is removed)
        iconBezierPath = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(self.sizeX / 3.0f, self.sizeY / 2.25f, self.sizeX / 3.0f, self.sizeX / 3.0f)];

        [highlightColor setFill];
        [iconBezierPath fill];
        CGContextRestoreGState(context);
like image 807
D A Avatar asked Mar 21 '13 15:03

D A


1 Answers

You can add back the piece that gets knocked out by the intersection using CGRectIntersection

    CGContextSaveGState(context);

    CGRect rect1 = CGRectMake(centrePoint.x - 2.0f, 0.0f, 4.0f, self.sizeY);
    CGRect rect2 = CGRectMake(0.0f, centrePoint.y - 2.0f, self.sizeX, 4.0f);
    CGRect rect3 = CGRectIntersection(rect1, rect2);

    CGContextAddRect(context, rect1);
    CGContextAddRect(context, rect2);
    CGContextAddRect(context, rect3);

    CGRect boundingRect = CGContextGetClipBoundingBox(context);
    CGContextAddRect(context, boundingRect);
    CGContextEOClip(context);

        // draw the icon shape (clipped portion is removed)
    iconBezierPath = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(self.sizeX / 3.0f, self.sizeY / 2.25f, self.sizeX / 3.0f, self.sizeX / 3.0f)];

    [highlightColor setFill];
    [iconBezierPath fill];

    CGContextRestoreGState(context);

This satisfies the requirements of your question, but whether it entirely satisfies your needs depends on the nature of the "other overlapping paths".

enter image description here

like image 156
foundry Avatar answered Nov 04 '22 21:11

foundry