关于算法:如何从三个点计算角度?

您所在的位置:网站首页 arccos计算角度公式 关于算法:如何从三个点计算角度?

关于算法:如何从三个点计算角度?

2024-01-05 04:27| 来源: 网络整理| 查看: 265

可以说你有这个:

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

假设P1是圆的中心点。 总是一样的。 我想要由P2和P3组成的角度,换句话说,就是紧挨着P1的角度。 内角要精确。 它始终是锐角,因此小于-90度。

我以为:天哪,这是简单的几何数学。 但是我现在已经寻找了大约6个小时的公式,却只发现人们谈论复杂的NASA东西,例如arccos和矢量标量产品。 我的头好像在冰箱里。

这里的一些数学大师认为这是一个简单的问题? 我认为这里的编程语言并不重要,但是对于那些认为确实重要的人来说:java和Objective-c。 我都需要它,但是还没有为它们加标签。

如果您的意思是P1是顶点的角度,那么使用余弦定律应该可以:

arccos((P122 + P132 - P232) / (2 * P12 * P13))

其中P 12 sub>是从P1到P2的段的长度,计算公式为

sqrt((P1x - P2x)2 + (P1y - P2y)2)

相关讨论 mathwords.com/c/cosine_inverse.htm @Rafa Firenze cos ^ -1是acos的常用符号,但是acos不太明确。 zh.wikipedia.org/wiki/Inverse_trigonometric_functions 糟糕的是,由于编辑不会损害任何内容,因此cos ^ -1当然是最常见的表示法,但它具有Math / CS / EE学位。 只有少数几种语言使用尖号来表示符号的力量,因此,如果您不想将其称为arcos,请输入cos?。 (如果您使用的是难以输入指数的商业操作系统,那么我希望可以购买一些键帽应用程序,或者可以安装浏览器插件。或者可以进行网络搜索以及复制和粘贴。) @MichaelScheper,我只在HTML受限的注释中使用了插入符号。我肯定会在任何实际答案中使用子/上标表示法。 其arccos,而不是arcos @L?uV?nhPhc,是的,您说对了,就是上次编辑之前的那种方式。固定。 值得一提的是,该公式源自"余弦法则"。所以人们不认为这是在做魔术:) 它有效,但是如何找到角度的符号? 检查下面的atan2解决方案。

如果您将其视为两个向量,一个从点P1到P2,另一个从P1到P3,则它变得非常简单。

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

然后,您可以反转点积公式: 得到角度:

请记住,仅表示: a1 * b1 + a2 * b2(此处只有2个尺寸...)

相关讨论 什么是| x |再次? 向量的幅度 检查atan2解决方案。

处理角度计算的最佳方法是使用atan2(y, x),即给定点x, y返回该点和X+轴相对于原点的角度。

鉴于计算是

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

也就是说,您基本上用-P1来平移两个点(换句话说,您平移了所有东西以使P1以原点结束),然后考虑了P3和P2的绝对角度之差。

atan2的优点是可以表示一个完整的圆(您可以在-π和π之间获得任何数字),而使用acos则需要根据符号处理几种情况以计算出正确的结果。

atan2的唯一奇异点是(0, 0) ...,这意味着P2和P3都必须与P1不同,因为在这种情况下谈论角度是没有意义的。

相关讨论 感谢您的回答。那正是我想要的。简单的解决方案,如果我在数值为负时仅添加2pi,则可以轻松获得逆时针角度。 @marcpt:atan2正是解决此问题的必要条件,但是看起来大多数人都无法理解或理解基于acos的解决方案不好的原因。对我来说幸运的是,很多年前,我离开了"互联网上有人错"(xkcd.com/386)阶段,而我不会为捍卫显而易见的斗争而奋斗:-) 感谢您指出这一点,但是您能以这种方式处理3D吗? @nicoco:在三个维度上如何定义角度?更具体地说,角度可以是负数还是大于pi(180度)? 3d中的两个非平行向量定义了一个平面,但是可以从两侧"看到"该平面:从一侧看,A会出现在B的"左侧",而从另一侧来看会出现在"右侧"。 。 @ 6505感谢您的回答,我在认真思考之前就发布了。我现在知道了。

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

12345678910111213141516/**  * 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(c.x-p0.x,2)+                         Math.pow(c.y-p0.y,2)); // p0->c (b)       var p1c = Math.sqrt(Math.pow(c.x-p1.x,2)+                         Math.pow(c.y-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)); }

奖励:HTML5画布示例

相关讨论 您可以通过减少sqrt和平方来提高效率。在这里(用Ruby编写)或在此更新的演示版(JavaScript)中查看我的答案。 您可以使用atan2作为更简单的解决方案。

基本上,您有两个向量,一个向量从P1到P2,另一个向量从P1到P3。因此,您只需要一个公式即可计算两个向量之间的角度。

在这里查看良好的解释和公式。

如果您认为P1是圆心,则您认为太复杂了。 您有一个简单的三角形,因此您的问题可以通过余弦定律解决。无需任何极坐标转换或类似方法。假设距离为P1-P2 = A,P2-P3 = B和P3-P1 = C:

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

您需要做的就是计算距离A,B和C的长度。 这些可以从您的点的x和y坐标轻松获得, 毕达哥拉斯定理

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

相关讨论 我有点困惑如何实际将其作为您将P1等视为单个值而不是(x,y)来实现 @Dominic Tobias:符号P1-P2 = A不应理解为"要计算A,从P1中减去P2",而应理解为"我将A定义为从P1到P2的距离",然后可以使用第二个公式计算。我只是想为距离定义一个简写,以使方程更易读。

最近我遇到了类似的问题,只需要区分正角和负角即可。如果这对任何人都有用,我建议我从此邮件列表中获取有关检测Android触摸事件上的旋转的代码段:

123456789101112131415161718192021222324 @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  = a-b;        this.bearing -= Math.toDegrees(diff);        this.invalidate();     }     mPreviousX = x;     mPreviousY = y;     return true;  } 带解释的非常简单的几何解

几天前,一个人陷入了同样的问题,不得不坐在那本数学书上。我通过合并和简化一些基本公式解决了这个问题。 sub>

让我们考虑这个数字-

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

1y = m * x + c

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

123456oy = 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-行

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

现在,我们需要? = β - α。在三角函数中,我们有一个公式

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

在替换eqn-4中的tan α(来自eqn-2)和tan b(来自eqn-3)并进行简化后,我们得到-

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

所以,

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

这就对了!

现在,拿下图-

此C#或Java方法计算角度(?)-

12345678910111213141516    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)             angle = Math.Acos(x / magnitude);         angle = angle * 180 / Math.PI;         if (y < 0)             angle = 360 - angle;         return angle;     }

干杯, 保罗

123456789101112131415161718192021222324252627function 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))))

使用高中数学有一个简单的答案。

假设您有3分

获取从A点到B点的角度

angle = atan2(A.x - B.x, B.y - A.y)

获得从B点到C的角度

angle2 = atan2(B.x - C.x, C.y - B.y)

123456Answer = 180 + angle2 - angle If (answer < 0){     return answer + 360 }else{     return answer }

我只是在最近制作的项目中使用了此代码,将B更改为P1。如果您愿意,也可以删除" 180 +"

好吧,其他答案似乎涵盖了所有必需的内容,因此,如果您使用的是JMonkeyEngine,我想仅添加以下内容:

Vector3f.angleBetween(otherVector)

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

1234567891011121314151617181920212223242526272829303132333435363738      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; }

}



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3