Wednesday, January 9, 2008

SDSCC


Proyecto de documentación y desarrollo de un sistema web para administrar una conferencia científica, que se realizo en equipo con Rogelio un compañero de curso, en el trabajo se tubo serios problemas de comunicación independientemente que se trato de manejar buenos métodos de sincronización de información SVN, videoconferencias, remote descktops y aun así no pudimos cumplir con el realizar un trabajo con la calidad suficiente para poder tener una buena realización al final. Sin embargo fue suficiente para pasar la materia (aunque suene emotivo realmente es algo denigrante usar la palabra suficiente, pero así son las cosas, así que aguas con los problemas de comunicación con tus equipos, debes asegurarte que te van a entender para que hay mayor provecho).

Les dejo el documento del proyecto para que estén enterados de que se trata mas a profundo.
Aqui

Labels: ,

Sunday, December 16, 2007

Trazo de splines

Trazo de splines

• Interpolar un conjunto de puntos usando los splines cubicos naturales.
• Interpolar un conjunto de puntos de una curva cerrada usando los mismos splines cubicos naturales.
• Interpolar el mismo conjunto de puntos del primer punto pero ahora usando los splines Catmull-Rom.
• El trazo debe realizase con gnuplot

Jose Angel Espinoza Portillo, onlyangel@onlyangel.net

Splines Cubicas Naturales

1 Teorıa
Fue una de las primeras curvas splines que se desarrollo para aplicaciones gr´aficas es el spline cubico natural. Esta se forma imponiendo que dos partes adyacentes e la curva posean la mismas primera y segunda derivada parametrica en su limite comun. Por tanto, los splines cubicos naturales tienen continuidad C 2 .




Si tenemos n + 1puntos de control, como en la Figura 1.1, entonces tenemos n partes de la curva con un total de 4n coeficientes de polinomio que hay que determinar. En cada uno de los n − 1 puntos de control interiores tenemos cuatro condiciones en el limite: las dos partes de la curva a cada lado de un punto de control deben tenerlas mismas primera y segunda derivadas parametricas en dicho punto de control, y cada curva debe pasar por ese punto de control. Esto nos proporciona 4n − 4 ecuaciones que hay que satisfacer con 4n coeficientes de polinomio, obtenemos una ecuaci´on adicional a partir del primer punto de control p0 y pn en el valor 0. Otra t´ecnica es anadir dos puntos de control extra (llamados puntos ficticios ), uno en cada extremo de la secuencia original de puntos de control. Es decir anadimos un punto de control etiquetado como p en el comienzo de la curva y un punto decontrol etiquetado como pn+1 en el final. Entonces todos los puntos e control originales son puntos anteriores y tenemos las 4n condiciones necesarias en el limite.

2 Base matematica del dibujo
Si tenemos una secuencia de puntos P = {P0 , P1 , · · · , Pn } donde cada Pa es un punto en el espacio (xa , ya ). Se tiene que desarrollar la siguiente Multiplicaci´on de matrices.



De esta manera se tienen todas las secciones de la curva a dibujar, la cual para ser rendereada por puntos se especifican segun la siguiente ecuaci´on basada en t.




3 Interpolando un Conjunto de Puntos
3.1 Se propone el siguiente P.




3.2 Se tendr´an unos M de:




3.3 Con lo que nos queda.


3.4 C´odigo de gluplot

X1(t) = 2*(1-t) + 4*t + (-30/6)*( (1-t)*(1-t)*(1-t) - (1-t) ) + (30/6)*( t*t*t - t )
Y1(t) = 3*(1-t) + 8*t + (30/6)*( (1-t)*(1-t)*(1-t) - (1-t) ) + (-30/6)*( t*t*t - t )
X2(t) = 4*(1-t) + 6*t + (-30/6)*( (1-t)*(1-t)*(1-t) - (1-t) ) + (30/6)*( t*t*t - t )
Y2(t) = 8*(1-t) + 3*t + (-30/6)*( (1-t)*(1-t)*(1-t) - (1-t) ) + (30/6)*( t*t*t - t )
X3(t) = 6*(1-t) + 8*t + (-30/6)*( (1-t)*(1-t)*(1-t)-(1-t) ) + (30/6)*( t*t*t - t)
Y3(t) = 3*(1-t) + 8*t + (30/6)*( (1-t)*(1-t)*(1-t)-(1-t) ) + (-30/6)*( t*t*t - t)
set xrange [0:10]
set yrange [0:10]
set multiplot
plot ’puntosNaturales.txt’ w p ps 2
set parametric
set trange [0:1]
plot X1(t),Y1(t), X2(t),Y2(t),X3(t),Y3(t)
unset multiplot
pause -1



3.5 Resultado



4 El caso del la figura circular
4.1 Se propone el siguiente P.




4.2 Se tendr´an unos M de:




4.3 Con lo que nos queda.



4.4 Codigo en GNUPLOT


X1(t) = 4*(1-t)+3*t + ((-11.81041)/6)*((1-t)*(1-t)*(1-t)-(1-t)) + ((8.33644)/6)*(t*t*t-t)
Y1(t) = 4*(1-t)+0*t + ((-12.21815)/6)*((1-t)*(1-t)*(1-t)-(1-t)) + ((0.76353)/6)*(t*t*t-t)
X2(t) = 3*(1-t)+4*t + ((8.33644)/6)*((1-t)*(1-t)*(1-t)-(1-t)) + ((-9.53533)/6)*(t*t*t-t)
Y2(t) = 0*(1-t)-4*t + ((0.76353)/6)*((1-t)*(1-t)*(1-t)-(1-t)) + ((9.16403)/6)*(t*t*t-t)
X3(t) = 4*(1-t)+0*t + ((-9.53533)/6)*((1-t)*(1-t)*(1-t)-(1-t)) + ((-0.19511)/6)*(t*t*t-t)
Y3(t) = -4*(1-t)-3*t + ((9.16403)/6)*((1-t)*(1-t)*(1-t)-(1-t)) + (( -7.41963)/6)*(t*t*t-t)
X4(t) = 0*(1-t)-4*t + ((-0.19511)/6)*((1-t)*(1-t)*(1-t)-(1-t)) + ((10.31579)/6)*(t*t*t-t)
Y4(t) = -3*(1-t)-4*t + (( -7.41963)/6)*((1-t)*(1-t)*(1-t)-(1-t)) + ((8.51451)/6)*(t*t*t-t)
X5(t) = -4*(1-t)-3*t + ((10.31579)/6)*((1-t)*(1-t)*(1-t)-(1-t)) + ((-11.06804)/6)*(t*t*t-t)
Y5(t) = -4*(1-t)+0*t + ((8.51451)/6)*((1-t)*(1-t)*(1-t)-(1-t)) + ((3.36161)/6)*(t*t*t-t)
X6(t) = -3*(1-t)-4*t + ((-11.06804)/6)*((1-t)*(1-t)*(1-t)-(1-t)) + ((21.95635)/6)*(t*t*t-t)
Y6(t) = 0*(1-t)+4*t + ((-3.36161)/6)*((1-t)*(1-t)*(1-t)-(1-t)) + ((-21.96094)/6)*(t*t*t-t)
X7(t) = -4*(1-t)+0*t + ((21.95635)/6)*((1-t)*(1-t)*(1-t)-(1-t)) + ((-2.84467)/6)*(t*t*t-t)
Y7(t) = 4*(1-t)+3*t + ((-21.96094)/6)*((1-t)*(1-t)*(1-t)-(1-t)) + ((10.56027)/6)*(t*t*t-t)
X8(t) = 0*(1-t)+4*t + ((-2.84467)/6)*((1-t)*(1-t)*(1-t)-(1-t)) + ((10.57766)/6)*(t*t*t-t)
Y8(t) = 3*(1-t)+4*t + ((10.56027)/6)*((1-t)*(1-t)*(1-t)-(1-t)) + ((-8.28013)/6)*(t*t*t-t)
set xrange [-7:7]
set yrange [-7:7]
set multiplot
plot ’puntosNaturalesCirculo.txt’ w p ps 2
set parametric
set trange [0:1]
plot X1(t),Y1(t), X2(t),Y2(t),X3(t),Y3(t), X4(t),Y4(t),X5(t),Y5(t), X6(t),Y6(t),X7(t),Y7(t),X8(t),Y8(
unset multiplot
pause -1


4.5 Resultado



Splines de Catmull-Rom
1 Teor´ıa y base matematica
Al igual que los splines de Hermite, los splines Catmull-Rom son polinomio de interpolaci´on por tramos c´ubicos con tangentes especificas en los puntos extremos en los limites de cada secci´on de la curva. La diferencia es que no introducimos los valores de las tangentes en los puntos extremos. En un spline CR, la pendiente en en el punto de control se calcula a partir de las coordenadas de los dos puntos de control adyacentes.

Una secci´on de un spline queda completamente determinada con cuatro puntos de control consecutivos. Los puntos de control centrales son los puntos extremos de la secci´on, y otros dos los puntos se utilizan en el calculo de las pendientes en los puntos extremos. Si tomamos P(u) como la representaci´on de la funci´on de punto param´etrica cubica de la secci´on de curva entre los puntos de control Pk−1 hasta Pk+1 se utilizan para establecer las condiciones en los limites de la secci´on del spline de este modo:




Por tanto, las pendientes en los puntos de control Pk y Pk+1 se toman proporcionales, respectivamente, a las cuerdas Pk
−1 Pk+1 y Pk Pk+2 el par´ametro t se denomina par´ametro de tensi´on, ya que controla como de flo jo o apretado se a justa el spline a los puntos de control de entrada.
Utilizando m´etodos similares a los utilizados para los polinomios Hermite, podemos convertir las condiciones de (2.1) de los limites en su forma matricial,



Donde la Matriz Catmun-Rom es:



con s = (1 − t)/2.
Desarrollando la Ecuacion matricial (2.2) en forma polinomica, tenemos:



donde los polinomios C ARK (u) con K = 0, 1, 2, 3 son las funciones de combinacion de la matriz base de los splines Catmull-Rom.

2 El caso del Curva Catmull-Rom
2.1 Se propone el siguiente P.




2.2 Se tienen unos M’s de:



De donde obtenemos la matriz base de Catmull-Rom multiplicandolas:



2.3 Con lo que nos queda un P(u).
Obtenemos C ARen conformidad con (2.2) para obtener (2.4) matricial(P (u)).




2.4 El Codigo en GNUPLOT

P1(t) = (-0.5*t*t*t + 1*t*t - 0.5*t + 0)
P2(t) = ( 1.5*t*t*t - 2.5*t*t + 0*t + 1)
P3(t) = (-1.5*t*t*t + 2*t*t + 0.5*t + 0)
P4(t) = ( 0.5*t*t*t - 0.5*t*t + 0*t + 0)
x1(t) = 1*P1(t) + 2*P2(t) + 4*P3(t) + 6*P4(t)
y1(t) = 8*P1(t) + 3*P2(t) + 8*P3(t) + 3*P4(t)
x2(t) = 2*P1(t) + 4*P2(t) + 6*P3(t) + 8*P4(t)
y2(t) = 3*P1(t) + 8*P2(t) + 3*P3(t) + 8*P4(t)
x3(t) = 4*P1(t) + 6*P2(t) + 8*P3(t) + 10*P4(t)
y3(t) = 8*P1(t) + 3*P2(t) + 8*P3(t) + 3*P4(t)
x4(t) = 4*P1(t) + 6*P2(t) + 8*P3(t) + 20*P4(t)
y4(t) = 8*P1(t) + 3*P2(t) + 8*P3(t) + 20*P4(t)
set xrange [0:10]
set yrange [0:10]
set multiplot
plot ’puntos.txt’ w p ps 2
set parametric
set trange [0:1]
plot x1(t), y1(t), x2(t), y2(t), x3(t), y3(t) ,x4(t), y4(t)
unset multiplot
pause -1

2.5 Resultado

Labels: ,

Wednesday, December 12, 2007

Mi carro con PovRay

Mi carro con PovRay
Dibujado de un carro en OpenGL utilizando ????

Jose Angel Espinoza Portillo
Graficacion • 14 Diciembre 2007



Que es Pov-Ray?
Pov-Ray es una herramienta que sirve para generar ambientes en 3D, basada la técnica de trazo de rayo. La cual consiste en dividir el campo de visión en una maya de pixeles y evaluar simular un rayo que pasa por cada pixel y evalúa el objeto que choca y el rebote de la luz desde todos los objetos y las fuentes de luz en el. y así sucesivamente con cada pixel, un ejemplo de esta técnica se puede ver en en la siguiente figura.

Implementación
Como implementar y que pasos seguir para el dibujado.

Base
De manera similar que en Open GL se programan muchas cosas dentro del código, el primer paso antes de empezar a implementar el carro es especificar las características básicas las cuales se especifican a continuación:




#include "colors.inc"
#include "shapes.inc"
#include "textures.inc"

camera {
location <2,5,>
look_at <0,>
}

background { color SkyBlue }
light_source { <20,> color rgb<1,> }


Esto posesionara la cámara en el punto <15,> mirando hacia <0,>, define el fondo en color azul cielo y posiciona una fuente de luz blanca en las coordenadas <20,>

Plano
Ahora se procede a agregar el siguiente código para integrar un plano infinito dentro de la vista:




plane { y, 1
pigment { checker Green, White }
finish { ambient .3 diffuse .7 }
}

El valor de pigment le dice que va a ser una maya de cuadros a continuación de los colores de los cuadros.






Cielo
Para simular el cielo, se agrega una esfera, la cual es magnificada para abarcar el espacio del cielo. Esta esfera es creada de la siguiente manera:

#declare Sky = sky_sphere {
pigment {
gradient y
color_map {
[0.75 color CornflowerBlue]
[1.00 color MidnightBlue]
}
scale 2
translate <-1, -1, -1>
}
pigment {
bozo
turbulence 0.6
octaves 7
omega .49876
lambda 2.5432
color_map {
[0.0 color rgbf<.75, .75, .75, 0.1>]
[0.4 color rgbf<.9, .9, .9, .9>]
[0.7 color rgbf<1,>]
}
scale 6/10
scale <1,>
}
pigment {
bozo
turbulence 0.6
octaves 8
omega .5123
lambda 2.56578
color_map {
[0.0 color rgbf<.375, .375, .375, 0.2>]
[0.4 color rgbf<.45, .45, .45, .9>]
[0.6 color rgbf<0.5,>]
}
scale 6/10
scale <1,>
}
}
sky_sphere { Sky }



El carrito
Los colores
Para hacer el carro primero se especificaron las 6 texturas del objeto pertenecientes a cada lado del mismo especificandole un grado de refleccion y el material del mismo(metal) de la siguiente manera:

#declare TRed = texture {
pigment { color rgb<0.8,> }
finish {
reflection {0.5 metallic}
diffuse 0.4

brilliance 2
specular 1 roughness 0.01
metallic
}
}
#declare TGreen = texture {
pigment { color rgb<0.2,> }
finish {
reflection {0.5 metallic}
diffuse 0.4

brilliance 2
specular 1 roughness 0.01
metallic
}
}
#declare TBlue = texture {
pigment { color rgb<0.2,> }
finish {
reflection {0.5 metallic}
diffuse 0.4

brilliance 2
specular 1 roughness 0.01
metallic
}
}

#declare TWhite = texture {
pigment { color rgb<0.8,> }
finish {
reflection {0.5 metallic}
diffuse 0.4

brilliance 2
specular 1 roughness 0.01
metallic
}
}
#declare TViolet = texture {
pigment { color rgb<0.8,> }
finish {
reflection {0.5 metallic}
diffuse 0.4

brilliance 2
specular 1 roughness 0.01
metallic
}
}

#declare TPurple = texture {
pigment { color rgb<0.8,> }
finish {
reflection {0.5 metallic}
diffuse 0.4

brilliance 2
specular 1 roughness 0.01
metallic
}
}


La figura
Basado en la figura diseñada para el mismo proyecto en OpenGL se implemento un objeto mesh basado en mayas de triángulos especificando que textura tiene cada triángulo esto se dibuja de la siguiente manera:


mesh {

triangle {
<0,>, <5,>, <5,>
texture { TRed }
}
triangle {
<0,>, <5,>, <0,>
texture { TRed }
}
triangle {
<1.25,>, <3.75,>, <3.75,>
texture { TRed }
}
triangle {
<1.25,>, <3.75,>, <1.25,>
texture { TRed }
}

triangle {
<0,>, <5,>, <5,>
texture { TGreen }
}
triangle {
<0,>, <5,>, <0,>
texture { TGreen }
}

triangle {
<0,>, <0,>, <0,>
texture { TWhite }
}
triangle {
<0,>, <0,>, <0,>
texture { TWhite }
}
triangle {
<1.25,>, <1,>, <1,>
texture { TWhite }
}
triangle {
<1.25,>, <1,>, <1.25,>
texture { TWhite }
}

triangle {
<0,>, <5,>, <5,>
texture { TViolet }
}
triangle {
<0,>, <5,> <0,>
texture { TViolet }
}
triangle {
<1,>, <4,>, <3.75,>
texture { TViolet }
}
triangle {
<1,>, <3.75,>, <1.25,>
texture { TViolet }
}

triangle {
<5,>, <5,>, <5,>
texture { TBlue }
}
triangle {
<5,>, <5,>, <5,>
texture { TBlue }
}
triangle {
<4,>, <4,>, <3.75,>
texture { TBlue }
}
triangle {
<4,>, <3.75,>, <3.75,>
texture { TBlue }
}

triangle {
<5,>, <0,>, <0,>
texture { TPurple }
}
triangle {
<5,>, <0,>, <5,>
texture { TPurple }
}
triangle {
<3.75,>, <1.25,>, <1,>
texture { TPurple }
}
triangle {
<3.75,>, <1,>, <4,>
texture { TPurple }
}

rotate x*-90
}

Cámara
Para efectos de presentación se moverá la cámara a otro punto para poder notar mejor la sombra y el efecto de reflejo de el piso en el objeto, reemplazando la cámara por lo siguiente.


camera {
location <15,>
look_at <0,>
}

Labels: ,

Tuesday, November 27, 2007

Mi carro en Perspectiva

Mi carro en Perspectiva
Dibujado de un carro en OpenGL y su proyección en Perspectiva
PDF File
Jose Angel Espinoza Portillo
Tarea 5 • Graficacion • 31 Octubre 2007


Trabajo realizado
Se utilizaron unos códigos implementados en una tarea anterior donde ya esa declarada la estructura de datos para los nodos que dan la forma del carro y de las caras del mismo, ademas de un conjunto de funciones ya implementadas donde podemos modificar el código para utilizarlo para nuestros fines en este reporte.

Archivos los archivos importantes para este reporte son
painter.cpp: Donde se encuentra la interfaz de la ventana de visualización.
quad.cpp: Es en este archivo donde se visualiza el modelo y también donde se dibujan y modifican las matrices de transformación implementadas.

Trabajo a realizar
Para que un objeto pueda tener una proyección en perspectiva hay que generar el efecto de que una cámara lo esta rodeando. Esta es una transformación que se puede efectuar en la matriz del objeto o en la matriz de proyección. Pero se elige hacer la modificación directamente en el modelo, ya que es preferible modificar el modelo que la proyección ya que tiene mas espacio en su pila de matrices y hay menos posibilidades de errores.
Para eso se utilizara un método de entrada no utilizado antes en este curso. Que es el teclado para dar comandos, se designan algunas teclas para que se mueva hacia arriba, abajo y ambos lados al igual que un zoom para determinar el acercamiento o alejamiento del objeto desde el punto de vista.

El código
Modificaciones que se tienen que hacer a el código anterior.
Para poder implementar una vista en perspectiva, se tienen que eliminar a toda relación con la visualización ortográfica empezando por las funciones glOrtho que están ubicadas por todo el archivo quad.cpp.
Se declaran algunas variables las cuales definen la altura del punto de visión y el ángulo de rotación del mismo, ademas de una variable step la cual define la cantidad de moviendo que hay entre un estado y otro.
Se modifica la función keyPressEvent, la cual es la que responde a las entradas de comandos quedando como se muestra a continuación:

void Quad::keyPressEvent ( QKeyEvent * e )
{
float step = 10;
switch ( tolower(e->key()) ) {
case '+':
signo = 1;
break;
case '-':
signo = -1;
break;
case 'a':
azi -= step;
break;
case 's':
ele -= step;
break;
case 'd':
azi += step;
break;
case 'w':
ele += step;
break;
case 'z':
zoom += 1;
break;
case 'x':
zoom -= 1;
break;
}
repaint();
}

paintGL
En esta función se debe de hacer la transformación de el ángulo de visión y dibujar el objeto al final para que la transformación de perspectiva surja efecto. Para esto primero hay que hacer:

glMatrixMode (GL_PROJECTION);
glLoadIdentity ();

gluPerspective(30,1,0.01,100);

que carga la matriz defaul a GL_PROJECTION la carga y la asigna una perspectiva.
Luego se hacen los cálculos de el punto donde estará el ojo de visión y aplicarle la transformación a el GL_MODEL con el gluLookAt de la siguiente manera.

glMatrixMode(GL_MODELVIEW);
glLoadIdentity (); /* clear the matrix */
eye[0] = zoom *sin(azi*PI/180) * cos(ele*PI/180);
eye[1] = zoom *sin(ele*PI/180) ;
eye[2] = zoom *cos(azi*PI/180) * cos(ele*PI/180);
printf("%f %f %f\n",eye[0],eye[1],eye[2]);
gluLookAt(eye[0],eye[1],eye[2],0,0,0,0,1,0);

recordando que zoom, azi y ele están controlados por las teclas presionadas.
Esto debe de estar antes de dibujar el objeto ya que esto definirá la posición en que se dibujara el objeto en el espacio y en la pantalla.

Labels: ,

Saturday, October 20, 2007

Mi carro en OpenGL


Mi carro en OpenGL
Dibujado de un carro en OpenGL y su proyección Ortogonal
Jose Angel Espinoza Portillo
Tarea 4 • Graficacion • 24 Octubre 2007


El FrameWork
Se utilizo un conjunto de códigos pre-configurados y listos para cargar una entidad de OpenGL en un widget de Qt, estos códigos fueron entregados por el Dr. Luis Gerardo de la Fraga y pude ser encontrado en el siguiente sitio: http://delta.cs.cinvestav.mx/~fraga/Cursos/Graficacion/2007/.
Algunas de las funciones ya implementadas son la rotación al dar click en el QGLWidget y arrastrar hacia alguna dirección.

Archivos
Utilizando el framework original de trabajo llamado “quad”. El cual contiene los archivos de código siguientes:
  • painter.cpp y painter.h: Implementación del QWidget es la ventana principal del sistema, aquí se implementan los botones, geometría, eventos y elementos que se observan en la ventana de la aplicación.
  • quad.cpp y quad.h: Implementa del QGLWidget que representa a el área en la cual se va a dibujar. Incluye funciones de trazado de inicialización de estados y de modos de renderización de el área de trazado.
  • main.cpp: Es el código que iniciativa la aplicación y le da la ejecución a el Qt para que interprete las instrucciones especificadas en canvas.cpp.


Diseño de el Carro
Especificación de las características de el carro y sus vértices.



Antes de empezar a programar hay que desarrollar una estructura de hilos para identificar la forma de el vehículo vista desde varios ángulos, y para especificar la dimensión de sus puntos (vértices).

De las estructuras anteriores se tomara la distancia de sus puntos desde un origen imaginario para definir un arreglo de vectores v1.



Definiendo el arreglo “v1”
Este arreglo se define en el archivo quad.h, para que pueda usarse en la clase, es inicializada en el constructor junto a su especificación con los puntos que en ella se representan de la siguiente manera.

Quad::Quad( QWidget *parent, const char *name )
...;
v1[0][0] = 0.0; v1[0][1] = 0.0; v1[0][2] = 4.0;
v1[1][0] = 5.0; v1[1][1] = 0.0; v1[1][2] = 4.0;
v1[2][0] = 5.0; v1[2][1] = 8.0; v1[2][2] = 4.0;
v1[3][0] = 0.0; v1[3][1] = 8.0; v1[3][2] = 4.0;

v1[4][0] = 1.0; v1[4][1] = 2.0; v1[4][2] = 4.0;
v1[5][0] = 4.0; v1[5][1] = 2.0; v1[5][2] = 4.0;
v1[6][0] = 4.0; v1[6][1] = 7.0; v1[6][2] = 4.0;
v1[7][0] = 1.0; v1[7][1] = 7.0; v1[7][2] = 4.0;

v1[8][0] = 1.25; v1[8][1] = 2.75; v1[8][2] = 5.25;
v1[9][0] = 3.75; v1[9][1] = 2.75; v1[9][2] = 5.25;
v1[10][0] = 3.75; v1[10][1] = 6.1; v1[10][2] = 5.25;
v1[11][0] = 1.25; v1[11][1] = 6.1; v1[11][2] = 5.25;

v1[12][0] = 0.0; v1[12][1] = 0.0; v1[12][2] = 1.0;
v1[13][0] = 5.0; v1[13][1] = 0.0; v1[13][2] = 1.0;
v1[14][0] = 5.0; v1[14][1] = 8.0; v1[14][2] = 1.0;
v1[15][0] = 0.0; v1[15][1] = 8.0; v1[15][2] = 1.0;
...;
}


Definiendo los valores en v1[n][o], v1[n][1] y v1[n][2] en los planos ‘x’, ‘y’ y ‘z’ respectivamente.

Dibujando el Carro
El arreglo anterior no es suficiente para que una figura sea dibujada en el espacio tridimensional, hay que indicarle a el OpenGL como debe unir los puntos anteriores y esto se hace como a continuación:

void Quad::paintGL(void){
...;
glBegin(GL_QUADS);
glColor3f( 1.0, 0.0, 0.0 );
glVertex3fv( &v1[0][0] );
glVertex3fv( &v1[1][0] );
glVertex3fv( &v1[2][0] );
glVertex3fv( &v1[3][0] );

glVertex3fv( &v1[8][0] );
glVertex3fv( &v1[9][0] );
glVertex3fv( &v1[10][0] );
glVertex3fv( &v1[11][0] );

glColor3f( 0.0, 1.0, 0.0 );
glVertex3fv( &v1[12][0] );
glVertex3fv( &v1[13][0] );
glVertex3fv( &v1[14][0] );
glVertex3fv( &v1[15][0] );

glColor3f( 1.0, 1.0, 1.0 );
glVertex3fv( &v1[0][0] );
glVertex3fv( &v1[3][0] );
glVertex3fv( &v1[15][0] );
glVertex3fv( &v1[12][0] );

glVertex3fv( &v1[8][0] );
glVertex3fv( &v1[4][0] );
glVertex3fv( &v1[7][0] );
glVertex3fv( &v1[11][0] );

glColor3f( 0.0, 0.0, 1.0 );
glVertex3fv( &v1[0][0] );
glVertex3fv( &v1[1][0] );
glVertex3fv( &v1[13][0] );
glVertex3fv( &v1[12][0] );

glVertex3fv( &v1[4][0] );
glVertex3fv( &v1[5][0] );
glVertex3fv( &v1[9][0] );
glVertex3fv( &v1[8][0] );

glColor3f( 1.0, 1.0, 0.0 );
glVertex3fv( &v1[1][0] );
glVertex3fv( &v1[2][0] );
glVertex3fv( &v1[14][0] );
glVertex3fv( &v1[13][0] );

glVertex3fv( &v1[5][0] );
glVertex3fv( &v1[6][0] );
glVertex3fv( &v1[10][0] );
glVertex3fv( &v1[9][0] );

glColor3f( 1.0, 0.0, 1.0 );
glVertex3fv( &v1[2][0] );
glVertex3fv( &v1[3][0] );
glVertex3fv( &v1[15][0] );
glVertex3fv( &v1[14][0] );

glVertex3fv( &v1[10][0] );
glVertex3fv( &v1[11][0] );
glVertex3fv( &v1[7][0] );
glVertex3fv( &v1[6][0] );
glEnd();
...;
}


Problemas


Al implementar el código anterior se detecto un problema con el eje de rotación y la orientación de los puntos, el dibujo se dibujaba como en esta figura:
Para solucionar estos problemas se le resto a todos los puntos la mitad del punto con mayor unidad de cada vértice y se intercambiaron los puntos de ‘z’ y ‘y’ con el siguiente código:

for (n=0;n<16;n++){ n="0;n<16;n++){" u =" v1[n][1];">

Calculando la proyección

Utilizando una matriz de transformación.

Principios matemáticos
Como fue visto en clase para hacer una proyección ortogonal es necesario un valor l para indicar la “Profundidad” visible del objeto y un ángulo a para designar la inclinación de la proyección y asignarlo a una matriz para especificar que transformación, la cual esta expresada en la Tabla (matriz) 01.
Tabla (matriz) 01

La cual multiplicada por la matriz de el objeto se dará el efecto deseado.

Implementación
Para la implementación de matrices en OpenGL se debe utilizar matrices tipo cuaternion que se implementa como un vector de 16 elementos de algún tipo en este caso GLfloat (que es una implementación de OpenGL que garantiza la potabilidad del tipo float en diferentes arquitecturas ) y se declara:

GLfloat matriz2[16];

Como básicamente es una matriz con ceros, se asignaron estos (los ceros) a todos los elementos y luego basandonos las posiciones de los indices señalados en la Tabla 02.
Tabla 02

Se escribió la matriz de la siguiente manera:

matriz2[0]=1;
matriz2[2]=-l*cos((angle*PI)/180);
matriz2[5]=1;
matriz2[6]=-l*sin((angle*PI)/180);
matriz2[15]=1;

Y luego antes de escribir el código de la representación de la figura escribir:

glMultMatrixf(matriz2);

Problema
Pero al implementar este código tal cual con las bases antes mencionadas encontrábamos otro problema, que era básicamente que no parecía dibujar nada en la pantalla, después de algunas comprobaciones matemáticas y con otros objetos nos percatamos de un patrón del error, el cual era básicamente la inversión de los indices de la matriz y fue en ese momento donde se descubrió que OpenGL no interpretaba los indices del cuaternion de la manera que inducimos sino como en la Tabla 03, y al final queda como a continuación:



matriz2[0]=1;
matriz2[8]=-l*cos((angle*PI)/180);
matriz2[5]=1;
matriz2[9]=-l*sin((angle*PI)/180);
matriz2[10] = 0.00001; /* Arregla un depth bug */
matriz2[15]=1;

Donde se usan l y angle que explicare a continuación.

Tabla 03



El painter
Dibujado de los componentes a utilizar
Se implementan por primera vez los objetos QSlider, para dar mas inter actividad a el sistema y conectandolo a unos SLOTS’s en el quad que modifican el valor de a (angulo) o l que se usan en el proceso de dibujado de el objeto en la ventana OpenGL.

Forma final de el Ejecutable

El cual tiene un switch entre la manipulación (Rotación) de el objeto que el Dr. de la Fraga tenia implementado originalmente con el nuevo objeto y la vista de la proyección del cuerpo. Los slides que modifican los valores de l y a (angulo).

Conclución
  • Es relativamente sencillo crear objetos 3D en OpenGL, pero lo que es complicado es la estructura que devén de tener los datos para su apropiado manejo.
  • Nunca seré un diseñador de autos.

Labels: ,

Monday, October 1, 2007

Dibujando un Reguilete

Vercion en PDF

Con QT y C++
Jose Angel Espinoza Portillo
Graficación
Septiembre - Octubre 2007


Preámbulo
Utilizando el framework original de trabajo llamado “linetest”. El cual contiene los archivos de código siguientes:


  • painter.cpp y painter.h: Implementación del QWidget es la ventana principal del sistema, aquí se implementan los botones, geometría, eventos y elementos que se observan en la ventana de la aplicación.

  • canvas.cpp y canvas.h: Implementa del QWidget que representa a el área en la cual se va a dibujar. Incluye funciones de trazado de lineas las cuales son la función en la que me base para dibujar el REGUILETE.

  • main.cpp: Es el código que iniciativa la aplicación y le da la ejecución a el Qt para que interprete las instrucciones especificadas en canvas.cpp.



Figura 1.

Insertar Botones a el FrameWork proporcionado
Se agrego el inicio del constructor de Painter::Painter() en painter.cpp


QPushButton *boton1 = new QPushButton("Direccion");
boton1->setFont( QFont( "Times", 18, QFont::Bold ) );
connect( boton1, SIGNAL(clicked()), canvas, SLOT(changeDirection()) );

QPushButton *boton2 = new QPushButton("Start/Stop");
boton2->setFont( QFont( "Times", 18, QFont::Bold ) );
connect( boton2, SIGNAL(clicked()), canvas, SLOT(switchMotioin()) );

Para crear la instancia en memoria de los botones con nombres boton1 y boton2.
Al final de la misma función se agrego:

leftBox->addWidget( boton1 );
leftBox->addWidget( boton2 );

Justo antes del “setLayout(grid);”, al compilar se vera una pantalla como en la Figura 1.

Comunicación entre el Canvas y el Painter
Este proceso a sido documentado anteriormente, así que me limito a agregar solo las modificaciones realizadas para este proyecto.
Se agregaron los Slots changeDirection y switchMotioin, para que puedan se accesados desde los botones del painter como se explico en el punto anterior y timeDone para se acezado desde un objeto QTimer, que se explicara a continuación.

Solucionando el Problema
Como un requisito de este problema es hacer que los reguiletes roten, se necesitó planear 3 partes:

  • Desarrollar una función drawReguilete a la cual le pasan por parámetros el numero de astas del reguilete y su centro y lo dibuja.

  • Agregar un QTimer para determinar el lapso para cambio de coordenadas rotación.

  • Programar las funciones que administren los estados de los últimos dos, puntos.


Desarrollando la función drawReguilete()
Basado en la implementación ya dada por el profesor para dibujar un destello la función de reguilete se implemento como sigue:

void Canvas::drawReguilete(int cx, int cy, int lados, QPainter *p){
int incrang = 360/lados; // Incremento del angulo para saber el angulo medio de cada hoja del reguilete
int l = 50; // Se define un largo l de las lineas de las hojas

int n = 360/incrang; //Se define el numero de repeticiones del algoritmo

for ( int i=0; isetPen(QColor("Blue"));
MidPointLine( cx, cy, px, py, p ); // Se dibuja la linea superior
MidPointLine( cx, cy, px2, py2, p );// Se dibuja la linea inferior
MidPointLine( px2, py2, px, py, p );// Se dibuja la linea que une las anteriores para cerrarla
}
}

Agregando el QTimer
Esta es un objeto que te llama una función cada determinado tiempo que el programador le especifique, para implementarla en el código, se agrego la siguiente librería en canvas.cpp:

#include

y dentro del constructor Canvas::Canvas() se agrego el siguiente codigo:

tiempo = new QTimer(this);
connect( tiempo, SIGNAL(timeout()), this, SLOT(timeDone()));

El cual instancia en memoria el el objeto QTimer, en la variable tiempo, y la conecta en su SIGNAL timeout() al objeto canvas en su SLOT timeDone(), el cual se describe a continuación:

void Canvas::timeDone(){
angulo += (10 * direccion);
repaint();
}

En este código se puede ver que se presenta la variable dirección, esta es manejada por las funciones de administración de estados y define la dirección de rotación de los reguiletes, también se observa la variable ángulo que se usa en el dibujado de el reguilete, como el ángulo acumulado de rotación del sistema.

Funciones de administración de estados.
Las siguientes funciones son las que responden a los SLOTS changeDirection y switchMotioin las cuales administran el cambio de estados de el reguilete por medio de la variables globales dirección y tiempo.

void Canvas::changeDirection(){
direccion *= -1;
}

void Canvas::switchMotioin(){
if (tiempo->isActive()){
tiempo->stop();
}else{
tiempo->start(400);
}
}

En changeDirection solo se multiplica su contenido por -1 haciendo que a todo lo que sea multiplicado esta variable tendrá una dirección contraria a la original.
Y en switchMotioin se pregunta a tiempo si esta activo (si se esta ejecutando algún tonteo de lapsos), si es así lo detiene de lo contrario lo inicia.

Labels: ,

Friday, September 21, 2007

Dibujar Fractales.

Vercion en PDF




Dibujar
los Fractales



Con
QT y C++



Jose
Angel Espinoza Portillo



Graficación



Septiembre
2007



Preámbulo



Se
proporciono un Framework de trabajo en el cual se harían las modificaciones. El
mismo ya era auto suficiente. Entonces solo era cuestión de modificarlo y
acomodarlo a nuestras necesidades y explotarlo al máximo.



El
FrameWork consta de 5 archivos de código principales:





painter.cpp y painter.h: Es la implementación del QWidget que resulta ser la ventana
principal del sistema, donde se implementan los botones, geometría, algunos
eventos y demás elementos que se observan en la ventana de la aplicación.





canvas.cpp y canvas.h: Es la implementación del QWidget que representa a el área en
la cual se va a dibujar. Incluye funciones de trazado de lineas y la activación
del evento (SIGNAL()) que dice la posición del puntero y las
mismas funciones que se invocan cada que se dibuja un objeto en sus limites.





main.cpp:
Es el código que iniciativa la aplicación y le da la ejec
ución a el Qt
para que interprete las instrucciones especificadas en canvas.cpp.



Insertar Botones a el FrameWork proporcionado



Se
agrego el inicio del constructor de Painter::Painter() en painter.cpp



QPushButton *boton1 = new QPushButton("A");



boton1->setFont( QFont( "Times", 18, QFont::Bold ) );





QPushButton *boton2 = new QPushButton("B");



boton2->setFont( QFont( "Times", 18, QFont::Bold ) );





QPushButton *boton3 = new QPushButton("C");



boton3->setFont( QFont( "Times", 18, QFont::Bold ) );





QPushButton *boton4 = new QPushButton("D");



boton4->setFont( QFont( "Times", 18, QFont::Bold ) );







Figura 1.



Para
crear la instancia en memoria de los botones con nombres boton1, ..., boton4.



Al
final de la misma función se agrego:





leftBox->addWidget( boton1 );



leftBox->addWidget( boton2 );



leftBox->addWidget( boton3 );



leftBox->addWidget( boton4 );





Justo
antes del “setLayout(grid);”,
al compilar se vera una pantalla como en la Figura 1.



Diferentes dibujos?



En
el archivo canvas.cpp, existe una función denominada Canvas::paintEvent() la cual es llamada cada vez que el cuadro de canvas es
redibujado, es en esta función donde mandas llamar la función Canvas::testLines() en la
cual se dibuja el patrón de la Figura 1 la cual venia como único patrón
predeterminado a dibujar.



Había
que modificar Canvas::paintEvent()
para que pudiera elegir en una serie de opciones que iban a ser seleccionados
por el usuario dependiendo del dibujo que quisiera desplegar. Así que se
declararon 4 funciones, una para cada patrón posible a dibujar y una variable
kind (propiedad) de el objeto Canvas la cual iba a ser quien decidiera que
patrón iba a ser dibujado el cual seria inicializado a cero en el constructor
de Canvas.



La
función Canvas::paintEvent()
quedo así:



void Canvas::paintEvent( QPaintEvent * )



{



QString s = "Angle = " + QString::number( ang );



QPainter p( this );



p.drawText( w/2 + 140, h/2, s );





switch (kind){



case 0 :testLines( &p );break;



case 1 :dibujo1( &p );break;



case 2 :dibujo2( &p );break;



case 3 :dibujo3( &p );break;



case 4 :dibujo4( &p );break;



}



}











Comunicación entre el
Canvas y el Painter



Para
que al momento de darle click en un botón en el Painter responda el Canvas hay
que agregar las posibles respuestas de Canvas para cada botón, estas son denominadas
SLOTS() y se declaran en el archivo .h con la etiqueta “public slots:”. Para
cada posible botón se declaro un slot. Esto se hizo agregando el siguiente
código a canvas.h:



public slots:



void setKind1();



void setKind2();



void setKind3();



void setKind4();





y
al mismo tiempo agregando a canvas.cpp las siguientes funciones:



void Canvas::setKind1()



{



kind
=
1;



repaint();



}



void Canvas::setKind2()



{



kind
=
2;



repaint();



}



void Canvas::setKind3()



{



kind
=
3;



repaint();



}



void Canvas::setKind4()



{



kind
=
4;



repaint();



}



las
cuales actualizan la variable kind y mandan redibujar el Canvas.



Para
que el objeto Painter pueda hacer uso de estos nuevos SLOT()’s se tiene que
conectar el comportamiento de los botones descritos anteriormente a el SLOT() que
le corresponde quedando el código de painter.cpp de la siguiente manera:





QPushButton *boton1 = new QPushButton("A");



boton1->setFont( QFont( "Times", 18, QFont::Bold ) );



connect( boton1, SIGNAL(clicked()),
canvas, SLOT(setKind1()) );





QPushButton *boton2 = new QPushButton("B");



boton2->setFont( QFont( "Times", 18, QFont::Bold ) );



connect( boton2, SIGNAL(clicked()),
canvas, SLOT(setKind2()) );





QPushButton *boton3 = new QPushButton("C");



boton3->setFont( QFont( "Times", 18, QFont::Bold ) );



connect( boton3, SIGNAL(clicked()),
canvas, SLOT(setKind3()) );





QPushButton *boton4 = new QPushButton("D");



boton4->setFont( QFont( "Times", 18, QFont::Bold ) );



connect( boton4, SIGNAL(clicked()),
canvas, SLOT(setKind4()) );










Dibujo de patrones.



Hasta
este momento hemos conectado Painter y Canvas, y unido sus funciones para que
se modifique que patrón de dibujo con el click de cada botón. Pero toda vía no
hemos definido los patrones así que se empezara a mostrar el código usado en
cada función para desplegar el patrón en el Canvas.



dibujo1()



Utiliza
la función dibujo1Cuadro()
para dibujar un rectángulo entre sus 4 combinaciones de sus puntos puntos:



void Canvas::dibujo1Cuadro(int x, int y, int x0, int y0, QPainter *p ){





MidPointLine(
x0+x, y0+y, x0+x, y0-y, p );



MidPointLine(
x0+x, y0-y, x0-x, y0-y, p );



MidPointLine(
x0-x, y0-y, x0-x, y0+y, p );



MidPointLine(
x0-x, y0+y, x0+x, y0+y, p );



}



Seguimos
con la implementación del patrón (Figura 2.):



void Canvas::dibujo1( QPainter *p )



{



int cx = w/2; // canvas center



int cy = h/2; // canvas center



int incrang = 5;



int l = 100;





int n = (360/incrang)/4;



// int n = 19;





for ( int i=0;
i < n; i++ ) {



float ang = i*incrang;





ang
= ang * ANGTORAD;





float val = l*cos(ang);



//float val =
l*cos(ang) + cx;



int px = Round( val );





val
= l*sin(ang);



//val = l*sin(ang) +
cy;



int py = Round( val );





//MidPointLine( cx,
cy, px, py, p );



dibujo1Cuadro(px
,py ,cx ,cy, p);



}



}





Figura 2.



dibujo2()



Utiliza
la función dibujo2Cuadro()
para dibujar un cuadro entre 4 puntos desfasados en algún ángulo:



void Canvas::dibujo2Cuadro(int x, int y, int x0, int y0, QPainter *p ){





MidPointLine(
x0+x, y0+y, x0-y, y0+x, p );



MidPointLine(
x0-y, y0+x, x0-x, y0-y, p );



MidPointLine(
x0-x, y0-y, x0+y, y0-x, p );



MidPointLine(
x0+y, y0-x, x0+x, y0+y, p );



}



Seguimos
con la implementación del patrón (Figura 3.):



void Canvas::dibujo2( QPainter *p )



{



int cx = w/2; // canvas center



int cy = h/2; // canvas center



int incrang = 10;



int l = 100;





int n = (360/incrang)/4;



// int n = 19;





for ( int i=0;
i < n; i++ ) {



float ang = i*incrang;





ang
= ang * ANGTORAD;





float val = l*cos(ang);



//float val =
l*cos(ang) + cx;



int px = Round( val );





val
= l*sin(ang);



//val = l*sin(ang) +
cy;



int py = Round( val );





//MidPointLine( cx,
cy, px, py, p );



dibujo2Cuadro(px
,py ,cx ,cy, p);



}



}



Figura 3.



dibujo3() : Hilbert



Al
inicio de la función se establecen valores como el tamaño de segmento y ángulo
inicial y procede a pasarle el control a una función denominada hilbert_level() a la cual se
le envía la información de nivel, dirección y distancia del segmento, la función
se despliega a continuación:



void Canvas::dibujo3( QPainter *p )



{



int l = w < h?w/32:h/32, angulo=0;



xo
= xd =
0; yo = yd = 0;



p->setPen("White");



MidPointLine(
0, h/2, w, h/2,
p );



MidPointLine( w/2, 0, w/2, h, p );





p->setPen("Blue");



hilbert_level(5, 0, l, p);



printf("///////////////");





}



Se
desarrollo una una función move(),
que se encarga de dibujar un segmento en una dirección, se muestra a
continuación:



void Canvas::move(int a, int l, QPainter *p){



switch(a){



case 0:yd -= l; break;



case 1 : xd -= l; break;



case 2 :yd += l; break;



case 3 : xd += l; break;



}



MidPointLine(
xo, yo, xd, yd, p );



xo=
xd;



yo=
yd;



}





La
función hilbert_level
es una función recursiva la cual dibuja el fractal de Hilbert, y se desarrolla
a continuación (Figura 4.):



void Canvas::hilbert_level(int level, int direction, int l, QPainter *p)



{



if (level==1) {



switch (direction) {



case 1:



move(3, l, p); move(2, l,
p); move(1, l, p);



break;



case 3:



move(1, l, p);



move(0, l, p);



move(3, l, p);



break;



case 0:



move(2, l, p);



move(3, l, p);



move(0, l, p);



break;



case 2:



move(0, l, p);



move(1, l, p);



move(2, l, p);



break;



}



}
else {



switch (direction) {



case LEFT:



hilbert_level(level-1,0,l,p);



move(RIGHT,
l, p);



hilbert_level(level-1,1,l,p);



move(DOWN,
l, p);



hilbert_level(level-1,1,l,p);



move(LEFT,
l, p);



hilbert_level(level-1,2,l,p);



break;



case RIGHT:



hilbert_level(level-1,2,l,p);



move(LEFT,
l, p);



hilbert_level(level-1,3,l,p);



move(UP,
l, p);



hilbert_level(level-1,3,l,p);



move(RIGHT,
l, p);



hilbert_level(level-1,0,l,p);



break;



case UP:



hilbert_level(level-1,1,l,p);



move(DOWN,
l, p);



hilbert_level(level-1,0,l,p);



move(RIGHT,
l, p);



hilbert_level(level-1,0,l,p);



move(UP,
l, p);



hilbert_level(level-1,3,l,p);



break;



case DOWN:



hilbert_level(level-1,3,l,p);



move(UP,
l, p);



hilbert_level(level-1,2,l,p);



move(LEFT,
l, p);



hilbert_level(level-1,2,l,p);



move(DOWN,
l, p);



hilbert_level(level-1,1,l,p);



break;



}



}



}



Figura 4.



dibujo4(): KGen



Esta
función dibuja un fractal denominado KGen. Inicia estableciendo los valores
iniciales y de largo total del segmento a dibujar. Se muestra a continuación la
implementación:



void Canvas::dibujo4( QPainter *p )



{



xo
=
0; yo = h/2;



angulo
=
0;



int l = w;



int i;



KGen
(l,
4, p);



}



La
funcion KGen es una función recursiva la cual es la encargada de dibujar el
fractal, se le proporciona el largo en que
se de ve dibujar el segmento al que se le esta llamando y el nivel de
implementación. Se muestra a continuación la implementación (Figura 5.):



void Canvas::KGen(int l, int nivel, QPainter *p){



if (nivel==0){



dibujo3CalculaPuntos(
l, angulo, p, nivel);



}else{



nivel--;



l=Round(l/3);



KGen(l,
nivel, p);



angulo+=60;



KGen(l,
nivel, p);



angulo-=120;



KGen(l,
nivel, p);



angulo+=60;



KGen(l,
nivel, p);



}



}



Figura 5.









Labels: ,