title: Smooth Drawing with Apple Pencil - some points out of order
body: <p>Following this Answer, I have implemented a CanvasView to draw with the Apple Pencil: <a href="https://stackoverflow.com/a/34583708/2529173">https://stackoverflow.com/a/34583708/2529173</a></p>
  
  <pre><code>import Foundation
  import UIKit
  
  class CanvasView: UIView {
  
      var points: [CGPoint]?
      var path: UIBezierPath?
      var pathLayer: CAShapeLayer!
  
      override func layoutSubviews() {
  
      }
  
      override func touchesBegan(_ touches: Set&lt;UITouch&gt;, with event: UIEvent?) {
          pathLayer = CAShapeLayer()
          pathLayer.fillColor = UIColor.clear.cgColor
          pathLayer.strokeColor = UIColor.red.cgColor
          pathLayer.lineWidth = 3
  
          self.layer.addSublayer(pathLayer)
  
          if let touch = touches.first {
              points = [touch.location(in: self)]
          }
      }
  
      override func touchesMoved(_ touches: Set&lt;UITouch&gt;, with event: UIEvent?) {
          if let touch = touches.first {
              if #available(iOS 9.0, *) {
                  if let coalescedTouches = event?.coalescedTouches(for: touch) {
                      points? += coalescedTouches.map { $0.location(in: self) }
                  } else {
                      points?.append(touch.location(in: self))
                  }
  
                  if let predictedTouches = event?.predictedTouches(for: touch) {
                      let predictedPoints = predictedTouches.map { $0.location(in: self) }
                      pathLayer.path = UIBezierPath(catmullRomInterpolatedPoints: points! + predictedPoints, closed: false, alpha: 0.5)?.cgPath
                  } else {
                      pathLayer.path = UIBezierPath(catmullRomInterpolatedPoints: points!, closed: false, alpha: 0.5)?.cgPath
                  }
              } else {
                  points?.append(touch.location(in: self))
                  pathLayer.path = UIBezierPath(catmullRomInterpolatedPoints: points!, closed: false, alpha: 0.5)?.cgPath
              }
          }
  
  
      }
  
      override func touchesEnded(_ touches: Set&lt;UITouch&gt;, with event: UIEvent?) {
          pathLayer.path = UIBezierPath(catmullRomInterpolatedPoints: points!, closed: false, alpha: 0.5)?.cgPath
          points?.removeAll()
      }
  }
  
  extension UIBezierPath {
  
      /// Simple smoothing algorithm
      ///
      /// This iterates through the points in the array, drawing cubic bezier
      /// from the first to the fourth points, using the second and third as
      /// control points.
      ///
      /// This takes every third point and moves it so that it is exactly inbetween
      /// the points before and after it, which ensures that there is no discontinuity
      /// in the first derivative as you join these cubic beziers together.
      ///
      /// Note, if, at the end, there are not enough points for a cubic bezier, it
      /// will perform a quadratic bezier, or if not enough points for that, a line.
      ///
      /// - parameter points: The array of `CGPoint`.
  
      convenience init?(simpleSmooth points: [CGPoint]) {
          guard points.count &gt; 1 else { return nil }
  
          self.init()
  
          move(to: points[0])
  
          var index = 0
  
          while index &lt; (points.count - 1) {
              switch (points.count - index) {
              case 2:
                  index += 1
                  addLine(to: points[index])
              case 3:
                  index += 2
                  addQuadCurve(to: points[index], controlPoint: points[index-1])
              case 4:
                  index += 3
                  addCurve(to: points[index], controlPoint1: points[index-2], controlPoint2: points[index-1])
              default:
                  index += 3
                  let point = CGPoint(x: (points[index-1].x + points[index+1].x) / 2,
                                      y: (points[index-1].y + points[index+1].y) / 2)
                  addCurve(to: point, controlPoint1: points[index-2], controlPoint2: points[index-1])
              }
          }
      }
  
      /// Create smooth UIBezierPath using Hermite Spline
      ///
      /// This requires at least two points.
      ///
      /// Adapted from https://github.com/jnfisher/ios-curve-interpolation
      /// See http://spin.atomicobject.com/2014/05/28/ios-interpolating-points/
      ///
      /// - parameter hermiteInterpolatedPoints: The array of CGPoint values.
      /// - parameter closed:                    Whether the path should be closed or not
      ///
      /// - returns:  An initialized `UIBezierPath`, or `nil` if an object could not be created for some reason (e.g. not enough points).
  
      convenience init?(hermiteInterpolatedPoints points: [CGPoint], closed: Bool) {
          self.init()
  
          guard points.count &gt; 1 else { return nil }
  
          let numberOfCurves = closed ? points.count : points.count - 1
  
          var previousPoint: CGPoint? = closed ? points.last : nil
          var currentPoint:  CGPoint  = points[0]
          var nextPoint:     CGPoint? = points[1]
  
          move(to: currentPoint)
  
          for index in 0 ..&lt; numberOfCurves {
              let endPt = nextPoint!
  
              var mx: CGFloat
              var my: CGFloat
  
              if previousPoint != nil {
                  mx = (nextPoint!.x - currentPoint.x) * 0.5 + (currentPoint.x - previousPoint!.x)*0.5
                  my = (nextPoint!.y - currentPoint.y) * 0.5 + (currentPoint.y - previousPoint!.y)*0.5
              } else {
                  mx = (nextPoint!.x - currentPoint.x) * 0.5
                  my = (nextPoint!.y - currentPoint.y) * 0.5
              }
  
              let ctrlPt1 = CGPoint(x: currentPoint.x + mx / 3.0, y: currentPoint.y + my / 3.0)
  
              previousPoint = currentPoint
              currentPoint = nextPoint!
              let nextIndex = index + 2
              if closed {
                  nextPoint = points[nextIndex % points.count]
              } else {
                  nextPoint = nextIndex &lt; points.count ? points[nextIndex % points.count] : nil
              }
  
              if nextPoint != nil {
                  mx = (nextPoint!.x - currentPoint.x) * 0.5 + (currentPoint.x - previousPoint!.x) * 0.5
                  my = (nextPoint!.y - currentPoint.y) * 0.5 + (currentPoint.y - previousPoint!.y) * 0.5
              }
              else {
                  mx = (currentPoint.x - previousPoint!.x) * 0.5
                  my = (currentPoint.y - previousPoint!.y) * 0.5
              }
  
              let ctrlPt2 = CGPoint(x: currentPoint.x - mx / 3.0, y: currentPoint.y - my / 3.0)
  
              addCurve(to: endPt, controlPoint1: ctrlPt1, controlPoint2: ctrlPt2)
          }
  
          if closed { close() }
      }
  
      /// Create smooth UIBezierPath using Catmull-Rom Splines
      ///
      /// This requires at least four points.
      ///
      /// Adapted from https://github.com/jnfisher/ios-curve-interpolation
      /// See http://spin.atomicobject.com/2014/05/28/ios-interpolating-points/
      ///
      /// - parameter catmullRomInterpolatedPoints: The array of CGPoint values.
      /// - parameter closed:                       Whether the path should be closed or not
      /// - parameter alpha:                        The alpha factor to be applied to Catmull-Rom spline.
      ///
      /// - returns:  An initialized `UIBezierPath`, or `nil` if an object could not be created for some reason (e.g. not enough points).
  
      convenience init?(catmullRomInterpolatedPoints points: [CGPoint], closed: Bool, alpha: Float) {
          self.init()
  
          guard points.count &gt; 3 else { return nil }
  
          assert(alpha &gt;= 0 &amp;&amp; alpha &lt;= 1.0, "Alpha must be between 0 and 1")
  
          let endIndex = closed ? points.count : points.count - 2
  
          let startIndex = closed ? 0 : 1
  
          let kEPSILON: Float = 1.0e-5
  
          move(to: points[startIndex])
  
          for index in startIndex ..&lt; endIndex {
              let nextIndex = (index + 1) % points.count
              let nextNextIndex = (nextIndex + 1) % points.count
              let previousIndex = index &lt; 1 ? points.count - 1 : index - 1
  
              let point0 = points[previousIndex]
              let point1 = points[index]
              let point2 = points[nextIndex]
              let point3 = points[nextNextIndex]
  
              let d1 = hypot(Float(point1.x - point0.x), Float(point1.y - point0.y))
              let d2 = hypot(Float(point2.x - point1.x), Float(point2.y - point1.y))
              let d3 = hypot(Float(point3.x - point2.x), Float(point3.y - point2.y))
  
              let d1a2 = powf(d1, alpha * 2)
              let d1a  = powf(d1, alpha)
              let d2a2 = powf(d2, alpha * 2)
              let d2a  = powf(d2, alpha)
              let d3a2 = powf(d3, alpha * 2)
              let d3a  = powf(d3, alpha)
  
              var controlPoint1: CGPoint, controlPoint2: CGPoint
  
              if fabs(d1) &lt; kEPSILON {
                  controlPoint1 = point2
              } else {
                  controlPoint1 = (point2 * d1a2 - point0 * d2a2 + point1 * (2 * d1a2 + 3 * d1a * d2a + d2a2)) / (3 * d1a * (d1a + d2a))
              }
  
              if fabs(d3) &lt; kEPSILON {
                  controlPoint2 = point2
              } else {
                  controlPoint2 = (point1 * d3a2 - point3 * d2a2 + point2 * (2 * d3a2 + 3 * d3a * d2a + d2a2)) / (3 * d3a * (d3a + d2a))
              }
  
              addCurve(to: point2, controlPoint1: controlPoint1, controlPoint2: controlPoint2)
          }
  
          if closed { close() }
      }
  
  }
  
  // Some functions to make the Catmull-Rom splice code a little more readable.
  // These multiply/divide a `CGPoint` by a scalar and add/subtract one `CGPoint`
  // from another.
  
  private func * (lhs: CGPoint, rhs: Float) -&gt; CGPoint {
      return CGPoint(x: lhs.x * CGFloat(rhs), y: lhs.y * CGFloat(rhs))
  }
  
  private func / (lhs: CGPoint, rhs: Float) -&gt; CGPoint {
      return CGPoint(x: lhs.x / CGFloat(rhs), y: lhs.y / CGFloat(rhs))
  }
  
  private func + (lhs: CGPoint, rhs: CGPoint) -&gt; CGPoint {
      return CGPoint(x: lhs.x + rhs.x, y: lhs.y + rhs.y)
  }
  
  private func - (lhs: CGPoint, rhs: CGPoint) -&gt; CGPoint {
      return CGPoint(x: lhs.x - rhs.x, y: lhs.y - rhs.y)
  }
  </code></pre>
  
  <p>Unfortunately, it is not that smooth because some points are out of the line which you can see here: <a href="https://i.stack.imgur.com/p8lkB.jpg" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/p8lkB.jpg" alt="enter image description here"></a></p>
  
  <p>I've tried to turn off the predicted touches, but it doesn't help much. What else can I do to optimize this?</p>