0

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
                print(laps)
            }
    }

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

rmaddy
  • 314,917
  • 42
  • 532
  • 579
Eliko
  • 1,137
  • 4
  • 16
  • 26
  • 2
    Instead of checking for 0, you can do angle summation and then divide it by 360, to get the number of spins. Basically, don't re-zero the angle, but just accumulate the angle in a variable. – Eugene Gordin Jun 03 '16 at 16:58
  • @EugeneZhenyaGordin Can you give me an example? – Eliko Jun 03 '16 at 16:59
  • ok...so say you start from 0 clockwise, when you get to the same point again instead of re-zero just continue adding the degrees, 385...450 etc. if you go counter clockwise, subtract. when the touches finished, device by 360 and you'll get the number of spins, if that value is negative, it means you were going counterclockwise. – Eugene Gordin Jun 03 '16 at 17:01
  • @EugeneZhenyaGordin How can i not re-zero it when it gets to the top again? – Eliko Jun 03 '16 at 17:03
  • so say you have the variable angle. When you start your motion clockwise, just add your delta to that var, angle += delta, where delta is number of degrees you moved. That's it. Your delta might be positive or negative depending on the direction of motion. – Eugene Gordin Jun 03 '16 at 17:06
  • 1
    this is a great example of the similar model in obj-c http://www.ios-blog.co.uk/tutorials/objective-c/creating-a-custom-rotation-gesture-recognizer-for-ios-apps/ – Eugene Gordin Jun 03 '16 at 17:08
  • But if I touch the angle in 50, then make 370 spin and stop touching (in 60), the the delta will be 10 and not 370. – Eliko Jun 03 '16 at 17:10
  • you should calculate displacement angle from point at 50 and point 60 in your case. It's pretty straight forward math to do so http://math.stackexchange.com/questions/185829/how-do-you-find-an-angle-between-two-points-on-the-edge-of-a-circle – Eugene Gordin Jun 03 '16 at 17:18
  • @EugeneZhenyaGordin Can you give a code example because I understand the math but not your point – Eliko Jun 03 '16 at 17:39

1 Answers1

2

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)))
Martin R
  • 529,903
  • 94
  • 1,240
  • 1,382