39. Composición de transformaciones

Componer transformaciones significa encadenar movimientos, giros y cambios de tamaño para construir una única operación. El resultado depende tanto de los valores como del orden en que se aplican.

39.1 Introducción

En una escena 2D rara vez aplicamos una sola transformación. Un personaje puede cambiar de tamaño, girar para mirar en una dirección y después trasladarse hasta su posición. Una pieza de una interfaz puede definirse en coordenadas locales, pertenecer a un panel y, a su vez, formar parte de la pantalla.

La composición permite expresar toda esa cadena como una transformación. Comprenderla evita saltos, órbitas inesperadas, escalas aplicadas a la posición y muchos otros errores habituales.

39.2 ¿Qué significa componer?

Si una transformación A recibe un punto y B transforma el resultado, escribimos:

P'=(B∘A)(P)=B(A(P))

Primero actúa A y después B. La composición produce otra función que puede guardarse, reutilizarse o aplicarse a todos los vértices de un objeto.

Por ejemplo, si S escala, R rota y T traslada, la secuencia «escalar, rotar y trasladar» es:

P'=T(R(S(P)))

39.3 Interpretación visual

Comparación entre rotar y trasladar una figura o trasladarla y rotarla, con resultados diferentes
Las mismas operaciones, aplicadas en distinto orden, pueden llevar una figura a posiciones y orientaciones diferentes.

39.4 El orden de aplicación importa

En general, las transformaciones no son conmutativas. Esto significa que intercambiar su orden cambia el resultado:

T∘R ≠ R∘T

Al rotar primero, la figura gira en su lugar y luego se desplaza. Al trasladar primero y rotar alrededor del origen, también gira el vector que separa la figura del origen: el objeto parece describir una órbita.

Una excepción importante es que dos traslaciones sí conmutan. También lo hacen dos escalados respecto del mismo centro y las rotaciones 2D respecto del mismo pivote. Esto no autoriza a reordenarlas libremente cuando se mezclan operaciones diferentes.

39.5 Ejemplo numérico paso a paso

Tomemos P=(2,1), una rotación de 90° alrededor del origen y una traslación t=(3,0).

Rotar y luego trasladar
R(2,1)=(−1,2)
T(−1,2)=(2,2)
Trasladar y luego rotar
T(2,1)=(5,1)
R(5,1)=(−1,5)

Los resultados (2,2) y (−1,5) son distintos aunque las operaciones y sus parámetros sean los mismos.

39.6 Composición mediante matrices

Con coordenadas homogéneas, traslación, rotación y escala pueden expresarse con matrices 3×3. Si usamos vectores columna, la matriz situada más cerca de P actúa primero:

P'=T·R·S·P
primero S, después R y finalmente T

La matriz compuesta C=T·R·S se calcula una sola vez y después se aplica a cada vértice. Esta idea es especialmente valiosa cuando una figura contiene cientos de puntos.

39.7 Matrices elementales

Para escala uniforme o no uniforme, rotación de ángulo θ y traslación (tx,ty):

S =[
sx00
0sy0
001
]
R =[
cos θ−sen θ0
sen θcos θ0
001
]
T =[
10tx
01ty
001
]

El último renglón permite integrar la traslación en la misma multiplicación. El tema siguiente profundizará en estas matrices.

39.8 Componer dos transformaciones afines

Una transformación afín puede escribirse como P'=A·P+t, donde A contiene la parte lineal y t la traslación. Si aplicamos primero (A₁,t₁) y después (A₂,t₂):

Acompuesta=A₂·A₁
tcompuesta=A₂·t₁+t₂

La segunda transformación no solo afecta al punto: también modifica la traslación producida por la primera. Esa es la razón algebraica por la cual el orden cambia el resultado.

39.9 Transformar alrededor de un pivote

Rotar o escalar respecto de C=(cx,cy) requiere tres pasos: mover C al origen, aplicar la operación y devolverlo a su lugar.

rotación alrededor de C: T(C)·R(θ)·T(−C)
escala alrededor de C: T(C)·S(sx,sy)·T(−C)

Leída de derecha a izquierda, la expresión coincide con los pasos físicos. Omitir una de las traslaciones hace que el objeto gire o crezca alrededor del origen global.

39.10 Coordenadas locales, mundiales y de pantalla

Un vértice comienza en el sistema local del objeto. La transformación del objeto lo lleva al mundo; la cámara lo lleva al sistema de vista y, finalmente, otra transformación lo convierte en coordenadas de pantalla.

Ppantalla=Cámara·Mundo·Plocal

En una jerarquía, la transformación mundial de un hijo combina la de su padre con la local:

Mhijo_mundo=Mpadre_mundo·Mhijo_local

Así, la mano acompaña al brazo y el brazo acompaña al personaje sin recalcular manualmente todas sus posiciones.

39.11 Transformación de puntos y vectores

Un punto representa una posición y debe recibir la traslación. Un vector de dirección representa un desplazamiento y no debe trasladarse. En coordenadas homogéneas se distinguen por su último componente:

punto: (x,y,1)   → recibe T
vector: (x,y,0) → ignora T

Las normales requieren un tratamiento especial cuando existe escala no uniforme: deben transformarse con la inversa transpuesta de la parte lineal y normalizarse después.

39.12 Transformación inversa

La inversa deshace una composición. Además de invertir cada operación, hay que invertir el orden:

C=T·R·S
C⁻¹=S⁻¹·R⁻¹·T⁻¹

Esto permite convertir un clic de pantalla a coordenadas locales, comprobar si el puntero está dentro de un objeto rotado o devolver un punto desde el mundo al sistema de una figura.

Una escala con sx=0 o sy=0 aplasta una dimensión y no tiene inversa.

39.13 Simulación interactiva: compara el orden

Ambos paneles parten de la misma figura y utilizan exactamente los mismos valores. El panel izquierdo aplica escala, rotación y traslación; el derecho invierte ese orden. Activa las etapas para observar los estados intermedios.

S → R → TT → R → S la operación de la izquierda ocurre primeromismos valores, distinto orden
S → R → T · centro final(3, 1)
T → R → S · centro final(1.84, 3.68)
Distancia entre resultados2.92
Matriz C₁ = T·R·S
Matriz C₂ = S·R·T

39.14 Implementación directa en JavaScript

Podemos expresar cada transformación como una función y componerlas explícitamente. El orden queda visible y es fácil de depurar:

const trasladar=(p,tx,ty)=>({x:p.x+tx,y:p.y+ty});
const escalar=(p,sx,sy)=>({x:p.x*sx,y:p.y*sy});

function rotar(p,angulo) {
  const c=Math.cos(angulo), s=Math.sin(angulo);
  return {x:p.x*c-p.y*s,y:p.x*s+p.y*c};
}

// Primero escala, después rota y finalmente traslada.
function transformar(p,sx,sy,angulo,tx,ty) {
  return trasladar(rotar(escalar(p,sx,sy),angulo),tx,ty);
}

39.15 Componer matrices en JavaScript

Una representación afín compacta usa seis valores: a, b, c, d, e y f. Con ellos se representan escala, rotación, corte y traslación en una sola estructura.

function multiplicar(A,B) {
  return {
    a:A.a*B.a+A.c*B.b,
    b:A.b*B.a+A.d*B.b,
    c:A.a*B.c+A.c*B.d,
    d:A.b*B.c+A.d*B.d,
    e:A.a*B.e+A.c*B.f+A.e,
    f:A.b*B.e+A.d*B.f+A.f
  };
}

const angulo = 30 * Math.PI / 180;
const T = {a:1,b:0,c:0,d:1,e:4,f:2};
const R = {a:Math.cos(angulo),b:Math.sin(angulo),
           c:-Math.sin(angulo),d:Math.cos(angulo),e:0,f:0};
const S = {a:1.5,b:0,c:0,d:0.8,e:0,f:0};
const p = {x:2,y:1};

const C=multiplicar(T,multiplicar(R,S));
const pTransformado={
  x:C.a*p.x+C.c*p.y+C.e,
  y:C.b*p.x+C.d*p.y+C.f
};
console.log("Punto transformado:", pTransformado);

39.16 Aplicar una matriz a una figura

Una vez compuesta la matriz, podemos transformar todos los vértices sin depender de ningún sistema de dibujo.

function aplicarMatriz(p, M) {
  return {
    x: M.a*p.x + M.c*p.y + M.e,
    y: M.b*p.x + M.d*p.y + M.f
  };
}

const C = {a:1.3,b:0.75,c:-0.4,d:0.69,e:4,f:2};
const vertices = [
  {x:-1,y:-1}, {x:1,y:-1},
  {x:1,y:1}, {x:-1,y:1}
];

const figuraTransformada = vertices.map(
  punto => aplicarMatriz(punto, C)
);

figuraTransformada.forEach((p, i) =>
  console.log(`V${i}: (${p.x.toFixed(2)}, ${p.y.toFixed(2)})`)
);

La misma matriz se aplica a cada vértice. Esto mantiene una única fuente de verdad para toda la figura y hace visible el resultado al ejecutar el código.

39.17 Errores frecuentes

  • Leer el producto matricial de izquierda a derecha cuando se usan vectores columna.
  • Cambiar el orden de las llamadas suponiendo que las operaciones conmutan.
  • Rotar o escalar alrededor del origen cuando se necesitaba un pivote local.
  • Aplicar la traslación de un objeto a sus vectores de dirección.
  • Mezclar grados con radianes.
  • Acumular transformaciones cuadro tras cuadro sin restaurar el contexto.
  • Intentar invertir una transformación cuya escala contiene cero.
  • Combinar convenciones de vectores fila y vectores columna.

39.18 Aplicaciones y conclusión

La composición sostiene la animación articulada, los árboles de escena, las cámaras, los editores vectoriales, las interfaces anidadas, los mapas, los videojuegos y la conversión entre sistemas de coordenadas.

Brazo orbital: transformaciones jerárquicas

Cada pieza hereda la transformación de su padre. Cuando gira el hombro también se desplazan el antebrazo, la pinza y el núcleo; cuando gira el codo, solamente cambia su rama del árbol.

Árbol: base → hombro → codo → pinzaHombro: · Codo: Pinza local: (135, 0)Pinza global: (0, 0)

Recuerda: componer es encadenar; el orden suele cambiar el resultado; con vectores columna, la matriz de la derecha actúa primero; y una transformación alrededor de un pivote necesita trasladar al origen y regresar.

En el próximo tema estudiaremos con mayor profundidad las matrices de transformación 2D.