Get angle from 2 positions

后端 未结 6 1241
失恋的感觉
失恋的感觉 2020-12-08 15:18

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 = 24         


        
相关标签:
6条回答
  • 2020-12-08 15:57

    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
    
    0 讨论(0)
  • 2020-12-08 15:58

    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)) )
    
    0 讨论(0)
  • 2020-12-08 16:00

    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.

    0 讨论(0)
  • 2020-12-08 16:02

    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.

    0 讨论(0)
  • 2020-12-08 16:04

    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.

    0 讨论(0)
  • 2020-12-08 16:06

    Tomas' answer in Swift 5.1

    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 : degrees + degrees
    }
    
    0 讨论(0)
提交回复
热议问题