首页 文章

如何从三点计算角度? [关闭]

提问于
浏览
120

让我们说你有这个:

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

假设 P1 是圆的中心点 . 它总是一样的 . 我想要由 P2P3 组成的角度,或者换句话说是 P1 旁边的角度 . 内角是精确的 . 它总是一个锐角,所以小于-90度 .

我想:伙计,这是简单的几何数学 . 但我现在已经找了一个大约6个小时的公式,并且只找到人们谈论复杂的美国宇航局的东西,如arccos和矢量标量产品 . 我的头感觉像在冰箱里 .

一些数学大师认为这是一个简单的问题吗?我不认为编程语言在这里很重要,但对于那些认为它的人来说:java和objective-c . 我需要它,但没有标记它们 .

16 回答

  • 4

    如果你的意思是P1是顶点的角度那么使用Law of Cosines应该工作:

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

    其中P12是从P1到P2的段的长度,由...计算

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

  • 12

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

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

    然后,您可以反转点积公式:

    dot product

    获得角度:

    angle between two vectors

    请记住
    dot product
    只是意味着:a1 * b1 a2 * b2(这里只有2个尺寸......)

  • 87

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

    鉴于计算是

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

    即你基本上将两个点翻译为 -P1 (换句话说,你翻译所有内容,以便 P1 在原点结束),然后你考虑 P3P2 的绝对角度的差异 .

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

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

  • 25

    让我举一个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(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));
    }
    

    额外奖励:Example with HTML5-canvas

  • 0

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

    看看here有一个很好的解释和公式 .

    alt text

  • 2

    如果你认为P1是圆圈的中心,你会觉得太复杂了 . 你有一个简单的三角形,所以law of cosines可以解决你的问题 . 不需要任何极坐标变换或某些 . 假设距离为P1-P2 = A,P2-P3 = B且P3-P1 = C:

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

    您需要做的就是计算距离A,B和C的长度 . 您可以从点的x坐标和y坐标轻松获得这些距离.Pythagoras' theorem

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

  • 7

    我最近遇到了类似的问题,只是我需要区分正角度和负角度 . 如果这对任何人都有用,我建议我从this mailing list获取有关检测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  = a-b;
           this.bearing -= Math.toDegrees(diff);
           this.invalidate();
        }
        mPreviousX = x;
        mPreviousY = y;
        return true;
     }
    
  • -1

    带解释的非常简单的几何解法

    几天前,一个人遇到了同样的问题,不得不坐在数学书上 . 我通过组合和简化一些基本公式解决了这个问题 .


    让我们考虑这个数字 -

    angle

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

    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)
    

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

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

    在eqn-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)) )
    

    这就对了!


    现在,采取以下数字 -

    angle

    这个C#或Java方法计算角度(Θ) -

    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;
        }
    
  • 2

    在Objective-C中你可以做到这一点

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

    或者阅读更多here

  • -2

    你提到过有角度的角度(-90) . 在许多应用中,角度可能有迹象(正面和负面,见http://en.wikipedia.org/wiki/Angle) . 如果这些点是(例如)P2(1,0),P1(0,0),P3(0,1)那么角度P3-P1-P2通常是正的(PI / 2),而角度P2-P1- P3是否定的 . 使用边长不会区分和 - 所以如果这很重要,你将需要使用向量或函数,如Math.atan2(a,b) .

    角度也可以超过2 * PI,虽然这与当前的问题无关,但是我编写自己的Angle类非常重要(同时也要确保度和弧度不会混淆) . 关于angle1是否小于角度2的问题关键取决于如何定义角度 . 确定一行(-1,0)(0,0)(1,0)是否表示为Math.PI或-Math.PI也很重要 .

  • 47

    my angle demo program

    最近,我也有同样的问题...在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;
    
  • 15

    这是一个C#方法,可以从一个圆上的点水平方向逆时针返回角度(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 (u.x / mag u)
            // nb, there are 2 possible angles and if u.y 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;
        }
    

    干杯,保罗

  • 19
    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))))
    
  • 8

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

    假设你有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)

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

    我刚刚在我最近的项目中使用了这个代码,将B更改为P1 ..如果你想要你也可以删除“180”

  • 6

    好吧,其他答案似乎涵盖了所需的一切,所以如果您使用的是JMonkeyEngine,我想添加它:

    Vector3f.angleBetween(otherVector)

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

  • 4
    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;
    }
    

    }

相关问题