HOWTO · C++
Calcular el ángulo entre dos vectores en C++
Este tutorial demuestra el proceso de calcular un ángulo entre dos vectores en C++.
En esta página
Usa el producto escalar para calcular el ángulo principal entre dos vectores de la misma dimensión. Para los vectores u y v, la fórmula es theta = acos((u · v) / (|u| * |v|)). En C++, calcula el producto escalar y la magnitud de cada vector, limita el valor del coseno al intervalo [-1, 1] para tener en cuenta los errores de redondeo de punto flotante y pásalo a std::acos. El resultado está en radianes; multiplícalo por 180 / pi si necesitas grados.
Entender el producto escalar y la fórmula del ángulo
Un vector es un conjunto ordenado de componentes, como (x, y) o (x, y, z). Su magnitud es su longitud, calculada como la raíz cuadrada de la suma de sus componentes al cuadrado. El producto escalar de dos vectores es la suma de los productos de sus componentes correspondientes. Por ejemplo, u · v es u[0] * v[0] + u[1] * v[1] + ....
El coseno del ángulo se obtiene al dividir el producto escalar por el producto de las dos magnitudes. Al aplicar el coseno inverso (acos), se obtiene el ángulo principal sin orientación, entre 0 y 180 grados (o entre 0 y pi radianes). Esta fórmula sirve en 2D, 3D y dimensiones superiores, siempre que ambos vectores tengan el mismo número de componentes. No indica una orientación, como el sentido horario o antihorario.
Calcular el ángulo con un array de C++
Este ejemplo completo usa dos arrays integrados con la misma longitud declarada. La función devuelve false si alguna de las dos magnitudes es cero, ya que el ángulo con un vector cero no está definido. De lo contrario, calcula el coseno, lo limita a su intervalo matemático válido e imprime el resultado en grados.
Ejecuta este ejemplo:
#include <algorithm>
#include <cmath>
#include <iomanip>
#include <iostream>
bool calculateAngleDegrees(const double u[], const double v[], int size,
double& angleDegrees) {
double dot = 0.0;
double squaredU = 0.0;
double squaredV = 0.0;
for (int i = 0; i < size; ++i) {
dot += u[i] * v[i];
squaredU += u[i] * u[i];
squaredV += v[i] * v[i];
}
if (squaredU == 0.0 || squaredV == 0.0) {
return false;
}
double cosine = dot / std::sqrt(squaredU * squaredV);
cosine = std::max(-1.0, std::min(1.0, cosine));
const double pi = std::acos(-1.0);
angleDegrees = std::acos(cosine) * 180.0 / pi;
return true;
}
int main() {
const int size = 3;
const double u[size] = {1.0, 0.0, 0.0};
const double v[size] = {0.0, 1.0, 0.0};
double angleDegrees = 0.0;
if (calculateAngleDegrees(u, v, size, angleDegrees)) {
std::cout << std::fixed << std::setprecision(1)
<< "Angle: " << angleDegrees << " degrees\n";
} else {
std::cout << "An angle requires two nonzero vectors.\n";
}
}
Los dos vectores de ejemplo son perpendiculares, por lo que el ángulo calculado es de 90 grados.
Calcular el ángulo con std::array
std::array representa una secuencia de tamaño fijo e incluye el número de elementos en su tipo. Esta versión requiere C++11 o posterior y obtiene el número de componentes del tipo del array, de modo que ambas entradas tienen el mismo número de componentes. El cálculo y el tratamiento de los vectores cero son iguales que en la versión con arrays integrados.
#include <algorithm>
#include <array>
#include <cmath>
#include <iomanip>
#include <iostream>
bool calculateAngleDegrees(const std::array<double, 3>& u,
const std::array<double, 3>& v,
double& angleDegrees) {
double dot = 0.0;
double squaredU = 0.0;
double squaredV = 0.0;
for (std::size_t i = 0; i < u.size(); ++i) {
dot += u[i] * v[i];
squaredU += u[i] * u[i];
squaredV += v[i] * v[i];
}
if (squaredU == 0.0 || squaredV == 0.0) {
return false;
}
double cosine = dot / std::sqrt(squaredU * squaredV);
cosine = std::max(-1.0, std::min(1.0, cosine));
const double pi = std::acos(-1.0);
angleDegrees = std::acos(cosine) * 180.0 / pi;
return true;
}
int main() {
const std::array<double, 3> u = {1.0, 0.0, 0.0};
const std::array<double, 3> v = {0.0, 1.0, 0.0};
double angleDegrees = 0.0;
if (calculateAngleDegrees(u, v, angleDegrees)) {
std::cout << std::fixed << std::setprecision(1)
<< "Angle: " << angleDegrees << " degrees\n";
} else {
std::cout << "An angle requires two nonzero vectors.\n";
}
}
Usa std::array<double, N> cuando la dimensión sea fija y se conozca en tiempo de compilación. No hace que el cálculo sea intrínsecamente más eficiente; su principal ventaja aquí es que el tamaño forma parte del tipo y se puede consultar con .size().
Gestionar vectores cero, dimensiones y ángulos con signo
El ángulo no está definido si alguno de los vectores tiene magnitud cero. Compruébalo antes de dividir por el producto de las magnitudes, tal como hacen los ejemplos. Con arrays integrados, indica la longitud compartida real y asegúrate de que ambos arrays contengan al menos esa cantidad de elementos. Con std::array, usar el mismo N en ambos tipos garantiza que las dimensiones coincidan.
La fórmula del producto escalar da un ángulo principal sin orientación. En 2D, se puede calcular un ángulo orientado con atan2(cross, dot), donde el producto vectorial escalar es u.x * v.y - u.y * v.x. En 3D, la fórmula del ángulo con signo atan2(n · (u × v), u · v) mide el ángulo orientado en el plano perpendicular a una normal unitaria elegida n, siempre que ambos vectores estén en ese plano. Si alguno queda fuera del plano deseado, proyecta primero ambos vectores sobre él y aplica la fórmula a las proyecciones; así se mide el ángulo entre los vectores proyectados. La normal define el sentido positivo; no se añade a la fórmula del producto escalar. Estos métodos de ángulo con signo devuelven radianes, que se pueden convertir a grados con el mismo factor indicado antes.
Preguntas frecuentes
¿Qué me dice el producto escalar? Combina las componentes correspondientes en un escalar. En relación con las magnitudes, su valor determina el coseno del ángulo: es positivo para un ángulo principal agudo, cero para vectores perpendiculares y negativo para un ángulo principal obtuso.
¿std::acos devuelve grados? No. Devuelve radianes. Convierte los radianes a grados multiplicándolos por 180 / pi; también puedes conservar los radianes si el resto del programa trabaja con esa unidad.
¿Los vectores pueden tener dimensiones distintas? No. El producto escalar empareja las componentes correspondientes, así que los vectores deben tener la misma dimensión. Con arrays integrados, usa una única longitud compartida correcta. std::array muestra el tamaño en su tipo.
¿Puedo usar la fórmula en 3D? Sí. La fórmula del producto escalar y la magnitud se aplica a vectores de cualquier dimensión, incluidos los de 3D. Recurre a un cálculo de ángulo con signo y una normal de referencia solo cuando importe la orientación.
¿Debería usar una biblioteca de matemáticas vectoriales? Para un cálculo pequeño, los ejemplos anteriores son suficientes. Una biblioteca como Eigen o GLM puede ser útil si el proyecto ya usa sus tipos de vectores y matrices o necesita más operaciones.