Search code examples
iosswiftuibezierpathcgpath

Want to draw explanatory sign using UIBezierPath


I need to draw explanatory sign using UIBezierPath.

what i am trying to draw is

Expected image

what i am getting using below code

enter image description here

private func linePath()-> CGPath {
        let viewCenter = CGPoint(x: bounds.midX, y: bounds.midY)
        
        let radius = bounds.midX/7.5
        
        let miniRadius = bounds.midX/15
        
        
        
        let path = UIBezierPath()
        ///path.move(to: viewCenter)
        path.addArc(withCenter: viewCenter, radius: miniRadius, startAngle: 0, endAngle: 180.degreesToRadians, clockwise: true)
        
        
        path.addQuadCurve(to: CGPoint(x: path.currentPoint.x - 5, y: path.currentPoint.y - 30), controlPoint: CGPoint(x: path.currentPoint.x - 10, y: path.currentPoint.y - 30))
        
       // path.addLine(to: CGPoint(x: path.currentPoint.x - 5, y: path.currentPoint.y - 30))
        
        path.addArc(withCenter: CGPoint(x: path.currentPoint.x + radius, y: path.currentPoint.y + radius/2), radius: radius, startAngle: 180, endAngle: 0.degreesToRadians, clockwise: true)
        
        path.close()
        return path.cgPath
    }

Any help or pointers are appreciated.


Solution

  • When drawing smooth shapes with Bézier curves, we want to make sure that there are no points of discontinuity of the slope in the overall path where one curve abuts another. I.e., we want to ensure there aren’t any points where the slopes before and after a start/end point are not equal.

    In short, make sure that the slope of the first control point for each Bézier curve matches the slope of the previous curve (and of course, that the second control point matches the slope of the following curve).

    Consider, the following, stroking the three paths, one arc and two cubic Bézier (plus stroking the control points for the Bézier):

    enter image description here

    I have done this with three curves, and I'm showing the control points for the green and yellow curves with the dark lines. Going clockwise, note how the yellow curve’s first control point is collinear with the tangent of the blue arc. And the yellow’s second control point is collinear with the green curve’s first control point. And, of course, the green curve’s second control point is collinear with the starting tangent of the blue curve.

    Getting rid of the distracting colors that yields:

    enter image description here

    FYI, this generated the above:

    func updatePath() {
        let verticalControlOffset = radius
        let horizontalControllOffset = radius / 2
        let height = radius * 5
    
        let path = UIBezierPath()
        path.addArc(withCenter: CGPoint(x: bounds.midX, y: bounds.minY + radius),
                    radius: radius,
                    startAngle: .pi,
                    endAngle: 2 * .pi,
                    clockwise: true)
    
        var startPoint = path.currentPoint
        var endPoint = CGPoint(x: bounds.midX, y: bounds.minY + height)
        var cp1 = CGPoint(x: startPoint.x, y: startPoint.y + verticalControlOffset)
        var cp2 = CGPoint(x: endPoint.x + horizontalControllOffset, y: endPoint.y)
    
        path.addCurve(to: endPoint,
                      controlPoint1: cp1,
                      controlPoint2: cp2)
    
        startPoint = path.currentPoint
        endPoint = CGPoint(x: bounds.midX - radius, y: bounds.minY + radius)
        cp1 = CGPoint(x: startPoint.x - horizontalControllOffset, y: startPoint.y)
        cp2 = CGPoint(x: endPoint.x, y: endPoint.y + verticalControlOffset)
    
        path.addCurve(to: endPoint,
                      controlPoint1: cp1,
                      controlPoint2: cp2)
    
        shapeLayer.path = path.cgPath
    }
    

    Now, this is not the exact same as your target shape. But it illustrates the issue, namely when joining a series of Bézier curves together, make sure the control points for adjoining curves line with each other. This is easy when your control points are all vertical and horizontal, but if not, you will want to use a little algebra and/or trigonometry to make sure they line up properly. And sometimes, when rendering complicated shapes, it is helpful to actually stroke lines to the control points, so you can easily visualize what is going on.