{"id":3043,"date":"2017-05-16T12:20:48","date_gmt":"2017-05-16T06:50:48","guid":{"rendered":"https:\/\/www.innovationm.com\/blog\/?p=3043"},"modified":"2017-05-16T12:20:48","modified_gmt":"2017-05-16T06:50:48","slug":"smooth-freehand-drawing-with-arrow-in-ios","status":"publish","type":"post","link":"https:\/\/www.innovationm.com\/blog\/smooth-freehand-drawing-with-arrow-in-ios\/","title":{"rendered":"Smooth Freehand Drawing with Arrow in iOS"},"content":{"rendered":"<p>&nbsp;<\/p>\n<p>Hello, folks.<\/p>\n<p>In this post we are going to implement a reusable component for freehand drawing. We will see how to use `UIGestureRecognizer` for drawing and using linear polarization\u00a0to make our drawing smooth. We will also create a method to draw an arrow with respect to two points.<\/p>\n<p>So let&#8217;s start with creating a simple `UIView` subclass on which we will draw. Just create the class `<span class=\"s1\">LineHolderView` and add following code:<\/span><\/p>\n<pre class=\"lang:swift decode:true\">class LineHolderView: UIView {\r\n    \r\n    private var bezierPathLine: UIBezierPath!\r\n    private var bufferImage: UIImage?\r\n    \r\n    override init(frame: CGRect) {\r\n        \r\n        super.init(frame: frame)\r\n        initializeView()\r\n    }\r\n    \r\n    required init?(coder aDecoder: NSCoder) {\r\n        \r\n        super.init(coder: aDecoder)\r\n        initializeView()\r\n    }\r\n    \r\n    override func draw(_ rect: CGRect) {\r\n        bufferImage?.draw(in: rect)\r\n        drawLine()\r\n    }\r\n    \r\n    private func drawLine() {\r\n        UIColor.red.setStroke()\r\n        bezierPathLine.stroke()\r\n    }\r\n    \r\n    private func initializeView() {\r\n        \r\n        isMultipleTouchEnabled = false\r\n        \r\n        bezierPathLine = UIBezierPath()\r\n        bezierPathLine.lineWidth = 4\r\n        \r\n        self.backgroundColor = UIColor.clear\r\n        \r\n        let panGesture = UIPanGestureRecognizer(target: self, action: #selector(viewDragged(_:)))\r\n        addGestureRecognizer(panGesture)\r\n        \r\n    }\r\n    \r\n    func viewDragged(_ sender: UIPanGestureRecognizer) {\r\n        \r\n        let point = sender.location(in: self)\r\n        \r\n        if point.x &lt; 0 || point.x &gt; frame.width || point.y &lt; 0 || point.y &gt; frame.height {\r\n            return\r\n        }\r\n        \r\n        switch sender.state {\r\n            \r\n        case .began:\r\n            bezierPathLine.move(to: point)\r\n            break\r\n            \r\n        case .changed:\r\n            bezierPathLine.addLine(to: point)\r\n            setNeedsDisplay()\r\n            break\r\n            \r\n        case .ended:\r\n            saveBufferImage()\r\n            bezierPathLine.removeAllPoints()\r\n            break\r\n        default:\r\n            break\r\n        }\r\n    }\r\n    \r\n    private func saveBufferImage() {\r\n        UIGraphicsBeginImageContextWithOptions(self.bounds.size, false, UIScreen.main.scale)\r\n        if bufferImage == nil {\r\n            let fillPath = UIBezierPath(rect: self.bounds)\r\n            UIColor.clear.setFill()\r\n            fillPath.fill()\r\n        }\r\n        bufferImage?.draw(at: .zero)\r\n        drawLine()\r\n        bufferImage = UIGraphicsGetImageFromCurrentImageContext()\r\n        UIGraphicsEndImageContext()\r\n    }\r\n}<\/pre>\n<p>&nbsp;<\/p>\n<p>What we did here, we created a subclass of `UIView` and in both initializers called a method `initializeView()`.<\/p>\n<p>In `initializeView()` method we disabled the multiple touch, create an object of `UIBezierPath` class and added and `UIPanGestureRecognizer` at the view. Here you can change the thickness of drawing at line 32.<\/p>\n<p>Now let&#8217;s see the implementation of method `viewDragged(_: )` which is the selector for `UIPanGestureRecognizer` and will be called when user drags on the view.<\/p>\n<p>So in this first we get the current location of user&#8217;s finger in view and if the location if outside of the container then we ignore the drawing. Now the `state` property of `UIPanGestureRecognizer` tells us whether the drag is started, changed or ended. So we have\u00a0Added a switch case on `state` property and did following of different states:<\/p>\n<ul>\n<li>Began: When user began the dragging we move our bezier path to that point.<\/li>\n<li>Changed: When drag changed we added an line to the current point.<\/li>\n<li>Ended:\u00a0In this we used the method `saveBufferImage()` to convert the current drawing into an image and store it. It will save the cost of redrawing whole path next time.<\/li>\n<\/ul>\n<p>In `draw(_:)` method we first draw the stored buffer image and then \u00a0we set the stroke color for line color and stroke the bezier path. You can change the stroke color if you want to change the line color.<\/p>\n<p>That&#8217;s it, set this `LineHolderView` as a class to any view in storyboard and done, start drawing.<\/p>\n<p>Here is the result:<\/p>\n<p><a href=\"https:\/\/www.innovationm.com\/blog\/wp-content\/uploads\/2017\/04\/IMG_0247.jpg\"><img fetchpriority=\"high\" decoding=\"async\" class=\"alignnone wp-image-3070 size-full\" src=\"https:\/\/www.innovationm.com\/blog\/wp-content\/uploads\/2017\/04\/IMG_0247.jpg\" alt=\"freehand-drawing-1\" width=\"1536\" height=\"2048\" srcset=\"https:\/\/www.innovationm.com\/blog\/wp-content\/uploads\/2017\/04\/IMG_0247.jpg 1536w, https:\/\/www.innovationm.com\/blog\/wp-content\/uploads\/2017\/04\/IMG_0247-225x300.jpg 225w, https:\/\/www.innovationm.com\/blog\/wp-content\/uploads\/2017\/04\/IMG_0247-768x1024.jpg 768w, https:\/\/www.innovationm.com\/blog\/wp-content\/uploads\/2017\/04\/IMG_0247-624x832.jpg 624w\" sizes=\"(max-width: 1536px) 100vw, 1536px\" \/><\/a><\/p>\n<p>As you can see in the above image the lines have sharp changes in it. So here we a concept named &#8216;Linear Polarization&#8217; to smoother our drawing. In Linear polarization we draw an arc with four points and two of them works as control points and the arc drawn below the tangent of first and second point and tangent of third and fourth points.<\/p>\n<p>Here are some examples of arcs drawn with two control points:<\/p>\n<p><a href=\"https:\/\/www.innovationm.com\/blog\/wp-content\/uploads\/2017\/04\/bezier.png\"><img decoding=\"async\" class=\"alignnone size-full wp-image-3088\" src=\"https:\/\/www.innovationm.com\/blog\/wp-content\/uploads\/2017\/04\/bezier.png\" alt=\"bezier\" width=\"500\" height=\"250\" srcset=\"https:\/\/www.innovationm.com\/blog\/wp-content\/uploads\/2017\/04\/bezier.png 500w, https:\/\/www.innovationm.com\/blog\/wp-content\/uploads\/2017\/04\/bezier-300x150.png 300w\" sizes=\"(max-width: 500px) 100vw, 500px\" \/><\/a><\/p>\n<p>&nbsp;<\/p>\n<p><a href=\"https:\/\/www.innovationm.com\/blog\/wp-content\/uploads\/2017\/04\/interestingshapes.png\"><img decoding=\"async\" class=\"alignnone size-full wp-image-3089\" src=\"https:\/\/www.innovationm.com\/blog\/wp-content\/uploads\/2017\/04\/interestingshapes.png\" alt=\"interestingshapes\" width=\"549\" height=\"469\" srcset=\"https:\/\/www.innovationm.com\/blog\/wp-content\/uploads\/2017\/04\/interestingshapes.png 549w, https:\/\/www.innovationm.com\/blog\/wp-content\/uploads\/2017\/04\/interestingshapes-300x256.png 300w\" sizes=\"(max-width: 549px) 100vw, 549px\" \/><\/a><\/p>\n<p>So here we will use an array to store the 4 points, and when we get four points then we will draw an arc between them with two control points using the `UIBezierPath` method `<span class=\"syntax-identifier\">addCurve<\/span>(<span class=\"syntax-identifier\">to<\/span> <span class=\"syntax-param-name\">endPoint<\/span>: <span class=\"syntax-type\">CGPoint<\/span>, <span class=\"syntax-identifier\"> controlPoint1<\/span>: <span class=\"syntax-type\">CGPoint<\/span>, <span class=\"syntax-identifier\"> controlPoint2<\/span>: <span class=\"syntax-type\">CGPoint<\/span>)`.<\/p>\n<p>Here is the complete code after changes:<\/p>\n<pre class=\"lang:swift decode:true\">class LineHolderView: UIView {\r\n    \r\n    private var bezierPathLine: UIBezierPath!\r\n    private var bufferImage: UIImage?\r\n\r\n    private var bezierCurvePoints: [CGPoint] = [] \/\/ Create an array to store points.\r\n    \r\n    override init(frame: CGRect) {\r\n        \r\n        super.init(frame: frame)\r\n        initializeView()\r\n    }\r\n    \r\n    required init?(coder aDecoder: NSCoder) {\r\n        \r\n        super.init(coder: aDecoder)\r\n        initializeView()\r\n    }\r\n    \r\n    override func draw(_ rect: CGRect) {\r\n        bufferImage?.draw(in: rect)\r\n        drawLine()\r\n    }\r\n    \r\n    private func drawLine() {\r\n        \r\n        UIColor.red.setStroke()\r\n        bezierPathLine.stroke()\r\n    }\r\n    \r\n    private func initializeView() {\r\n        \r\n        isMultipleTouchEnabled = false\r\n        \r\n        bezierPathLine = UIBezierPath()\r\n        bezierPathLine.lineWidth = 4\r\n        \r\n        self.backgroundColor = UIColor.clear\r\n        \r\n        let panGesture = UIPanGestureRecognizer(target: self, action: #selector(viewDragged(_:)))\r\n        addGestureRecognizer(panGesture)\r\n        \r\n    }\r\n    \r\n    func viewDragged(_ sender: UIPanGestureRecognizer) {\r\n        \r\n        let point = sender.location(in: self)\r\n        \r\n        if point.x &lt; 0 || point.x &gt; frame.width || point.y &lt; 0 || point.y &gt; frame.height {\r\n            return\r\n        }\r\n        \r\n        switch sender.state {\r\n            \r\n        case .began:\r\n            bezierCurvePoints.append(point) \/\/ Add first point in array.\r\n            break\r\n            \r\n        case .changed:\r\n            \r\n            bezierCurvePoints.append(point)\r\n            \r\n            \/\/ If we get 4 points.\r\n            if bezierCurvePoints.count == 4 {\r\n\r\n                \/\/ Draw an arc from point 0 to 3 with point 1 and 2 as control points.\r\n                bezierPathLine.move(to: bezierCurvePoints[0])\r\n                bezierPathLine.addCurve(to: bezierCurvePoints[3], controlPoint1: bezierCurvePoints[1], controlPoint2: bezierCurvePoints[2])\r\n                \r\n                let point = bezierCurvePoints[3]\r\n                \r\n                bezierCurvePoints.removeAll()\r\n                \r\n                \/\/ Store end point of arc as a start point for next arc.\r\n                bezierCurvePoints.append(point)\r\n                setNeedsDisplay()\r\n            }\r\n            \r\n            break\r\n            \r\n        case .ended:\r\n\r\n            saveBufferImage()\r\n            \r\n            \/\/ Remove all points.\r\n            bezierCurvePoints.removeAll()\r\n            bezierPathLine.removeAllPoints()\r\n            break\r\n        default:\r\n            break\r\n        }\r\n    }\r\n    \r\n    private func saveBufferImage() {\r\n        UIGraphicsBeginImageContextWithOptions(self.bounds.size, false, UIScreen.main.scale)\r\n        if bufferImage == nil {\r\n            let fillPath = UIBezierPath(rect: self.bounds)\r\n            UIColor.clear.setFill()\r\n            fillPath.fill()\r\n        }\r\n        bufferImage?.draw(at: .zero)\r\n        drawLine()\r\n        bufferImage = UIGraphicsGetImageFromCurrentImageContext()\r\n        UIGraphicsEndImageContext()\r\n    }\r\n}<\/pre>\n<p>&nbsp;<\/p>\n<p>Compile and Run it. You will get some output like this:<\/p>\n<p>&nbsp;<\/p>\n<p><a href=\"https:\/\/www.innovationm.com\/blog\/wp-content\/uploads\/2017\/04\/IMG_0248.jpg\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-3071 size-full\" src=\"https:\/\/www.innovationm.com\/blog\/wp-content\/uploads\/2017\/04\/IMG_0248.jpg\" alt=\"freehand-drawing-2\" width=\"1536\" height=\"2048\" srcset=\"https:\/\/www.innovationm.com\/blog\/wp-content\/uploads\/2017\/04\/IMG_0248.jpg 1536w, https:\/\/www.innovationm.com\/blog\/wp-content\/uploads\/2017\/04\/IMG_0248-225x300.jpg 225w, https:\/\/www.innovationm.com\/blog\/wp-content\/uploads\/2017\/04\/IMG_0248-768x1024.jpg 768w, https:\/\/www.innovationm.com\/blog\/wp-content\/uploads\/2017\/04\/IMG_0248-624x832.jpg 624w\" sizes=\"(max-width: 1536px) 100vw, 1536px\" \/><\/a><\/p>\n<p>As you can see the drawing is improved but it have some problem when there is a mismatch in the tangents of last and starting point of the curve as shown in following picture.<\/p>\n<p><a href=\"https:\/\/www.innovationm.com\/blog\/wp-content\/uploads\/2017\/04\/mismatched.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-3090\" src=\"https:\/\/www.innovationm.com\/blog\/wp-content\/uploads\/2017\/04\/mismatched.png\" alt=\"mismatched\" width=\"612\" height=\"349\" srcset=\"https:\/\/www.innovationm.com\/blog\/wp-content\/uploads\/2017\/04\/mismatched.png 612w, https:\/\/www.innovationm.com\/blog\/wp-content\/uploads\/2017\/04\/mismatched-300x171.png 300w\" sizes=\"(max-width: 612px) 100vw, 612px\" \/><\/a><\/p>\n<p>So now we have to match the tangents by calculating a new intersection point between two curves like following picture:<\/p>\n<p><a href=\"https:\/\/www.innovationm.com\/blog\/wp-content\/uploads\/2017\/04\/shiftingjunctionpoint.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-3091\" src=\"https:\/\/www.innovationm.com\/blog\/wp-content\/uploads\/2017\/04\/shiftingjunctionpoint.png\" alt=\"shiftingjunctionpoint\" width=\"600\" height=\"800\" srcset=\"https:\/\/www.innovationm.com\/blog\/wp-content\/uploads\/2017\/04\/shiftingjunctionpoint.png 600w, https:\/\/www.innovationm.com\/blog\/wp-content\/uploads\/2017\/04\/shiftingjunctionpoint-225x300.png 225w\" sizes=\"(max-width: 600px) 100vw, 600px\" \/><\/a><\/p>\n<p>So we have to calculate a middle point of 3rd point of first curve and 1st point of second curve. So we will need an extra point to calculate the midpoint. Now the points array will have 5 points.<\/p>\n<p>Change the class with following code and run.<\/p>\n<pre class=\"lang:swift decode:true\">class LineHolderView: UIView {\r\n    \r\n    private var bezierPathLine: UIBezierPath!\r\n    private var bufferImage: UIImage?\r\n\r\n    private var bezierCurvePoints: [CGPoint] = []\r\n    \r\n    override init(frame: CGRect) {\r\n        \r\n        super.init(frame: frame)\r\n        initializeView()\r\n    }\r\n    \r\n    required init?(coder aDecoder: NSCoder) {\r\n        \r\n        super.init(coder: aDecoder)\r\n        initializeView()\r\n    }\r\n    \r\n    override func draw(_ rect: CGRect) {\r\n        bufferImage?.draw(in: rect)\r\n        drawLine()\r\n    }\r\n    \r\n    private func drawLine() {\r\n        \r\n        UIColor.red.setStroke()\r\n        bezierPathLine.stroke()\r\n    }\r\n    \r\n    private func initializeView() {\r\n        \r\n        isMultipleTouchEnabled = false\r\n        \r\n        bezierPathLine = UIBezierPath()\r\n        bezierPathLine.lineWidth = 4\r\n        \r\n        self.backgroundColor = UIColor.clear\r\n        \r\n        let panGesture = UIPanGestureRecognizer(target: self, action: #selector(viewDragged(_:)))\r\n        addGestureRecognizer(panGesture)\r\n        \r\n    }\r\n    \r\n    func viewDragged(_ sender: UIPanGestureRecognizer) {\r\n        \r\n        let point = sender.location(in: self)\r\n        \r\n        if point.x &lt; 0 || point.x &gt; frame.width || point.y &lt; 0 || point.y &gt; frame.height {\r\n            return\r\n        }\r\n        \r\n        switch sender.state {\r\n            \r\n        case .began:\r\n            bezierCurvePoints.append(point)\r\n            break\r\n            \r\n        case .changed:\r\n            \r\n            bezierCurvePoints.append(point)\r\n\r\n            if bezierCurvePoints.count == 5 {\r\n                \r\n\r\n                \/\/ Calculate center point of 3rd and 5th point\r\n                let x1 = bezierCurvePoints[2].x\r\n                let y1 = bezierCurvePoints[2].y\r\n                \r\n                let x2 = bezierCurvePoints[4].x\r\n                let y2 = bezierCurvePoints[4].y\r\n                \r\n                \/\/ Replace 4th point with the calculated center point\r\n                bezierCurvePoints[3] = CGPoint(x: (x1 + x2) \/ 2, y: (y1 + y2) \/ 2)\r\n                \r\n                \/\/ Draw arc between 1st and 4th point\r\n                bezierPathLine.move(to: bezierCurvePoints[0])\r\n                bezierPathLine.addCurve(to: bezierCurvePoints[3], controlPoint1: bezierCurvePoints[1], controlPoint2: bezierCurvePoints[2])\r\n                \r\n                let point1 = bezierCurvePoints[3]\r\n                let point2 = bezierCurvePoints[4]\r\n                \r\n                bezierCurvePoints.removeAll()\r\n                \r\n                \/\/ Last two points will be starting two points for next arc.\r\n                bezierCurvePoints.append(point1)\r\n                bezierCurvePoints.append(point2)\r\n                \r\n                setNeedsDisplay()\r\n            }\r\n            \r\n            break\r\n            \r\n        case .ended:\r\n            \r\n            saveBufferImage()\r\n            \r\n            bezierCurvePoints.removeAll()\r\n            bezierPathLine.removeAllPoints()\r\n            break\r\n        default:\r\n            break\r\n        }\r\n    }\r\n    \r\n    private func saveBufferImage() {\r\n        UIGraphicsBeginImageContextWithOptions(self.bounds.size, false, UIScreen.main.scale)\r\n        if bufferImage == nil {\r\n            let fillPath = UIBezierPath(rect: self.bounds)\r\n            UIColor.clear.setFill()\r\n            fillPath.fill()\r\n        }\r\n        bufferImage?.draw(at: .zero)\r\n        drawLine()\r\n        bufferImage = UIGraphicsGetImageFromCurrentImageContext()\r\n        UIGraphicsEndImageContext()\r\n    }\r\n}<\/pre>\n<p>&nbsp;<\/p>\n<p>Compile and Run it. You will get some output like this:<\/p>\n<p><a href=\"https:\/\/www.innovationm.com\/blog\/wp-content\/uploads\/2017\/04\/IMG_0249.jpg\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-3072 size-full\" src=\"https:\/\/www.innovationm.com\/blog\/wp-content\/uploads\/2017\/04\/IMG_0249.jpg\" alt=\"freehand-drawing-3\" width=\"1536\" height=\"2048\" srcset=\"https:\/\/www.innovationm.com\/blog\/wp-content\/uploads\/2017\/04\/IMG_0249.jpg 1536w, https:\/\/www.innovationm.com\/blog\/wp-content\/uploads\/2017\/04\/IMG_0249-225x300.jpg 225w, https:\/\/www.innovationm.com\/blog\/wp-content\/uploads\/2017\/04\/IMG_0249-768x1024.jpg 768w, https:\/\/www.innovationm.com\/blog\/wp-content\/uploads\/2017\/04\/IMG_0249-624x832.jpg 624w\" sizes=\"(max-width: 1536px) 100vw, 1536px\" \/><\/a><\/p>\n<p>Now we have a smooth drawing.<\/p>\n<h3>Create Arrow<\/h3>\n<p>Now, lets create an arrow head at the end of the line segment. for this we will use last two points to calculate three points to create an arrow.<\/p>\n<p>To calculate these points we will use following steps.<\/p>\n<ol>\n<li>First we will convert this line segment(made by last two points) into unit vector and translate this unit vector to origin.\n<ol>\n<li>calculate normal\n<ul>\n<li>\n<pre class=\"lang:default decode:true \">normal = \u221a(dx\u00b2 + dy\u00b2)<\/pre>\n<p><a href=\"https:\/\/www.innovationm.com\/blog\/wp-content\/uploads\/2017\/05\/Freehand-Drawing-1.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-3093\" src=\"https:\/\/www.innovationm.com\/blog\/wp-content\/uploads\/2017\/05\/Freehand-Drawing-1.png\" alt=\"Freehand Drawing 1\" width=\"300\" height=\"300\" srcset=\"https:\/\/www.innovationm.com\/blog\/wp-content\/uploads\/2017\/05\/Freehand-Drawing-1.png 300w, https:\/\/www.innovationm.com\/blog\/wp-content\/uploads\/2017\/05\/Freehand-Drawing-1-150x150.png 150w\" sizes=\"(max-width: 300px) 100vw, 300px\" \/><\/a><\/li>\n<\/ul>\n<\/li>\n<li>calculate unit vector\n<ul>\n<li>\n<pre class=\"lang:default decode:true \">udx = dx\/normal\r\nudy = dy\/normal<\/pre>\n<p><a href=\"https:\/\/www.innovationm.com\/blog\/wp-content\/uploads\/2017\/05\/Freehand-Drawing-2.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-3094\" src=\"https:\/\/www.innovationm.com\/blog\/wp-content\/uploads\/2017\/05\/Freehand-Drawing-2.png\" alt=\"Freehand Drawing 2\" width=\"300\" height=\"300\" srcset=\"https:\/\/www.innovationm.com\/blog\/wp-content\/uploads\/2017\/05\/Freehand-Drawing-2.png 300w, https:\/\/www.innovationm.com\/blog\/wp-content\/uploads\/2017\/05\/Freehand-Drawing-2-150x150.png 150w\" sizes=\"(max-width: 300px) 100vw, 300px\" \/><\/a><\/li>\n<\/ul>\n<\/li>\n<\/ol>\n<\/li>\n<li>Now rotate this point `(udx, udy)` by 150\u00b0 clockwise and anti-clockwise.\n<ul>\n<li>\n<pre class=\"lang:default decode:true \">\/\/ Rotate 150 degree clockwise to get first point\r\nax = (udx * cos(150)) - (udy * sin(150))\r\nay = (udx * sin(150)) + (udy * cos(150))\r\n        \r\n\/\/ Rotate 150 degree anticlockwise to get second point\r\nbx = (udx * cos(150)) + (udy * sin(150))\r\nby = (-1 * udx * sin(150)) + (udy * cos(150))<\/pre>\n<p><a href=\"https:\/\/www.innovationm.com\/blog\/wp-content\/uploads\/2017\/05\/Freehand-Drawing-3.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-3095\" src=\"https:\/\/www.innovationm.com\/blog\/wp-content\/uploads\/2017\/05\/Freehand-Drawing-3.png\" alt=\"Freehand Drawing 3\" width=\"300\" height=\"300\" srcset=\"https:\/\/www.innovationm.com\/blog\/wp-content\/uploads\/2017\/05\/Freehand-Drawing-3.png 300w, https:\/\/www.innovationm.com\/blog\/wp-content\/uploads\/2017\/05\/Freehand-Drawing-3-150x150.png 150w\" sizes=\"(max-width: 300px) 100vw, 300px\" \/><\/a><\/li>\n<\/ul>\n<\/li>\n<li>Now we have two points `(ax, ay)` and `(bx, by)`. Lets translate these points to end of the line segment to get the points for our arrow.\n<ul>\n<li>\n<pre class=\"lang:default decode:true \">ax0 = ax + x2\r\nay0 = ay + y2\r\n\r\nbx0 = bx + x2\r\nby0 = by + y2<\/pre>\n<p><a href=\"https:\/\/www.innovationm.com\/blog\/wp-content\/uploads\/2017\/05\/Freehand-Drawing-4.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-3096\" src=\"https:\/\/www.innovationm.com\/blog\/wp-content\/uploads\/2017\/05\/Freehand-Drawing-4.png\" alt=\"Freehand Drawing 4\" width=\"300\" height=\"300\" srcset=\"https:\/\/www.innovationm.com\/blog\/wp-content\/uploads\/2017\/05\/Freehand-Drawing-4.png 300w, https:\/\/www.innovationm.com\/blog\/wp-content\/uploads\/2017\/05\/Freehand-Drawing-4-150x150.png 150w\" sizes=\"(max-width: 300px) 100vw, 300px\" \/><\/a><\/li>\n<\/ul>\n<\/li>\n<li>Till now this arrow if of unit length, to get a proper length scale these points with and scaling factor(s).\n<ul>\n<li>\n<pre class=\"lang:default decode:true \">ax0 = s*ax + x2\r\nay0 = s*ay + y2\r\n\r\nbx0 = s*bx + x2\r\nby0 = s*by + y2<\/pre>\n<p><a href=\"https:\/\/www.innovationm.com\/blog\/wp-content\/uploads\/2017\/05\/Freehand-Drawing-5.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-3097\" src=\"https:\/\/www.innovationm.com\/blog\/wp-content\/uploads\/2017\/05\/Freehand-Drawing-5.png\" alt=\"Freehand Drawing 5\" width=\"300\" height=\"300\" srcset=\"https:\/\/www.innovationm.com\/blog\/wp-content\/uploads\/2017\/05\/Freehand-Drawing-5.png 300w, https:\/\/www.innovationm.com\/blog\/wp-content\/uploads\/2017\/05\/Freehand-Drawing-5-150x150.png 150w\" sizes=\"(max-width: 300px) 100vw, 300px\" \/><\/a><\/li>\n<\/ul>\n<\/li>\n<li>Now combine these points `(ax0, ay0)`, `(x2, y2)` and `(bx0, by0)` to create a line segment for arrow.<\/li>\n<\/ol>\n<p>&nbsp;<\/p>\n<p>The complete implementation of the algorithm is given below.<\/p>\n<pre class=\"lang:swift decode:true\">func getArrowHeadPoints() -&gt; (point1: CGPoint, point2: CGPoint, point3: CGPoint)? {\r\n    \r\n    var points: (CGPoint, CGPoint, CGPoint)? = nil\r\n    \r\n    if bezierCurvePoints.count &gt;= 2 {\r\n        \r\n        let start = bezierCurvePoints[bezierCurvePoints.count - 2]\r\n        let end = bezierCurvePoints[bezierCurvePoints.count - 1]\r\n        \r\n        let dx = end.x - start.x\r\n        let dy = end.y - start.y\r\n        \r\n        let normal = sqrt(dx*dx + dy*dy)\r\n        \r\n        \/\/ Convert into unit vectors\r\n        var udx = dx \/ normal\r\n        var udy = dy \/ normal\r\n        \r\n        if normal == 0 {\r\n            udx = 0\r\n            udy = 0\r\n        }\r\n        \r\n        \/\/ Rotate 150 degree clockwise to get first point\r\n        let ax = (udx * cos150) - (udy * sin150)\r\n        let ay = (udx * sin150) + (udy * cos150)\r\n        \r\n        \/\/ Rotate 150 degree anticlockwise to get second point\r\n        let bx = (udx * cos150) + (udy * sin150)\r\n        let by = (-1 * udx * sin150) + (udy * cos150)\r\n        \r\n        \/\/ Scale 20 points and then translate to end point for both points\r\n        let ax0 = end.x + 20 * ax\r\n        let ay0 = end.y + 20 * ay\r\n        \r\n        let ax1 = end.x + 20 * bx\r\n        let ay1 = end.y + 20 * by\r\n        \r\n        let point1 = CGPoint(x: ax0, y: ay0)\r\n        let point2 = CGPoint(x: ax1, y: ay1)\r\n        let point3 = CGPoint(x: end.x, y: end.y)\r\n        \r\n        points = (point1, point2, point3)\r\n    }\r\n    \r\n    return points\r\n}<\/pre>\n<p>&nbsp;<\/p>\n<p>Use this method to get three points and draw line with these three lines in your `draw(_:)` method.<\/p>\n<p>Thanks for reading. Hope you like the post. \ud83d\ude42<\/p>\n","protected":false},"excerpt":{"rendered":"<p>&nbsp; Hello, folks. In this post we are going to implement a reusable component for freehand drawing. We will see how to use `UIGestureRecognizer` for drawing and using linear polarization\u00a0to make our drawing smooth. We will also create a method to draw an arrow with respect to two points. So let&#8217;s start with creating a [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":3098,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[3,71,8],"tags":[14,160,122,89,165,13,178,85,10,22],"class_list":["post-3043","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-ios","category-mobile","category-mobile-architecture-and-design","tag-innovationm","tag-ios","tag-ipad","tag-iphone","tag-mobile","tag-mobile-design","tag-swift-3-0","tag-ui","tag-ui-design","tag-uiimage"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.4 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Smooth Freehand Drawing with Arrow in iOS | InnovationM Blog<\/title>\n<meta name=\"description\" content=\"Tutorial on how to use bezier path to create a freehand drawing view in iOS with Swift 3 and improve the smoothness of the drawing with linear polarization.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.innovationm.com\/blog\/smooth-freehand-drawing-with-arrow-in-ios\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Smooth Freehand Drawing with Arrow in iOS | InnovationM Blog\" \/>\n<meta property=\"og:description\" content=\"Tutorial on how to use bezier path to create a freehand drawing view in iOS with Swift 3 and improve the smoothness of the drawing with linear polarization.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.innovationm.com\/blog\/smooth-freehand-drawing-with-arrow-in-ios\/\" \/>\n<meta property=\"og:site_name\" content=\"InnovationM - Blog\" \/>\n<meta property=\"article:published_time\" content=\"2017-05-16T06:50:48+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.innovationm.com\/blog\/wp-content\/uploads\/2017\/05\/Freehand-Drawing.png\" \/>\n\t<meta property=\"og:image:width\" content=\"624\" \/>\n\t<meta property=\"og:image:height\" content=\"347\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"InnovationM Admin\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"InnovationM Admin\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"8 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/www.innovationm.com\\\/blog\\\/smooth-freehand-drawing-with-arrow-in-ios\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.innovationm.com\\\/blog\\\/smooth-freehand-drawing-with-arrow-in-ios\\\/\"},\"author\":{\"name\":\"InnovationM Admin\",\"@id\":\"https:\\\/\\\/www.innovationm.com\\\/blog\\\/#\\\/schema\\\/person\\\/a831bf4602d69d1fa452e3de0c8862ed\"},\"headline\":\"Smooth Freehand Drawing with Arrow in iOS\",\"datePublished\":\"2017-05-16T06:50:48+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/www.innovationm.com\\\/blog\\\/smooth-freehand-drawing-with-arrow-in-ios\\\/\"},\"wordCount\":769,\"commentCount\":0,\"image\":{\"@id\":\"https:\\\/\\\/www.innovationm.com\\\/blog\\\/smooth-freehand-drawing-with-arrow-in-ios\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.innovationm.com\\\/blog\\\/wp-content\\\/uploads\\\/2017\\\/05\\\/Freehand-Drawing.png\",\"keywords\":[\"InnovationM\",\"iOS\",\"iPad\",\"iPhone\",\"Mobile\",\"Mobile Design\",\"Swift 3.0\",\"UI\",\"UI Design\",\"UIImage\"],\"articleSection\":[\"iOS\",\"Mobile\",\"Mobile Architecture and Design\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/www.innovationm.com\\\/blog\\\/smooth-freehand-drawing-with-arrow-in-ios\\\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/www.innovationm.com\\\/blog\\\/smooth-freehand-drawing-with-arrow-in-ios\\\/\",\"url\":\"https:\\\/\\\/www.innovationm.com\\\/blog\\\/smooth-freehand-drawing-with-arrow-in-ios\\\/\",\"name\":\"Smooth Freehand Drawing with Arrow in iOS | InnovationM Blog\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.innovationm.com\\\/blog\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/www.innovationm.com\\\/blog\\\/smooth-freehand-drawing-with-arrow-in-ios\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/www.innovationm.com\\\/blog\\\/smooth-freehand-drawing-with-arrow-in-ios\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.innovationm.com\\\/blog\\\/wp-content\\\/uploads\\\/2017\\\/05\\\/Freehand-Drawing.png\",\"datePublished\":\"2017-05-16T06:50:48+00:00\",\"author\":{\"@id\":\"https:\\\/\\\/www.innovationm.com\\\/blog\\\/#\\\/schema\\\/person\\\/a831bf4602d69d1fa452e3de0c8862ed\"},\"description\":\"Tutorial on how to use bezier path to create a freehand drawing view in iOS with Swift 3 and improve the smoothness of the drawing with linear polarization.\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/www.innovationm.com\\\/blog\\\/smooth-freehand-drawing-with-arrow-in-ios\\\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/www.innovationm.com\\\/blog\\\/smooth-freehand-drawing-with-arrow-in-ios\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/www.innovationm.com\\\/blog\\\/smooth-freehand-drawing-with-arrow-in-ios\\\/#primaryimage\",\"url\":\"https:\\\/\\\/www.innovationm.com\\\/blog\\\/wp-content\\\/uploads\\\/2017\\\/05\\\/Freehand-Drawing.png\",\"contentUrl\":\"https:\\\/\\\/www.innovationm.com\\\/blog\\\/wp-content\\\/uploads\\\/2017\\\/05\\\/Freehand-Drawing.png\",\"width\":624,\"height\":347},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/www.innovationm.com\\\/blog\\\/smooth-freehand-drawing-with-arrow-in-ios\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/www.innovationm.com\\\/blog\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Smooth Freehand Drawing with Arrow in iOS\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/www.innovationm.com\\\/blog\\\/#website\",\"url\":\"https:\\\/\\\/www.innovationm.com\\\/blog\\\/\",\"name\":\"InnovationM - Blog\",\"description\":\"\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/www.innovationm.com\\\/blog\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/www.innovationm.com\\\/blog\\\/#\\\/schema\\\/person\\\/a831bf4602d69d1fa452e3de0c8862ed\",\"name\":\"InnovationM Admin\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/5c99d9eece9dfbc82297cf34ddd58e9fe05bb52fe66c8f6bf6c0a45bfb6d7629?s=96&r=g\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/5c99d9eece9dfbc82297cf34ddd58e9fe05bb52fe66c8f6bf6c0a45bfb6d7629?s=96&r=g\",\"contentUrl\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/5c99d9eece9dfbc82297cf34ddd58e9fe05bb52fe66c8f6bf6c0a45bfb6d7629?s=96&r=g\",\"caption\":\"InnovationM Admin\"},\"sameAs\":[\"http:\\\/\\\/www.innovationm.com\\\/\"],\"url\":\"https:\\\/\\\/www.innovationm.com\\\/blog\\\/author\\\/innovationmadmin\\\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Smooth Freehand Drawing with Arrow in iOS | InnovationM Blog","description":"Tutorial on how to use bezier path to create a freehand drawing view in iOS with Swift 3 and improve the smoothness of the drawing with linear polarization.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.innovationm.com\/blog\/smooth-freehand-drawing-with-arrow-in-ios\/","og_locale":"en_US","og_type":"article","og_title":"Smooth Freehand Drawing with Arrow in iOS | InnovationM Blog","og_description":"Tutorial on how to use bezier path to create a freehand drawing view in iOS with Swift 3 and improve the smoothness of the drawing with linear polarization.","og_url":"https:\/\/www.innovationm.com\/blog\/smooth-freehand-drawing-with-arrow-in-ios\/","og_site_name":"InnovationM - Blog","article_published_time":"2017-05-16T06:50:48+00:00","og_image":[{"width":624,"height":347,"url":"https:\/\/www.innovationm.com\/blog\/wp-content\/uploads\/2017\/05\/Freehand-Drawing.png","type":"image\/png"}],"author":"InnovationM Admin","twitter_misc":{"Written by":"InnovationM Admin","Est. reading time":"8 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.innovationm.com\/blog\/smooth-freehand-drawing-with-arrow-in-ios\/#article","isPartOf":{"@id":"https:\/\/www.innovationm.com\/blog\/smooth-freehand-drawing-with-arrow-in-ios\/"},"author":{"name":"InnovationM Admin","@id":"https:\/\/www.innovationm.com\/blog\/#\/schema\/person\/a831bf4602d69d1fa452e3de0c8862ed"},"headline":"Smooth Freehand Drawing with Arrow in iOS","datePublished":"2017-05-16T06:50:48+00:00","mainEntityOfPage":{"@id":"https:\/\/www.innovationm.com\/blog\/smooth-freehand-drawing-with-arrow-in-ios\/"},"wordCount":769,"commentCount":0,"image":{"@id":"https:\/\/www.innovationm.com\/blog\/smooth-freehand-drawing-with-arrow-in-ios\/#primaryimage"},"thumbnailUrl":"https:\/\/www.innovationm.com\/blog\/wp-content\/uploads\/2017\/05\/Freehand-Drawing.png","keywords":["InnovationM","iOS","iPad","iPhone","Mobile","Mobile Design","Swift 3.0","UI","UI Design","UIImage"],"articleSection":["iOS","Mobile","Mobile Architecture and Design"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.innovationm.com\/blog\/smooth-freehand-drawing-with-arrow-in-ios\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.innovationm.com\/blog\/smooth-freehand-drawing-with-arrow-in-ios\/","url":"https:\/\/www.innovationm.com\/blog\/smooth-freehand-drawing-with-arrow-in-ios\/","name":"Smooth Freehand Drawing with Arrow in iOS | InnovationM Blog","isPartOf":{"@id":"https:\/\/www.innovationm.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.innovationm.com\/blog\/smooth-freehand-drawing-with-arrow-in-ios\/#primaryimage"},"image":{"@id":"https:\/\/www.innovationm.com\/blog\/smooth-freehand-drawing-with-arrow-in-ios\/#primaryimage"},"thumbnailUrl":"https:\/\/www.innovationm.com\/blog\/wp-content\/uploads\/2017\/05\/Freehand-Drawing.png","datePublished":"2017-05-16T06:50:48+00:00","author":{"@id":"https:\/\/www.innovationm.com\/blog\/#\/schema\/person\/a831bf4602d69d1fa452e3de0c8862ed"},"description":"Tutorial on how to use bezier path to create a freehand drawing view in iOS with Swift 3 and improve the smoothness of the drawing with linear polarization.","breadcrumb":{"@id":"https:\/\/www.innovationm.com\/blog\/smooth-freehand-drawing-with-arrow-in-ios\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.innovationm.com\/blog\/smooth-freehand-drawing-with-arrow-in-ios\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.innovationm.com\/blog\/smooth-freehand-drawing-with-arrow-in-ios\/#primaryimage","url":"https:\/\/www.innovationm.com\/blog\/wp-content\/uploads\/2017\/05\/Freehand-Drawing.png","contentUrl":"https:\/\/www.innovationm.com\/blog\/wp-content\/uploads\/2017\/05\/Freehand-Drawing.png","width":624,"height":347},{"@type":"BreadcrumbList","@id":"https:\/\/www.innovationm.com\/blog\/smooth-freehand-drawing-with-arrow-in-ios\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.innovationm.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Smooth Freehand Drawing with Arrow in iOS"}]},{"@type":"WebSite","@id":"https:\/\/www.innovationm.com\/blog\/#website","url":"https:\/\/www.innovationm.com\/blog\/","name":"InnovationM - Blog","description":"","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.innovationm.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Person","@id":"https:\/\/www.innovationm.com\/blog\/#\/schema\/person\/a831bf4602d69d1fa452e3de0c8862ed","name":"InnovationM Admin","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/secure.gravatar.com\/avatar\/5c99d9eece9dfbc82297cf34ddd58e9fe05bb52fe66c8f6bf6c0a45bfb6d7629?s=96&r=g","url":"https:\/\/secure.gravatar.com\/avatar\/5c99d9eece9dfbc82297cf34ddd58e9fe05bb52fe66c8f6bf6c0a45bfb6d7629?s=96&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/5c99d9eece9dfbc82297cf34ddd58e9fe05bb52fe66c8f6bf6c0a45bfb6d7629?s=96&r=g","caption":"InnovationM Admin"},"sameAs":["http:\/\/www.innovationm.com\/"],"url":"https:\/\/www.innovationm.com\/blog\/author\/innovationmadmin\/"}]}},"_links":{"self":[{"href":"https:\/\/www.innovationm.com\/blog\/wp-json\/wp\/v2\/posts\/3043","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.innovationm.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.innovationm.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.innovationm.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.innovationm.com\/blog\/wp-json\/wp\/v2\/comments?post=3043"}],"version-history":[{"count":0,"href":"https:\/\/www.innovationm.com\/blog\/wp-json\/wp\/v2\/posts\/3043\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.innovationm.com\/blog\/wp-json\/wp\/v2\/media\/3098"}],"wp:attachment":[{"href":"https:\/\/www.innovationm.com\/blog\/wp-json\/wp\/v2\/media?parent=3043"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.innovationm.com\/blog\/wp-json\/wp\/v2\/categories?post=3043"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.innovationm.com\/blog\/wp-json\/wp\/v2\/tags?post=3043"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}