3

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

Borys T
  • 239
  • 2
  • 13

1 Answers1

5

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)
aheze
  • 24,434
  • 8
  • 68
  • 125
  • 2
    whats the difference from `0*.pi` to `2*.pi` and `1*.pi` to `3*.pi`? I don't get it. `-90` and `270` are not the same angle. If that were true `0` and `360` would be as well. – Leo Dabus Oct 09 '20 at 00:09
  • Yes, -90 and 270 are not the same angle, but if you put it on a circle, it's the same location. 0 is at the right-middle, and you can either go left (negative) or right (positive) – aheze Oct 09 '20 at 00:11
  • 1
    I see what you mean. The solution here is to use `-0.5 * .pi, endAngle: -2.5 * .pi` if he needs to use clockwise `false` – Leo Dabus Oct 09 '20 at 00:15
  • 1
    This extension looks familiar. :) https://stackoverflow.com/a/29179878/2303865 – Leo Dabus Oct 09 '20 at 00:19
  • Oh, I see it now. Thank you. – Borys T Oct 09 '20 at 00:19
  • 1
    @LeoDabus wait, it's yours! I've been using it in my projects for so long. Sorry I didn't credit, I'll edit – aheze Oct 09 '20 at 00:20
  • 1
    @aheze I still I don't understand why you can cross the zero clockwise while you can't cross it counter clockwise. It doesn't make any sense to me. It should behave the same. – Leo Dabus Oct 09 '20 at 01:20
  • I'm not entirely sure either, but I think it's because there needs to be a way to fill the entire circle, or leave it blank. I did some tests, though: [Normal](https://imgur.com/a/U3QjPbm), [20 added to start angle](https://imgur.com/a/TsDA1tL), [20 subtracted from start angle](https://imgur.com/a/UlEHXgP). I'm trying to make sense of it. – aheze Oct 09 '20 at 02:56
  • 1
    @LeoDabus Ok, I think I got it. Here's some [screenshots](https://drive.google.com/file/d/1z8CEDkJJwdQ1matrX8IqVRzoTE-0Tp-J/view?usp=sharing). If you gradually increase/decrease the angles, you can see how it's opposite depending on clockwise/counterclockwise – aheze Oct 09 '20 at 05:02
  • 1
    This illustrates it better. The arcs complements each other. So none is the complement of full. Y9u should add this info to your post. – Leo Dabus Oct 09 '20 at 05:27
  • 2
    So if the value increases clockwise will be full if the value decreases counterclockwise will be full. That totally makes sense to me now. – Leo Dabus Oct 09 '20 at 05:42