Geometría básica
En este artículo consideraremos las operaciones básicas sobre puntos en el espacio euclidiano, que constituyen el fundamento de toda la geometría analítica. Para cada punto consideraremos el vector dirigido de a . Más adelante no distinguiremos entre y y usaremos el término punto como sinónimo de vector.
Operaciones lineales
Tanto los puntos 2D como los 3D forman un espacio lineal, lo que significa que para ellos están definidas la suma de puntos y la multiplicación de un punto por un número. Aquí están esas implementaciones básicas para 2D:
struct point2d {
ftype x, y;
point2d() {}
point2d(ftype x, ftype y): x(x), y(y) {}
point2d& operator+=(const point2d &t) {
x += t.x;
y += t.y;
return *this;
}
point2d& operator-=(const point2d &t) {
x -= t.x;
y -= t.y;
return *this;
}
point2d& operator*=(ftype t) {
x *= t;
y *= t;
return *this;
}
point2d& operator/=(ftype t) {
x /= t;
y /= t;
return *this;
}
point2d operator+(const point2d &t) const {
return point2d(*this) += t;
}
point2d operator-(const point2d &t) const {
return point2d(*this) -= t;
}
point2d operator*(ftype t) const {
return point2d(*this) *= t;
}
point2d operator/(ftype t) const {
return point2d(*this) /= t;
}
};
point2d operator*(ftype a, point2d b) {
return b * a;
}Y los puntos 3D:
struct point3d {
ftype x, y, z;
point3d() {}
point3d(ftype x, ftype y, ftype z): x(x), y(y), z(z) {}
point3d& operator+=(const point3d &t) {
x += t.x;
y += t.y;
z += t.z;
return *this;
}
point3d& operator-=(const point3d &t) {
x -= t.x;
y -= t.y;
z -= t.z;
return *this;
}
point3d& operator*=(ftype t) {
x *= t;
y *= t;
z *= t;
return *this;
}
point3d& operator/=(ftype t) {
x /= t;
y /= t;
z /= t;
return *this;
}
point3d operator+(const point3d &t) const {
return point3d(*this) += t;
}
point3d operator-(const point3d &t) const {
return point3d(*this) -= t;
}
point3d operator*(ftype t) const {
return point3d(*this) *= t;
}
point3d operator/(ftype t) const {
return point3d(*this) /= t;
}
};
point3d operator*(ftype a, point3d b) {
return b * a;
}Aquí ftype es algún tipo usado para las coordenadas, habitualmente int, double o long long.
Producto punto
Definición
El producto punto (o escalar) de los vectores y se puede definir de dos maneras equivalentes. Geométricamente es el producto de la longitud del primer vector por la longitud de la proyección del segundo vector sobre el primero. Como se puede ver en la imagen de abajo, esta proyección no es otra cosa que , donde es el ángulo entre y . Así, .
El producto punto tiene algunas propiedades notables:
Es decir, es una función conmutativa que es lineal respecto de ambos argumentos. Denotemos los vectores unitarios como
, \mathbf e_y = , \mathbf e_z = .
Con esta notación podemos escribir el vector como . Y como para los vectores unitarios
vemos que, en términos de coordenadas, para y se cumple
Esa es también la definición algebraica del producto punto. A partir de esto podemos escribir funciones que lo calculen.
ftype dot(point2d a, point2d b) {
return a.x * b.x + a.y * b.y;
}
ftype dot(point3d a, point3d b) {
return a.x * b.x + a.y * b.y + a.z * b.z;
}Al resolver problemas se debe usar la definición algebraica para calcular productos punto, pero conviene tener presente la definición geométrica y las propiedades para aplicarlas.
Propiedades
Podemos definir muchas propiedades geométricas mediante el producto punto. Por ejemplo
- Norma de (longitud al cuadrado):
- Longitud de :
- Proyección de sobre :
- Ángulo entre vectores:
- Del punto anterior se ve que el producto punto es positivo si el ángulo entre ellos es agudo, negativo si es obtuso e igual a cero si son ortogonales, es decir, si forman un ángulo recto.
Nótese que todas estas funciones no dependen del número de dimensiones, de modo que serán las mismas en el caso 2D y en el 3D:
ftype norm(point2d a) {
return dot(a, a);
}
double abs(point2d a) {
return sqrt(norm(a));
}
double proj(point2d a, point2d b) {
return dot(a, b) / abs(b);
}
double angle(point2d a, point2d b) {
return acos(dot(a, b) / abs(a) / abs(b));
}Para ver la siguiente propiedad importante debemos mirar el conjunto de puntos para los cuales para alguna constante fija . Se puede ver que este conjunto de puntos es exactamente el conjunto de puntos para los cuales la proyección sobre es el punto y forman un hiperplano ortogonal a . En la figura de abajo se puede ver el vector junto con varios de esos vectores que tienen el mismo producto punto con él, en 2D:
En 2D estos vectores formarán una recta; en 3D formarán un plano. Nótese que este resultado nos permite definir una recta en 2D como o , donde es un vector ortogonal a la recta, es cualquier vector que ya esté sobre la recta y . De la misma manera se puede definir un plano en 3D.
Producto cruz
Definición
Supongamos que tenemos tres vectores , y en el espacio 3D unidos en un paralelepípedo como en la imagen de abajo:
¿Cómo calcularíamos su volumen? De la escuela sabemos que hay que multiplicar el área de la base por la altura, que es la proyección de sobre la dirección ortogonal a la base. Eso significa que si definimos como el vector ortogonal tanto a como a y cuya longitud es igual al área del paralelogramo formado por y , entonces será igual al volumen del paralelepípedo. Por consistencia diremos que estará siempre dirigido de modo que la rotación del vector hacia el vector , vista desde el punto de , sea siempre antihoraria (véase la imagen de abajo).
Esto define el producto cruz (o vectorial) de los vectores y y el producto mixto de los vectores , y .
Algunas propiedades notables de los productos cruz y mixto:
-
-
-
Para cualquier y existe exactamente un vector tal que para cualquier vector .
En efecto, si hubiera dos de esos vectores y entonces para todos los vectores , lo cual solo es posible cuando . -
-
. En efecto, para todos los vectores se cumple la cadena de igualdades:
Lo que demuestra por el punto 3.
-
donde es el ángulo entre y , ya que es igual al área del paralelogramo formado por y .
Dado todo esto y que para los vectores unitarios se cumple la siguiente ecuación
podemos calcular el producto cruz de y en forma coordenada:
Lo cual también se puede escribir de forma más elegante:
,~a\cdot(b\times c) =
Aquí denota el determinante de una matriz.
Alguna forma de producto cruz (concretamente el producto seudoescalar) también se puede implementar en el caso 2D. Si quisiéramos calcular el área del paralelogramo formado por los vectores y computaríamos . Otra forma de obtener el mismo resultado es multiplicar (base del paralelogramo) por la altura, que es la proyección del vector sobre el vector rotado , que a su vez es . Es decir, calcular .
Si tenemos en cuenta el signo, el área será positiva si la rotación de a (es decir, desde el punto de vista de ) se realiza en sentido antihorario y negativa en caso contrario. Eso define el producto seudoescalar. Nótese que también es igual a , donde es el ángulo de a contado en sentido antihorario (y negativo si la rotación es horaria).
¡Implementemos todo esto!
point3d cross(point3d a, point3d b) {
return point3d(a.y * b.z - a.z * b.y,
a.z * b.x - a.x * b.z,
a.x * b.y - a.y * b.x);
}
ftype triple(point3d a, point3d b, point3d c) {
return dot(a, cross(b, c));
}
ftype cross(point2d a, point2d b) {
return a.x * b.y - a.y * b.x;
}Propiedades
En cuanto al producto cruz, es igual al vector cero si y solo si los vectores y son colineales (forman una recta común, es decir, son paralelos). Lo mismo vale para el producto mixto: es igual a cero si y solo si los vectores , y son coplanares (forman un plano común).
De esto podemos obtener ecuaciones universales que definen rectas y planos. Una recta se puede definir mediante su vector director y un punto inicial , o por dos puntos y . Se define como o como . En cuanto a los planos, se pueden definir por tres puntos , y como o por un punto inicial y dos vectores directores que yacen en ese plano y : .
En 2D el producto seudoescalar también puede usarse para comprobar la orientación entre dos vectores, porque es positivo si la rotación del primero al segundo es antihoraria y negativo en caso contrario. Y, por supuesto, puede usarse para calcular áreas de polígonos, lo cual se describe en otro artículo. El producto mixto puede usarse para el mismo propósito en el espacio 3D.
Ejercicios
Intersección de rectas
Hay muchas formas posibles de definir una recta en 2D y no hay que dudar en combinarlas. Por ejemplo, tenemos dos rectas y queremos encontrar sus puntos de intersección. Podemos decir que todos los puntos de la primera recta se pueden parametrizar como , donde es el punto inicial, es la dirección y es algún parámetro real. En cuanto a la segunda recta, todos sus puntos deben satisfacer . De esto podemos hallar fácilmente el parámetro :
Implementemos una función para intersectar dos rectas.
point2d intersect(point2d a1, point2d d1, point2d a2, point2d d2) {
return a1 + cross(a2 - a1, d2) / cross(d1, d2) * d1;
}Intersección de planos
Sin embargo, a veces puede ser difícil usar intuiciones geométricas. Por ejemplo, se dan tres planos definidos por puntos iniciales y direcciones y se quiere encontrar su punto de intersección. Se puede notar que basta con resolver el sistema de ecuaciones:
En lugar de pensar en un enfoque geométrico, se puede elaborar uno algebraico que se obtiene de inmediato. Por ejemplo, dado que ya implementaste una clase de punto, te será fácil resolver este sistema usando la regla de Cramer, porque el producto mixto es simplemente el determinante de la matriz obtenida a partir de los vectores como columnas:
point3d intersect(point3d a1, point3d n1, point3d a2, point3d n2, point3d a3, point3d n3) {
point3d x(n1.x, n2.x, n3.x);
point3d y(n1.y, n2.y, n3.y);
point3d z(n1.z, n2.z, n3.z);
point3d d(dot(a1, n1), dot(a2, n2), dot(a3, n3));
return point3d(triple(d, y, z),
triple(x, d, z),
triple(x, y, d)) / triple(n1, n2, n3);
}Ahora puedes intentar encontrar por tu cuenta enfoques para las operaciones geométricas habituales, para acostumbrarte a todo esto.