title: Animate a CAShapeLayer circle into a rounded-corner triangle
body: <p>I'd like to animate a shape as it transitions from a circle to a rounded-corner triangle.</p>
  
  <p><strong>TL;DR: How do I animate a <code>CAShapeLayer</code>'s <code>path</code> between two <code>CGPath</code> shapes? I know that they need to have the same number of control points, but I think I'm doing that - what's wrong with this code?</strong></p>
  
  <p>The beginning and end states would look something like this:
  <a href="http://clrk.it/4vJS+">transition http://clrk.it/4vJS+</a></p>
  
  <p>Here's what I've tried so far: I'm using a <code>CAShapeLayer</code>, and animating a change in its <code>path</code> property.</p>
  
  <p>According to the <a href="http://file:///Users/bryclark/Library/Developer/Shared/Documentation/DocSets/com.apple.adc.documentation.iOS.docset/Contents/Resources/Documents/documentation/GraphicsImaging/Reference/CAShapeLayer_class/index.html#//apple_ref/occ/instp/CAShapeLayer/path">documentation</a> (emphasis mine):</p>
  
  <blockquote>
    <p>The path object may be animated using any of the concrete subclasses of <code>CAPropertyAnimation</code>. Paths will interpolate as a linear blend of the "on-line" points; "off-line" points may be interpolated non-linearly (e.g. to preserve continuity of the curve's derivative). <strong>If the two paths have a different number of control points or segments the results are undefined.</strong></p>
  </blockquote>
  
  <p>In an attempt to get the circle and triangle to have the same number of control points, I made them both four-pointed shapes: the circle is a heavily-rounded rectangle, and the triangle is "hiding" a fourth control point on one side.</p>
  
  <p>Here's my code:</p>
  
  <pre><code>self.view.backgroundColor = .blueColor()
  
  //CREATE A CASHAPELAYER
  let shape = CAShapeLayer()
  shape.frame = CGRect(x: 50, y: 50, width: 200, height: 200)
  shape.fillColor = UIColor.redColor().CGColor
  self.view.layer.addSublayer(shape)
  
  let bounds = shape.bounds
  
  //CREATE THE SQUIRCLE
  let squareRadius: CGFloat = CGRectGetWidth(shape.bounds)/2
  
  let topCorner = CGPointMake(bounds.midX, bounds.minY)
  let rightCorner = CGPointMake(bounds.maxX, bounds.midY)
  let bottomCorner = CGPointMake(bounds.midX, bounds.maxY)
  let leftCorner = CGPointMake(bounds.minX, bounds.midY)
  
  let squarePath = CGPathCreateMutable()
  let squareStartingPoint = midPoint(leftCorner, point2: topCorner)
  CGPathMoveToPoint(squarePath, nil, squareStartingPoint.x, squareStartingPoint.y)
  addArcToPoint(squarePath, aroundPoint: topCorner, onWayToPoint: rightCorner, radius: squareRadius)
  addArcToPoint(squarePath, aroundPoint: rightCorner, onWayToPoint: bottomCorner, radius: squareRadius)
  addArcToPoint(squarePath, aroundPoint: bottomCorner, onWayToPoint: leftCorner, radius: squareRadius)
  addArcToPoint(squarePath, aroundPoint: leftCorner, onWayToPoint: topCorner, radius: squareRadius)
  CGPathCloseSubpath(squarePath)
  let square = UIBezierPath(CGPath: squarePath)
  
  //CREATE THE (FAKED) TRIANGLE
  let triangleRadius: CGFloat = 25.0
  
  let trianglePath = CGPathCreateMutable()
  let triangleStartingPoint = midPoint(topCorner, point2: rightCorner)
  
  let startingPoint = midPoint(topCorner, point2: leftCorner)
  CGPathMoveToPoint(trianglePath, nil, startingPoint.x, startingPoint.y)
  let cheatPoint = midPoint(topCorner, point2:bottomCorner)
  addArcToPoint(trianglePath, aroundPoint: topCorner, onWayToPoint: cheatPoint, radius: triangleRadius)
  addArcToPoint(trianglePath, aroundPoint: cheatPoint, onWayToPoint: bottomCorner, radius: triangleRadius)
  addArcToPoint(trianglePath, aroundPoint: bottomCorner, onWayToPoint: leftCorner, radius: triangleRadius)
  addArcToPoint(trianglePath, aroundPoint: leftCorner, onWayToPoint: topCorner, radius: triangleRadius)
  CGPathCloseSubpath(trianglePath)
  let triangle = UIBezierPath(CGPath: trianglePath)
  
  
  shape.path = square.CGPath
  </code></pre>
  
  <p>...and later on, in <code>viewDidAppear</code>:</p>
  
  <pre><code>let animation = CABasicAnimation(keyPath: "path")
  animation.fromValue = self.square.CGPath
  animation.toValue = self.triangle.CGPath
  animation.duration = 3
  self.shape.path = self.triangle.CGPath
  self.shape.addAnimation(animation, forKey: "animationKey")
  </code></pre>
  
  <p>I have two quick little functions for making the code more legible:</p>
  
  <pre><code>func addArcToPoint(path: CGMutablePath!, aroundPoint: CGPoint, onWayToPoint: CGPoint, radius: CGFloat) {
      CGPathAddArcToPoint(path, nil, aroundPoint.x, aroundPoint.y, onWayToPoint.x, onWayToPoint.y, radius)
  }
  
  func midPoint(point1: CGPoint, point2: CGPoint) -&gt; CGPoint {
      return CGPointMake((point1.x + point2.x)/2, (point1.y + point2.y)/2)
  }
  </code></pre>
  
  <p>My current result looks like this:</p>
  
  <p><img src="https://i.stack.imgur.com/PULIq.gif" alt="triangle-to-square"></p>
  
  <p><strong>NOTE:</strong> I'm trying to build the circle out of a very-rounded square, in an attempt to get the same number of control points in the vector shape. In the above GIF, the corner radius has been reduced to make the transformation more visible.</p>
  
  <p>What do you think is going on? How else might I achieve this effect?</p>