Eliko Eliko - 4 months ago 7
Swift Question

Calculate how much laps the user did in a Circle Path

I have made a blue ball that can be dragged by the user only on a red circled path:
enter image description here

I want to check how many times the user make a forward or backward lap (the start & end is at the top of the circle path), for example - If he drag the ball in a clockwise way so the laps is +1, and if he drag it to other way the laps is -1.

I tried to do this(This inculdes the dragging of the ball and my try to count laps):

@IBAction func dragBall(recognizer: UIPanGestureRecognizer) {
let point = recognizer.locationInView(self.view);
let earthX = Double(point.x)
let earthY = Double(point.y)
let midViewXDouble = Double(midViewX)
let midViewYDouble = Double(midViewY)
let angleX = (earthX - midViewXDouble)
let angleY = (earthY - midViewYDouble)
let angle = atan2(angleY, angleX)
let earthX2 = midViewXDouble + cos(angle)*100
let earthY2 = midViewYDouble + sin(angle)*100
circlePath2 = UIBezierPath(arcCenter: CGPoint(x: earthX2,y: earthY2), radius: CGFloat(10), startAngle: CGFloat(0), endAngle:CGFloat(M_PI * 2), clockwise: true)
shapeLayer2.path = circlePath2.CGPath

if degrees == 0 {
laps += 1

And it worked! but when the user drags the ball very fast it do not calculate, and it do not calculate backwards.


Here is a possible solution, following the approach indicated in the comments. First you need some additional instance variables:

var previousAngle = -M_PI_2 // top position if y-coordinate points down
var totalAngle = 0.0
var laps = 0

In dragBall, you calculate how much the angle has changed. Since the angle can "jump" from -π to π, or vice versa, the difference is normalised to the range -π ... π:

var delta = angle - previousAngle
if delta > M_PI {
    delta -= 2 * M_PI
} else if delta < -M_PI {
    delta += 2 * M_PI
previousAngle = angle

Then update the total change in the angle:

totalAngle += delta

and from that you can determine the number of laps:

laps = Int(floor(totalAngle/(2 * M_PI)))