Uibezierpath Appending Overlapping Isn't Filled

UIBezierPath appending overlapping isn't filled

You were on the right track with setting the usesEvenOddFillRule to false. In addition to that, you need to make sure your shapes are both drawn in the same direction (clockwise or counter-clockwise).

I reversed the order of your addLines when drawing the triangle to reverse it.

override func draw(_ rect: CGRect) {
let firstShape = UIBezierPath()

firstShape.move(to: CGPoint(x: 100, y: 100))
firstShape.addLine(to: CGPoint(x: 150, y: 170))
firstShape.addLine(to: CGPoint(x: 100, y: 150))
firstShape.close()

let secondShape = UIBezierPath(rect: CGRect(x: 125, y: 125, width: 75, height: 75))

let combined = UIBezierPath()
combined.append(firstShape)
combined.append(secondShape)
combined.usesEvenOddFillRule = false

UIColor.black.setFill()
combined.fill()
}

Union UIBezierPaths rather than apend path

Finally a solution!!

Using https://github.com/adamwulf/ClippingBezier you can find the intersecting points. Then you can walk through the path, turning left if clockwise or vice-versa to stay on the outside. Then you can generate a new path using the sequence of points.

Two UIBezierPaths intersection as a UIBezierPath

I wrote a UIBezierPath library that will let you cut a given closed path into sub shapes based on an intersecting path. It'll do essentially exactly what you're looking for: https://github.com/adamwulf/ClippingBezier

NSArray<UIBezierPath*>* componentShapes = [shapePath uniqueShapesCreatedFromSlicingWithUnclosedPath:scissorPath];

Alternatively, you can also just find the intersection points:

NSArray* intersections = [scissorPath findIntersectionsWithClosedPath:shapePath andBeginsInside:nil];

UIBezierPath not cleared on redraw

I think the problem is merely that your drawing is huge and strays outside the cell because your views do not clip to bounds. That's incoherent. Each cell needs to draw just its own content.

In other words, the overlapping you are seeing has nothing to do with the custom view drawing; it has to do with the cell drawing. You are infecting the neighboring cells with your drawing.

By the way, you say:

but this isn't at all ideal since I lose the background (it becomes black)."

You can fix that by saying self.backgroundColor = .clear in your init.

reuse UIBezierPath object

Give this a try:

UIBezierPath *bgPath = [UIBezierPath bezierPath];
UIColor *color = [UIColor colorWithHex:BG_ARC_COLOR];
[color set];
[bgPath addArcWithCenter:self.center radius:BG_RADIUS startAngle:START_ANGLE endAngle:END_ENGLE clockwise:ANTY_CLOCK_WISE];
bgPath.lineWidth = BG_ARC_WIDTH;
bgPath.lineCapStyle = kCGLineCapRound;
bgPath.lineJoinStyle = kCGLineCapRound;
[bgPath stroke];

[bgPath removeAllPoints];

[bgPath moveToPoint:self.center];
[bgPath addArcWithCenter:self.center radius:BG_CIRCYLE_RADIUS startAngle:0 endAngle:2 * M_PI clockwise:CLOCK_WISE];
[bgPath addLineToPoint:self.center];
[bgPath fill];

iOS - Clipping union of two paths using UIBezierPath appendPath

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".

Sample Image



Related Topics



Leave a reply



Submit