Buscar este blog

miércoles, 29 de diciembre de 2010

Versión v0.2


Después de un mes con el proyecto dejado de lado, he aprovechado las navidades para trabajar en él un poco, y la verdad es que los resultados son satisfactorios, por ahora.

Los cambios son sencillos, he programado un algoritmo basado en fuerzas para imprimir el árbol, la cámara se mueve si se mantiene pulsado el ratón, y también hay programado un algoritmo de coloreado inventado por mí. Además, se ven los nombres de los clados que representan los nodos cuando se coloca el ratón encima.

He aquí un video de ejemplo:



Mas técnicamente, los dos algoritmos principales son los siguientes:


Algoritmo basado en resortes


Es el algoritmo usado para calcular la posición de los nodos del árbol. Es un algoritmo de la familia de los algoritmos basados en fuerzas, conocido popularmente como Spring Embedder (resortes embebidos). Este algoritmo consiste en lo siguiente: cada arista es, en realidad, un resorte, —es decir, un muelle— que tiene una longitud dada. Cada pareja de nodos no conectados, se unirán con una arista ficticia que también modelará a un resorte. Las aristas verdaderas serán resortes de atracción, y las aristas ficticias serán resortes de repulsión.



Las posiciones de los nodos se inicializan aleatoriamente, y se unirán con muelles de la forma indicada. Cada resorte intentará volver a su posición inicial, generándose un sistema de fuerzas que buscará una situación de equilibrio. Es como si forzaramos una serie de puntos unidos con muelles, algunos estirados y otros comprimidos, y luego tiraramos el conjunto al aire. El gráfico anterior ilustra bastante bien su comportamiento, dando finalmente una visualización elegante del árbol.


Algoritmo basado en intervalos de colores


Este algoritmo es invención mía, y funciona de la siguiente forma: a cada nodo se le asigna un intervalo de colores, y se colorea con el centro de dicho intervalo. Dicho intervalo se parte en tantos subintervalos como hijos tenga el nodo, y, análogamente, se colorea con su centro. Se procede recursivamente para todo el árbol, siendo el intervalo de la raíz del árbol el propio cubo RGB (y por tanto, la raíz del árbol será de color gris, pues es el centro del cubo).

La forma de partir cada intervalo es el siguiente. Partiendo del cubo RGB asignado a la raíz, primero se elige para particionar la dimensión R —es decir, la del color rojo—. Así, si la raíz tiene n hijos, el cubo se partirá en n rectángulos 3D, donde el ancho en la dimensión R de cada rectángulo 3D será el ancho del nodo raíz dividido entre 'n'. Para el siguiente nivel, cada cubo se partirá en la dimensión G, luego en la B, luego nuevamente en la R, y así sucesivamente.

La idea de éste algoritmo es que cada nodo sea dueño de una región, del cubo RGB de la que ninguno de sus hijos podrá escapar. Así, aunque en los primeros niveles haya saltos en la gama de colores —sobre todo si cada nodo tiene pocos hijos—, a medida que se incrementa la profundidad la gama de colores de nodos relacionados será mas homogénea, y el propio coloreado será un indicador gráfico de la cercanía entre nodos.

Aspectos por cambiar o mejorar

Hay todavía muchas cosas importantes por mejorar en la aplicación. El más importante por ahora es que la aplicación no cuenta con ninguna base de datos externa. El árbol está creado nodo a nodo en el fichero program.cpp, es decir, embebido en el propio código. Este es quizás el siguiente aspecto crucial de la aplicación, tener una base de datos externa, y crear la visualización del árbol leyendo los datos a partir de dicha base de datos. Seguramente usaré posgreeSQL.

Otros aspectos menores son referidos, por ejemplo, al peso de las aristas. Por ahora, cada arista tiene el mismo peso, que viene indicado en el propio algoritmo basado en resortes —en realidad, no existe aún ninguna clase arista que tenga un atributo peso, sencillamente es una pareja de nodos—. Habrá que asignar un peso a cada arista, usando algún criterio relacionado con el árbol filogenético —por ejemplo, proporcional al número de nietos que tenga un hijo—, y adaptar el algoritmo de resortes para que éste cambio no produzca efectos indeseables en la visualización.

Otro aspecto a cambiar es el posicionado del árbol. El árbol entero es movido según el sistema de fuerzas que provoquen los resortes, y habrá que cambiar el algoritmo para que, al menos la raíz, quede fija en un punto dado, porque a veces el árbol se mueve demasiado hacia un extremo y hay que mover la cámara para volver a centrarlo.

Hasta otra ...
Leer más...

sábado, 13 de noviembre de 2010

Mi primer blur

Bueno, tan pronto como traducí mi aplicación a openGL, ya le añadí el blur. Por ahora el resultado es pobre porque solo me queda perfilar los efectos, pero la dinámica de trabajo, que es lo que me interesaba, ya la conozco. Este es el resultado final:




La visualización es pobre por dos motivos: no hago cálculos de qué color corresponde a cada nodo, ya que todavía estoy viendo como pintar árboles, no cuál es el contenido del árbol, cosa de la que depende el color asignado (y cuestión todavía que tengo que definir). Y las aristas tampoco tienen blur aún (y tampoco se han colocado sombras).

Estos aspectos se definirán ya muy a posteriori, mi siguiente prioridad ahora es programar el algoritmo de visualización del grafo (es decir, el que coloca cada nodo en un lugar adecuado para una estética visualización), y luego, pelearme con la impresión de texto.
Leer más...

Adios Ogre

Desde mi última entrada, han ocurrido muchas cosas en mi proyecto, pero qué han tenido muy poca repercusión en su aspecto actual. Como ya adelanté en la presentación, quería que mi proyecto se pareciera al aspecto de Gource por cuestión de elegancia, y todos éstos cambios tienen su origen en la persecución de ésta idea.

Como un grafo, y por tanto un árbol, no es más que nodos y aristas, los modelos 3D con los que hace falta trabajar son muy sencillos. Sumándole ésto a que el tamaño de cada nodo, o de cada arista, puede ir cambiando en tiempo de ejecución, el dibujado, y con ello los modelos también deberían hacerlo. Ésto me llevo directamente a trabajar con el tipo ManualObject de Ogre, que te permite definir los modelos vértice a vértice, definir subobjetos, y cambiarlos en tiempo de ejecución. Es decir, todo lo que necesitaba, aunque precisamente por trabajar con objetos geométricos a bajo nivel veía a Ogre un recurso demasiado disparatado. Ogre está orientado para trabajar con modelos complejos, en escenarios complejos, con cálculos complejos. Yo no necesito muchos efectos gráficos ni de iluminación, y es todo relativamente sencillo. Pero por tal de no empezar a aprender openGL, por cuestión de tiempo, decidí seguir adelante.

La primera idea para simular el efecto de Gource era mediante el uso de una esfera, con una luz en su centro que la reflejara, para que tuviera el aspecto de una estrella brillante. Cómo se nota que era la primera vez que trabajaba en un contexto 3D. Cuándo tienes un objeto, iluminarlo solo cambia la intensidad de la luz en su superficie, en los lugares donde la luz incida, oscureciéndose a medida que la superficie se aleja de la luz, o se hace más innacebile para ella. Una luz no se verá si no hay ningún objeto en el que reflejarla. Y por poner una luz dentro de un objeto, nunca va a tener un aspecto de "bombilla".

Una vez comprendido ésto, cambié de táctica. Relegé la construcción 3D del árbol en un nuevo objeto, usando el patrón estrategia (StrategyMakeTree). Ahora tenía dos construcciones, una mediante esferas (SphereMakeTree), y otra recurriendo al llamado efecto Tyndall (ColloidMakeTree).

El efecto Tyndall es lo que ocurre cuando un rayo de luz entra en una habitación, o cuando el agua se refleja en el mar. El aire de la habitación, o el agua, tienen una serie de impurezas. Cuando un rayo de luz penetra, cada partícula impura refleja la luz que incide en ella, creando una serie de puntos de luz indistinguibles entre sí para el ojo humano, dando la sensación de un continuo iluminado. Luz reflejada en aire o agua pura no es visible en forma de rayo, debido a que no tiene partículas que puedan reflejar la luz incidente en ellas. En la imágen siguiente se ve un láser que atraviesa dos vasos, uno con agua pura, y otro con impurezas, y se observa como el agua pura no muestra al rayo atravesándolo, mientras que las impurezas disueltas en el agua sí que lo permiten.



Un sistema como el aire o el agua con impurezas, son llamados coloides, y mi nueva idea, era, por supuesto, que cada nodo fuera un coloide. Se crearía una nube de puntos con forma esférica, de forma que en su centro hubiera una mayor densidad, y en el límite de su radio poca. Luego, situando una luz en su centro se simularía un coloide, difuminándose la intensidad lumínica a medida que la luz se alejaba de su centro, hasta diluirse con el fondo negro.

Pero por más formas ideadas para implementar un coloide, ninguna tuvo éxito. Para experimentar, comencé construyendo una esfera que tuviera siempre una misma densidad de puntos. Pero si construía una esfera de poca densidad, se veía en vez de un coloide una nube dispersa de puntos. Si la construía con poca densidad. Se veía una esfera sólida en vez de un coloide. Si hacía una esfera de poca densidad, con mucho radio, y alejando mucho la cámara, se volvía a ver una esfera sólida.

Mi siguiente paso fue ver como lo hacía Gource. Me llevé un tiempo estudiando su código fuente, lo que me llevó a aprender bastantes cosas de openGL para comprenderlo. Explorándo el código descubrí, entre otras cosas, que el efecto de destellos de luz cuando se creaba una rama nueva se llama bloom. El desenfocado que buscaba, blur (blur no es más que borroso en inglés). También descubrí que existe una rama de la teoría de grafos que se llama visualización de grafos, y Gource usa un algoritmo de visualización basado en fuerzas, esto es, que el grafo funciona como un sistema gravitatorio, donde cada nodo afecta a la posición de los restantes nodos, hasta alcanzar una posición de equilibrio, que es la posición final de visualización.

Otro detalle interesante es que, como el árbol está cambiando de posición y orientación constantemente, las aristas están curvadas de modo que incrementen la sensación de movimiento, curvándose la aristas en un sentido semejante al sentido de giro del árbol. Para construir estás aristas curvadas, se hace uso de splines.

La forma que tiene gource de dibujar el blur (el desenfoque), es mediante el uso de texturas. Se especifican las coordenadas de un cuadro, se coloca encima una imágen que contiene un círculo difunado que hace las veces de desenfoque, y encima se coloca otra imágen con el nodo en cuestión. El color de la textura de desenfoque se mezcla con el del nodo, y con eso finalmente parece que es el propio nodo el que brilla.

Intenté hacer lo propio con Ogre, creando la clase GourceianMakeTree. Y empezaron los problemas. Por más vueltas que le daba, no conseguía que la textura se renderizara bien. Sobre el funcionamiento interno de ManualObject existe poca documentación, en la lista de correo de la forja tampoco hubo nadie que me pudiera ayudar de forma totalmente satisfactoria. Incluso un desarrollador con el que mantengo contacto por correo, muy familiarizado con Ogre y openGL, con el que aprendí muchísimo, tampoco supo como resolver mi problema. Todo ello demuestra el poco conocimiento, uso o divulgación, de los ManualObject, lo que me convenció más aún que Ogre no estaba hecho para trabajar de esa forma (ya que nadie más lo hacía).

Así que decidí dejar Ogre, y con ello OIS, y cambiarme a openGL, con Glut primero, y con SDL después. Este paso de glut a SDL fue debido a que, aunque glut sea orientado a eventos -cosa que hace más elegante el diseño para este tipo de aplicaciones-, su sintaxis me obligaba a hacer cosas poco elegantes, como tratar con atributos externos o trabajar con referencias a funciones miembro, con sintaxis prefijada, y sin tener control total sobre la función MainLoop, que es la función de Glut que lleva el control de toda la aplicación.

Una vez perdidos unos cuantos dias aprendiendo openGL, pude finalmente reescribir mi aplicación. El diseño prácticamente no ha cambiado. Las clases se organizan de la misma forma, solo que las funciones miembro sí que son distintas y hacen cosas distintas.

Un detalle curioso (que tuve que descrubir yo, y nunca se advierte cuando se habla de SDL + openGL), entre Glut y SDL es que, mientras Glut toma el sistema de coordenadas del escenario centrado en la pantalla, SDL toma el centro del escenario en la coordenada (0, 0) de la pantalla, es decir, la esquina superior izquierda. Además, la pantalla se convierte en el primer cuadrante invertido, ya que la coordenada y de la pantalla crece desplazándose hacia abajo, como de costumbre en SDL. Es decir, que hay que tener en cuenta que SDL no cambia su comportamiento sea una ventana openGL o una pantalla "clásica".

Y respecto al aspecto actual del proyecto, pocas novedades. Todavía no tengo programado el desenfoque, solo pinto un cuadro blanco por cada clado, conectados por aristas. En la siguiente imágen se muestra una captura.



No hay ningún algoritmo "propio" de impresión del árbol. Sencillamente, los hijos los imprimo en columna, con un desplazamiento x constante, por tanto, los hijos de padres distintos podrían solaparse.
Leer más...

lunes, 25 de octubre de 2010

¿git-svn?, quizás otro día.

Me he llevado día y pico quebrándome la cabeza intentando aclararme sobre como interactuar entre git y svn, sin tener dos repositorios independientes almacenados de forma local. Así que intenté entender el comportamiento de git-svn a fin de usar dicho comando para actualizar svn desde mi repo git.

Sé que eso trae muchos problemas con las ramas del proyecto, que es quizás el aspecto de arquitectura que más dificulta la tarea de su sincronización. Pero partía de una premisa: nunca habrá cambios "nuevos" en el repositorio svn que no haya sido subidos por mí, es decir, nunca voy a necesitar hacer el clásico pull desde svn (que en git-svn, es git svn rebase).

Pero eso no fue suficiente. Para empezar, no conseguí usar el repo de svn como un repo remoto sin más. Primero hay que bajarse el repo svn (con git svn clone), luego usar git de forma normal, sincronizándolo con tu repo git de la web también de forma normal, y todo de forma normal, y cuándo lo desees, con git svn dcommit subes tus cambios a svn. Ésto es aceptable, aunque desearía no verme obligado a hacer un svn clone cuando el repo svn está completamente vacío, estándo el de git con contenido incluido. Sencillamente no me gusta o no me fío del todo.

Pero además, los dcommit de git-svn modifican la información de los commits de git puro, para adaptarlo. No quiero que svn ensucie a git. Además, ésto provoca una "pega" adicional: si realizas un commit, creas una nueva rama, vuelves a la master y realizas un dcommit, cuando intentes mergear la nueva rama no encuentra su punto de anclaje al haber sido modificado por dcommit, lo que produce conflictos.

Ese es un detalle que no me gustaba nada, y que me hacía temer errores en un futuro. No quiero partirme la cabeza con una herramienta, porque las herramientas significan exáctamente lo contrario: ahorrarte trabajo, no producirtelo. Si no veo las cosas claras o no me convencen, las reniego. Y después de tanto, todavía no me llegó a quedar claro como se sincronizaban las ramas y los tags (en general, la jerarquía de directorios de svn) entre git y svn.

Así que, al final, tendré dos copias locales. Cuando quiera actualizar svn, copio los archivos y santas pascuas, cosa que ya me habían aconsejado en la lista de correo del CUSL5.
Leer más...

Cámaras... ¡Acción!

Ya me han confirmado la aceptación en la forja del proyecto. Era obvio que me lo aceptarían, ya que me lo aceptaron en el cusl5 (no creo que se peleen entre ellos), pero había que esperar, y la verdad es que no ha sido tanta la espera. Y ahora tengo todas las herramientas necesarias y todo el contexto para poder empezar a trabajar.

Así que, con todo, ésto son los "cuerpos oficiales" del proyecto:

Y por ahora ésto es todo. A la derecha del blog, hay un gadget llamado "Sitios del proyecto y su autor" con éstas referencias. A medida que vaya configurando y/o añadiendo más sitios se irán comentando en éste blog y se colocará en dicho gadget. Por ejemplo, cuando active la página web principal del proyecto (que seguramente estará basado en la wiki que genera doxygen), se informará y se colocará en dicho gadget. O cuando disponga de documentación, o si activo la lista de correo (cosa que creo innecesaria por ahora), etc. En todo éstos casos, las "noticias" tendrán la etiqueta "Metaproyecto" -cómo ésta entrada-.

Meta es un prefijo que procede del griego y que se usa para indicar que vamos a elevarnos un grado de abstracción. En éste caso, las entradas etiquetadas con metaproyecto indican entradas que hablan sobre cosas del proyecto a gran escala o "desde fuera", como los sitios relacionados con el proyecto, el uso dado a los repositorios, las presentaciones realizadas del mismo, etc; y nunca de detalles sobre implementación, resolución de problemas, confección de ideas para nuevas funcionalidades y demás cuestiones relacionadas con el desarrollo.

Creo que tener bien identificado éste tipo de meta-información es muy necesario, ya es que la que mejor permiten orientar a los "seguidores", y mucho más aún, a los nuevos visitantes. A medida que se vayan colocando nuevas etiquetas con fines especificos o importantes, también se comentarán en entradas de "metaproyecto".

Para no crear complejidad innecesaria que confunda al personal, en la forja de rediris he desactivado todas las opciones que no uso, así, en la página del proyecto de la forja de rediris están desactivadas las opciones de documentación, de foros, de lista de correos, etc; y la visión del contenido del proyecto es mucho más clara: si no encuentras la lista de correo es que no se usa, y todos contentos. Para eso está este blog, y si llegara a tener mucha participación, entonces habilitaré la lista.
Leer más...

domingo, 24 de octubre de 2010

Presentación

Me acaban de confirmar la aceptación de mi nuevo proyecto, FreePhyloTree, en el CUSL5, y aquí inauguro éste blog para ir informando de mi progreso, mis ideas, mis peleas con las librerías, los intentos de suicidio a los que sobreviva y demás florituras que acaezcan en el desarrollo de éste proyecto.

Antes que nada (y por tercera vez, tanto en el CUSL5, como en la forja), explicaré en qué consiste el proyecto. Se llama FreePhyloTree, y es una herramienta de visualización 3D de árboles filogenéticos, también llamados filogramas. ¿Qué es un filograma?, pues un árbol que refleja las relaciones evolutivas entre especies.

Por ejemplo, éste es un filograma bonito y decorado:



Este árbol refleja, por ejemplo, como nosotros estamos más emparentados con los roedores que con las gallinas, ya que el ancestro común con los roedores es posterior al ancestro común con las gallinas, que está más cerca de la raíz. Y también refleja que existe un ancestro común a todos: la raíz del árbol. Para más información sobre la clasificación de las especies y los árboles filogenéticos, pueden visitar éste artículo de mi otro blog: clasificación de los seres vivos. Existen muchas maneras de representar árboles filogenéticos, y aquí se muestran otros ejemplos:





Por mi parte, quiero crear árboles filogenéticos con una apariencia como ésta:



Esta imagen tan bonita y elegante no es ni más ni menos que Gource, una herramienta hecha por google para visualizar el historial de cambios de un proyecto bajo git. Cada nodo de ese árbol es un directorio, y cada hoja, un fichero del proyecto. Gource crea una animación que va modificando ese árbol a la par que se van modificando los ficheros del proyecto (es decir, a medidas que se suceden las versiones del repositorio).

Cuando conocí dicho software, sencillamente me encantó. Unido ésto a que me interesa el campo de la evolución biológica y que además no conocía ningún software que ayudara a su estudio, cuando decidí inscribirme al CUSL5 no se me ocurrió otra cosa que fusionar ambas ideas.

Visualizadores de árboles filogenéticos, existen muchos. Libres menos, pero también los hay, y en realidad hay bastantes. En 3D, también. Pero ninguno es una herramienta didáctica, es sencillamente eso, un visualizador. En FreePhyloTree se pretende camuflar una especie de enciclopedia sobre evolución biológica dentro de un visualizador de árboles filogenéticos: visualizando el árbol, se conocen las relaciones evolutivas, y seleccionando cierto clado, se obtiene la información textual que ayuda a entender su historia y contexto evolutivo: historia de los descubrimientos, época geológica, contexto ecológico, etc. Llevar el seguimiento de la historia evolutiva de una especie se hace, así, mucho más fácil.

Todavía no tengo planificado de qué naturaleza será dicha "enciclopedia": si cada clado se anexará a una página wiki integrada con el sistema, si existirá una línea temporal, con qué tipos de árboles contaremos (filogramas o cronogramas, o una fusión de ambos), o de qué forma se interactuará con la base de datos.

Normalmente, diversos autores tienen diversas ideas sobre la historia evolutiva de un grupo de organismos, lo que provoca una obvia confusión en los estudiantes: es muy complicado entender la filogenia de una especie si en cada referencia se muestra una historia evolutiva distinta; así que también se pretenderá crear una visualización cómoda y comprensible de los distintos posibles árboles que relacionan a un mismo grupo de organismos.

El blog del proyecto, será el blog que estás leyendo. El repositorio principal está alojado en gitorious, y el repositorio secundario, y necesario para el CUSL5, estará alojado en la forja de rediris (pendiente de confirmación). En este último (ya que va con svn, -y ya va siendo hora de permitir git-) guardaré solo los commits importantes, los que añadan alguna funcionalidad nueva y así se facilite el seguimiento del repositorio (y de paso no ensuciamos el historial de commits y no volvemos loco a los evaluadores ;) ). La página principal del proyecto también es la ofrecida por la forja (pendiente de confirmación primero, y de construcción después).
Leer más...