How to calculate an angle from points?

前端 未结 5 1697
天涯浪人
天涯浪人 2020-12-02 22:03

I want to get a simple solution to calculate the angle of a line (like a pointer of a clock).

I have 2 points:

cX, cY - the center of the line.
eX, e         


        
相关标签:
5条回答
  • 2020-12-02 22:44

    If you're using canvas, you'll notice (if you haven't already) that canvas uses clockwise rotation(MDN) and y axis is flipped. To get consistent results, you need to tweak your angle function.

    From time to time, I need to write this function and each time I need to look it up, because I never get to the bottom of the calculation.

    While the suggested solutions work, they don't take the canvas coordinate system into consideration. Examine the following demo:

    Calculate angle from points - JSFiddle

    function angle(originX, originY, targetX, targetY) {
        var dx = originX - targetX;
        var dy = originY - targetY;
    
        // var theta = Math.atan2(dy, dx);  // [0, Ⲡ] then [-Ⲡ, 0]; clockwise; 0° = west
        // theta *= 180 / Math.PI;          // [0, 180] then [-180, 0]; clockwise; 0° = west
        // if (theta < 0) theta += 360;     // [0, 360]; clockwise; 0° = west
    
        // var theta = Math.atan2(-dy, dx); // [0, Ⲡ] then [-Ⲡ, 0]; anticlockwise; 0° = west
        // theta *= 180 / Math.PI;          // [0, 180] then [-180, 0]; anticlockwise; 0° = west
        // if (theta < 0) theta += 360;     // [0, 360]; anticlockwise; 0° = west
    
        // var theta = Math.atan2(dy, -dx); // [0, Ⲡ] then [-Ⲡ, 0]; anticlockwise; 0° = east
        // theta *= 180 / Math.PI;          // [0, 180] then [-180, 0]; anticlockwise; 0° = east
        // if (theta < 0) theta += 360;     // [0, 360]; anticlockwise; 0° = east
    
        var theta = Math.atan2(-dy, -dx); // [0, Ⲡ] then [-Ⲡ, 0]; clockwise; 0° = east
        theta *= 180 / Math.PI;           // [0, 180] then [-180, 0]; clockwise; 0° = east
        if (theta < 0) theta += 360;      // [0, 360]; clockwise; 0° = east
    
        return theta;
    }
    
    0 讨论(0)
  • 2020-12-02 22:48

    You find here two formulas ,one from positive axis x and anticlockwise

    and one from the north and clockwise.

    There is x=x2-x1 and y=y2=y1 .There is E=E2-E1 and N=N2-N1.

    The formulas are working for any value of x,y, E and N.

    For x=y=0 or E=N=0 the result is undefined.

    f(x,y)=pi()-pi()/2*(1+sign(x))*(1-sign(y^2))

         -pi()/4*(2+sign(x))*sign(y)
    
         -sign(x*y)*atan((abs(x)-abs(y))/(abs(x)+abs(y)))
    

    f(E,N)=pi()-pi()/2*(1+sign(N))*(1-sign(E^2))

         -pi()/4*(2+sign(N))*sign(E)
    
         -sign(E*N)*atan((abs(N)-abs(E))/(abs(N)+abs(E)))
    
    0 讨论(0)
  • 2020-12-02 22:53

    You want the arctangent:

    dy = ey - cy
    dx = ex - cx
    theta = arctan(dy/dx)
    theta *= 180/pi // rads to degs
    

    Erm, note that the above is obviously not compiling Javascript code. You'll have to look through documentation for the arctangent function.

    Edit: Using Math.atan2(y,x) will handle all of the special cases and extra logic for you:

    function angle(cx, cy, ex, ey) {
      var dy = ey - cy;
      var dx = ex - cx;
      var theta = Math.atan2(dy, dx); // range (-PI, PI]
      theta *= 180 / Math.PI; // rads to degs, range (-180, 180]
      //if (theta < 0) theta = 360 + theta; // range [0, 360)
      return theta;
    }
    
    0 讨论(0)
  • 2020-12-02 22:57

    One of the issue with getting the angle between two points or any angle is the reference you use.

    In maths we use a trigonometric circle with the origin to the right of the circle (a point in x=radius, y=0) and count the angle counter clockwise from 0 to 2PI.

    In geography the origin is the North at 0 degrees and we go clockwise from to 360 degrees.

    The code below (in C#) gets the angle in radians then converts to a geographic angle:

        public double GetAngle()
        {
            var a = Math.Atan2(YEnd - YStart, XEnd - XStart);
            if (a < 0) a += 2*Math.PI; //angle is now in radians
    
            a -= (Math.PI/2); //shift by 90deg
            //restore value in range 0-2pi instead of -pi/2-3pi/2
            if (a < 0) a += 2*Math.PI;
            if (a < 0) a += 2*Math.PI;
            a = Math.Abs((Math.PI*2) - a); //invert rotation
            a = a*180/Math.PI; //convert to deg
    
            return a;
        }
    
    0 讨论(0)
  • 2020-12-02 22:59

    Runnable version of Christian's answer.

    function angle(cx, cy, ex, ey) {
      var dy = ey - cy;
      var dx = ex - cx;
      var theta = Math.atan2(dy, dx); // range (-PI, PI]
      theta *= 180 / Math.PI; // rads to degs, range (-180, 180]
      return theta;
    }
    function angle360(cx, cy, ex, ey) {
      var theta = angle(cx, cy, ex, ey); // range (-180, 180]
      if (theta < 0) theta = 360 + theta; // range [0, 360)
      return theta;
    }
    
    show("right", 0, 0, 1, 0);
    show("top right", 0, 0, 1, 1);
    show("top", 0, 0, 0, 1);
    show("top left", 0, 0, -1, 1);
    show("left", 0, 0, -1, 0);
    show("bottom left", 0, 0, -1, -1);
    show("bottom", 0, 0, 0, -1);
    show("bottom right", 0, 0, 1, -1);
    
    // IGNORE BELOW HERE (all presentational stuff)
    table {
      border-collapse: collapse;
    }
    table, th, td {
      border: 1px solid black;
      padding: 2px 4px;
    }
    tr > td:not(:first-child) {
      text-align: center;
    }
    tfoot {
      font-style: italic;
    }
    <table>
      <thead>
        <tr><th>Direction*</th><th>Start</th><th>End</th><th>Angle</th><th>Angle 360</th></tr>
      </thead>
      <tfoot>
         <tr><td colspan="5">* Cartesian coordinate system<br>positive x pointing right, and positive y pointing up.</td>
      </tfoot>
      <tbody id="angles">
      </tbody>
    </table>
    <script>
    function show(label, cx, cy, ex, ey) {
      var row = "<tr>";
      row += "<td>" + label + "</td>";
      row += "<td>" + [cx, cy] + "</td>";
      row += "<td>" + [ex, ey] + "</td>";
      row += "<td>" + angle(cx, cy, ex, ey) + "</td>";
      row += "<td>" + angle360(cx, cy, ex, ey) + "</td>";
      row += "</tr>";
      document.getElementById("angles").innerHTML += row;
    }
    </script>

    0 讨论(0)
提交回复
热议问题