Removing lagging latency in drawing UIBezierPath smooth lines in Swift - ios

The code below draws smooth curved lines by overriding touches, but there is noticeable lagging or latency. The code uses addCurveToPoint and calls setNeedsDisplay after every 4 touch points which causes a jumpy appearance as the drawing doesn't keep up with finger movements. To remove the lagging or perceived latency, touch points 1, 2, 3 (leading up to touch point 4) could be temporarily filled with addQuadCurveToPoint and addLineToPoint.
How can this actually be achieved in code to remove perceived lagging by using a temporary Line and QuadCurved line before displaying a final Curved line?
If the below class is attached to one UIView (e.g. viewOne or self), how do I make a copy of the drawing to another UIView outside the class (e.g. viewTwo) after touchesEnded?
// ViewController.swift
import UIKit
class drawSmoothCurvedLinesWithLagging: UIView {
let path=UIBezierPath()
var incrementalImage:UIImage?
var points = [CGPoint?](count: 5, repeatedValue: nil)
var counter:Int?
var strokeColor:UIColor?
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
override func drawRect(rect: CGRect) {
autoreleasepool {
incrementalImage?.drawInRect(rect)
strokeColor = UIColor.blueColor()
strokeColor?.setStroke()
path.lineWidth = 20
path.lineCapStyle = CGLineCap.Round
path.stroke()
}
}
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
counter = 0
let touch: AnyObject? = touches.first
points[0] = touch!.locationInView(self)
}
override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) {
let touch: AnyObject? = touches.first
let point = touch!.locationInView(self)
counter = counter! + 1
points[counter!] = point
if counter == 2{
//use path.addLineToPoint ?
//use self.setNeedsDisplay() ?
}
if counter == 3{
//use path.addQuadCurveToPoint ?
//use self.setNeedsDisplay() ?
}
if counter == 4{
points[3]! = CGPointMake((points[2]!.x + points[4]!.x)/2.0, (points[2]!.y + points[4]!.y)/2.0)
path.moveToPoint(points[0]!)
path.addCurveToPoint(points[3]!, controlPoint1: points[1]!, controlPoint2: points[2]!)
self.setNeedsDisplay()
points[0]! = points[3]!
points[1]! = points[4]!
counter = 1
}
}
override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
self.drawBitmap()
self.setNeedsDisplay()
path.removeAllPoints()
counter = 0
}
override func touchesCancelled(touches: Set<UITouch>?, withEvent event: UIEvent?) {
self.touchesEnded(touches!, withEvent: event)
}
func drawBitmap(){
UIGraphicsBeginImageContextWithOptions(self.bounds.size, true, 0.0)
strokeColor?.setStroke()
if((incrementalImage) == nil){
let rectPath:UIBezierPath = UIBezierPath(rect: self.bounds)
UIColor.whiteColor().setFill()
rectPath.fill()
}
incrementalImage?.drawAtPoint(CGPointZero)
path.stroke()
incrementalImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
}
}
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}

Yes, adding a curve every few points will give it a stuttering lag. So, yes, you can reduce this affect by adding a line to points[1], adding a quad curve to points[2] and adding a cubic curve to points[3].
As you said, make sure to add this to a separate path, though. So, in Swift 3/4:
class SmoothCurvedLinesView: UIView {
var strokeColor = UIColor.blue
var lineWidth: CGFloat = 20
var snapshotImage: UIImage?
private var path: UIBezierPath?
private var temporaryPath: UIBezierPath?
private var points = [CGPoint]()
override func draw(_ rect: CGRect) {
snapshotImage?.draw(in: rect)
strokeColor.setStroke()
path?.stroke()
temporaryPath?.stroke()
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
if let touch = touches.first {
points = [touch.location(in: self)]
}
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
guard let touch = touches.first else { return }
let point = touch.location(in: self)
points.append(point)
updatePaths()
setNeedsDisplay()
}
private func updatePaths() {
// update main path
while points.count > 4 {
points[3] = CGPoint(x: (points[2].x + points[4].x)/2.0, y: (points[2].y + points[4].y)/2.0)
if path == nil {
path = createPathStarting(at: points[0])
}
path?.addCurve(to: points[3], controlPoint1: points[1], controlPoint2: points[2])
points.removeFirst(3)
temporaryPath = nil
}
// build temporary path up to last touch point
if points.count == 2 {
temporaryPath = createPathStarting(at: points[0])
temporaryPath?.addLine(to: points[1])
} else if points.count == 3 {
temporaryPath = createPathStarting(at: points[0])
temporaryPath?.addQuadCurve(to: points[2], controlPoint: points[1])
} else if points.count == 4 {
temporaryPath = createPathStarting(at: points[0])
temporaryPath?.addCurve(to: points[3], controlPoint1: points[1], controlPoint2: points[2])
}
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
finishPath()
}
override func touchesCancelled(_ touches: Set<UITouch>?, with event: UIEvent?) {
finishPath()
}
private func finishPath() {
constructIncrementalImage()
path = nil
setNeedsDisplay()
}
private func createPathStarting(at point: CGPoint) -> UIBezierPath {
let localPath = UIBezierPath()
localPath.move(to: point)
localPath.lineWidth = lineWidth
localPath.lineCapStyle = .round
localPath.lineJoinStyle = .round
return localPath
}
private func constructIncrementalImage() {
UIGraphicsBeginImageContextWithOptions(bounds.size, false, 0.0)
strokeColor.setStroke()
snapshotImage?.draw(at: .zero)
path?.stroke()
temporaryPath?.stroke()
snapshotImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
}
}
You could even marry this with iOS 9 predictive touches (as I described in my other answer), which could reduce lag even further.
To take this resulting image and use it elsewhere, you can just grab the incrementalImage (which I renamed to snapshotImage, above), and drop it into an image view of the other view.
For Swift 2 rendition, see previous revision of this answer.

Related

How to erase Core Graphics Context drawing in Swift?

I have used core graphics in a view to drawing lines. Now, I need to erase the lines that I daw using an erase button. I don't know what should I do to get a clear view with no lines.
Here is the code I used for drawing lines.
struct Line {
var points: [CGPoint]
var strokeColor: UIColor
var strokeWidth: CGFloat
}
class CanvasView: UIView {
private var lines: [Line] = []
private var strokeWidth: CGFloat = 8.0
private var strokeColor: UIColor = .white
override func draw(_ rect: CGRect) {
super.draw(rect)
guard let context = UIGraphicsGetCurrentContext() else { return }
lines.forEach { line in
context.setStrokeColor(line.strokeColor.cgColor)
context.setLineWidth(line.strokeWidth)
context.setLineCap(.round)
for (index, point) in line.points.enumerated() {
if index == 0 {
context.move(to: point)
} else {
context.addLine(to: point)
}
}
context.strokePath()
}
}
override func touchesBegan(_ touches: Set<UITouch>, with: event: UIEvent?) {
guard let point = touches.first.location(in: self) else { return }
let newLine = Line(points: [point], strokeColor: strokeColor, strokeWidth: strokeWidth)
lines.append(newLine)
setNeedsDisplay()
}
override func touchesMoved(_ touches: Set<UITouch>, with: event: UIEvent?) {
guard let point = touches.first.location(in: self) else { return }
guard var lastLine = lines.popLast() else { return }
lastLine.points.append(point)
lines.append(lastLine)
setNeedsDisplay()
}
}
I have connected this CanvasView: UIView class to my own view to use Core Graphics Context drawing.
I need a way to erase what I draw in my UIView using a button click.
Your drawing is depends on your list of Line so the thing you just need to do is make func where you clear all your lines then redraw. So at this time, when you call draw(_ rect:) again check if there is no value in your lines then clear view.
class CanvasView: UIView {
private var lines: [Line] = []
private var strokeWidth: CGFloat = 8.0
private var strokeColor: UIColor = .white
func clearView() {
self.lines = []
setNeedsDisplay()
}
override func draw(_ rect: CGRect) {
super.draw(rect)
guard let context = UIGraphicsGetCurrentContext() else { return }
if self.lines.count == 0 {
// context clear here
context.clear(self.bounds)
}
lines.forEach { line in
context.setStrokeColor(line.strokeColor.cgColor)
context.setLineWidth(line.strokeWidth)
context.setLineCap(.round)
for (index, point) in line.points.enumerated() {
if index == 0 {
context.move(to: point)
} else {
context.addLine(to: point)
}
}
context.strokePath()
}
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
guard let point = touches.first?.location(in: self) else { return }
let newLine = Line(points: [point], strokeColor: strokeColor, strokeWidth: strokeWidth)
lines.append(newLine)
setNeedsDisplay()
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
guard let point = touches.first?.location(in: self) else { return }
guard var lastLine = lines.popLast() else { return }
lastLine.points.append(point)
lines.append(lastLine)
setNeedsDisplay()
}
}
And in your ViewController just simply call func canvasView.clearView()

Touch drawing not working when UIPanGestureRecognizer implemented for view

I have screen to test the device touch screen with popping bubbles. And some imageView added in subviews of bubbles made of cross for them. Then user swipe over the bubbles to check the touch screen.
And I want drawing on the same view. When user swipes the finger over the bubbles, a line will be drawn. I have separate class for drawing and assign it to main parent view of controller.
If I remove code for UIPanGestureRecognizer then drawing works and there are no lags.
If I add gesture to view for popping the bubbles like this
view.addGestureRecognizer(gestureRecognizer)
Then there is a lag, and drawing doesn't work.
I want both things like popping bubbles and drawing on view.
The main problem of this gesture is when I add this in view, then drawing works without any lag but popping bubbles doesn't work.
let gestureRecognizer : UIPanGestureRecognizer = UIPanGestureRecognizer(target: self, action: #selector(panGestureRecognized(_:)))
gestureRecognizer.maximumNumberOfTouches = 1
gestureRecognizer.minimumNumberOfTouches = 1
view.addGestureRecognizer(gestureRecognizer)
Drawing view class
import UIKit
class DrawingView: UIView {
var drawColor = UIColor.black
var lineWidth: CGFloat = 5
private var lastPoint: CGPoint!
private var bezierPath: UIBezierPath!
private var pointCounter: Int = 0
private let pointLimit: Int = 128
private var preRenderImage: UIImage!
// MARK: - Initialization
override init(frame: CGRect) {
super.init(frame: frame)
initBezierPath()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
initBezierPath()
}
func initBezierPath() {
bezierPath = UIBezierPath()
bezierPath.lineCapStyle = CGLineCap.round
bezierPath.lineJoinStyle = CGLineJoin.round
}
// MARK: - Touch handling
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
let touch: AnyObject? = touches.first
lastPoint = touch!.location(in: self)
pointCounter = 0
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
let touch: AnyObject? = touches.first
let newPoint = touch!.location(in: self)
bezierPath.move(to: lastPoint)
bezierPath.addLine(to: newPoint)
lastPoint = newPoint
pointCounter += 1
if pointCounter == pointLimit {
pointCounter = 0
renderToImage()
setNeedsDisplay()
bezierPath.removeAllPoints()
}
else {
setNeedsDisplay()
}
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
pointCounter = 0
renderToImage()
setNeedsDisplay()
bezierPath.removeAllPoints()
}
override func touchesCancelled(_ touches: Set<UITouch>?, with event: UIEvent?) {
touchesEnded(touches!, with: event)
}
// MARK: - Pre render
func renderToImage() {
UIGraphicsBeginImageContextWithOptions(self.bounds.size, false, 0.0)
if preRenderImage != nil {
preRenderImage.draw(in: self.bounds)
}
bezierPath.lineWidth = lineWidth
drawColor.setFill()
drawColor.setStroke()
bezierPath.stroke()
preRenderImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
}
// MARK: - Render
override func draw(_ rect: CGRect) {
super.draw(rect)
if preRenderImage != nil {
preRenderImage.draw(in: self.bounds)
}
bezierPath.lineWidth = lineWidth
drawColor.setFill()
drawColor.setStroke()
bezierPath.stroke()
}
// MARK: - Clearing
func clear() {
preRenderImage = nil
bezierPath.removeAllPoints()
setNeedsDisplay()
}
// MARK: - Other
func hasLines() -> Bool {
return preRenderImage != nil || !bezierPath.isEmpty
}
}

Draw on large UIView take a lot of memory

when I start to draw on large UIView ( width: 3700 , height: 40000 ), it takes a lot of memory
when app starts, memory is 150 MB and when start drawing on it( calling setNeedsDisplay method) take around 1 GB and app is gonna crash
class DrawingVc: UIViewController {
let contentView = DrawableView()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .white
contentView.translatesAutoresizingMaskIntoConstraints = false
contentView.backgroundColor = .clear
self.view.addSubview(contentView)
contentView.frame = CGRect(x: 0, y: 0, width:view.frame.width, height:
view.frame.height * 50)
}
here is the code of custom view, as you can see, setNeedsDisplay runs on touchMoves
class DrawableView: UIView {
var mLastPath: UIBezierPath?
weak var scdelegate: DrawableViewDelegate?
var isDrawEnable = true
private var drawingLines : [UIBezierPath] = []
override init(frame: CGRect) {
super.init(frame: frame)
}
required public init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
override func draw(_ rect: CGRect) {
debugPrint("request draw")
drawLine()
}
private func drawLine() {
UIColor.blue.setStroke()
for line in drawingList {
line.lineWidth = 4
line.stroke()
line.lineCapStyle = .round
}
}
var drawingList = [UIBezierPath]()
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
if touches.count == 2 {
return
}
let location = (touches.first?.location(in: self))!
mLastPath = UIBezierPath()
mLastPath?.move(to: location)
prevPoint = location
drawingList.append(mLastPath!)
}
var prevPoint: CGPoint?
var isFirst = true
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
debugPrint("touchesMoved: " , (touches.first?.location(in: self).x)! , (touches.first?.location(in: self).y)! )
if let coalescedtouches = event?.coalescedTouches(for: touches.first!)
{
for coalescedTouch in coalescedtouches
{
let locationInView = coalescedTouch.location(in: self)
if let prevPoint = prevPoint {
let midPoint = CGPoint( x: (locationInView.x + prevPoint.x) / 2, y: (locationInView.y + prevPoint.y) / 2)
if isFirst {
mLastPath?.addLine(to: midPoint)
}else {
mLastPath?.addQuadCurve(to: midPoint, controlPoint: prevPoint)
}
isFirst = false
} else {
mLastPath?.move(to: locationInView)
}
prevPoint = locationInView
}
}
setNeedsDisplay()
}
}
What makes this problem and how that fix?
Your view is larger than the largest possible screen on an iOS device, so I suppose your view is embedded in a scrollview. You should only draw the visible parts of your view. Unfortunately, this is not supported by UIView directly. You may take a look on CATiledLayer, which supports drawing of only visible parts of a layer, and it supports different levels of details for zoomed layers, too.

Artefacts drawing lines in Swift Xcode

The below class attaches to a UIView and draws lines while moving a finger across the screen. However, when moving a finger very fast from left to right moving from top to bottom, the drawing temporarily shows sharp pointy edges on changing direction. This occurs both on the device and simulator.
What is causing this issue and how can this artefact be eliminated in the code so that only smooth rounded, not sharp edges are seen when changing direction fast?
class drawLine: UIView
{
var comittedSegments: Int = 0
var points = [CGPoint]()
var committedPath = UIBezierPath()
var drawPath = UIBezierPath()
var incrementalImage: UIImage?
var strokeColor:UIColor?
override func drawRect(rect: CGRect) {
autoreleasepool {
incrementalImage?.drawInRect(rect)
strokeColor = UIColor.darkGrayColor()
strokeColor?.setStroke()
drawPath.lineWidth = 20
drawPath.lineCapStyle = CGLineCap.Round
drawPath.stroke()
}
}
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
let touch: AnyObject? = touches.first
comittedSegments = 0
committedPath.removeAllPoints()
points.removeAll()
points.append( touch!.locationInView(self) )
}
override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) {
let touch: AnyObject? = touches.first
let point = touch!.locationInView(self)
points.append( point )
if points.count == 5
{
points[3] = CGPointMake((points[2].x + points[4].x)/2.0, (points[2].y + points[4].y)/2.0)
committedPath.moveToPoint(points[0])
committedPath.addCurveToPoint(points[3], controlPoint1: points[1], controlPoint2: points[2])
comittedSegments = comittedSegments + 1
self.setNeedsDisplay()
points[0] = points[3]
points[1] = points[4]
points.removeRange(2...4)
drawPath = committedPath
}
else if points.count > 1
{
drawPath = committedPath.copy() as! UIBezierPath
drawPath.CGPath = committedPath.CGPath
drawPath.moveToPoint( points[0] )
for point in points[1..<points.count] {
drawPath.addLineToPoint(point)
}
self.setNeedsDisplay()
}
}
override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
self.drawBitmap()
self.setNeedsDisplay()
committedPath.removeAllPoints()
points.removeAll()
}
override func touchesCancelled(touches: Set<UITouch>?, withEvent event: UIEvent?) {
self.touchesEnded(touches!, withEvent: event)
}
func drawBitmap() {
UIGraphicsBeginImageContextWithOptions(self.bounds.size, true, 0.0)
strokeColor?.setStroke()
if(incrementalImage == nil) {
let rectPath:UIBezierPath = UIBezierPath(rect: self.bounds)
UIColor.whiteColor().setFill()
rectPath.fill()
}
incrementalImage?.drawAtPoint(CGPointZero)
committedPath.stroke()
incrementalImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
}
}
In addition to setting lineCapStyle, set lineJoinStyle:
drawPath.lineJoinStyle = .Round
drawPath.lineCapStyle = .Round

Differences between addCurveToPoint and addQuadCurveToPoint drawing smooth curved lines in Swift

Note: In the below question, I use the term 'lagging' when I probably mean 'latency' when drawing using the addCurveToPoint function.
Problem:
Both bezier curve functions, addQuadCurveToPoint and addCurveToPoint have one strength and one weakness each. The aim is to get the perfect combination of both, a perfect continuous smooth curved line that is lag-free when drawn. The images below show where the touch on the screen typically is in comparison to the updated drawing.
The below image uses the function addQuadCurveToPoint. It draws fast
with no lagging while drawing during touch events, but the end result is a
less perfect smooth curved line that appears more segmented.
The below image uses the function
addCurveToPoint. It draws near perfect continuous smooth curved
lines but is slower with some lag noticeable while drawing during
touch events.
Question:
Can anyone help explain or give a solution please:
how to get perfect addQuadCurveToPoint curved lines or lag-free addCurveToPoint curved lines?
Note: The focus of this question is immediate lagging from the initial touch event for addCurveToPoint, not lagging over time, and also the less perfect curve line for addQuadCurveToPoint.
This code example is just one type of many implementations of addCurveToPoint:
// Swift 2 code below tested using Xcode 7.0.1.
class drawView: UIView {
var path:UIBezierPath?
var incrementalImage:UIImage?
var points = [CGPoint?](count: 5, repeatedValue: nil)
var counter:Int?
var infoView:UIView = UIView()
var strokeColor:UIColor?
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
self.multipleTouchEnabled = false
self.backgroundColor = UIColor.whiteColor()
path = UIBezierPath()
path?.lineWidth = 20.0
strokeColor = UIColor.darkGrayColor()
path?.lineCapStyle = CGLineCap.Round
}
override init(frame: CGRect) {
super.init(frame: frame)
self.multipleTouchEnabled = false
path = UIBezierPath()
path?.lineWidth = 20.0
}
override func drawRect(rect: CGRect) {
incrementalImage?.drawInRect(rect)
strokeColor?.setStroke()
path?.stroke()
}
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
counter = 0
let touch: AnyObject? = touches.first
points[0] = touch!.locationInView(self)
infoView.removeFromSuperview()
}
override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) {
let touch: AnyObject? = touches.first
let point = touch!.locationInView(self)
counter = counter! + 1
points[counter!] = point
if counter == 4{
points[3]! = CGPointMake((points[2]!.x + points[4]!.x)/2.0, (points[2]!.y + points[4]!.y)/2.0)
path?.moveToPoint(points[0]!)
path?.addCurveToPoint(points[3]!, controlPoint1: points[1]!, controlPoint2: points[2]!)
self.setNeedsDisplay()
points[0]! = points[3]!
points[1]! = points[4]!
counter = 1
}
}
override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
self.drawBitmap()
self.setNeedsDisplay()
path?.removeAllPoints()
counter = 0
}
override func touchesCancelled(touches: Set<UITouch>?, withEvent event: UIEvent?) {
self.touchesEnded(touches!, withEvent: event)
}
func drawBitmap(){
UIGraphicsBeginImageContextWithOptions(self.bounds.size, true, 0.0)
strokeColor?.setStroke()
if((incrementalImage) == nil){
let rectPath:UIBezierPath = UIBezierPath(rect: self.bounds)
UIColor.whiteColor().setFill()
rectPath.fill()
}
incrementalImage?.drawAtPoint(CGPointZero)
path?.stroke()
incrementalImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
}
}
This code example is just one type of many implementations of addQuadCurveToPoint:
// Swift 2 code below tested using Xcode 7.0.1.
class DrawableView: UIView {
let path=UIBezierPath()
var previousPoint:CGPoint
var lineWidth:CGFloat=20.0
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
override init(frame: CGRect) {
previousPoint=CGPoint.zero
super.init(frame: frame)
}
required init?(coder aDecoder: NSCoder) {
previousPoint=CGPoint.zero
super.init(coder: aDecoder)
let panGestureRecognizer=UIPanGestureRecognizer(target: self, action: "pan:")
panGestureRecognizer.maximumNumberOfTouches=1
self.addGestureRecognizer(panGestureRecognizer)
}
override func drawRect(rect: CGRect) {
// Drawing code
UIColor.darkGrayColor().setStroke()
path.stroke()
path.lineWidth=lineWidth
path.lineCapStyle = .Round
}
func pan(panGestureRecognizer:UIPanGestureRecognizer)->Void
{
let currentPoint=panGestureRecognizer.locationInView(self)
let midPoint=self.midPoint(previousPoint, p1: currentPoint)
if panGestureRecognizer.state == .Began
{
path.moveToPoint(currentPoint)
}
else if panGestureRecognizer.state == .Changed
{
path.addQuadCurveToPoint(midPoint,controlPoint: previousPoint)
}
previousPoint=currentPoint
self.setNeedsDisplay()
}
func midPoint(p0:CGPoint,p1:CGPoint)->CGPoint
{
let x=(p0.x+p1.x)/2
let y=(p0.y+p1.y)/2
return CGPoint(x: x, y: y)
}
}

Resources