Implementando la carga dinámica de clases en Processing

Introducción

La carga dinámica de clases es una característica muy conocida de los lenguajes orientados a objetos que permite crear instancias de clases con solo conocer su nombre.  Esto permite a los desarrolladores crear aplicaciones que utilicen clases que sean creadas después de la aplicación sin necesidad de recompilar la misma.  También es muy útil cuando se desea generalizar la creación de un conjunto de objetos mediante el patrón de fábrica.

Gracias a la reflexión en Java y otros lenguajes como C# es muy fácil de implementar, sin embargo en Processing (derivado de Java) su implementación fue un poco mas elaborada ya que las clases que implementa el usuario son en realidad clases internas del proyecto desarrollado.

Explicación

En Processing cuando se crea un Proyecto y en él se implementan las clases A, B y C, y este se compila, internamente se crea un archivo de código fuente Java conteniendo a este código de la siguiente manera.

import processing.core.*;

// Imports del usuario

// Otros imports

public class Proyecto extends PApplet {

    class A
    {
        // ...
    }

    class B
    {
        // ...
    }

    class C
    {
        // ...
    }

    static public void main(String args[]) {
        PApplet.main(new String[] { "--bgcolor=#DFDFDF", "Proyecto" });
    }
}

Implementación

Para realizar la implementación de una versión simple del patrón de fábrica utilizando la carga dinámica de clases en Processing se supondrá que existe la clase Padre de la cual se derivan las clases Hijo1 e Hijo2 del proyecto Demostracion.

Crear un objeto donde se almacenará la instancia a crearse de manera dinámica.

Padre instance = null;

Recuperar la referencia al cargador de clases del sistema.

ClassLoader classLoader = ClassLoader.getSystemClassLoader();

Cargar la referencia de la clase a partir de su nombre (className), en este caso podría ser Hijo1 o Hijo2.  Recuerde que esta clase es realmente interna a la clase Demostracion.

Class loadedClass = classLoader.loadClass("Demostracion$" + className);

Obtener una referencia al constructor que se desea utilizar para crear la instancia.  En este caso se eligió un constructor que recibe dos parámetros: una cadena y un real.  Nótese además que todos los constructores reciben una referencia al applet de Processing, en este caso de Demostracion (que hereda a su vez de PApplet).

java.lang.reflect.Constructor constructor = loadedClass.getConstructor(new Class[] {PApplet.class, String.class, float.class});

Crear la nueva instancia utilizando el constructor obtenido en el paso anterior.  Al método newInstance se le especifican los valores de los parámetros que serán suplidos en el constructor.

instance = (Padre) constructor.newInstance(new Object[] {applet, str, flt});

Nótese como el primero de ellos, applet, hace referencia al applet de Processing que se está ejecutando.  Al no encontrar una forma mas elegante para obtener esta referencia al applet, declarar una variable global para almacenarlo.

PApplet applet;

Y obtener su valor en el procedimiento setup.

void setup()
{
    // ...

    applet = this;

    // ...
}

En el código mostrado anteriormente se deberán manejar las excepciones ClassNotFoundException y ClassCastException para poder llevar a feliz término su ejecución.

Enlaces

Construcción de la librería Simple-OpenNI para Processing bajo Ubuntu de 32 bits

Introducción

Simple-OpenNI es una librería de Processing que actúa como un recubrimiento (wrapper) para utilizar fácilmente OpenNI desde este lenguaje de programación.

La distribución binaria de esta librería puede ser descargada directamente desde el sitio web del proyecto.  En el presente artículo se describirán los pasos necesarios para construír esta librería a partir de su distribución de fuentes lo cual resulta interesante para garantizar compatibilidad con las versiones de las librerías nativas instaladas y mantener la última versión disponible, así como utilizar arquitecturas cuyas distribuciones binarias no se encuentren disponibles.

Prerequisitos

Para poder construír la librería bajo GNU/Linux Ubuntu es necesario contar con los siguientes requisitos previamente instalados.

  1. OpenNI y NITE
  2. Java Development Kit.
    $ sudo aptitude install openjdk-6-jdk openjdk-6-jre openjdk-6-jre-headless openjdk-6-jre-lib
    Activar la versión recién instalada: /usr/lib/jvm/java-6-openjdk/jre/bin/java
    $ sudo update-alternatives –config java
  3. CMake
    $ sudo aptitude install cmake
  4. Swig >= v2.0.2
    $ sudo aptitude install swig
  5. Eigen >= v3.0
    $ sudo aptitude install libeigen3-dev
  6. Boost >= v1.46 (use the static build)
    $ sudo aptitude install libboost-all-dev

Procedimiento

Obtener la última versión del código fuente de la librería.

$ svn checkout http://simple-openni.googlecode.com/svn/trunk/ simple-openni-read-only

$ cd simple-openni-read-only/SimpleOpenNI/

Ajustar el script de construcción modificando la invocación a cmake de la siguiente manera.  (Ajustar las rutas que se consideren convenientes, en especial a DP5_JAR)

$ vi buildLinux32.sh

(actualizar)

cmake -DOPEN_NI_INCLUDE=/usr/include/ni/
      -DXN_NITE_INCLUDE=/usr/include/nite/
      -DXN_NITE_LIB=/usr/lib/
      -DEIGEN3D_INCLUDE=/usr/include/eigen3/
      -DP5_JAR=~/Processing/2.0a4/lib/core.jar
      -JAVA_INCLUDE_PATH=/usr/lib/jvm/java-6-openjdk/include/
      -JAVA_INCLUDE_PATH2=/usr/lib/jvm/java-6-openjdk/include/linux
      ..

Realizar la construcción de la librería.

$ ./buildLinux32.sh

Instalar la librería recién construída.

$ ./installLinux.sh

Verificar la instalación de la librería

El procedimiento anterior construye e instala la librería de Simple-OpenNI bajo ~/sketchbook/libraries/SimpleOpenNI/ dejándola lista para ser utilizada con Processing.

$ tree -d ~/sketchbook/libraries/SimpleOpenNI/

/home/jimezam/sketchbook/libraries/SimpleOpenNI/
├── documentation
│   ├── resources
│   └── SimpleOpenNI
├── examples
│   ├── eclipse
│   ├── Nite
│   │   ├── CircleCtrl
│   │   ├── Hands
│   │   └── Slider2d
│   └── OpenNI
│       ├── AlternativeViewpoint3d
│       ├── DepthImage
│       ├── DepthImageXml
│       │   └── data
│       ├── DepthInfrared
│       ├── DepthMap3d
│       ├── Hands3d
│       ├── MultiCam
│       ├── RecorderPlay
│       ├── Scene
│       ├── SceneDepth
│       ├── Threaded
│       ├── User
│       ├── User3d
│       ├── User3dCallback
│       ├── UserSaveCalib
│       └── UserScene3d
└── library

Enlaces

Instalar Java (de Oracle) en GNU/Linux CentOS 6

Introducción.

A continuación se describe el procedimiento necesario para instalar el ambiente de desarrollo (JDK) de Java desarrollado por Oracle en GNU/Linux CentOS 6.  Este procedimiento probablemente funcione con GNU/Linux Fedora.

Instalación.

Descargar la última versión en RPM disponible en la siguiente ubicación.

# wget -o s1 -b -c http://download.oracle.com/otn-pub/java/jdk/7/jdk-7-linux-i586.rpm

# rpm -i jdk-7-linux-i586.rpm

Si se cuenta con otras versiones de Java (OpenJDK por ejemplo) deberá ajustar la versión por defecto que utilizará el sistema operativo.  Es posible que deba ajustar el índice (2 en el ejemplo) de la versión que se está instalando.

# alternatives –install /usr/bin/java java /usr/java/jdk1.7.0/bin/java 2

# alternatives –config java

Verificación.

Para verificar el funcionamiento de la versión de Java recién instalada, abra una consola y ejecute los siguientes comandos.

# java -version

java version “1.7.0”Java(TM) SE Runtime Environment (build 1.7.0-b147)
Java HotSpot(TM) Server VM (build 21.0-b17, mixed mode)

# javac -version
 
javac 1.7.0

Problemas para reproducir sonidos en Processing con Minim bajo Ubuntu 10.10

Introducción.

Minim parece ser una muy buena librería para la reproducción y manipulación de archivos de audio utilizando a Processing como lenguaje de desarrollo.

Experimentando con esta librería intentaba reproducir dos sonidos provenientes de dos archivos WAV diferentes, sin embargo siempre obtenía el siguiente mensaje de error a pesar de que cuando lo intentaba con uno sólo funcionaba correctamente.

JavaSound Minim error
==== Couldn’t open the line: line with format PCM_SIGNED 44100.0 Hz, 16 bit, mono, 2 bytes/frame, little-endian not supported. ====

Este problema me sucedía tanto al utilizar AudioSample como con AudioSnippet.

Solución.

Aparentemente el problema está relacionado con la plataforma Ubuntu ya que esta apuesta por OpenJDK como máquina virtual de Java por encima de la distribución oficial de Oracle (sun-java6) y por este motivo desafortunadamente olvidaron agregarle el soporte para el sistema PulseAudio que utiliza por defecto esta distribución.

La solución propuesta en los foros es copiar los archivos necesarios desde los directorios de OpenJDK a sus equivalentes de SunJava6.  En mi caso que utilizo exclusivamente la última versión fue necesario que instalara temporalmente el paquete openjdk-6-jre-lib, copiara los siguientes archivos y lo desinstalara nuevamente.

$ sudo cp /usr/lib/jvm/java-6-openjdk/jre/lib/[ARCH]/libpulse-java.so /usr/lib/jvm/java-6-sun/jre/lib/[ARCH]/

$ sudo cp /usr/lib/jvm/java-6-openjdk/jre/lib/ext/pulse-java.jar /usr/lib/jvm/java-6-sun/jre/lib/ext/

Se debe tener cuidado al reemplazar la subcadena [ARCH] contenida en la primera instrucción a ejecutar con la correspondiente plataforma instalada realmente, ya sea de 32 bits (será entonces i386) o de 64 bits (amd64).  La ejecución del comando uname -m debería brindar información suficiente al respecto.

Enlaces.

Charla introducción a Processing en 2010/09

La semana anterior tuve una charla con algunos ingenieros de sistemas de la ciudad de Armenia (Quindío) en la cual los introduje al lenguaje de programación Processing.

La charla se dividió en dos sesiones cortas cuya finalidad era explicar el lenguaje desde la perspectiva de los usuarios (para qué sirve) como desde la perspectiva de los desarrolladores (cómo se usa).  En la primera sesión se trataron las siguientes preguntas básicas.

  1. Qué es ?
  2. Qué se puede hacer con él ?
  3. Cómo se obtiene ?
  4. Cómo se instala ?
  5. Cómo es su ambiente de desarrollo ?
  6. Hola Mundo Processing.
  7. Cómo se exporta el sketch ?

Para esto preparé una presentación estilo documento muy resumido con la información mas importante del lenguaje y vínculos para ampliar estos conocimientos.

En la segunda sesión de la charla se realizó una rápida introducción al API del lenguaje de programación y se realizó paso a paso un ejemplo práctico básico para ejemplificar parte de la funcionalidad mas utilizada del lenguaje: el sketch Laberinto.

Ejemplo práctico de demostración del lenguaje Processing

El ejemplo práctico quedó documentado en dos versiones: una versión procedimental que es mas simple, fácil de entender pero menos elegante y una versión orientada a objetos un poco mas elaborada, ambas con la misma funcionalidad.

El applet del laberinto puede ser accedido mediante el siguiente enlace.

http://demo.jorgeivanmeza.com/Processing/Laberinto/0.1/applet/

Las teclas que deben utilizarse en el sketch son las siguientes.

  • Flechas del cursor: mover al jugador.
  • R: reiniciar el juego.
  • Espacio: teletransportar al jugador.

El código fuente del sketch, tanto de la versión prcedimiental como el de la orientada a objetos, puede ser descargado de la siguiente ubicación.

http://demo.jorgeivanmeza.com/Processing/Laberinto

Burbujas 2, ahora en el escritorio con Processing

Introduccion.

Después de bastante tiempo, hay una nueva versión de uno de mis juegos preferidos: Burbujas.  Esta vez para el escritorio y la web, desarrollado con Processing.  Por este motivo es necesario contar con la máquina virtual de Java para su ejecución.

Bubbles 2

El código del pequeño juego ha sido publicado bajo la licencia Attribution-NonCommercial motivo por el cual su código fuente puede ser obtenido, estudiado y modificado.

Misión.

El juego se trata de la mayor cantidad de burbujas posibles.  Al hacer esto se debe tener en cuenta que sólo es posible explotar grupos de burbujas que reunan a por lo menos dos burbujas del mismo tipo en cualquiera de las cuatro direcciones: norte, sur, oriente y occidente.

El primer disparo selecciona las burbujas del mismo tipo que se encuentren adyacentes y el segundo disparo las hace explotar.  La selección de las burbujas puede hacerse con el ratón o con las flechas del teclado y los disparos pueden hacerse con el clic derecho del ratón o con la barra de espacio del teclado.

Otras teclas útiles en el juego son R (reset) reinicia el juego, H (hint) modo de ayuda y Q (quit) termina la sesión de juego.

Enlaces.