2012-03-08 19 views
32

Quiero obtener una solución simple para calcular el ángulo de una línea (como un puntero de un reloj).¿Cómo calcular un ángulo desde puntos?

tengo 2 puntos:

cX, cY - the center of the line. 
eX, eY - the end of the line. 

The result is angle (0 <= a < 360). 

cuya función es capaz de proporcionar este valor?

+0

Necesita al menos tres puntos para calcular un ángulo. ¿Cuál es usted tercero? ¿El eje x o el eje y? – Sirko

+2

Suponiendo el eje x –

+0

línea de 2 dimensiones. – durumdara

Respuesta

72

desea que el arco tangente:

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

Em, tenga en cuenta que el código Javascript anterior, obviamente, no está compilando. Deberá consultar la documentación de la función arctangent.

Editar: Usando Math.atan2(y,x) se encargará de todas las especialidades y la lógica adicional para usted:

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; 
} 
+5

Hombre, me encantó la trigonometría. – Purag

+5

Tenga en cuenta que para evitar la división por 0, debe probar si 'dx == 0' primero; si es así, entonces regrese 90 grados si 'dy> 0' y 270 grados si' dy <0'. –

+0

@EtiennePerot: Recordé otra función útil y actualicé mi respuesta para usarla en su lugar. –

8

versión Ejecutable de 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

Uno de los problema con conseguir el ángulo entre dos puntos o cualquier ángulo es la referencia que utiliza.

En matemáticas utilizamos un círculo trigonométrico con el origen a la derecha del círculo (un punto en x = radio, y = 0) y contamos el ángulo en sentido contrario a las agujas del reloj de 0 a 2PI.

En geografía, el origen es el norte a 0 grados y vamos en sentido horario desde 360 ​​grados.

El código de abajo (en C#) obtiene el ángulo en radianes entonces se convierte en un ángulo geográfica:

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

Si está utilizando la lona, ​​se dará cuenta (si no lo ha hecho) que lienzo utiliza rotación en el sentido de las agujas del reloj (MDN) y y eje se voltea. Para obtener resultados consistentes, debe modificar su función angle.

De vez en cuando, necesito escribir esta función y cada vez que necesito buscarla, porque nunca llego al final del cálculo.

Si bien las soluciones sugeridas funcionan, no tienen en cuenta el sistema de coordenadas del lienzo. Examine la siguiente demostración:

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; 
} 
Cuestiones relacionadas