32. Producto vectorial

El producto vectorial de dos vectores tridimensionales produce un nuevo vector perpendicular a ambos. Su dirección sigue la regla de la mano derecha y su magnitud mide un área.

32.1 Introducción

El producto escalar produce un número que mide alineación. El producto vectorial, también llamado producto cruz, produce un vector con una propiedad diferente: es perpendicular a los dos vectores originales.

Esta operación es fundamental para calcular normales, orientaciones, áreas y efectos de rotación en gráficos, física y geometría computacional.

u × v es un vector perpendicular a u y a v.

32.2 Definición en ℝ3

El producto vectorial usual estudiado en este curso toma dos vectores de ℝ3 y devuelve otro vector de ℝ3:

× : ℝ3 × ℝ3 ⟶ ℝ3

Su resultado queda determinado por tres elementos:

  • Es perpendicular a ambos operandos.
  • Su magnitud depende del ángulo entre ellos.
  • Su sentido sigue la regla de la mano derecha.

32.3 Fórmula por componentes

Sean u = (ux, uy, uz) y v = (vx, vy, vz):

u × v = (
  uyvz − uzvy,
  uzvx − uxvz,
  uxvy − uyvx
)
function productoVectorial(u, v) {
  return [
    u[1] * v[2] - u[2] * v[1],
    u[2] * v[0] - u[0] * v[2],
    u[0] * v[1] - u[1] * v[0]
  ];
}

console.log(productoVectorial([1, 2, 3], [4, 5, 6])); // [-3, 6, -3]

32.4 Relación con un determinante

La fórmula puede recordarse mediante un determinante formal:

u × v = det([[i, j, k], [ux, uy, uz], [vx, vy, vz]])

Al expandir por la primera fila se obtiene:

i(uyvz − uzvy) − j(uxvz − uzvx) + k(uxvy − uyvx)

El signo negativo del término asociado a j es una fuente frecuente de errores.

32.5 Productos de los vectores canónicos

La orientación positiva de los ejes cumple:

i × j = k,   j × k = i,   k × i = j

Invertir el orden cambia el signo:

j × i = −k,   k × j = −i,   i × k = −j
const cruz = (u, v) => [
  u[1] * v[2] - u[2] * v[1],
  u[2] * v[0] - u[0] * v[2],
  u[0] * v[1] - u[1] * v[0]
];

const i = [1, 0, 0];
const j = [0, 1, 0];
console.log(cruz(i, j)); // [0, 0, 1]
console.log(cruz(j, i)); // [0, 0, -1]

32.6 Regla de la mano derecha

Para determinar el sentido de u × v, se orientan los dedos de la mano derecha desde u hacia v por el giro más corto. El pulgar extendido señala la dirección del producto.

El orden es esencial. Al intercambiar los operandos, el sentido se invierte:

v × u = −(u × v)
const u = [1, 2, 3];
const v = [4, 5, 6];
const cruz = (a, b) => [
  a[1] * b[2] - a[2] * b[1],
  a[2] * b[0] - a[0] * b[2],
  a[0] * b[1] - a[1] * b[0]
];

console.log(cruz(u, v)); // [-3, 6, -3]
console.log(cruz(v, u)); // [3, -6, 3]

32.7 Ejemplo paso a paso

Sean u = (1, 2, 3) y v = (4, 5, 6):

componente x: 2 · 6 − 3 · 5 = −3
componente y: 3 · 4 − 1 · 6 = 6
componente z: 1 · 5 − 2 · 4 = −3

u × v = (−3, 6, −3)

El resultado no depende de un dibujo: se obtiene directamente de las componentes.

32.8 Verificar la perpendicularidad

Si w = u × v, entonces sus productos escalares con u y v son cero:

u · w = 0 y v · w = 0
const u = [1, 2, 3];
const v = [4, 5, 6];
const w = [-3, 6, -3];
const dot = (a, b) => a.reduce((suma, valor, i) => suma + valor * b[i], 0);

console.log(dot(u, w)); // 0
console.log(dot(v, w)); // 0

32.9 Magnitud del producto vectorial

Si θ es el ángulo entre u y v:

||u × v|| = ||u|| ||v|| sen θ

La magnitud es máxima cuando los vectores son perpendiculares y cero cuando son paralelos o alguno es nulo.

const cruz = (u, v) => [
  u[1] * v[2] - u[2] * v[1],
  u[2] * v[0] - u[0] * v[2],
  u[0] * v[1] - u[1] * v[0]
];

const resultado = cruz([3, 0, 0], [0, 4, 0]);
console.log(resultado);               // [0, 0, 12]
console.log(Math.hypot(...resultado)); // 12

32.10 Área de un paralelogramo y un triángulo

La magnitud ||u × v|| es el área del paralelogramo construido sobre u y v. La mitad corresponde al triángulo formado por esos lados.

áreaParalelogramo = ||u × v||
áreaTriángulo = ||u × v|| / 2
function areaTriangulo(A, B, C) {
  const u = B.map((valor, i) => valor - A[i]);
  const v = C.map((valor, i) => valor - A[i]);
  const cruz = [
    u[1] * v[2] - u[2] * v[1],
    u[2] * v[0] - u[0] * v[2],
    u[0] * v[1] - u[1] * v[0]
  ];
  return Math.hypot(...cruz) / 2;
}

console.log(areaTriangulo([0, 0, 0], [4, 0, 0], [0, 3, 0])); // 6

32.11 Vectores paralelos y puntos colineales

Dos vectores no nulos son paralelos cuando su producto vectorial es el vector cero. Del mismo modo, tres puntos A, B y C son colineales si (B − A) × (C − A) es cero.

function sonParalelos(u, v, tolerancia = 1e-10) {
  const cruz = [
    u[1] * v[2] - u[2] * v[1],
    u[2] * v[0] - u[0] * v[2],
    u[0] * v[1] - u[1] * v[0]
  ];
  return Math.hypot(...cruz) <= tolerancia;
}

console.log(sonParalelos([1, 2, 3], [2, 4, 6])); // true

En código numérico conviene usar una tolerancia relativa a las magnitudes de los vectores.

32.12 Propiedades algebraicas

PropiedadExpresión
Anticonmutativau × v = −(v × u)
Distributivau × (v + w) = u × v + u × w
Compatibilidad escalar(ku) × v = k(u × v)
Producto consigo mismou × u = 0
No asociativaEn general, (u × v) × w ≠ u × (v × w)

El producto vectorial no es conmutativo ni asociativo; el orden y los paréntesis importan.

32.13 Normal de un triángulo

Dados los vértices A, B y C, una normal de la superficie se obtiene con (B − A) × (C − A). Al normalizarla se conserva únicamente su dirección.

function normalTriangulo(A, B, C, tolerancia = 1e-12) {
  const u = B.map((valor, i) => valor - A[i]);
  const v = C.map((valor, i) => valor - A[i]);
  const n = [
    u[1] * v[2] - u[2] * v[1],
    u[2] * v[0] - u[0] * v[2],
    u[0] * v[1] - u[1] * v[0]
  ];
  const longitud = Math.hypot(...n);
  return longitud <= tolerancia ? null : n.map(valor => valor / longitud);
}

console.log(normalTriangulo([0, 0, 0], [1, 0, 0], [0, 1, 0]));
// [0, 0, 1]

Si los puntos son colineales, el triángulo es degenerado y no posee una normal definida.

32.14 Orden de los vértices y orientación

Intercambiar B y C invierte la normal. Por eso el orden de los vértices de una malla determina qué lado se considera frontal.

const cruz = (u, v) => [
  u[1] * v[2] - u[2] * v[1],
  u[2] * v[0] - u[0] * v[2],
  u[0] * v[1] - u[1] * v[0]
];

const AB = [1, 0, 0];
const AC = [0, 1, 0];
console.log(cruz(AB, AC)); // [0, 0, 1]
console.log(cruz(AC, AB)); // [0, 0, -1]

32.15 Análogo del producto vectorial en 2D

En geometría plana se utiliza con frecuencia el componente z que resultaría al considerar los vectores como tridimensionales con z = 0:

cruz2D(u, v) = uxvy − uyvx

El resultado es un escalar con signo: positivo indica un giro antihorario y negativo, horario, usando la convención cartesiana habitual.

function orientacion(A, B, C, tolerancia = 1e-10) {
  const AB = [B[0] - A[0], B[1] - A[1]];
  const AC = [C[0] - A[0], C[1] - A[1]];
  const z = AB[0] * AC[1] - AB[1] * AC[0];
  if (Math.abs(z) <= tolerancia) return "colineales";
  return z > 0 ? "antihoraria" : "horaria";
}

console.log(orientacion([0, 0], [1, 0], [0, 1])); // antihoraria

32.16 Aplicación: torque

En mecánica, el torque producido por una fuerza F aplicada a una distancia vectorial r respecto del eje es:

τ = r × F

Su dirección indica el eje de giro y su magnitud mide la capacidad de producir rotación.

const r = [2, 0, 0];
const fuerza = [0, 5, 0];
const torque = [
  r[1] * fuerza[2] - r[2] * fuerza[1],
  r[2] * fuerza[0] - r[0] * fuerza[2],
  r[0] * fuerza[1] - r[1] * fuerza[0]
];

console.log(torque); // [0, 0, 10]

32.17 Aplicación: ejes de una cámara

A partir de una dirección frontal y una referencia vertical pueden construirse ejes perpendiculares para una cámara.

const cruz = (u, v) => [
  u[1] * v[2] - u[2] * v[1],
  u[2] * v[0] - u[0] * v[2],
  u[0] * v[1] - u[1] * v[0]
];

const frente = [0, 0, -1];
const verticalAproximada = [0, 1, 0];
const derecha = cruz(frente, verticalAproximada);
const arriba = cruz(derecha, frente);

console.log({ derecha, arriba }); // [1,0,0] y [0,1,0]

Si la dirección frontal y la vertical aproximada son paralelas, el producto es cero y debe elegirse otra referencia.

32.18 Validación, precisión y errores frecuentes

Una implementación debe comprobar que ambos argumentos tengan exactamente tres componentes finitas. Para detectar paralelismo o triángulos degenerados se utiliza una tolerancia adaptada a la escala.

function cruzValidado(u, v) {
  const validos = [u, v].every(vector =>
    Array.isArray(vector) && vector.length === 3 && vector.every(Number.isFinite)
  );
  if (!validos) throw new Error("Se requieren dos vectores 3D válidos");
  return [
    u[1] * v[2] - u[2] * v[1],
    u[2] * v[0] - u[0] * v[2],
    u[0] * v[1] - u[1] * v[0]
  ];
}

console.log(cruzValidado([1, 0, 0], [0, 1, 0]));

Errores frecuentes son alterar el orden, equivocarse en el signo de la segunda componente, esperar un escalar, usar vectores 2D directamente, normalizar un resultado cero y confundir producto escalar con vectorial.

32.19 Qué debes recordar de este tema

  • El producto vectorial usual toma dos vectores 3D y produce otro vector 3D.
  • u × v es perpendicular a u y a v.
  • Su sentido se determina con la regla de la mano derecha.
  • v × u = −(u × v), por lo que el orden importa.
  • ||u × v|| = ||u||||v|| sen θ.
  • Su magnitud es el área del paralelogramo formado por u y v.
  • Un producto cero indica paralelismo o la presencia de un vector nulo.
  • El producto vectorial permite calcular normales, orientación y torque.

32.20 Conclusión

El producto vectorial convierte dos direcciones tridimensionales en una perpendicular orientada. Su magnitud y sentido codifican información geométrica esencial para superficies, áreas y rotaciones.

En el próximo tema estudiaremos la proyección de un vector sobre otro, que permite separar la parte alineada con una dirección determinada.