Talk at Hangar.

September 22nd, 2006 § 10 comments § permalink

So yesterday I gave a talk about my experience with processing at the begining processing workshop which is being held at Hangar by Joan Soler.

First part was about my reasons for learning-using-loving processing and how I’ve managed to use it in a commercial context. Then I went into a tutorial explaining the ascii video sketch. Finally i improvised an explanation of a del.icio.us information visualization project I had done at a previous workshop, which i think turned to be the most interesting thing for the audience.

It was my first experience as a speaker and although i don’t think it went too bad, the ascii tutorial didn’t work as I expected. Going too deep into code details doesn’t seem to be approppriate for a one hour session. Lesson learned.

Anyway, here are the slides (in spanish only) and the source files for the ascii tutorial.

Thanks very much to Joan for inviting me and to all the assistants for not leaving the room.

Tutorial de Processing en Castellano

June 14th, 2006 § 5 comments § permalink

Gerald Kogler ha traducido el clásico Processing Tutorial for Macromedia Minds de Josh Nimoy al castellano. Tal y como su nombre indica, si vienes de entornos como flash o director es de lo mejorcito para hacerte con la herramienta. Igualmente, dado que es un tutorial de iniciación, es una buena lectura para los que quieran dar el salto:

Tutorial de Processing para Mentes Macromedia.

Posicionamiento en grid. Bucle anidado vs bucle unico

July 13th, 2005 § 3 comments § permalink

Pues siguiendo con la serie de code-tips-que-no-aportan-nada-nuevo-pero-me-sirven-para-no-olvidarlos, hoy tenemos dos maneras de distribuir objetos en un grid (el código es actionscript pero vale para cualquier lenguaje).

Habitualmente siempre que he tenido que hacer un grid (¿rejilla? ¿grilla?) utilizo dos bucles for anidados. El código suele ser algo así:


// contador de clips
cont = 0;
// separacion del grid respecto al borde
offset = 20;
// separacion entre clips
dist = 10
//-----------------------------------------------------------
// filas
for (i=0; i<5; i++) {
	// columnas
	for (j=0; j<5; j++) {
                // duplicamos un clip a en el escenario
		var nuevoClip = a.duplicateMovieClip("a"+cont, cont);
                // posicionamos
		with (nuevoClip) {
			_x = offset+i*(nuevoClip._width + dist);
			_y = offset+j*(nuevoClip._height + dist);
		}
                // aumentamos el contador
		cont++;
	}
}

El otro día vi en algún sitio una manera de hacerlo con un sólo bucle y no comprendía bien el funcionamiento. El código que vi era algo parecido a esto:


// contador de clips
cont = 0;
// filas
filas = 5;
// columnas
columnas = 6;
// total cuadros
total= filas*columnas;
// separacion del grid respecto al borde
offset = 20;
// separacion entre clips
dist = 10
//-----------------------------------------------------------
for (k=0; k<total ; k++) {
	// duplicar clip b
	var nuevoClip = b.duplicateMovieClip("b"+cont, cont);
	// posicionar
	with (nuevoClip) {
		_x = offset + Math.floor(k % filas)*(nuevoClip._width + dist);
                _y = offset + Math.floor(k / filas)*(nuevoClip._height + dist);
	}
	cont++;
}


Lo fundamental es que si dividimos la posición actual k por el numero de filas y lo convertimos a entero, nos da la fila en la que estamos:

clip 0: k = 0, filas = 5; Math.floor(0 / 5) = 0; // primera fila
clip 1: k = 1, filas = 5; Math.floor(1 / 5) = 0; // primera fila

clip 4: k = 4, filas = 4; Math.floor(4 / 5) = 0; // primera fila
clip 5: k = 5, filas = 5; Math.floor(5/ 5) = 1; // segunda fila

clip 16: k = 16, filas = 5; Math.floor(16 / 5) = 3; // cuarta fila

clip 24: k = 24, filas = 5; Math.floor(24 / 5) = 4; // ultima fila

Para la posicion x utilizamos el operador módulo %. El resto de la misma división que hemos utilizado para la fila, nos da la posicion en la columna:

clip 0: k = 0, filas = 5; Math.floor(0 % 5) = 0; // (el resto es 0) => primera columna
clip 1: k = 1, filas = 5; Math.floor(1 % 5) = 1; //(el resto es 1) => segunda columna

clip 4: k = 4, filas = 4; Math.floor(4 % 5) = 4; // ultima columna
clip 5: k = 5, filas = 5; Math.floor(5 % 5) = 0; // primera columna

clip 16: k = 16, filas = 5; Math.floor(16% 5) = 1; // segunda columna

clip 24: k = 24, filas = 5; Math.floor(24 % 5) = 4; // ultima columna

Luego, simplemente con multiplicar los valores de fila y columna por la distancia entre clips + la anchura o altura de cada clip (nuevoClip._width + dist) (tal y como hicimos también en el primer ejemplo), hallamos la posición del elemento en el grid.

Y para muestra, los dos ejemplos

Y eso es todo.

Pasar funcion como parametro. 2: Multiples parametros.

June 7th, 2005 § 4 comments § permalink

En una entrada anterior comentaba cómo pasar el nombre de una función a otra como parámetro. Sin embargo, no sabía cómo pasarle un número indeterminado de parámetros a la función llamada. Tras varios intentos fallidos, lo dejé en el tintero. Hoy, buscando otra cosa, he encontrado lo que me quedaba para solucionarlo en otro blog. Me explico:

Cada vez que llamamos una función, de forma predefinida se crea dentro de esta un array de nombre arguments, que almacena todos los parámetros pasados.


function a(param1, param2, param3) {
  trace(arguments);
}
a ("pepe", "juan", "jorge");
// la ventana de salida muestra : pepe, juan, jorge
// * ya lo se, qué parametros mas aburridos *

Dado que arguments es un array, podemos hacer todas las operaciones de esta clase con ella. Por ejemplo:


function a(param1, param2, param3) {
  trace(arguments.length);
}
a ("pepe", "juan", "jorge");
// la ventana de salida muestra : 3

La idea era pasar el array de parámetros de una funcion a la segunda, pero ahí me quedé. No había manera de concatenar los parámetros para pasarlos a la función de dentro. Pero… hoy me he encontrado con esto:

Using an array as a list of arguments

Tenía toda la pinta de ser lo que andaba buscando. Y en efecto:

Si utilizo el método function.apply() puedo pasar un array como lista de argumentos.


// array de parametros
d_arr = ["un", "dos"]

function c (arg1, arg2) {
	trace ( arg1+ ", "+arg2);
}
// uso el método function.apply() pasándole el nombre de la matriz 
// como parámetro. *el otro parámetro no nos sirve aquí, por eso paso null.
c.apply(null, d_arr);

Juntando todo esto, pues, tenemos la solución definitiva para pasar cualquier función (tenga parámetros o no) como parámetro de otra:


// función genérica que llamará a cualquier función con cualquier número de parámetros
function a(func, args) {
	// eliminamos el primer elemento del array arguments.
	newArguments = arguments.splice(1, arguments.length);
	// y llamamos a la función desde dentro con function.apply()
	// pasándole el nuevo array arguments como parámetro.
	func.apply(null, newArguments);
}
// función cualquiera, sosa.
function b(arg1, arg2, arg3) {
	// trace de los de toda la vida con 3 parámetros
	trace("Vaya post "+arg1+" "+arg2+" "+arg3);
}
// llamada
a(b, "más", "mal", "explicado.");
// la ventana de salida mostrará "Vaya post más mal explicado"

Y eso es todo. Así no se me olvida.

Pasar funcion como parametro

January 20th, 2005 § 12 comments § permalink

El otro día estaba intentando hacer una función en actionscript que me llamara a otra función después de una pausa aleatoria. Dado que pensaba utilizarla para varias cosas distintas dentro del mismo programa, la llamada a la segunda función debía ser un parámetro, al estilo de setInterval (no utilicé éste por diversas razones). La llamada a la función sería tal que así:


pausaAleatoria(funcionLlamada, valorMin, valorMax);

Entonces me topé con un problema que me ha surgido muchas veces y hasta ahora no había podido resolver: ¿Cómo ejecuto la función cuyo nombre he pasado como parámetro dentro de la otra? Dado que es lo que hace precisamente setInterval, resulta lógico que sea posible hacerlo…

La manera más obvia de hacerlo me parecía pasarle el nombre de la función como string y hacer varios tipos de eval (eval("funcionLlamada" + ()), eval ("funcionLlamada()") así que probé muchas cosas en esta línea, pero nada funcionaba. Varias búsquedas por la web también resultaron infructuosas.

Ahora que por fin me han dado la solución (gracias, natalia) resulta, como casi todo una vez q lo sabes, ridículamente sencillo. No hay que hacer ningún eval ni prestidigitación de ningún tipo. Un ejemplo:


// esta es una función cualquiera
function a () {
  trace ("soy la funcion a");
}
// y desde otra función vamos a llamar a la primera
function b (funcionLlamada) {
  trace ("soy la funcion b");
  funcionLlamada();
}
// y lo ejecutamos tal que así.
b(a);
// en la ventana de trace aparecerá 
// soy la funcion b 
// soy la funcion a

La clave (que yo no alcanzaba a ver) está en que los paréntesis que ponemos después de una función son un operador y no un simbolo arbitrario. Igual que el signo + entre dos valores significa “suma esto”, el operador () significa “ejecuta esto”

Quizás este problema solo lo haya tenido yo por mi idiosincrática manera de programar, pero aquí lo dejo como referencia para mi y todo el que lo quiera. Seguro que alguna vez a alguien le sirve.

Nota: El tema de pasarle parámetros es igual de facil si conocemos a priori el número de parámetros que queremos pasarle. Basta con ponerlos dentro del operador (); pero dado que lo que quería era una función genérica, esto no me sirve . Si consigo (o alguien me cuenta) la solución para pasarle un número indeterminado de parámetros, también la pongo por aquí, no sea que se me vuelva a olvidar. Buenas tardes.

3d en processing: 2, Sistemas de coordenadas

December 12th, 2004 § 2 comments § permalink

Segunda parte del tutorial de 3d básico en processing. En la primera parte planteamos algunas cuestiones relacionadas con el orden de los comandos y cómo éste afecta a la ejecución. Ahora veremos cómo se traduce esto en el trabajo en 3d, y comprobaremos que es muy poco intuitivo.

Funciones utilizadas:

box();
translate();
rotate();

1. Creación de un objeto en 3d:

Vamos a crear un objeto 3d básico en processing, por ejemplo una caja. No se me asusten los que vengan de actionscript. Es insultantemente fácil:


// Creamos una caja que mide 
// 20px de ancho(x), alto(y) y largo(z)
box (20, 20, 20);

Al probar el código observamos que la caja no se ha creado en el centro del sketch. En processing, igual que en actionscript, el origen de coordenadas (0, 0) está arriba a la izquierda. La caja se crea con centro en ese origen:
Caja en 3d semioculta sobre fondo gris

2. Transformaciones: translate() y rotate():

¿Cómo cambiamos la caja de sitio? También muy fácil. Con la función translate():


// los  parámetros de translate son 
// x=50 e y=50.
translate(50, 50);
box(20, 20, 20);

Cuadrado blanco sobre fondo gris
Ahora aparece en el centro. Aunque aparentemente es sólo un cuadrado, sigue siendo nuestra caja 3d. Si añadimos noFill() al principio podremos observarlo.

Creo que es buen momento para familiarizarse con translate() cambiando valores y observando los resultados (nótese que puede tener también 3 parámetros -x, y, z-).

Si queremos rotar nuestro objeto simplemente tendremos que utilizar otra función: rotate() (o para restringir a coordenadas específicas rotateX(), rotateY o rotateZ()). Un ejemplo:


// primero nos situamos en el centro
// de la pantalla
translate(50, 50);
// utilizamos rotate para rotar la caja. 
// OJO: esta función no se expresa en 
// grados sino en radianes
rotate(1.0);
// creamos la caja.
box(20, 20, 20);

Caja en 3d semioculta
Ya vimos en el anterior tutorial la importancia del orden de los comandos en processing. ¿Qué pasa si invertimos las transformaciones aplicadas en el último ejemplo?


rotate(1.0);
translate(50, 50);
box(20, 20, 20);

Caja en 3d semioculta
Como se observa, la transformación no da el mismo resultado. En teoría debería ser igual rotar un objeto y luego desplazarlo que hacerlo al revés. El estado final debería ser el mismo. ¿Por qué pasa esto?

Vamos a retrasar la respuesta hasta haber planteado otro problema en la siguiente sección.

3. Más de un objeto a la vez.

Veamos cómo lo haríamos para crear 3 cajas en distintas posiciones. Comenzamos creando una caja en unas coordenadas específicas:


// VARIOS OBJETOS:
// Caja 1 (Negra)
// Para situar una primitiva 3d en un lugar
// en el espacio, hacemos una traslación del
// sistema de coordenadas con translate(x, y, z);
// color de linea rojo
stroke(255, 0, 0); 
// color de relleno negro
fill(0); 
// traslación de coordenadas.
// x=30, y=30, z=10;
translate (30, 30, 10);
// y creamos una caja
box (15, 10, 50);

Caja en 3d semioculta
En el mismo archivo creamos una segunda caja:


//Caja 2 (Gris)
// Si ahora hacemos otra caja y especificamos
// exactamente las mismas coordenadas en el 
// translate, la caja deberia aparecer en el mismo
// lugar, y por tanto solaparse con la anterior...
// caja gris
fill(127); 
translate (30, 30, 10);
box (15, 10, 50);
// ...pero no lo hace.

Caja en 3d semioculta
¿Qué ha pasado? Nuestra caja debería aparecer en el mismo lugar que la anterior pero aparece más abajo y a la derecha.

La razón es la siguiente: La función translate() no transforma las coordenadas de un objeto específico, sino las coordenadas del “universo” completo de la pantalla. De este modo cuando vamos alterando sucesivamente los parámetros x, y, z las transformaciones se van “acumulando”.

Para comprenderlo analicemos los movimientos en el sistema de coordenadas de nuestro ejemplo:

La caja negra está a 30 pixeles (tanto en x como en y) de el origen de coordenadas (esquina superior izquierda) y 10 pixeles más “cerca” de nosotros (eje z) que éste. Si observamos detenidamente la segunda caja podemos ver que ésta ha efectuado las mismas transformaciones pero respecto al nuevo sistema de coordenadas (es decir, respecto a x=30, y= 30, z=10). La posición de la nueva caja respecto al origen de coordenadas original es, pues:

x= 30+30= 60, 
y= 30+30= 60, 
z= 10+10= 20.

**Para comprobarlo podemos hacer un nuevo sketch que sólo contenga una caja con translate(60, 60, 20) y se observará que la posición de esta es igual a la de nuestra caja gris del ejemplo.

…y finalizando con nuestro sketch de 3 cajas, aplicaremos lo último aprendido. Sabemos que las coordenadas de nuestro sistema ahora tienen origen en la segunda caja. Si queremos colocar una nueva justo debajo, tan sólo tendremos que alterar el eje y:


 // Caja 3 (Blanca)
fill(255);
translate (0, 10, 0);
box (15, 10, 50);

El sketch completo junto con el código fuente puede observarse aquí:
Caja en 3d semioculta

Comentarios:

Acabamos de encontrar dónde radica la dificultad (al menos para el que escribe) de trabajar con varios objetos en 3d en processing: En vez de tener un sistema de coordenadas fijo para situar los elementos especificando su posición absoluta, tenemos que ir colocandolos respecto a la última transformación. Por eso en el apartado 2 de este tutorial la rotación y la traslación daba resultados distintos según el orden en que las ejecutáramos. Teniendo esto en cuenta, no es difícil imaginar que la programación puede hacerse innecesariamente compleja con mucha rapidez.

Esta es la razón principal que ha inspirado este tutorial. En los dos siguientes capítulos ofreceremos dos soluciones. Una obtenida mediante comandos de processing (aún muy poco intuitiva) y la otra en forma de librería externa, que proporciona un sistema mucho más fácil de comprender.

Es todo por esta entrega. Como siempre, comentarios, correcciones, sugerencias y palabras en general son bienvenidos. Hasta la próxima.

3d en processing: 1, Flujo de ejecución

December 1st, 2004 § 7 comments § permalink

Esta es la primera parte del tutorial de 3d básico en processing. Es una introducción general y he intentado q sirva independientemente del resto de los pasos: no contiene nada de 3d.

Para probar el código basta con copiarlo y pegarlo en el editor*. Al principio de cada tutorial incluiré enlaces de las funciones utilizadas a la referencia en castellano de processing, amablemente traducida por Pedro Alpera.

*Nota: Al pegar en el editor de processing ejemplos de código copiados de una página web éste se cuelga (probablemente por los datos de formato), por lo que es mejor copiar el código fuente en los applets o simplemente escribirlo.

Funciones utilizadas

rect()
fill()
stroke()

1. Flujo de ejecución:

Dado que en processing carecemos de la típica línea de tiempo de flash o director, el orden de ejecución del código sólo va a estar determinado por el orden en que lo escribamos (estamos hablando de código simple, sin funciones ni objetos). Lo primero que hayamos escrito se ejecutará primero, y así sucesivamente.

Ejemplo 1:


// SECUENCIALIDAD DEL CÓDIGO EN PROCESSING 00
// El cuadrado de arriba a la izquierda es el primero
// en ser dibujado, y queda más al fondo.
rect(15, 15, 50, 50); 
// el siguiente queda en la mitad
rect(25, 25, 50, 50); 
// y el de más abajo es el último y queda al frente
rect(35, 35, 50, 50); 

El resultado es el siguiente:
3 cuadrados blancos solapados sobre fondo gris

Aunque parezca trivial, no lo es. Si por ejemplo quisieramos crear un cuadrado y rellenarlo de un color, lo haríamos en ese orden, ¿no?


rect(15, 15, 50, 50);  // crea un cuadrado
fill(0); // lo rellena del color negro...?

Efectivamente, no. Como se comprobará si se prueba el ejemplo, el cuadrado permanece blanco (que es el color en el que se dibuja por defecto). En processing es necesario hacerlo al revés: primero se especifica una propiedad y luego el objeto al que ha de ser aplicada.


fill(0);   // ahora si, especificamos el color negro.
rect(15, 15, 50, 50);   // y se aplica a el cuadrado.

2. Persistencia de las propiedades

Una vez establecida una propiedad (como fill() o color() ), ésta se aplica a todos los objetos siguientes (hasta que se especifique lo contrario):


fill(0); //especificamos el color negro
rect(15,15, 34, 37); // creamos un cuadrado 
rect(25,25, 10, 50); // y otro. los dos son negros.

¿Cómo se especifica lo contrario? Pues simplemente llamando de nuevo a la misma propiedad y cambiando el valor…


fill(0); //especificamos el color negro
rect(15,15, 34, 37); // creamos un cuadrado 
rect(25,25, 10, 50); // y otro. los dos son negros.
fill(127); //ahora el relleno es gris
rect(10,10, 20, 20);  // y este cuadrado es gris

También se pueden anular algunas propiedades mediante comandos especiales (por ejemplo, noFill() para quitar el relleno o noStroke() para… bueno, creo que se entiende).

Un segundo ejemplo con todos los pasos combinados.
Ejemplo 2:


// SECUENCIALIDAD DEL CÓDIGO EN PROCESSING 01
// Dado que el código es secuencial, 
// si queremos aplicar una propiedad a un
// objeto, tenemos que especificarla antes.
// Especificamos un color de relleno  
fill(150);   
// el primer cuadrado se rellena con ese color
rect(50, 25, 45, 45); 
// especificamos un color de linea
stroke(240); 
// Como no hemos cambiado el color de relleno,
// el siguiente cuadrado mantiene el gris del primero.
// El color de linea si ha cambiado.
rect(55, 30, 35, 35); 
 // Ahora cambiamos el color de relleno  
fill(200);
// El tercer cuadrado tiene un relleno distinto
// y mantiene el color de linea de el anterior.
rect(60, 35, 25, 25); 
// y finalmente quitamos el relleno
noFill();
// y creamos un último rectangulo
rect(45, 45, 50, 50);

El resultado es este:
4 cuadrados con bordes y rellenos de diferentes colores

Y eso es todo por ahora.

Para saber más:

Acabando este tutorial me encontré uno muy parecido en los foros de processing, y es que quizás sea un poco inútil hacer más tutoriales sobre una herramienta con tantos recursos para aprender. En cualquier caso aquí está:
drawing statements and execution flow, part I

Hasta el siguiente.

Por supuesto, si tienen alguna duda, corrección, comentario o sugerencia, no duden en utilizar el formulario destinado a tal efecto. Justo debajo de esta línea :)

Where Am I?

You are currently browsing the Tutorial category at Software over the rainbow.