skip to Main Content

I want to draw the Moon and then animate Moon’s shadow. But after launching this code I can see some glitches on animation line:
enter image description here

GIF:
enter image description here

Why is this happening?

Playground code here

Update 1:
Both paths created by this function but with different angles (0 and π/2*0.6):

func calculateMoonPath(for angle: CGFloat) -> UIBezierPath {
    let center = CGPoint(x: view.bounds.midX, y: view.bounds.midY)
    let radius = view.bounds.height/2
    
    let path = UIBezierPath(arcCenter: center,
                            radius: radius,
                            startAngle: -.pi/2,
                            endAngle: .pi/2,
                            clockwise: true)
    path.addArc(withCenter: .init(x: center.x - radius * tan(angle), y: center.y),
                radius: radius / CGFloat(cosf(Float(angle))),
                startAngle: .pi/2 - angle,
                endAngle: angle - .pi/2,
                clockwise: false
    )
    path.close()
    return path
}

2

Answers


  1. In my experience, the code that generates arcs creates different numbers of cubic bezier curves under the covers as the arc angle changes.

    That changes the number of control points in the two curves, and messes up the animation. (as David Rönnqvist says, animations are undefined if the starting and ending path have a different number of control points.)

    From what I’ve read, a full circle requires 4 cubic bezier curves to complete.

    It wouldn’t be that hard to create a variant of the addArc method that always built the arc using 4 cubic bezier curves, regardless of the arc angle. That’s what I would suggest.

    You could probably break your arc into 4 pieces (Using 4 sequential calls to addArc(withCenter:...) with different start and end angles such that they combine to make your desired full arc. Each of those should be short enough arc lengths to be a single Bezier curve, so you should get the same number of control points for the beginning and ending combined curve.

    If you rewrite your calculateMoonPath function like this:

    func calculateMoonPath(for angle: CGFloat) -> UIBezierPath {
        let center = CGPoint(x: view.bounds.midX, y: view.bounds.midY)
        let radius = view.bounds.height/2
    
        let path = UIBezierPath(arcCenter: center,
                                radius: radius,
                                startAngle: -.pi/2,
                                endAngle: .pi/2,
                                clockwise: true)
        let startAngle = .pi/2 - angle
        let endAngle = angle - .pi/2
        let delta = (endAngle - startAngle) / 4
        for index in 0...3 {
            let thisStart = startAngle + delta * CGFloat(index)
            let thisEnd = startAngle + delta * CGFloat(index + 1)
            path.addArc(withCenter: .init(x: center.x - radius * tan(angle), y: center.y),
                        radius: radius / CGFloat(cosf(Float(angle))),
                        startAngle: thisStart,
                        endAngle: thisEnd,
                        clockwise: false
            )
        }
        path.close()
        return path
    }
    

    That yields the following:

    enter image description here

    Login or Signup to reply.
  2. The way you do each of the two lines,

    is simply, two control points!

    One at each end.

    That’s all there is to it. Don’t try using an arc.

    Here …

    https://www.desmos.com/calculator/cahqdxeshd

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search