Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

An issue with CAShapeLayer and UIBezierPath drawing circle counterclockwise

I'm trying to draw a circle that starts and ends at 12 o'clock counterclockwise. The issue I'm having is that the shape is not being drawn. Im' using init(arcCenter center: CGPoint, radius: CGFloat, startAngle: CGFloat, endAngle: CGFloat, clockwise: Bool) initializer for the path and if I use clockwise: true, it works. If startAngle is set to 0 and endAngle to 2 * .pi it works with clockwise: false. However combination of clockwise: false and startAngle: -0.5 * .pi, endAngle: 1.5 * .pi doesn't work. Is there a reason for this and how can I fix it?

This one works:

let shapeLayer = CAShapeLayer()
let arcCenter = view.center
let circularPath = UIBezierPath(arcCenter: arcCenter, radius: 100, startAngle: 0, endAngle: 2 * CGFloat.pi, clockwise: false)
shapeLayer.path = circularPath.cgPath
shapeLayer.strokeColor = UIColor.red.cgColor
shapeLayer.lineWidth = 10
shapeLayer.lineCap = .round
shapeLayer.fillColor = .none
view.layer.addSublayer(shapeLayer)

And this one. Results look the same.

UIBezierPath(arcCenter: arcCenter, radius: 100, startAngle: -0.5 * .pi, endAngle: 1.5 * .pi, clockwise: true)

Success

But not this one:

UIBezierPath(arcCenter: arcCenter, radius: 100, startAngle: -0.5 * .pi, endAngle: 1.5 * .pi, clockwise: false)

Failed

like image 667
Borys T Avatar asked Feb 03 '26 01:02

Borys T


1 Answers

It's easier to think about this in degrees.

  • -0.5 * .pi radians equals -90 degrees
  • 1.5 * .pi radians equals 270 degrees
  • 0 degrees is at the middle-right of the circle

However, if you think about it, -90 and 270 are at the same position on the circle.


clockwise = true:

UIBezierPath(arcCenter: arcCenter, radius: 100, startAngle: -0.5 * .pi, endAngle: 1.5 * .pi, clockwise: true)

clockwise = false:

UIBezierPath(arcCenter: arcCenter, radius: 100, startAngle: -0.5 * .pi, endAngle: 1.5 * .pi, clockwise: false)

So how come clockwise draws the long way, but counterclockwise doesn't? Take a look at this: gradually increasing arc angles

If you pick two points (or you could say angles) on the circle and gradually increase one of them, you can see how the ring lengthens/shortens based on whether it's going clockwise/counterclockwise. The rings complement each other -- if you put the clockwise ring on top of the counterclockwise one, they fit perfectly together in a circle.

So, when you increase the ending point so that it's the equivalent of the starting point (start: -90, end: 270):

  • the clockwise ring will be full
  • the counterclockwise ring will be empty

whereas when you switch the negatives (start: 90, end: -270):

  • the clockwise ring will be empty
  • the counterclockwise ring will be full

Also, here's a handy extension (thanks @Leo Dabus!) so you don't have to deal with radians anymore:

extension BinaryInteger {
    var degreesToRadians: CGFloat { CGFloat(self) * .pi / 180 }
}

extension FloatingPoint {
    var degreesToRadians: Self { self * .pi / 180 }
    var radiansToDegrees: Self { self * 180 / .pi }
}

/// usage:
UIBezierPath(arcCenter: arcCenter, radius: 100, startAngle: -90.degreesToRadians, endAngle: 270.degreesToRadians, clockwise: true)
like image 137
aheze Avatar answered Feb 04 '26 14:02

aheze



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!