Get angle from 2 positions
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(开发者_如何学PythonObject1,Object2);
double degrees = ((radians * 180) / Pi);
But I just get 2.949023 returned where I want something like 45 degrees etc.
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.
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
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.
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
}
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.
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)) )
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
}
精彩评论