如何从三点计算angular度?

可以说你有这个:

P1 = (x=2, y=50) P2 = (x=9, y=40) P3 = (x=5, y=20) 

假设P1是一个圆的中心点。 它总是一样的。 我想要由P2P3的angular度,换句话说就是P1的angular度。 内angular要精确。 它始终是一个锐angular,所以不到-90度。

我想:男人,那简单的几何math。 但是我现在已经找了6个小时左右的公式,只能find人们在谈论复杂的NASA的东西,比如arccos和vector标量产品。 我的头感觉像是在冰箱里。

这里的一些math大师认为这是一个简单的问题? 我不认为编程语言在这里是重要的,但对于那些认为它的人:java和objective-c。 我需要这两个,但没有标记这些。

如果你的意思是P1的angular度,那么使用余弦定律应该是:

ARCCOS ((P 12 2 + P 13 2 – P 23 2 )/(2 * P 12 * P 13 ))

其中P 12是从P1到P2的段的长度,由下式计算

sqrt((P1 x -P2 x2 +(P1 y -P2 y2

如果你认为它是两个vector,一个从P1到P2,一个从P1到P3,它会变得非常简单

所以:
a =(p1.x – p2.x,p1.y – p2.y)
b =(p1.x – p3.x,p1.y – p3.y)

然后你可以颠倒点积公式:
点产品
得到的angular度:
两个矢量之间的角度

请记住 点产品 只是意味着:a1 * b1 + a2 * b2(这里只有2个维度)

如果你有3分,你有一个三angular形的边缘长度都是已知的。 所以使用余弦规则:

http://en.wikipedia.org/wiki/Law_of_cosines

让我举一个JavaScript例子,我曾经为此付出了很多努力:

 /** * Calculates the angle (in radians) between two vectors pointing outward from one center * * @param p0 first point * @param p1 second point * @param c center point */ function find_angle(p0,p1,c) { var p0c = Math.sqrt(Math.pow(cx-p0.x,2)+ Math.pow(cy-p0.y,2)); // p0->c (b) var p1c = Math.sqrt(Math.pow(cx-p1.x,2)+ Math.pow(cy-p1.y,2)); // p1->c (a) var p0p1 = Math.sqrt(Math.pow(p1.x-p0.x,2)+ Math.pow(p1.y-p0.y,2)); // p0->p1 (c) return Math.acos((p1c*p1c+p0c*p0c-p0p1*p0p1)/(2*p1c*p0c)); } 

奖金: HTML5canvas的例子

基本上你有两个vector,一个vector从P1到P2,另一个从P1到P3。 所以你需要的是一个公式来计算两个向量之间的angular度。

看看这里有一个很好的解释和公式。

替代文字

如果你认为P1是一个圆圈的中心,那么你就太复杂了。 你有一个简单的三angular形,所以你的问题可以用余弦定律来解决 。 无需任何极坐标变换或其他。 说距离是P1-P2 = A,P2-P3 = B和P3-P1 = C:

angular度= arccos((B ^ 2-A ^ 2-C ^ 2)/ 2AC)

所有你需要做的是计算距离A,B和C的长度。这些很容易从你的点的X和Y坐标和毕达哥拉斯定理

长度= sqrt((X2-X1)^ 2 +(Y2-Y1)^ 2)

处理angular度计算的最好方法是使用atan2(y, x)给定一个点x, y返回从该点到X+轴相对于原点的angular度。

鉴于计算是

 double result = atan2(P3.y - P1.y, P3.x - P1.x) - atan2(P2.y - P1.y, P2.x - P1.x); 

即你基本上用-P1翻译这两点(换句话说,你把所有的东西都翻译成P1最后在原点),然后你考虑P3P2的绝对angular度的差异。

atan2的优点是可以表示整个圆(您可以得到-π和π之间的任意数字),而用acos需要根据符号处理几个例子来计算正确的结果。

atan2唯一的奇点是(0, 0) …这意味着P2P3必须与P1不同,因为在这种情况下,谈论angular度是没有意义的。

最近我遇到了一个类似的问题,只是我需要区分正面和负面的angular度。 如果这对任何人都有用,我推荐从这个邮件列表中抓取关于检测Android上的触摸事件旋转的代码片段:

  @Override public boolean onTouchEvent(MotionEvent e) { float x = e.getX(); float y = e.getY(); switch (e.getAction()) { case MotionEvent.ACTION_MOVE: //find an approximate angle between them. float dx = x-cx; float dy = y-cy; double a=Math.atan2(dy,dx); float dpx= mPreviousX-cx; float dpy= mPreviousY-cy; double b=Math.atan2(dpy, dpx); double diff = ab; this.bearing -= Math.toDegrees(diff); this.invalidate(); } mPreviousX = x; mPreviousY = y; return true; } 

在Objective-C中,你可以通过

 float xpoint = (((atan2((newPoint.x - oldPoint.x) , (newPoint.y - oldPoint.y)))*180)/M_PI); 

或者在这里阅读更多

你提到了一个有符号的angular度(-90)。 在许多应用中,angular度可能有标志(正面和负面,见http://en.wikipedia.org/wiki/Angle )。 如果点(例如)P2(1,0),P1(0,0),P3(0,1),则angular度P3-P1-P2通常为正(PI / 2),而angular度P2- P3是否定的。 使用边的长度将不区分+和 – 所以如果这个问题,你将需要使用向量或函数,如Math.atan2(a,b)。

angular度也可以超过2 * PI,虽然这与当前的问题无关,但是我写了我自己的angular度课程(也是为了确保度数和弧度不会混淆)是非常重要的。 关于angular度1是否小于angular度2的问题主要取决于angular度是如何定义的。 决定是否将行(-1,0)(0,0)(1,0)表示为Math.PI或-Math.PI也可能很重要

我的角度演示程序

最近,我也有同样的问题…在Delphi中它非常类似于Objective-C。

 procedure TForm1.FormPaint(Sender: TObject); var ARect: TRect; AWidth, AHeight: Integer; ABasePoint: TPoint; AAngle: Extended; begin FCenter := Point(Width div 2, Height div 2); AWidth := Width div 4; AHeight := Height div 4; ABasePoint := Point(FCenter.X+AWidth, FCenter.Y); ARect := Rect(Point(FCenter.X - AWidth, FCenter.Y - AHeight), Point(FCenter.X + AWidth, FCenter.Y + AHeight)); AAngle := ArcTan2(ClickPoint.Y-Center.Y, ClickPoint.X-Center.X) * 180 / pi; AngleLabel.Caption := Format('Angle is %5.2f', [AAngle]); Canvas.Ellipse(ARect); Canvas.MoveTo(FCenter.X, FCenter.Y); Canvas.LineTo(FClickPoint.X, FClickPoint.Y); Canvas.MoveTo(FCenter.X, FCenter.Y); Canvas.LineTo(ABasePoint.X, ABasePoint.Y); end; 

解释非常简单的几何解法

几天前,一个陷入同样的​​问题,不得不坐在math书。 我通过结合和简化一些基本公式来解决这个问题。


让我们考虑这个数字 –

角度

我们想知道Θ ,所以我们首先需要找出αβ 。 现在,对于任何直线 –

 y = m * x + c 

A =(ax,ay)B =(bx,by)O =(ox,oy) 。 所以对于OA

 oy = m1 * ox + c ⇒ c = oy - m1 * ox ...(eqn-1) ay = m1 * ax + c ⇒ ay = m1 * ax + oy - m1 * ox [from eqn-1] ⇒ ay = m1 * ax + oy - m1 * ox ⇒ m1 = (ay - oy) / (ax - ox) ⇒ tan α = (ay - oy) / (ax - ox) [m = slope = tan ϴ] ...(eqn-2) 

以同样的方式,对于线OB

 tan β = (by - oy) / (bx - ox) ...(eqn-3) 

现在,我们需要ϴ = β - α 。 在三angular学中,我们有一个公式 –

 tan (β-α) = (tan β + tan α) / (1 - tan β * tan α) ...(eqn-4) 

在等式(4)中,取代tan α的值(来自eqn-2)和tan b (来自eqn-3),并且通过简化,

 tan (β-α) = ( (ax-ox)*(by-oy)+(ay-oy)*(bx-ox) ) / ( (ax-ox)*(bx-ox)-(ay-oy)*(by-oy) ) 

所以,

 ϴ = β-α = tan^(-1) ( ((ax-ox)*(by-oy)+(ay-oy)*(bx-ox)) / ((ax-ox)*(bx-ox)-(ay-oy)*(by-oy)) ) 

这就对了!


现在,

角度

这个C#或Java方法计算angular度( Θ ) –

  private double calculateAngle(double P1X, double P1Y, double P2X, double P2Y, double P3X, double P3Y){ double numerator = P2Y*(P1X-P3X) + P1Y*(P3X-P2X) + P3Y*(P2X-P1X); double denominator = (P2X-P1X)*(P1X-P3X) + (P2Y-P1Y)*(P1Y-P3Y); double ratio = numerator/denominator; double angleRad = Math.Atan(ratio); double angleDeg = (angleRad*180)/Math.PI; if(angleDeg<0){ angleDeg = 180+angleDeg; } return angleDeg; } 

下面是一个C#方法,用于从一个圆上的一个点的水平逆时针返回angular度(0-360)。

  public static double GetAngle(Point centre, Point point1) { // Thanks to Dave Hill // Turn into a vector (from the origin) double x = point1.X - centre.X; double y = point1.Y - centre.Y; // Dot product u dot v = mag u * mag v * cos theta // Therefore theta = cos -1 ((u dot v) / (mag u * mag v)) // Horizontal v = (1, 0) // therefore theta = cos -1 (ux / mag u) // nb, there are 2 possible angles and if uy is positive then angle is in first quadrant, negative then second quadrant double magnitude = Math.Sqrt(x * x + y * y); double angle = 0; if(magnitude > 0) angle = Math.Acos(x / magnitude); angle = angle * 180 / Math.PI; if (y < 0) angle = 360 - angle; return angle; } 

干杯,保罗

 function p(x, y) {return {x,y}} function normaliseToInteriorAngle(angle) { if (angle < 0) { angle += (2*Math.PI) } if (angle > Math.PI) { angle = 2*Math.PI - angle } return angle } function angle(p1, center, p2) { const transformedP1 = p(p1.x - center.x, p1.y - center.y) const transformedP2 = p(p2.x - center.x, p2.y - center.y) const angleToP1 = Math.atan2(transformedP1.y, transformedP1.x) const angleToP2 = Math.atan2(transformedP2.y, transformedP2.x) return normaliseToInteriorAngle(angleToP2 - angleToP1) } function toDegrees(radians) { return 360 * radians / (2 * Math.PI) } console.log(toDegrees(angle(p(-10, 0), p(0, 0), p(0, -10)))) 

好吧,其他答案似乎涵盖了一切需要,所以我想只是添加这个,如果你使用JMonkeyEngine:

Vector3f.angleBetween(otherVector)

因为这是我来这里寻找:)

  Atan2 output in degrees PI/2 +90 | | | | PI ---.--- 0 +180 ---.--- 0 | | | | -PI/2 +270 public static double CalculateAngleFromHorizontal(double startX, double startY, double endX, double endY) { var atan = Math.Atan2(endY - startY, endX - startX); // Angle in radians var angleDegrees = atan * (180 / Math.PI); // Angle in degrees (can be +/-) if (angleDegrees < 0.0) { angleDegrees = 360.0 + angleDegrees; } return angleDegrees; } // Angle from point2 to point 3 counter clockwise public static double CalculateAngle0To360(double centerX, double centerY, double x2, double y2, double x3, double y3) { var angle2 = CalculateAngleFromHorizontal(centerX, centerY, x2, y2); var angle3 = CalculateAngleFromHorizontal(centerX, centerY, x3, y3); return (360.0 + angle3 - angle2)%360; } // Smaller angle from point2 to point 3 public static double CalculateAngle0To180(double centerX, double centerY, double x2, double y2, double x3, double y3) { var angle = CalculateAngle0To360(centerX, centerY, x2, y2, x3, y3); if (angle > 180.0) { angle = 360 - angle; } return angle; } 

}