4

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.

Drawing with addQuadCurveToPoint

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.

enter image description here


Question:

Can anyone help explain or give a solution please:

  1. 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)
    }

}
user4806509
  • 2,925
  • 5
  • 37
  • 72
  • 1
    One is a quadratic bezier curve (with one control point) and the other a cubic bezier curve (with two control points). But a precise answer on why your curves are smooth or why it lags depends strongly on your *code* (which you did not show): How many curves are created, how are the control points computed, etc etc ? – Martin R Nov 05 '15 at 08:03
  • Is this the same code as in your previous question http://stackoverflow.com/questions/33527348/drawing-curved-lines-without-lagging? ? – Martin R Nov 05 '15 at 08:37
  • @Martin R, thanks, I understand from the developer documentation they are quadratic and cubic bezier curves with different control points. I've added a code sample above using `addCurveToPoint`. When drawing begins, there is a short persistent lag as I guess the first points are captured and calculated (?). How can that lag be removed? I have compared and tried very many different code examples on the web including GitHub and consistently for all examples I’ve experienced, `addQuadCurveToPoint` draws fast but not entirely perfect, and `addCurveToPoint` draws perfectly but features the lagging. – user4806509 Nov 05 '15 at 08:42
  • Yes, @Martin R, that is correct. But it isn't unique to that piece of code. Consistently for all examples I’ve experienced, `addQuadCurveToPoint` draws fast but not entirely perfect, and `addCurveToPoint` draws perfectly but features the lagging. I'm trying to determine the best of both worlds. – user4806509 Nov 05 '15 at 08:44
  • @Martin R, I've also added an example for `addQuadCurveToPoint` as well. – user4806509 Nov 05 '15 at 08:50
  • Your two examples handle touches completely differently. One is using `touchesMoved` and the other is using a pan gesture recognizer. Why do you believe that it's the quad-vs-cubic curve that's the difference rather than the fact that you handle input completely differently? You're also drawing completely differently. If you want to check the impact of the type of curve, make sure all the rest of the code is as similar as possible. – Rob Napier Nov 05 '15 at 14:52
  • @Rob Napier that's right, the examples handle touches differently, these are just two of the many different implementations. I believe that it's the quad-vs-cubic curve as I've tried many different combinations. For both `addCurveToPoint` and `addQuadCurveToPoint`, these have been tried with both touchesMoved and panGesture. In all cases, drawing with `addCurveToPoint`, while drawing more perfectly lags behind the touch position, while `addQuadCurveToPoint` keeps up with the touch position but draws less perfectly. I’ve updated the images showing the touch position on the screen when drawing. – user4806509 Nov 06 '15 at 05:22
  • I would love to be proven wrong and shown that `addCurveToPoint` or `addQuadCurveToPoint` can both indeed draw perfect curves and be lag free! – user4806509 Nov 06 '15 at 05:23

0 Answers0