swiftuibezierpathhermite

swift: Hermite round cap UIBezierpath


I have a section in my app where users can draw something. Because of the slow refresh rate of touchesMoved, if a user draws fast, the line doesn't go smooth. That's why I'm using Hermite. It sets a point for every refresh rate and then draws a UIBezierpath (with extension to make it smooth) between those points. It's working perfectly ! I have a smooth design right now !

The only problem is that I'm sometimes not getting a round begin cap and if I switch on the same path back it also happens.

I think it has something to do with the code that draws a bezierpath between those points. So I'm looking for someone that also uses Hermite and knows how to fix this. enter image description here


Solution

  • The hermite spline is just a series of cubic beziers. But you can get these weird discrepancies with UIBezierPath. For example, there is a UIBezierPath rendering problem when you add multiple cubic beziers where the start, control point 1, control point 2, and end are all collinear. So, I've added a check to my hermite spline path to check to see if these four points are collinear, and, if so, just add a line in those cases.

    So, instead of just:

    addCurve(to: endPoint, controlPoint1: control1, controlPoint2: control2)
    

    I do:

    let angleFull = angle(between: previousPoint, and: endPoint)
    let angle1 = angle(between: previousPoint, and: control1)
    let angle2 = angle(between: control2, and: endPoint)
    
    if (angleFull == angle1 || angle1 == nil) && (angleFull == angle2 || angle2 == nil) {
        addLine(to: endPoint)
    } else {
        addCurve(to: endPoint, controlPoint1: control1, controlPoint2: control2)
    }
    

    Where

    private func angle(between point1: CGPoint, and point2: CGPoint) -> CGFloat? {
        if point1 == point2 { return nil }
        return atan2(point2.y - point1.y, point2.x - point1.x)
    }
    

    Another, more generalized solution (though a bit inelegant, IMHO), approach, is to avoid joining these cubic curves entirely, so, before adding each cubic curve, do a move(to:) the previous point first. That should prevent all problems stemming from bugs related to joining cubic beziers.