6

In SpriteKit, the clockwise direction is reversed for UIBezierPath but not for CGPath. For example, if I have

do {
    let path = CGPathCreateMutable()
    CGPathAddArc(path, nil, 0, 0, 10, 0, CGFloat(M_PI_2), true)
    let node = SKShapeNode(path: path)
    node.position = CGPoint(x: self.size.width/2, y: self.size.height/2)
    self.addChild(node)
}
do {
    let path = UIBezierPath()
    path.addArcWithCenter(CGPoint(x: 0, y: 0), radius: 10, startAngle: 0, endAngle: CGFloat(M_PI_2), clockwise: true)
    let node = SKShapeNode(path: path.CGPath)
    node.position = CGPoint(x: self.size.width/2, y: self.size.height/2 - 100)
    self.addChild(node)
}

in GameScene.didMoveToView(view: SKView), the first node draws a 3/4 arc with top-right missing, but the second node draws a quarter arc at top-right. The reversed "clockwise" direction in UIBezierPath is explained in this post, but why doesn't CGPath behave the same? Isn't UIBezierPath just a wrapper around CGPath?

Note: This happens to both Objective-C and Swift (so not language-specific). Did not try on Mac App with NSBezierPath.

Franklin Yu
  • 8,920
  • 6
  • 43
  • 57
  • 1
    I first read "Do not try on Mac App with NSBezierPath!", like it would be somehow dangerous – yeoman Sep 09 '20 at 06:08

1 Answers1

14

CGPath and UIBezierPath use different coordinate systems. UIBezierPath's origin is at the top-left corner of the drawing area and CGPath's origin in at the bottom-left. Consequently, 90º is the lowest point on the circle for UIBezierPath and the highest point for CGPath. Since 0º is at the same point (right-most point) on the circle for both paths, the resulting clockwise arcs from 0º to 90º are drawn differently.

With the origin at the top-left, 90º (π/2) is at the lowest point on the circle and, therefore, a clockwise UIBezierPath arc is drawn as shown in the figure below. Since SpriteKit's origin is at the bottom-left, this arc appears flipped (vertically) when used to create the SKShapeNode.

enter image description here

With the origin at the bottom-left, 90º is at the top of the circle and a clockwise CGPath arc is drawn as shown below. Since SpriteKit's origin is also at the bottom-left, the shape node arc appears in the same orientation.

enter image description here

0x141E
  • 12,613
  • 2
  • 41
  • 54
  • Thank you. I just found the reference about this for [`UIBezierView`](https://developer.apple.com/library/ios/documentation/2DDrawing/Conceptual/DrawingPrintingiOS/BezierPaths/BezierPaths.html#//apple_ref/doc/uid/TP40010156-CH11-SW5) and [`CGPath`](https://developer.apple.com/library/mac/documentation/GraphicsImaging/Conceptual/drawingwithquartz2d/dq_overview/dq_overview.html#//apple_ref/doc/uid/TP30001066-CH202-CJBBAEEC). – Franklin Yu Apr 27 '16 at 00:13
  • 1
    "Since SpriteKit's origin is at the bottom-left, this arc appears flipped (vertically) when used to create the SKShapeNode." I'm surprised this isn't more visibly documented. A vertical flip is literally the difference between clockwise and counterclockwise and I've been tearing my hair out wondering why my UIBezierCurve was coming out counterclockwise through my SKShapeNode. – Randy Jay Yarger May 15 '20 at 14:25