Rotaci贸n de un cubo 3D usando Java

marzo 4 20108 comentarios

Guardado en : Ciencia, Programaci贸n

Resumen

Se muestra una manera sencilla de graficar y rotar un Cubo.

Se comienza con la teoría de transformaciones lineales y proyecciones en el plano, se describen las matrices de rotación y al final se muestra un código muy sencillo de una aplicación hecha en Java que ejemplifica y muestra las transfomaciones descritas.

Introducción

Se puede rotar una figura en tres dimensiones, sobre el eje X, sobre el eje Y o sobre el eje Z.

En el caso de una computadora, la pantalla es un espacio de dos dimensiones, por lo tanto hay que hacer una proyección sobre el plano XY cada vez que se manipulen figuras tridimensionales.

Existe un vector v en el plano R2 con coordenadas (x, y) y un ángulo alfa con respecto al eje X,
se desea rotar el vector en un ángulo teta en sentido contrario de las manecillas del reloj con respecto al eje X. El nuevo vector v ‘ forma un ángulo teta+alfarespecto al vector v y existe la misma longitud r en ambos vectores como se muestra en la figura:

fig1

Utilizando las definiciones de seno y coseno obtenemos que para el vector v

Formula1

Para el vector v‘, de forma similar, se obtiene que:

formula2

La suma de dos ángulos esta dada por:

formula3

Si se considera r = 1 y se sustituyen los valores correspondientes de x e y de la figura 1 tenemos.

Formula4

Formula5

Escribiendo las mismas ecuaciones en forma de matrices se obtiene:

Formula7

La matriz (1) es mejor conocida como matriz de rotación, la cual determina las nuevas coordenadas (x’, y’) obtenidas por rotar un ángulo teta un punto (x, y) en sentido contrario de las manecillas del reloj.

Si las rotaciones se quieren hacer en el espacio R3, se necesita considerar el valor del eje de rotación (en el cual se desea girar) igual a uno y poner el resto de los valores igual a cero. En el caso de la matriz (1) se considera que rota con respecto al eje z.

Las matrices de rotación correspondientes a cada uno de los ejes están dadas por:

Matrcies rotacion

Para poder mostrar la rotación en tres dimensiones en un plano de dos dimensiones hay que hacer una proyección. Una proyección es una trasnformación lineal que toma un punto en el espacio de tres dimensiones y lo proyecta en un plano, que en este caso sera el plano xy. La matriz de transfomación que nos brinda la proyección de un punto en el plano xy es:

Formula8

Ahora vamos a usar las matrices anteriores para tratar de rotar un cubo.

Para construir un cubo se pueden tomar una lista de vértices, aristas o caras, para ejemplos ilustrativos vamos a tomar una lista de ocho vértices y vamos a enumerarlos como sigue:

Fig2

Si trazamos lineas que unan los vértices de forma tal que formen las aristas del cubo, se obtiene la siguiente figura:

Fig3

La figura 3 muestra un cubo centrado en el origen pero a pesar de que la figura mostrada aparenta ser un cuadrado (dos dimensiones) se sabe que tiene una tercera dimensión dado que tiene las tres coordenadas en cada uno de sus ocho vértices, pero al proyectar sus puntos en el plano xy todos los valores z de los puntos son "planchados" al plano xy. Para darse cuenta de la forma tridimensional de la figura basta con rotar los puntos del cubo sobre el eje x o sobre el eje y.

Fig4

El cubo aparenta estar representado en el espacio de tres dimensiones, pero carece de volumen, propiedad típica de los cuerpos tridimensionales. Para lograr una apariencia de volumen se necesitan crear diferentes polígonos que representen cada una de las caras del cubo, los vértices de cada cara del cubo serán los vértices de cada polígono y se puede asignar un color diferente a cada uno de ellos como se muestra.

Fig5

Para ilustrar mejor lo antes mencionado, se contruy贸 un applet que muestra un cubo en 3D el cual puede rotar utlizando las matrices descritas.

Da click en el siguiente enlace para abrir el applet:

Rotaci贸n 3D de un cubo usando Java

Debes mover el rat贸n mientras mantienes presionado el bot贸n izquierdo sobre el cubo para observar su rotaci贸n.

A continuación se muestra el código que muestra la utilización de matrices de rotación y proyecciones en el plano.

 /**
this software is under GNU GPL
@author: Jorge Alejandro Guti茅rrez Orozco
compilation
    javac Cube.java
Ejecution
    appletviewer Hola.html
*/
 
import java.applet.*;
import java.awt.*;
import java.awt.event.*;
import java.lang.Math;
import java.awt.Polygon;
 
/* Represents a point in space */
 
class Point{
 
public double x;
 
public double y;
 
public double z;
 
Point(){ this.x=0; this.y=0; this.z=0; }
 
Point(double x,double y, double z){ this.x=x; this.y=y; this.z=z; }
 
/* for move it at origin */
 
int getXCoordinate(){return Cube.origin + (int)this.x;}
 
int getYCoordinate(){return Cube.origin - (int)this.y;}
 
int getZCoordinate(){return 0;} /* projection on XY plane*/
 
}
 
class Face{
 
Point p1,p2,p3,p4;
 
Polygon side= new Polygon();
 
Face(){}
 
Face(Point p1,Point p2,Point p3,Point p4){
 
this.p1=p1;this.p2=p2;this.p3=p3;this.p4=p4;
 
this.side.addPoint(p1.getXCoordinate(),p1.getYCoordinate());
 
this.side.addPoint(p2.getXCoordinate(),p2.getYCoordinate());
 
this.side.addPoint(p3.getXCoordinate(),p3.getYCoordinate());
 
this.side.addPoint(p4.getXCoordinate(),p4.getYCoordinate());
 
}
 
public void drawFace(Graphics g){ g.fillPolygon(side); }
 
public boolean isVisible(){
 
Point aux1, aux2;
 
aux1 = new Point(p2.x-p1.x, p2.y-p1.y, p2.z-p1.z); // p1->p2
 
aux2 = new Point(p4.x-p1.x, p4.y-p1.y, p4.z-p1.z); // p1->p4
 
if((aux1.x*aux2.y - aux1.y*aux2.x) > 0)
 
return true;
 
return false;
 
}
 
}
 
public class Cube extends Applet implements
 
Runnable, MouseMotionListener{
 
Thread luxury;
 
static Point[] vertex = new Point[8]; // Cube vertexes
 
static int maxSize =300; // screen size
 
static int origin = maxSize/2; // (0,0)
 
static int xMouseP=0, yMouseP =0; // X and Y mouse's positions
 
int xAux , yAux ; // old X and Y mouse's positions
 
int module = 50; // length of lines of cube.
 
Image canvasAux;
 
Graphics backBuffer;
 
public void init(){
 
setSize(maxSize,maxSize);
 
setBackground( new Color(0.2f,0.6f,0.1f,1.0f) );
 
addMouseMotionListener(this);
 
/*Initial coordinates of eight vertex
module is half the length of the cube*/
 
int[] coordX = new int[]{-module,module,module,-module,-module,module,module,-module};
 
int[] coordY = new int[]{-module,-module,module,module,-module,-module,module,module};
 
int[] coordZ = new int[]{module,module,module,module,-module,-module,-module,-module};
 
canvasAux = createImage(500,500);
 
backBuffer = canvasAux.getGraphics();
 
for(int i =0; i<vertex.length; i++){
 
vertex[i] = new Point(coordX[i],coordY[i],coordZ[i]);
 
}
 
}
 
public void start(){
 
try { luxury = new Thread(this); luxury.start(); }
 
catch (Exception e){}
 
}
 
public void run() {}
 
public void stop(){}
 
public void paint(Graphics g){
 
/* Cube's points.
Requires four points to create a face,
requires six faces to create a cube.*/
 
int[] pts1 = new int[]{0,1,5,0,0,3};
 
int[] pts2 = new int[]{1,5,4,3,4,2};
 
int[] pts3 = new int[]{2,6,7,7,5,6};
 
int[] pts4 = new int[]{3,2,6,4,1,7};
 
Color[] colorRGB = new Color[]{ Color.black, Color.blue,Color.orange,
 
Color.pink,Color.red, Color.yellow};
 
Face[] faces = new Face[6];
 
backBuffer.clearRect(0,0,500,500);
 
for(int i=0; i<6; i++){
 
backBuffer.setColor(colorRGB[i]);
 
faces[i] = new 
 
Face(vertex[pts1[i]],vertex[pts2[i]],vertex[pts3[i]],vertex[pts4[i]]);
 
if(faces[i].isVisible()){
 
faces[i].drawFace(backBuffer);
 
}
 
}
 
g.drawImage(canvasAux,0,0,this);
 
g.drawString(" Touche ", 30,30);
 
g.drawString(" X " + xMouseP, 30,50);
 
g.drawString(" Y " + yMouseP, 30,65);
 
return;
 
}
 
public void update(Graphics g){ paint(g); }
 
public void destroy(){
 
try {Thread.sleep(1500);}
 
catch (InterruptedException e) {
 
System.out.println("Exception in sleep");
 
}
 
}
 
/* Rotate each vertex of cube over X, Y and Z axis */
 
void rota(double angleTeta, double anglePhi, double anglePsi) {
 
double teta= Math.toRadians(angleTeta);
 
double phi= Math.toRadians(anglePhi);
 
double psi= Math.toRadians(anglePsi);
 
Point pAux = new Point();
 
Point pAux1 = new Point();
 
Point pAux2 = new Point();
 
for(int i =0; i<8; i++){
 
/* Rotating over x */
 
pAux1.x = vertex[i].x;
 
pAux1.y= vertex[i].y * Math.cos(teta) + vertex[i].z * (-Math.sin(teta));
 
pAux1.z = vertex[i].y * Math.sin(teta) + vertex[i].z * Math.cos(teta);
 
/* Rotating over y */
 
pAux2.x = pAux1.x * Math.cos(phi) + pAux1.z * Math.sin(phi);
 
pAux2.y = pAux1.y;
 
pAux2.z = pAux1.x * (-Math.sin(phi)) + pAux1.z * Math.cos(phi);
 
/* Rotating over z */
 
pAux.x= pAux2.x * Math.cos(psi) + pAux2.y * (-Math.sin(psi));
 
pAux.y = pAux2.x * Math.sin(psi) + pAux2.y * Math.cos(psi);
 
pAux.z= pAux2.z;
 
/* new position */
 
vertex[i].x = pAux.x;
 
vertex[i].y = pAux.y;
 
vertex[i].z = pAux.z;
 
}
 
}
 
/* For move the cube over X and Y axis */
 
public void mouseDragged( MouseEvent e ){
 
/* old coordinates */
 
xAux = xMouseP;
 
yAux = yMouseP;
 
/* new coordinates */
 
xMouseP = e.getX();
 
yMouseP = e.getY();
 
if(yMouseP > yAux){ rota(2,0,0); }
 
if(yMouseP < yAux){ rota(-2,0,0); }
 
if(xMouseP > xAux){ rota(0,2,0); }
 
if(xMouseP < xAux){ rota(0,-2,0); }
 
repaint();
 
e.consume();
 
}
 
public void mouseMoved( MouseEvent e ) { }
 
}

El código anterior pertenece a un archivo llamado Cube.java, para poder visualizar el applet generado se necesita crear una archivo html.

El siguiente código solo es un html para desplegar el applet.

<!-- hola.html -->
<HTML>
<BODY>
Cubo
<APPLET width="500" height="500" CODE="Cube.class"><br /></APPLET>
</BODY>
</HTML>

En caso de contar con un IDE (Eclipse, jGrasp, etc.) no existe necesidad de crear dicho html para visualizar el cubo.

Comparte esta informaci贸n:
  • Digg
  • Sphinn
  • del.icio.us
  • Facebook
  • Mixx
  • Google Bookmarks
  • BarraPunto
  • LinkedIn
  • Technorati
  • TwitThis

Quiz谩 te interese :

Acerca del autor: Jorge Alejandro

8 Respuestas a “Rotaci贸n de un cubo 3D usando Java”

  1. Daniel dice:

    Podr铆as incrustar el Applet para verlo en funcionamiento?

    ?
  2. Daniel dice:

    A帽adiendo el coloreado de sintaxis es m谩s f谩cil seguir el c贸digo :)

    ?
  3. wafto dice:

    La rotaci贸n en el eje y esta invertido.

  4. Efectivamente hay mucha confusi贸n con respecto a la matr铆z de rotaci贸n en la web, la mayor铆a de las pags tienen una matr铆z donde el seno negativo est谩 en la segunda fila, pero ello representa una rotaci贸n en sentido de las manecillas del reloj:

    http://en.wikipedia.org/wiki/Rotation_matrix

    Puedes revisar el applet en el siguiente enlace para comprobar que el sentido de la rotaci贸n va acorde con el movimiento del rat贸n:

    http://www.ubicuos.com/wp-content/uploads/2010/03/Hola.html

    Much铆simas gracias por la observaci贸n.

    ?
  5. Huguin dice:

    Yeah, es muy bueno, puedo visualizarlo creando el archivo html, pero no en netbeans, de todos modos revisare el codigo para ver la l贸gica, genial.

  6. tyomero dice:

    Jorge Alejandro dijo:

    “Efectivamente hay mucha confusi贸n con respecto a la matr铆z de rotaci贸n en la web, la mayor铆a de las pags tienen una matr铆z donde el seno negativo est谩 en la segunda fila, pero ello representa una rotaci贸n en sentido de las manecillas del reloj:”

    Esa es la desventaja del internet, cualquier persona puede escribir lo que quiera, sea cierto o no. Lo cierto es que realmenete no encontrar铆an tal “confusion” si utilizar谩n referencias confiables, o si entendieran como se deduce las matrices de transformaci贸n.

    El an谩lisis no es d铆ficil, lo 煤nico que necesitas es conocer las identidades de suma de 谩ngulos.

  7. Gustavo dice:

    Analic茅 el c贸digo pero no le veo la utilidad del Thread luxury. Se lo quit茅 al c贸digo y sigue funcionando el c贸digo, para que sirve entonces ? el m茅todo run() de todos modos no hace nada.
    Buen programa.

  8. Mary dice:

    Pues yo le he quitado el hilo y se alent贸 un poco, yo creo que este hilo es para manejar procesos adicionales ( tal vez por eso le llama “lujo”) sin necesidad de que la eficiencia de la rotaci贸n se viese afectada, no s茅, se me imagina que podr铆ais agregar iluminaci贸n al cubo o tal vez otros c谩lculos de manera independiente a la graficaci贸n. Excelente programa!
    @Jorge_Alejandro: porqu茅 no agrega铆s la iluminaci贸n que te digo? Tomar茅 tu c贸digo para fines educativos jejeje. Buen trabajo.

Deja un comentario


Licencia y uso

Las técnicas demostradas en los tutoriales pueden ser utilizadas sin ninguna limitación y tampoco es obligatorio dar una atribución.


Los textos, imágenes y tutoriales son propiedad de sus respectivos autores, nuestro contenido se encuentra bajo licencia Creative Commons Share-Alike.

Escribe algo para el sitio

El escribir un tutorial o un artículo, mandarnos un enlace para Ubicuos, no solamente es una forma de obtener publicidad, si no también de dar algo a la comunidad y nosotros te lo recompensamos con los premios del mes! Leer más de nuestras promociones

驴Sugerencias?

Este es TU sitio, si tienes sugerencias o ideas de c贸mo podemos mejorarlo para ti, 隆Por favor h谩znoslos saber!

Hacemos nuestro mayor esfuerzo en proporcionar un sitio 煤til y amigable y esperamos que disfrutes tu tiempo aqu铆.

Ayuda a Difundir

Te gusta Ubicuos?

Ve las formas en que nos puedes apoyar.

Apoyando a Ubicuos.com

Submit your linkClose

-->