22

I have 2 objects and when I move one, I want to get the angle from the other.

For example:

Object1X = 211.000000, Object1Y = 429.000000
Object2X = 246.500000, Object2Y = 441.500000

I have tried the following and every variation under the sun:

double radians = ccpAngle(Object1,Object2);
double degrees = ((radians * 180) / Pi); 

But I just get 2.949023 returned where I want something like 45 degrees etc.

Arnaud
  • 7,259
  • 10
  • 50
  • 71
  • What point should be the vertex of the angle? Assuming the origin, then I get angle between the two objects to be 2.986 degrees. – ughoavgfhw May 19 '11 at 20:46
  • [**How to Get angle from 2 positions **][1] [1]: http://stackoverflow.com/questions/9457988/bearing-from-one-coordinate-to-another/29471137#29471137 – MAnoj Sarnaik Apr 08 '15 at 08:42

7 Answers7

50

Does this other answer help?

How to map atan2() to degrees 0-360

I've written it like this:

- (CGFloat) pointPairToBearingDegrees:(CGPoint)startingPoint secondPoint:(CGPoint) endingPoint
{
    CGPoint originPoint = CGPointMake(endingPoint.x - startingPoint.x, endingPoint.y - startingPoint.y); // get origin point to origin by subtracting end from start
    float bearingRadians = atan2f(originPoint.y, originPoint.x); // get bearing in radians
    float bearingDegrees = bearingRadians * (180.0 / M_PI); // convert to degrees
    bearingDegrees = (bearingDegrees > 0.0 ? bearingDegrees : (360.0 + bearingDegrees)); // correct discontinuity
    return bearingDegrees;
}

Running the code:

CGPoint p1 = CGPointMake(10, 10);
CGPoint p2 = CGPointMake(20,20);

CGFloat f = [self pointPairToBearingDegrees:p1 secondPoint:p2];

And this returns 45.

Hope this helps.

Community
  • 1
  • 1
Tomas McGuinness
  • 7,651
  • 3
  • 28
  • 40
  • That works and i believe everything i did last night would have worked as well. Turns out i was basing it from the position of the cursor not the object so thats why i thought my readings were wrong. Ooops. Thanks for the help – Jonathan Ogle-Barrington May 20 '11 at 08:04
  • 1
    Realising the mistake is half the battle! – Tomas McGuinness May 20 '11 at 09:07
  • loving you answer, but it needs to be said that for your function, there is an existing cocos method: // aim gun float radians = atan2(self.position.y-crosshairPosition.y, crosshairPosition.x-self.position.x); float degree = CC_RADIANS_TO_DEGREES(radians); gun.rotation = degree; – renevdkooi May 01 '12 at 05:36
  • that messed up the code, but I think you can make out what is is. after getting the atan2 you can convert directly to CC_RADIANS_TO_DEGREE. The method behind it is what you wrote yourself. – renevdkooi May 01 '12 at 05:37
  • This is the right answer. The accepted one returns a strange angle value. – MatterGoal May 05 '13 at 21:06
18

Here's how I'm doing it in Swift for those interested, it's based on @bshirley's answer above w/ a few modifications to help match to the calayer rotation system:

extension CGFloat {
    var degrees: CGFloat {
        return self * CGFloat(180) / .pi
    }
}

extension CGPoint {
    func angle(to comparisonPoint: CGPoint) -> CGFloat {
        let originX = comparisonPoint.x - x
        let originY = comparisonPoint.y - y
        let bearingRadians = atan2f(Float(originY), Float(originX))
        var bearingDegrees = CGFloat(bearingRadians).degrees

        while bearingDegrees < 0 {
            bearingDegrees += 360
        }

        return bearingDegrees
    }
}

This provides a coordinate system like this:

        90
180              0
        270

Usage:

point.angle(to: point2)
CGPoint.zero.angle(to: CGPoint(x: 0, y: 1)) // 90
Logan
  • 52,262
  • 20
  • 99
  • 128
  • how can i achieve this in swift 3 – Uma Madhavi Mar 28 '17 at 10:43
  • @UmaMadhavi updated the answer a bit, all you needed was an external arg, but I made it conform to the new design guidelines? – Logan Mar 28 '17 at 10:48
  • In the place of point & point2 how can i send latitude & longitude values. – Uma Madhavi Mar 28 '17 at 10:52
  • @UmaMadhavi that requires different math based on curvature of earth and coordinate system. I think this question is more applicable for that: http://stackoverflow.com/questions/26998029/calculating-bearing-between-two-cllocation-points-in-swift – Logan Mar 28 '17 at 11:00
12

I modified @tomas' solution to be streamlined. It's likely (it was for me) that this math is going to be called frequently.

In my incarnation, you have to perform the difference between the two points yourself (or if you're lucky, (0,0) is already one of your points). The value being calculated is the direction of the point from (0,0). Yes, that's simple enough and you could inline it if you really want to. My preference is for more readable code.

I also converted it to a function call:

CGFloat CGPointToDegree(CGPoint point) {
  // Provides a directional bearing from (0,0) to the given point.
  // standard cartesian plain coords: X goes up, Y goes right
  // result returns degrees, -180 to 180 ish: 0 degrees = up, -90 = left, 90 = right
  CGFloat bearingRadians = atan2f(point.y, point.x);
  CGFloat bearingDegrees = bearingRadians * (180. / M_PI);
  return bearingDegrees;
}

If you don't want negative values, you need to convert it yourself. Negative values were fine for me - no need to make unneeded calculations.

I was using this in a cocos2d environment, this is how I call it: (Mathematically, we are translating the plane to make p0 the origin. Thus subtracting p0 from p1 (p0 - p0 = {0,0}). The angles are unchanged when the plane is translated.)

CGPoint p0 = self.position;
CGPoint p1 = other.position;
CGPoint pnormal = ccpSub(p1, p0);
CGFloat angle = CGPointToDegree(pnormal);

ccpSub is provided by cocos2d, it's subtraction of a tuple - you can do that yourself if you don't have that available

aside: it's generally not polite style to name the method as above with the CG___ naming scheme, which identifies the function as part of CoreGraphics - so if you want to rename it to MyConvertCGPointToBearing() or FredLovesWilma() then you should do that.

bshirley
  • 8,217
  • 1
  • 37
  • 43
4

Tomas' answer in Swift 5

func angle(between starting: CGPoint, ending: CGPoint) -> CGFloat {
    let center = CGPoint(x: ending.x - starting.x, y: ending.y - starting.y)
    let radians = atan2(center.y, center.x)
    let degrees = radians * 180 / .pi
    return degrees > 0 ? degrees : 360 + degrees
}
vicegax
  • 4,709
  • 28
  • 37
  • 1
    I tried this one, but it needs correction in the return statement we need to add 360 like return degrees > 0 ? degrees : degrees + 360 – David Chelidze Jan 25 '23 at 22:38
1

There is no angle between two points. If you want to know the angle between the vectors from the origin (0,0) to the objects, use the scalar (dot) product:

theta = arccos ( (veca dot vecb) / ( |veca| * |vecb| )

The math std lib of the language your are using surely provides functions for arcus cosine, scalar product and length.

Hyperboreus
  • 822
  • 5
  • 4
0

The vertex of the angle is the point (0,0).

Consider object1X=x1 ....object2Y=y2.

Angle(object1-object2) = 
   90       * (  (1 + sign(x1)) * (1 - sign(y1^2))
               - (1 + sign(x2)) * (1 - sign(y2^2)) )
 + 45       * (  (2 + sign(x1)) * sign(y1)
               - (2 + sign(x2)) * sign(y2)         )
 + 180/pi() * sign(x1*y1) * atan( (abs(x1) - abs(y1)) / (abs(x1) + abs(y1)) )
 - 180/pi() * sign(x2*y2) * atan( (abs(x2) - abs(y2)) / (abs(x2) + abs(y2)) )
Stefan Becker
  • 5,695
  • 9
  • 20
  • 30
0

Will leave it here. Corrected code, plus with rotation of the axis by 90 degrees counterclockwise. I've used it for touches. viewCenter is just center of the view

override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
    if let touch = touches.first {
        let location = touch.location(in: self)            
        guard let viewCenter = self.viewCenter else { return }
        let angle = angle(between:  CGPoint(x: location.x, y: location.y) , ending:viewCenter)
        print(angle)
      }
}

func angle(between starting: CGPoint, ending: CGPoint) -> CGFloat {
    let center = CGPoint(x: ending.x - starting.x, y: ending.y - starting.y)
    let angle90 = deg2rad(90)
    //Rotate axis by 90 degrees counter clockwise
    let rotatedX = center.x * cos(angle90) + center.y * sin(angle90)
    let rotatedY = -center.x * sin(angle90) + center.y * cos(angle90)
    let radians = atan2(rotatedY, rotatedX)
    let degrees = radians * 180 / .pi
    return degrees > 0 ? degrees : degrees + 360
}
    
func deg2rad(_ number: CGFloat) -> CGFloat {
    return number * .pi / 180
}
David Chelidze
  • 1,143
  • 12
  • 19