Search code examples
iosswiftuibezierpath

Hide part of UIBezierPath


I have 3 UIBezierPath with 2 circle and a line running from 1 circle's center to the other and it looks like the bottom picture. I want to hide the part of the line inside the circle like the top picture. Is there any easy way to do this?

My strategy would be to draw a invisible line from the centers and then draw a black line from the circumference of the 2 circles since I know the slopes etc but it seems like too much work. enter image description here

    private func pathForBoxCircle1() -> UIBezierPath {

        let circlePath = UIBezierPath(arcCenter:circle1BoxCurrentCenter, radius: 25, startAngle: 0.0, endAngle: CGFloat(2*M_PI), clockwise: false)
        //circlePath.fill()
        pathBoxCircle1Global = circlePath

        return circlePath
    }

    private func pathForBoxCircle2() -> UIBezierPath {

        let circlePath = UIBezierPath(arcCenter:circle2BoxCurrentCenter, radius: 25, startAngle: 0.0, endAngle: CGFloat(2*M_PI), clockwise: false)
        //circlePath.fill()
        pathBoxCircle2Global = circlePath

        return circlePath
    }
    private func pathForHorizonLine() -> UIBezierPath {
        let path = UIBezierPath()
        path.move(to: circle1BoxCurrentCenter)
        path.addLine(to: circle2BoxCurrentCenter)
        path.lineWidth = 5.0
        //pathHorizonLineGlobal = path


        return path
    }

    override func draw(_ rect: CGRect) {

        pathForBoxCircle1().stroke()
        pathForBoxCircle2().stroke() // same as stroke()
        pathForHorizonLine().stroke()


    }

Solution

  • You can't mix transparent and opaque lines in the same shape. You are going to have to draw 2 circles and then the line segment from the outside of the first circle to the outside of the 2nd circle.

    To do that you'll need trig, or perhaps Pythagoras, to calculate the coordinates of the points where your connecting lines intersect your 2 circles.

    If C1 is your first circle, C2 is your 2nd circle, C1 is at (C1.x, C1.y), C2 is at (C2.x, C2.y), the radius of C1 is R1, and the radius of C2 is R2, then the pseudo-code would look something like this:

    angle1 = atan2(C1.y - C2y, C1.x - C2.x)
    
    angle2 = atan2(C2.y - C1.y, C2.x - C1.x)
    
    xOffset1 = R1 * cos(angle1)
    yOffset1 = R1 * sin(angle1)
    
    point1 = (C1.x + xOffset1, C1.y + yOffset1)
    
    xOffset2 = R2 * cos(angle2)
    yOffset2 = R2 * sin(angle2)
    
    point2 = (C2.x + xOffset2, C2.y +  yOffset2)
    

    Draw your circles, then draw lines between point1 and point2.

    (Note that my trig is a little rusty, and that I sketched this out on a piece of scratch paper. I think it's correct, but it's completely untested.)