2

I'm try to dynamically create puzzle piece, and it looks like this:
not filled puzzle piece
I want to fill this shape with some color so it will looks like this:
filled puzzle piece
so I can use it for masking some image.
PROBLEM: I creating this shape with 4 UIBezierPath, then convert it to 1 path using appendPath.
I want to fill this path but when I use fill I got this:
bad filled puzzle piece
Do you have any ideas how I can fill same shapes?

Artem Shmatkov
  • 1,434
  • 5
  • 22
  • 41

3 Answers3

6

After some time I found a reason why I got these results. If you want to create some path for filling you should not use moveToPoint method, instead you should just once set first point using moveToPoint and then draw all lines with addLineToPoint, addCurveToPoint, etc.

After you complete draw your path do not forget send closePath message.

Before I knew this, I drew every side of puzzle piece using different UIBezierPath instances and for every path I set first point using moveToPoint.

Artem Shmatkov
  • 1,434
  • 5
  • 22
  • 41
  • I'm running into the same problem, but I don't think your solution will work. Using your puzzle piece as an analogy, the right and bottom edges are created using cubic bezier curves that are essentially identical, with the second one simply being a CGAffineTransform of the other. Even without using the moveToPoint on the second curve, the transform appears to keep the two curves from joining, so the scope of the fill is just the curve defining each side. If someone has a solution to this where the transform can still be used, please share. – Victor Engel Apr 27 '13 at 22:48
  • @Victor Engel, my solution is working and I use it in my application. Why you talking about CGAffineTransform? I am not using it to draw puzzle piece lines. All bezier lines was drawn using coordinates which was calculated for each bezier curve. – Artem Shmatkov Apr 28 '13 at 05:48
  • I wasn't trying to suggest that was your issue. I was using your illustration to illustrate a complication. You many not use a transform, but a transform COULD be used to transform one to the other without having to figure out the other coordinates. I think my solution will be to apply the transform to CGPoints so that the paths don't need to be transformed. Then I can add them all in one path. – Victor Engel Apr 28 '13 at 05:53
  • I believe `closePath` is not needed, it's implicitly called. – ninjaneer Jul 26 '14 at 09:25
  • @zakhej Hey mate! Thanks for sharing, you save me couple of hours :D – RomOne Aug 10 '16 at 09:45
1

If you have a path defining your puzzle piece, it'll be easier to manipulate it if you turn it into a CAShapeLayer:

CAShapeLayer *myShapeLayer = [CAShapeLayer layer];
myShapeLayer.path = myBezierCurves.CGPath;
myShapeLayer.fillColor = [[UIColor blackColor] CGColor];

myShapeLayer.strokeColor = [[UIColor redColor] CGColor];
myShapeLayer.lineWidth = 2;
Eric
  • 16,003
  • 15
  • 87
  • 139
0

Try this: as intention to make one UIbenzierPath with all combined points

Add below method in .m file.

 void MyCGPathApplierFunc (void *info, const CGPathElement *element) {

UIBezierPath *drawingPath = (UIBezierPath *)info;
CGPoint *points = element->points;
CGPathElementType type = element->type;

switch(type) {
    case kCGPathElementMoveToPoint: // contains 1 point
        [drawingPath moveToPoint:[[NSValue valueWithCGPoint:points[0]] CGPointValue]];
        break;

    case kCGPathElementAddLineToPoint: // contains 1 point
        [drawingPath addLineToPoint:[[NSValue valueWithCGPoint:points[0]] CGPointValue]];
        break;
    case kCGPathElementAddQuadCurveToPoint: // contains 1 point
        [drawingPath addQuadCurveToPoint:[[NSValue valueWithCGPoint:points[0]] CGPointValue]];
        break;

   case kCGPathElementAddCurveToPoint: // contains 1 point
        [drawingPath addCurveToPoint:[[NSValue valueWithCGPoint:points[0]] CGPointValue]];
        break;

    case kCGPathElementCloseSubpath: // contains no point
        break;
}
}

Add UIBezierPath *combinedpath; in .h file U can use method like:

combinedpath = [[UIBezierPath alloc]init];
CGPathApply(appendedBenzierPath.CGPath, (void *)combinedpath, MyCGPathApplierFunc);
[self setNeedsDisplay];

Now fill in these combinedpath

- (void)drawRect:(CGRect)rect
{
  [[UIColor blackColor] setStroke];
  [combinedpath strokeWithBlendMode:kCGBlendModeNormal alpha:1.0];
  [combinedpath fill];
}
Paresh Navadiya
  • 38,095
  • 11
  • 81
  • 132