You are on page 1of 27

Instrucciones de dibujo en 2D con Processing

Píxel | línea recta | triángulo | círculo/elipse | cuadrado/rectángulo | curva bezier | arco

Píxelset()
Modo de Uso
set (x,y,c);
Parámetros
X x del pixel
Y y del pixel
C Color. Si se usa un valor entero, se interpreta como valor de gris.
Ejemplo código
size(150,150); //define el tamaño de ventana
background(0); //pinta la ventana de negro
set(75,75,255); //dibuja un pixel blanco

Línea Rectaline()
Modo de Uso
line (x1,y1,x2,y2);
Parámetros
x1 x de un extremo
y1 y de un extremo
x2 x del otro extremo
y2 y del otro extremo
Ejemplo código
size(150,150); //define el tamaño de ventana
background(255); //pinta el fondo de blanco
strokeWeight(4); //ancho de la linea (4 pixeles)
line(10,20,130,140);

Triángulotriangle()
Modo de Uso
triangle(x1,y1,x2,y2,x3,y3);
Parámetros
x1 x del primer vértice
y1 y del primer vértice
x2 x del segundo vértice
y2 y del segundo vértice
x3 x del tercer vértice
y3 y del tercer vértice
Ejemplo código
size(150,150); //define el tamaño de ventana
background(255); //pinta el fondo de blanco
strokeWeight(4); //ancho de la linea (4 pixeles)
triangle(10,110,80,20,130,130);

Círculo / Elipseellipse()

Modo de uso
ellipse(x1,y1,x1,y2);
Parámetros
El uso de los parametros depende de ellipseMode();
ellipseMode(CENTER); (valor por defecto)
x1 x del centro
y1 y del centro
x2 ancho (diámetro)
y2 alto (diámetro)
ellipseMode(CORNER);
x1 x del vértice superior izquierdo del rectángulo que la contiene
y1 y del vértice superior izquierdo del rectángulo que la contiene
x2 ancho (diámetro)
y2 alto (diámetro)
ellipseMode(CORNERS);
x1 x de un vértice del rectángulo que la contiene
y1 y de un vértice del rectángulo que la contiene
x2 x del vértice opuesto del rectángulo que la contiene
y2 y del vértice opuesto del rectángulo que la contiene
Ejemplo código
size(150,150); //define el tamaño de ventana
background(255); //pinta el fondo de blanco
strokeWeight(4); //ancho de la linea (4 pixeles)
rectMode(CENTER); //(valor por defecto)
ellipse(70,80,130,80);

Cuadrado / Rectángulorectangle()
Modo de uso
rect(x1,y1,x1,y2);
Parámetros
El uso de los parametros depende de rectMode();
rectMode(CENTER);
x1 x del centro
y1 y del centro
x2 ancho
y2 alto
rectMode(CORNER); (valor por defecto)
x1 x del vértice superior izquierdo
y1 y del vértice superior izquierdo
x2 ancho
y2 alto
rectMode(CORNERS);
x1 x de un vértice
y1 y de un vértice
x2 x del vértice opuesto
y2 y del vértice opuesto
Ejemplo código
size(150,150); //define el tamaño de ventana
background(255); //pinta el fondo de blanco
strokeWeight(4); //ancho de la linea (4 pixeles)
rectMode(CORNER); //modo en que se interpretarán los parámetros en rect()
rect(10,10,120,80);

Cuadriláteroquad()
Modo de Uso
quad(x1,y1,x2,y2,x3,y3,x4,y4);
Parámetros
x1 x del primer vértice
y1 y del primer vértice
x2 x del segundo vértice
y2 y del segundo vértice
x3 x del tercer vértice
y3 y del tercer vértice
x4 x del cuarto vértice
y4 y del cuarto vértice
Ejemplo código
size(150,150); //define el tamaño de ventana
background(255); //pinta la ventana de blanco
strokeWeight(4); //ancho de la linea (4 pixeles)
quad(20,10,130,30,110,115,40,140);

Curvabezier()
Modo de Uso
bezier(x1,y1,x2,y2,x3,y3,x4,y4);
Parámetros
x1 x de un extremo
y1 y de un extremo
x2 x del punto de dirección de salida
y2 y del punto de dirección de salida
x3 x de la dirección de llegada
y3 y de la dirección de llegada
x4 x del otro extremo
y4 y del otro extremo
Ejemplo código
size(150,150); //define el tamaño de ventana
background(255); //pinta la ventana de blanco
strokeWeight(4); //ancho de la linea (4 pixeles)
bezier(20,10,40,140,120,30,110,115);

Arcoarc()
Esta función es similar a ellipse, con dos párametro más para indicar el inicio y el final del arco que se representará.
Modo de uso
arc(x1,y1,x1,y2,rad1,rad2);
Parámetros
El uso de los primeros cuatro parámetros depende de ellipseMode();
En este caso se explican los parámetro con ellipseMode(CENTER); que es el valor por
defecto.
ver ellipse();
x1 x del centro
y1 y del centro
x2 ancho (diámetro)
y2 alto (diámetro)
rad1 punto de inicio
rad2 punto de final
Ejemplo código
size(150,150); //define el tamaño de ventana
background(255); //pinta la ventana con colore de fondo blanco
strokeWeight(4); //ancho de la linea (4 pixeles)
ellipseMode(CENTER); //modo de los parámetros en ellipse() y arc();
arc(80,70,120,80,PI/2,0);

Tipos de datos y operaciones


 Introducción
La programación trata acerca de la cosbtrucción de algoritmos (conjunto de instrucciones que la computadora deberá
seguir), durante el desarrollo de dichos algoritmos es necesario establecer algunos datos. Los datos sirven
generalmente como parámetros que establecen el grado y forma con el que se ejecutan ciertas instrucciones. Para dar
un ejemplo, en el siguiente algoritmo:
 
size(150,150); //define el tamaño de ventana
background(0); //pinta la ventana de negro
set(75,75,255); //dibuja un pixel blanco
todos los números que aparecen (como el 150 en la instrucción size) son datos. En este casos todos los datos que
aparecen son constantes, es decir que no cambian su valor durante el transcurso del algoritmo, pero también es
posible establecer datos
variables. Los textos que aparecen en cada línea después de la doble barra (//) son comentarios, sirven para que el
programador puedo escribir notas para guiarse sin que el compilador las tome como instrucciones,es decir que no son
instrucciones ejecutables y el programa las desestima como tales.

Las Variables
Las variables son espacios de memoria que permiten almacenar datos e ir variando sus valores durante el transcurso
de un programa. Una variables deber ser declarada para poder ser utilizada, luego se le puedo asignar un valor y ser
utilizada:

 
int miVar; //declara una variable numérica llamada "miVar"
miVar = 23; //le asigna el valor 23 a la variable miVar
println(miVar); //imprime el valor almacenado en miVar.

En el ejemplo anterior, en la primer línea se declaró una variable (es decir un espacio de memoria RAM) llamada
"miVar", en la segunda línea se le asignó el valor numérico 23, y en la tercer línea la instrucción println nos permite ver
el valor almacenado actualmente en la variable miVar. La instrucción println imprime el valor de variable, así como el
resultado de operaciones, en el área negra de la interface de processing.

Tipos de datos
Los datos que se pueden guardar en variables pueden ser de diferentes tipos, estos tipos responden a la naturaleza de
información que pueden guardar y operar. Por ejemplo, los dostipos de datos prinicipales son los numérico y los
alfanuméricos. Los primeros, como su nombre lo indica, almacenan valores numéricos, lo que permite realizar
operaciones matemáticas con ellos, mientras los alfanumércos almacenan y operan caracteres, es decir letras y otros
signos que sirvan para escribir.

Datos numéricos
Dentro de los tipos numéricos exiten dos tipos principales: los enteros y los reales (con decimales). Los enteros
invluyen a los números naturales (que sirven para contar cosas: 1,2,3,...) a los negativos (-1,-2,-3,...) y al cero. Mientras
que los reales incluyen a los enteros pero también a los números fraccionarios, racionales e irracionales (como la raiz
cuadrada de dos o el número Pi), es decir todo lo que puede ser representado con decimales (0.14 , 15.67 ,
-6.8998762 ,etc.).

Los enteros se declaran con la palabara int, que viene del término ingles integer. Mientras que los reales se declaran
con la palabra float, este término viene de la denominación inglesa de "coma flotante" qué es como se llamaba a estos
números. Así, en el ejemplo que sigue, la primer línea declara una variable llamada "miVar" de tipo entero, la segunda
declara una variable de tipo real llamada "otraVar", la tercer línea declara 3 variables "a","b" y "c" de tipo entero, y la
última línea dos vriables (d y e) de tipo real.

 
int miVar;
float otraVar;
int a,b,c;
float d,e;

Cada tipo de dato define las operaciones que se pueden realizar con dichas variables. Por ejemplo, las variables
enteras permiten las 4 operaciones aritméticas básicas: +,-,*,/ (es decir: suma, resta, multiplicación y división,
respectivamente). Si bien la variables de tipo real tambien permite las cuatros operaciones básicas, una de la
diferencias principales es que la división es diferente. Por ejemplo, la división con datos enteros devuelve valores
enteros, mientras que la división real devuelve un resultado con decimales.

 
int a,b,e;
float c,d,f;
a = 10;
b = 3;
c = 40.0;
d = 6.0;
println( a / b ); //imprime 3
println( c / d ); //imprime 6.66666666...
e = a + b * 8;
f = c - d * 2.0;
En este ejemplo, la división entre las variables a y b devuelve como resultado un 3 (en vez de 3.3333... que sería el
resultado más preciso), mientras que la división entre c y d devuelve 6.6666666.... . En las dos últimas líneas se puede
ver también que es posible operar variables entre sì y asignar el resultado de dicha operación a otra variable.

El ejemplo que sigue muestra algunas formas abreviadas de escribir ciertas operaciones, como en el caso de a=a+1
que pueden ser escrito como a++:

 
int x,b;
x = 100;
b = 5;
x++; // esto equivale a x=x+1
x--; // esto equivale a x=x-1
x+=b; // esto equivale a x=x+b
x-=b; // esto equivale a x=x-b
x*=b; // esto equivale a x=x*b
x/=b; // esto equivale a x=x/b

Datos alfanuméricos
Los datos alfanuméricos permiten trabajar con caracteres y cadenas de caracteres (secuencias de caracteres). Los
caracteres que la computadora puede utilizar pertenecen al código ASCII (ver el tema en Wikipedia). Los dos tipos de
datos alfanuméricos que se pueden usar son el tipo caracter y el tipo cadena de caracteres, la diferencia entre estos
dos tipos es que el primero sólo puede almacenar un caractere mientras que el segundo puede almacenar secuencias y
por ende palabras oraciones y cualquier otro tipo de secuencia . Los caracteres se declaran con la palabra char y sus
valores constantes se encierran con comillas simples:

char miVar;
miVar = 'b';
println(miVar); imprime una b

Las cadenas de caracteres se declaran con la palabra String y sus valores constantes se encierran entre comillas
dobles. La función de las comillas en ambos casos es de distinguir los valores alfanuméricos del resto del texto del
algoritmo. En el ejemplo que sigue se puede ver también la única operación que permiten los tipos alfanuméricos, la
concatenación, que se representa con el signo (+). En la cuarta línea se puede ver como se le asigna a la variable c la
concatenación de la variable a y la variable b, es decir el valos de la variable a ("hola ") y el valor de la variable b
("mundo!!!!"), lo que sería "hola "+"mundo!!!!":

String a,b,c;
a = "hola ";
b = "mundo!!!!";
c = a + b;
println(a); imprime hola
println(c); imprime hola mundo!!!!

Otros tipos de datos


Además de los tipos de datos numéricos y alfanuméricos, existen otros tipos. Uno de estos, son los datos de tipo
lógico, que permiten operar y almacenar valores de verdad lógica. Los datos lógicos pueden adquirir dos valores:
verdadero y falso,, que en ingles se escriben: true y false. Estos tipos de datos los veremos más adelante.

Dependiendo del Lenguaje de programación que se trate, veremos que pueden existir muchos más tipos de datos
primitivos. Por ejemplo en Processing existe el tipo de dato para tratar colores, llamado color.

Interactividad básica
Los modos estático y dinámico
Los siguientes ejemplos muestran como trabajar con interactividad en Processing. Este lenguaje permite trabajar e dos
modos de programación, uno estático y otro dinámico. En el primer modo se escriben las instrucciones en orden
descendente pero sin una organización externa, mientras que en el segundo modo de programación el código se
organiza en estructuras. Las dos estructuras principales con setup() y draw() (que en versiones anteriores de
Processing se llamaba loop() ).

En el ejemplo que sigue, las instrucciones que se detallan se ejecutan de arriba a abajo, y el código se ejecuta una
única vez, lo que hace que el algoritmo sirva para generar una ùnica imagen estática:
int a;
a = 10;
size(150,150);
background(100);
a = (a+1) % 150;
rect(a,50,10,10);

A diferencia de el anterior ejempo, en el siguiente, las instrucciones mismas instrucciones estan organizadas dentro de
la estructura void setup(){ ... } y la estructura void draw(){ ... } . Las instrucciones que se encuentran en el setup() sólo
se ejecutan una única vez al inicio del programa. Las instrucciones que se encuentran en el draw() se ejecutan 30
veces por segundo luego de la ejecución del setup(). Fuera de estas dos estructuras se pueden escribir declaraciones
de variables u otras estructuras que luego veremos.

int a;
void setup(){
a = 10;
size(150,150);
}
void draw(){
background(100);
a = (a+1) % 150;
rect(a,50,10,10);
}

El uso del mouse


Para detectar la posición del mouse en la pantalla existen dos variables del sistema llamadas mouseX y mouseY.
Estas variables representan la posición horizontal y vertical del mouse, respectivamente. No es necesario declarar estas
variables dado que ya pertenecen al sistema. Con el simple hecho de referenciarlas, estas devuelven en cada momento
los valores numéricos que expresan la posición del mouse. En los ejemplos siguientes se usan estas variables para
dibujar un rectángulo en la posición del mouse:

Ejemplo: Siguiendo el mouse (dejando rastro)

int x,y;
void setup(){
background(230); //la diferencia esta en esta linea
size(200,200);
}
void draw(){
x=mouseX-25;
y=mouseY-25;
rect(x,y,50,50);
}

Ejemplo: Siguiendo el mouse (sin rastro)

int x,y;
void setup(){
size(200,200);
}
void draw(){
background(230); //la diferencia esta en esta linea
x=mouseX-25;
y=mouseY-25;
rect(x,y,50,50);
}

Otros ejemplos
Ejemplo: Redimensionando el rectángulo con el mouse

int x,y;
void setup(){
size(200,200);
rectMode(CORNER);
}
void draw(){
background(230);
x=mouseX-100;
y=mouseY-100;
rect(100,100,x,y);
}
Ejemplo: Movimiento inverso

int x,y;
void setup(){
size(200,200);
//rectMode(CORNER);
}
void draw(){
background(230);
x=200-mouseX-25;
y=200-mouseY-25;
rect(x,y,50,50);
}

Ejemplo: Seguimientos y movimientos inverso

int x,y,x1,y1;
void setup(){
size(200,200);
noFill();
}

void draw(){
background(230);
x=200-mouseX-25;
y=200-mouseY-25;
x1=mouseX-25;
y1=mouseY-25;
rect(x,25,50,50);
rect(x1,125,50,50);
rect(25,y,50,50);
rect(125,y1,50,50);
}

Ejemplo: Multiplicación

int x,x2,x3,x4,x5,x6;
void setup(){
size(600,200);
noFill();
}
void draw(){
background(230);
x=mouseX;
x2=x*2;
x3=x*3;
x4=x*4;
x5=x*5;
x6=x*6;
line(x,0,x,200);
line(x2,0,x2,200);
line(x3,0,x3,200);
line(x4,0,x4,200);
line(x5,0,x5,200);
line(x6,0,x6,200);
}

Ejemplo: División

int x,x2,x3,x4,x5,x6;
void setup(){
size(600,200);
noFill();
}
void draw(){
background(230);
x=mouseX;
x2=x/2;
x3=x2/2;
x4=x3/2;
x5=x4/2;
x6=x5/2;
line(x,0,x,200);
line(x2,0,x2,200);
line(x3,0,x3,200);
line(x4,0,x4,200);
line(x5,0,x5,200);
line(x6,0,x6,200);
}

Ejemplo: Controlando colores con el mouse

int x,y,xc,yc;
void setup(){
size(255,255);
noStroke();
}
void draw(){
x=mouseX;
y=mouseY;
xc=255-x;
yc=255-y;
fill(x,y,0);
rect(0,0,255,255);
fill(xc,yc,255);
rect(50,50,155,155);
}

Estructuras de control condicionales


Estructuras de control
Los ejemplos de los anteriores apartados siguen una línea única de ejecución, es decir, no tienen posibilidad de bifurcar
su línea de ejecución, ni de repetir ninguna porción de su código. Para poder dirigir, controlar, la forma en que se ejecuta
el algoritmo, es decir, para controlar su flujo de ejecución, existen dos tipos principales de estructuras: las estructuras
condicionales y las estructuras iterativas (repetitivas). Entendemos por estructura a un tipo de demarcación del código
que nos permite organizarlo de alguna forma. En el ejemplo que sigue se ve una estructura condicional que bifurca el
código en dos líneas de ejecución:

 ...
void draw(){
if(mouseX>200){ //comienzo estructura
background(255); //primera línea de ejecución
}else{ //separación entre las líneas
background(0); //segunda línea de ejecución
} //fin de la estructura
}

Las estructuras condicionales

Las estructuras condicionales permiten bifurcar un algoritmo en función de una condición. Existen diferentes tipos de
estructuras condicionales, una de las primeras que veremos es la estructura if-then que se traduce como si-entonces,
lo que quiere decir es "si tal cosa entonces hacer tal otra":

 if( condición ){
cuerpo de la estructura
}
La estructura if-then permite encerrar una porción de código entre sus dos llaves ( { } ) . Esa porción de código se
ejecuta sólo si se cumple la condición que se encuentra entre los paréntesis:

void setup(){
size(200,200);
}
void draw(){
background( 0 );
fill(255);
if( mouseX > 100 ){
rect( 50 , 50 , 100 , 100 );
}
fill(255,0,0,150);
rect(100,0,100,200);
}

En el ejemplo de arriba, la instrucción "rect(..." , sólo se ejecuta cuando se


cumple la condición "mouseX>200", es decir, se dibuja un rectángulo en
la pantalla sólo cuando el mouse está más a la derecha de los 100 píxeles.
El segundo rectángulo marca la zona en que la posición horizontal del
mouse supera el valor de 100. A continuación se puede ver un diagrama
de flujo que muestra en qué orden se van ejecutando las instrucciones y
bajo qué condiciones:

Como muestra el diagrama de arriba el orden en que se ejecutan las


instrucciones es:

1ero, se pinta el fondo de negro


2do, se define el color de relleno en blanco, se pregunta
3ero, se evalua si el mouse supera la posición horizontal 100
4to, sólo si la condición se cumple se dibuja el cuadrado del centro de
color blanco
5to, se define el color de relleno como rojo con un poco de transparencia
6to, se dibuja un rectángulo del color rojo que muestra el área activa

La Condición
En este punto es preciso ver qué es una condición. Se considera condición a cualquier variable, constante u
operación que devuelva un valor lógico. Los valores lógicos sólo pueden adoptar dos estados: verdadero o falso. En
inglés los los valores lógicos verdadero o falso, se escriben true o false respectivamente. Es decir, true o false son las
dos únicas constantes lógicas que existen.

Una estructura if-then se ejecuta si la condición devuelve un valor true. En el ejemplo anterior la condición era una
operación de comparación ( mouseX > 100 ), las comparaciones dan como resultado un valor de verdad, como muestra
el siguiente ejemplo:

 int a = 10;
println( a > 5 ); //esta operación devuelve el valor true
println( a > 15 ); //esta operación devuelve el valor false

Los comparativos
Los operadores comparativos son los siguientes:

println( 3 > 2 ); // esto significa 3 es mayor que 2


println( 2 < 3 ); // esto significa 2 es menor que 3
println( 2 == 2 ); // esto significa 2 es igual a 2
println( 3 >= 2 ); // esto significa 3 es mayor o igual que 2
println( 2 <= 3 ); // esto significa 2 es menor o igual que 3
println( 3 != 2 ); // esto significa 3 es distinto a 2

En el ejemplo anterior todas las líneas devuelven true. Hay que señalar que el signo de "igual a" se escribe con un
doble signo (=), no hay que confundir el (==), que es una comparación, con el (=), que es una asignación.

En los casos del mayor o igual (>=), la operación devuelve true tanto en los casos en que el primer valor es mayor al
segundo, así como cuando el valor es igual al segundo, es decir que 3>=2 devuelve true y 2==2 también devuelve true.
El mismo caso se dá con el signo menor o igual.
La estructura if-then-else
La estructura if-then, permite ejecutar u omitir una porción de código en función de una condición. A veces es necesario
bifurcar el código en vez de omitirlo. La estructura if-then-else, que se traduciría como si-entonces-sino, quiere decir
"si tal cosa entonces hacer tal cosa sino hacer tal otra":

if( condición ){
se ejecuta si la condición es verdadera
}else{
se ejecuta si la condición es falsa
}

En el ejemplo que sigue, que es una variación del primer ejemplo, se puede ver como se bifurca el algoritmo a partir de
la condición. Si la condición ( mouseX > 100 ) se cumple, entonces se dibuja el cuadrado, sino se dibuja el círculo:

void setup(){
size(200,200);
}
void draw(){
background( 0 );
fill(255);
if( mouseX > 100 ){
rect( 50 , 50 , 100 , 100 );
}else{
ellipse( 100 , 100 , 100 , 100 );
}
fill(255,0,0,150);
rect(100,0,100,200);
}

La estructura if-then-else if-else


La estructura if-then-else_if-else, permite evaluar varias condiciones para tomar diferentes caminos en función de cada
una y por último tomar un camino si no se ha cumplido ninguna de estas:

 if( condición 1 ){
se ejecuta si la condición 1 es verdadera
}else if( condición 2 ){
se ejecuta si la condición 1 es falsa y la 2 es verdadera
}else if( condición 3 ){
se ejecuta si la condición 1 y 2 son falsas y la 3 es verdadera
...
}else{
se ejecuta si todas las condiciones anteriores son falsas
}

En el ejemplo que sigue, que es una nueva variación del primer ejemplo, se puede ver como se bifurca dos veces el
algoritmo a partir de dos condiciones:

void setup(){
size(200,200);
}
void draw(){
background( 0 );
fill(255);
if( mouseX > 100 ){
rect( 50 , 50 , 100 , 100 );
}else if( mouseX > 50 ){
ellipse( 100 , 100 , 100 , 100 );
}else{
triangle(50,150,100,50,150,150);
}
fill(255,0,0,70);
rect(100,0,100,200);
rect(50,0,150,200);
}

Las variables booleanas


Así como existen los valores de verdad true y false, valores lógicos o booleanos (en honor a George Boole ver el tema
en Wikipedia), también existen variables de tipo lógico. Estas variables se declaran con la palabra boolean y sólo
pueden adquirir valores booleanos: true o false. Debido a que las comparaciones devuelven valores booleanos, se
puede asignar a una variable booleana el resultado de una comparación:

 boolean a,b;
int c = 10;
int d = 20;
a = true;
b = c > d;
println( a ); //imprime true
println( b ); //imprime false
En los ejemplos anteriores se podría reemplazar, en la condición, la operación de comparación por una variable
booleana:

 ...
boolean a;
a = mouseX > 100;
if( a ){

En este caso no es muy útil, pero existen casos en que se hace necesario cambiar la condición en forma dinámica.

Las operaciones booleanas


Así como cada tipo de dato permite realizar ciertas operaciones, los datos booleanos pueden ser operados por tres
operadores llamados: and (que se escribe && ), or (que se escribe || ) y not (que se escribe ! ). Estos operadores
sirven para combinar más de un valor de verdad y obtener uno solo como resultado:

println( true && true ); //imprime true


println( true && false); //imprime false
println( false && true ); //imprime false
println( false && false); //imprime false

println( true || true ); //imprime true


println( true || false); //imprime true
println( false || true ); //imprime true
println( false || false); //imprime false

println( ! true ); //imprime false


println( ! false ); //imprime true

Como muestra el ejemplo anterior, el operador and (&&) devuelve un valor true sólo cuando los dos operadores son
true, caso contrario devuelve false. El operador or (||) devuelve un valor false sólo cuando ambos operadores son
false, caso contrario devuelve true. Y el operador not (!) invierte el valor de verdad de true a false y viceversa.

Estos operadores sirven para evaluar varias comparaciones en una sola condición, como muestra el ejemplo siguiente,
en donde las condición es cierta cuando se cumplen las dos comparaciones a la vez: cuando mouseX>100 y
mouseY>100:

void setup(){
size(200,200);
}
void draw(){
background( 0 );
fill(255);
if( mouseX > 100 && mouseY > 100){ //solo se cumple //cuando
las dos condiciones son ciertas
rect( 50 , 50 , 100 , 100 );
}
fill(255,0,0,150);
rect(100,100,100,100);
}

El ejemplo que sigue muestra como se usa el operador or para unir condiciones que no se superponen, dado que
alcanza que se de una para ser verdadera:

void setup(){
size(200,200);
}
void draw(){
background( 0 );
fill(255);
if( mouseX > 160 || mouseX < 40){ //basta que una de las //
dos condiciones sea cierta para cumplirse
rect( 50 , 50 , 100 , 100 );
}
fill(255,0,0,150);
rect(160,0,40,200);
rect(0,0,40,200);
}
El ejemplo que sigue muestra como el operador not invierte la condición, haciendo que se cumpla cuando mouseX NO
es mayor a 100:

void setup(){
size(200,200);
}
void draw(){
background( 0 );
fill(255);
if( !(mouseX > 100) ){ //se cumple si NO es mayor a 100
rect( 50 , 50 , 100 , 100 );
}
fill(255,0,0,150);
rect(0,0,100,200);
}

Estructuras de control condicionales (parte II)


Incrementos cíclicos
Hasta aquí hemos visto las estructuras condicionales, ahora veremos una aplicación de estas estructuras a un problema
de incremento con restricciones. Supongamos que tenemos un ejemplo como el que sigue en donde incrementamos
una variable para desplazar un objeto en la pantalla: (si el objeto ya salio de pantalla haga click sobre el ejemplo para
que vuelva a empezar)

int x;
void setup(){
size(200,200);
smooth();
x = 10;
}
void draw(){
background(0,0,50);
ellipse(x,100,20,20);
x++;
println(x);
}
void mousePressed(){
x = 10;
}

En el ejemplo anterior hemos empleado una estructura void mousePressed(), esta estructura es como setup() o
draw(), con la única diferencia de que esta estructura se ejecuta cuando hacemos click con el mouse. Este ejemplo
establece el valor inicial de la variable x en 10, luego en cada fotograma que se ejecuta la estructura draw() la variable
x se incrementa en 1. Esto sucede hasta que se termine el programa o el usuario haga click. Es fácil ver que con un
algoritmo como este, el valor de x se incrementará hasta el infinito (o por lo menos hasta valores muy grandes en
función de la presición del lenguaje de prorgramación), pero en principio esto es un problema dado que si bien
queremos que el objeto se desplace no queremos que se vaya de pantalla.

La forma de resolver este problema es usando un if-then que nos permita "condicionar" el incremento:

int x;
void setup(){
size(200,200);
smooth();
x = 10;
}
void draw(){
background(0,0,50);
ellipse(x,100,20,20);
x++;
if( x > width ){ //agregamos esta línea para condicionar
el //incremento
x = 0;
}
}

Como se puede ver en este ejemplo, el "if( x > width )" evalúa si la variable x tiene una valor mayor al ancho de la
pantalla (determinado por la variable del sistema llamada width), y si esto es cierto entonces le asigna a x un cero, el
equivalente a enviar al objeto al extremo izquierdo de la pantalla. Cabe aclarar que en este ejemplo hubiera sido lo
mismo poner "if( x > 200 )" dado que ese es el ancho de la pantalla, pero al usar la variable width nos aseguramos de
que si cambiamos el ancho en algún momento con la instrucción size() entonces no estaremos obligados a buscar los
valores del ancho por todo el programa dado que width se acomoda automáticamente.

El ejemplo que sigue es análogo al anterior sólo que el objeto va de derecha a izquierda y por ende cambia la "condición
de borde", teniendo que evaluar si x es menor a cero, y en caso de ser cierto le asigna el valor width, el equivalente a
trasladar al objeto al borde derecho:

int x;
void setup(){
size(200,200);
smooth();
x = 100;
}
void draw(){
background(0,0,50);
ellipse(x,100,20,20);
x--;
if( x < 0){
x = width;
}
}

Incremento ida y vuelta


Supongamos ahora que desamos hacer que el objeto vaya ida y vuelta de un extremo al otro. Entonces no encontramos
con el problema de que la condición de borde depende de en qué dirección estamos llendo, pero no sólo eso, sino que
el incremento también depende de la dirección en la que se está moviendo. En el ejemplo que sigue, pusimos una
variable que se encarga de señalar la dirección hacia la que nos dirigimos. El círculo comienza en el centro y se aleja
hacia la izquierda o derecha en función de la variable llamada haciaLaDerecha que es booleana e indica la dirección
que sigue el objeto. (si el objeto sale de pantalla haga click con el mouse y el objeto volverá al centro de la pantalla y
cambiará de dirección)

int x;
boolean haciaLaDerecha;
void setup(){
size(200,200);
smooth();
x = width/2; //inicia del centro
haciaLaDerecha = true; //establece como dirección la derecha
}
void draw(){
background(0,0,50);
ellipse(x,100,20,20);
if( haciaLaDerecha ){
x++; //incrementa si haciaLaDerecha es true
}
else{
x--; //decrementa si haciaLaDerecha es false
}
}
void mousePressed(){
x=width/2; //si se presiona el mouse vuelve al punto //central y
haciaLaDerecha = !haciaLaDerecha; //cambia de dirección
}

En el ejemplo podemos ver como en función de la variable booleana llamada haciaLaDerecha, se produce un
incremento (x++) o un decremento (x--). Al presionar el mouse, el objeto vuelve al centro (x=width/2), a la vez que
cambia de dirección, dado que la instrucción "haciaLaDerecha = !haciaLaDerecha", cambia el valor de la variable de
true a false y viceversa, funciona como un interruptor ON/OFF.

Entonces ya que establecimos con la variable haciaLaDerecha la dirección en que se mueve el objeto, entonces ahora
podemos hacer que este cambie de dirección cuando este choca el borde:

int x;
boolean haciaLaDerecha;
void setup(){
size(200,200);
smooth();
x = width/2; //inicia del centro
haciaLaDerecha = true; //establece como dirección la //derecha
}
void draw(){
background(0,0,50);
ellipse(x,100,20,20);
if( haciaLaDerecha ){
x++; //incrementa si haciaLaDerecha es true
if( x > width ){ //si choca el borde derecha
haciaLaDerecha = false; //cambia //de dirección
}
}else{
x--; //decrementa si haciaLaDerecha es false
if( x < 0 ){ //si choca el borde izquierdo
haciaLaDerecha = true; //cambia //de dirección
}
}
}

Cuando el objeto se dirije hacia la derecha (es decir cuando la variable haciaLaDerecha es true), entonces el borde se
evalúa preguntando si x es mayor que width, mientras que cuendo el objeto se dirije a la izquierda, dicha evaluación se
realiza preguntado si x es menor que cero.

Aprovechando el signo positivo o negativo


El ejemplo que sigue hace lo mismo que el anterior, sólo que en vez de tener una variable booleana llamada
haciaLaDerecha, tiene una variable entera llamada paso que se encarga de señalar la dirección así como de
establecer el incremento o decremento. Veamos cómo hace esto:

int x;
int paso;
void setup(){
size(200,200);
smooth();
x = width/2; //inicia del centro
paso = 2;
}
void draw(){
background(0,0,50);
ellipse(x,100,20,20);
x += paso; //cuando paso es negativo, esto es un //decremento
if( x > width || x < 0 ){ //si choca algún borde
paso *= -1; //cambia de dirección
}
}

La clave de este programa está en la operación "x += paso", dado que si paso es positivo (en este caso el valor 2),
entonces esta operación es un incremento (y por ende el objeto se desplaza hacia la derecha), pero cuando paso tiene
un valor negativo ( -2 ), entonces esta operación es un decremento (sumar a un valor otro negativo es el equivalente a
restar) y por ende el objeto se dirije a la izquierda. Esta posibilidad del uso del signo para poder realizar decrementos o
incrementos con una sola operación nos permite transformar el cambio de dirección en un cambio de signo, lo que se
resuelve en la operación " paso *= -1", que significa multiplicar a paso por -1 (menos uno). Dado que ambos cambios
de dirección son idénticos, entonces podemos evaluar una única condición que se ver si x se pasó de algún borde (x >
width || x < 0).

En dos dimensiones
El ejemplo que sigue traslada estos conceptos de movimiento unidimensional a un movimiento bi-dimensional.
Simplemento duplicamos las variables x y paso con otras para el movimiento vertical (y y pasoY), dado que el paso del
movimiento vertical se llama pasoY, decidí cambiar el nombre de paso por pasoX. Para el límite vertical usamos la
variable de sistema height que es la altura de la pantalla.

Note que cambiamos la altura con respecto a la anchura, así como el paso de avance horizontal con respecto al vertical,
para mostrar que el ejemplo aún funciona:

int x,y;
int pasoX,pasoY;
void setup(){
size(200,300);
smooth();
x = 87;
y = 13;
pasoX = 2;
pasoY = 4;
}
void draw(){
background(0,0,50);
ellipse(x,y,20,20);
x += pasoX; //movimiento horizontal
if( x > width || x < 0 ){ //bordes horizontales
pasoX *= -1; //cambia de dirección horizontal
}
y += pasoY; //movimiento vertical
if( y > height || y < 0 ){ //bordes verticales
pasoY *= -1; //cambia de dirección vertical
}

Estructuras de control iterativas (repetitivas)


Introducción
Cuando en un apartado anterior introdujimos el tema de las estructuras de control, se dijo que existían dos tipos
principales de estructuras: las condicionales y la iterativas (o repetitivas, que es un sinónimo). Mientras que las
estructuras condicionales permiten bufurcar el flujo de ejecución en función de una condición, las estructuras iterativas
permiten repetir una porción de código en función de una condición.

Los ciclos for-next


La estructura iteartiva más utilizada es la que se conoce como ciclo for-next. Esta estructura permite repetir, una
cantidad determinada de veces, las instrucciones que se encuentran en su interior. Como veremos a continuación, la
estructura posee tre parámetros que son: la inicialización, la condición y el incremento:

...
for( inicializacion ; condición ; incremento ){
cuerpo de la estructura
}
...

Como muestra el esquema anterior, estos tres parámetros van separados por puntos y comas (;) a diferencia de la
mayoría de las instrucciones en donde los parámetros en que los parámetros van separados por comas (,). En el
ejemplo a continuación se muestra una ciclo for-next utilizado para repetir una instrucción 3 veces:

size(200,200);
int a = 10;
for(int i=0 ; i<3 ; i++){
rect( a , 75 , 50 , 50 );
a += 60;
}

En el ejemplo anterior, las intrucciones que se encuentran en el interior del ciclo for-next ( "rect( a ,
75 , 50 , 50 )" y "a += 60") se repiten 3 veces. Es decir que este programa es el equivalente al que sigue, donde la
variable a va adoptando los valores 10,70 y 130, que son las posiciones horizontales de los cuadrados:

size(200,200);
int a = 10;
rect( a , 75 , 50 , 50 );
a += 60;
rect( a , 75 , 50 , 50 );
a += 60;
rect( a , 75 , 50 , 50 );
a += 60;

¿Cómo es que se produce esta repetición? Bueno, la forma en que la estructura se ejecuta es la siguiente:
Paso 1: en el primer ciclo se ejecuta la inicialización (en este caso se declara la variable entera llamada i, y se le asigna
el valor 0 ) y luego se evalua la condición (en este caso se evalua si el valor de la variable i es menor a 3) y si se cumple
se ejecuta el cuerpo de la estructura .
Paso 2: en el siguiente ciclo, ya no se ejecuta la inicialización, sino que se ejecuta el incremento (en este caso i++, que
significa incrementar en 1 el valor de la variable i) y luego se vuelve a evaluar la condición (nuevamente i<3) y si se
cumple la condición se vuelve a ejecutar el cuerpo del ciclo.
Paso 3 al N-ésimo: a partir de aquí la estructura repite los mismos paso que el paso 2.
En el ejemplo anterior, se inicia la variable i en 0 y como cumple la condición de ser menor a 3 (0 es menor que 3),
entonces se ejecuta el cuerpo ( "rect( a , 75 , 50 , 50 )" y "a += 60"), luego se incrementa i (i++) y como i vale 1 y sigue
siendo menor a 3, se vuelve a ejecutar el cuerpo, posteriormente vuelve a hacer el incremento y a evaluar la condición e
i que pasa a valer 2 sigue siendo menor que 3, y se vuelve a ejecutar el cuerpo, hasta que en el siguiente incremento i
pasa a valer 3 que ya no es menor a 3 (sino igual), y por ende termina el ciclo.

La condición
En un ciclo for-next es muy importante que la condición se dé al menos una vez, por que sino no se ingresa nunca en
el ciclo:
size(200,200);
int a = 10;
for(int i=4 ; i<3 ; i++){ //esta línea se modifico poniendo i=4
rect( a , 75 , 50 , 50 );
a += 60;
}

En el ejemplo anterior se muestra queque la condición de i<3 nunca se cumplirá dado que el valor de i se inicia en 4,
por ende nunca se ingresa al ciclo y las instrucciones que está en su interior nunca serán ejecutadas.
Tanto la inicialización, como la condición y el incremento, son muy flexible y permiten utiilizar una gran rango de
operaciones y valores. Por ejemplo la inicialización puede ser con valores distintos de 0 y el incremento puede ser de
valores diferentes a 1 , así como otras operaciones metamáticas más allá de la suma:

for(int i=1 ; i<10 ; i+=2){ //imprime los números impares del 1 al 9


println(i);
}
for(int i=10 ; i>0 ; i--){ //este sería un ciclo que decrece desde 10 a 1
println(i);
}
for(int i=1 ; i<=256 ; i*=2){ //en este los valores se duplican desde 1
println(i); // hasta 256, pasando por 2,4,8,16,32,64 y 128
}

Los bucles infinitos


Otro caso importante de tener en cuenta es el caso del bucle infinito, en donde la condición nunca deja de cumplirse y
por ende el ciclo nunca termina. Cuando esto sucede, generalmente queda bloqueada la máquina (colgada) y a veces
es necesaria apagarla y volver a encenderla:

// si no desea colgar su computadora NO EJECUTE ESTE CÓDIGO


for(int i=1 ; i>0 ; i++){
println(i);
}

Como se puede ver en el caso anterior, la condición de i>0 se cumple siempre, dado qie i se inicia con el valor 1 y en
cada paso se incrementa, pasando por 2, 3, 4, 5, 6, ... y así hasta el infinito.

La practicidad de los parámetros


En el primer ejemplo, la variable a que usamos para determinar la ubicación de los cuadrados, adquiere los valores 10,
60, 130, mientras que la variable del ciclo for-next pasa por los valores 0, 1 y 2. Es posible que la misma variable i del
ciclo adopte los valores que necesitamos para ubicar a los cuadrados:

size(200,200);
for(int i=10 ; i<=130 ; i+=60){
rect( i , 75 , 50 , 50 );
}

Esto es posible por que los valores se incrementan en forma fija (saltando de a 60). Cabe aclarar
que la variable del ciclo for-next puede tener cualquier nombre.

Los ciclos anidados


Supongamos que queremos hacer un tablero de ajedrez, es decir un tablero de 8x8 cuadros en
donde se alternan los cuadros negros y blancos. El primer problema al que nos enfrentamos es el
de hacer los 8x8 cuadros, independientemente del color que tengan. Para hacer una única hilera de
cuadrados podemos seguir los ejemplos anteriores:

size(200,200);
for(int i=0 ; i<8 ; i++){
rect( i * 25 , 0 , 25 , 25 );
}

Si quisieramos repetir 8 veces esta hilera modifiando su posición vertical, entonces debemos anidar dos ciclos for-next,
haciendo que un nuevo ciclo (exterior al anterior) repita 8 veces las instrucciones necesarias para hacer una hilera:

size(200,200);
for(int j=0 ; j<8 ; j++){ //este ciclo repite 8 veces al otro ciclo
for(int i=0 ; i<8 ; i++){
rect( i * 25 , j * 25 , 25 , 25 ); //aqui se // agrego "j * 25"
}
}
Queda pendiente la custión de la alternacia entre cuadros negros y blancos. Para estos
aprovecharemos una propiedad del table: como muestra la figura siguiente, si sumamos el
número de fila más el número de columna en cada cuadro, notaremos que la alternancia entre
resultados pares e impares es equivalente a la de cuadros negros y blancos en una tablero:

Por lo que aprovechamos esta propiedad y utilizamos una estructura if-then-else para pintar
de negro o blanco en función de la paridad de la suma entre el número de fila y el de columna.
En el ejemplo que sigue, el número de fila es j, mientras que el número de columna es i, así
que para evaluar si la suma de estos valores es par, verificamos que el resto de dividir dicha
suma por 2 sea 0, dado que los números pares devuelven resto 0 al ser divididos por 2. Esto
se traduce a preguntar si (i+j) % 2 == 0, dado que el símbolo (%) es el resto de la división
entera:

size(200,200);
for(int j=0 ; j<8 ; j++){
for(int i=0 ; i<8 ; i++){
if( (i+j) % 2 == 0 ){ //si la suma //fila+columna es par entonces pinta de
negro
fill( 0 );
}else{
fill( 255 );
}
rect( i * 25 , j * 25 , 25 , 25 );
}
}

Ejemplo: Estructuras de Control Iterativas: For-Next

size(200,200);
ellipseMode(CORNER);
background(230);
for(int a=0;a<200;a+=20){
ellipse(a,a,18,18);
}
 
Ejemplo: Estructuras de Control Iterativas: For-Next Anidados
 
size(200,200);
ellipseMode(CORNER);
background(230);
for(int a=0;a<200;a+=20){
for(int b=0;b<200;b+=20){
ellipse(a,b,18,18);
}
}
 
Ejemplo: Estructuras de Control Iterativas: For-Next Anidados

void setup(){
size(200,200);
}
void draw(){
background(230);
for(int i=0;i<=200;i+=20){
for(int j=0;j<=200;j+=20){
line(i,j,mouseX,mouseY);
}
}
}

Más ejemplos
En los siguientes ejemplos se utilizan ciclos for-next para realizar degradé pintando pixel x pixel. Para eso utiliza una
instrucción especial de Processing llamada set( ), que permite establecer el color de un pixel determinado. La instrcción
set( ), tiene los siguientes parámetros:

set( x , y , color );
size(200,200);
color c = color( 255 , 0 , 0 );
set( 10 , 20 , c );

Los dos primeros parámetros son la posición horizontal y vertical del pixel (x e y) y el tercer parámetro es un color. El
color se establece con un tipo de dato color que posee Processing. Una variable de tipo color se declara con la palabra
homónima y para asignarle valores es necesario usar la función, también, color( ), que posee tres parámetros, uno para
cada componente color de la paleta RGB (colores primarios de la luz o paleta aditiva del color):
color c;
c = color( red , green , blue );

Los valores de cada canal (red, green y blue, que son rojo, verde y azul respectivamente) pueden adoptar valores entre
0 y 255. Así, en el ejemplo que sigue se puede ver que conforme la variable i aumenta de 0 a 255 (debido al ciclo for-
next), el color rojo aumenta debido a la instrucción que define el color de los pixeles ( "color c = color(i,0,0)" ), en donde
i está puesta en el lugar de la componente roja:

size(255,255);
for(int i=0 ; i<=255 ; i++){
for(int j=0 ; j<=255 ; j++){
color c = color(i,0,0);
set(i,j,c);
}
}

El que sigue es un ejemplo interactivo del anterior sólo que fue variado para que el nivel de verde
aumentara horizontalmente, el nivel de azul, verticalmente, y el valor de rojo en función de la posición horizontal del
mouse.

color c;
void setup(){
size(255,255);
}
void draw(){
for(int i=0;i<=255;i++){
for(int j=0;j<=255;j++){
c= color(mouseX,i,j);
set(i,j,c);
}
}
}

Otro ejemplo, pero en este el fondo y las figuras tienen distintos degradé que responden al mouse:

color c;
void setup(){
size(250,250);
noStroke();
ellipseMode(CORNER);
}
void draw(){
for(int i=0;i<=250;i++){
for(int j=0;j<=250;j++){
c=color(mouseX,i,j);
set(i,j,c);
}
}
for(int a=0;a<250;a+=25){
for(int b=0;b<250;b+=25){
c= color(255-mouseX,a,b);
fill(c);
ellipse(a+2,b+2,20,20);
}
}
}
 
Por último, el ejemplo que sigue aprovecha este recurso expresivo, de variar en forma independiente los degradé de las
figuras y los fondos, para hacer un modesto homenaje a un gran artista que se llamó Victor Vasarely.
El ejemplos que sigue tiene como detalle interesante el hecho de que el límite del ciclo for-next está determinado por
una variable en vez de una cosntante, lo que significa que la cantidad de veces que se repite la estructura varía en cada
ejecución del ciclo. Es importante entender que Processing ejecuta todo el ciclo antes de mostrar el fotograma,
recordemos que Processing procesa por defecto 30 fotogramas por segundo, con lo que toda la ejecucióndel ciclo se
produce con esta tasa. En el ejemplo que sigue, la condición del ciclo está determinada por una comparación con
mouseX:

void setup(){
size(250,250);
noStroke();
rectMode(CORNERS);
background(0,0,255);
}
void draw(){
for(int i=0;i<=120 && i< mouseX;i+=10){//en esta lìnea
se produce la condición
fill(i*2,0,250-i*2);
rect(i,i,250-i,250-i);
}
}

Otro ejemplo:

int px,py;
void setup(){
size(250,250);
noStroke();
rectMode(CENTER);
background(0,0,255);
}
void draw(){
for(int i=0;i<=240;i+=10){
px=int(mouseX/250.0*i+(250-i)/2);
py=int(mouseY/250.0*i+(250-i)/2);
fill(0,i,0);
rect(px,py,250-i,250-i);
}
}
 
El ejemplo que sigue, dibuja una grilla de cuadrados en donde sus tamaños disminuyen conforme aumenta el número
de fila o columna, determinando primero cual de estos dos números es mayor:

int mayor;
size(400,400);
background(0);
rectMode(CENTER);
noStroke();
for(int i=0 ; i<20 ; i++){
for(int j=0 ; j<20 ; j++){
if(i>j){
mayor=i;
}else{
mayor=j;
}
rect( i*20+10 , j*20+10 , 20-mayor-1 , 20-mayor-1 );
}
}

El ejemplo que sigue es idéntico, pero se diferencia en que es vez de ver cuál es mayor de las dos magnitudes (el
número de fila o columna), ve cuál es menor:

int menor;
size(400,400);
background(0);
rectMode(CENTER);
noStroke();
for(int i=0 ; i<20 ; i++){
for(int j=0 ; j<20 ; j++){
if( i<j ){
menor=i;
}else{
menor=j;
}
rect( i*20+10 , j*20+10 , 20-menor-1 , 20-menor-1 );
}
}
El ejemplo que sigue es una grilla de círculos en donde su tamaño depende de la posición horizontal del mouse.
(Recuerde que algunos navegadores requieren que ud. haga click en el applet para ponerlo en foco y poder interactuar
con el mismo):

void setup(){
size(400,400);
ellipseMode(CENTER);
}
void draw(){
background(255);
fill(0);
float ancho=mouseX/5;
for(int i=0;i<=400;i+=40){
for(int j=0;j<=400;j+=40){
ellipse(i+20,j+20,ancho,ancho);
}
}
}

En el ejemplo que sigue el criterio es similar. El tamaño está determinado por la distancia vertical al mouse. Como la
posición vertical del mouse es mouseY y el ciclo que recorre las posiciones verticales de los cículos es j, la distancia
vertical está determinada por la operación: abs(mouseY-j) En donde la función abs( ) significa el valor absoluto que es
la magnitud de un número desprovisto de signo, es decir que el resultado siempre es positivo sin importar de que el
signo del resultado de la resta mouseY-j dé negativo:

void setup(){
size(400,400);
ellipseMode(CENTER);
}
void draw(){
background(255);
fill(0);
for(int j=0;j<=400;j+=40){
float ancho=abs(mouseY-j)/5;
for(int i=0;i<=400;i+=40){
ellipse(i+20,j+20,ancho,ancho);
}
}
}

Números pseudo-aleatorios
El azar y los números pseudo-aleatorios
En la computación no existen los números al azar dado que la computadoras son máquinas "idealmente" determinista,
existen varios factores físicos que agregan un factor de aleaoriedad a las computadoras, pero en principio las
computadoras son deterministas. Debido a esto y a la necesidades que surgen de disponer de valores aleatorios,
existen funciones de números pseudo-aleatorios que nos permiten escapar del determinismo computacional. Estas
funciones son capaces de generar secuencias de números con patrones análogos a los números aleatorios.
En Processing la función que permite generar números pseudo-aleatorios se llama random( ) y puede usar uno o dos
parámetros. Si usa uno, la función arroja números cada vez que se la invoca, restringiendo estos valores entre cero y el
valor del parámetros. En el ejemplo siguiente la función random( ) arroja valores entre 0 y 10:

void setup(){
}
void draw(){
float a = random(10);
println( a );
}

Estos valores pueden ser utilizados para obtener parámetros como la posición de un rectángulo en la pantalla:

void setup(){
size(200,200);
background(0);
fill(100,100,255,100);
}
void draw(){
rect( random(width) , random(height) , 20 , 20 );
}
void mousePressed(){
background(0);
}
En este ejemplo las funciones random(width) y random(height) devuelven valores pseudo-aleatorios para la posición
horizontal (entre cero y el ancho de la pantalla) y para la posición vertical (entre cero y el alto de la pantalla). Mientras
no se presione el mouse, el draw( ) acumula cuadrados en la pantalla.

Límite superior e inferior


Tambiém es posible restringir el límite inferior y superior de la función random( ) usando dos parámetros: En el ejemplo
que sigue, la función random(10,20) devuelve valores pseudo-aleatorios entre 10 y 20:

void setup(){
}
void draw(){
float a = random(10,20);
println( a );
}

Esto es útil en casos como el del ejemplo que sigue, en el que queremos que los números de la secuencia ronden por
las valores de la posición horizontal y vertical del mouse:

int col;
void setup(){
size(400,400);
background(0);
colorMode(HSB);
col = 0;
}
void draw(){
col = (col+1) % 256;
fill(col,255,255,100);
ellipse(
random(mouseX-30, mouseX+30) ,random(mouseY-30,mouseY+30)
, 20 , 20 );
}
void mousePressed(){
background(0);
}

En este ejemplo las funciones random( mouseX-30 , mouseX+30 ) y random( mouseY-30 , mouseY+30 ) devuelven
valores al pseudo-aleatorios dentro de los un rango de 30 píxeles verticales y horizontales del mouse. Cuando se
presiona el botón, se ejecuta el background(0) que pinta el fondo de negro.
La forma en que se suceden cíclicamente los colores es por el uso de la paleta HSB, Processing permite usar esta
paleta cuya sigla significa Hue, Saturation y Brightness (Tinte, Saturación y Brillo). Con la instrucción
colorMode(HSB) se determina que se usara la paleta HSB (caso contrario sería colorMode(RGB) para la paleta RGB).
Usando esta paleta las instrucciones de pintado, como fill( ) usan 3 o 4 parámetros: tinte, saturación, brillo y
opacidad (en caso de usar 4 parámetros). Así la variable llamada col y que tiene un incremento cíclico dada la
operación "col = (col+1) % 256", permite ir cambiando el tinte.

El ruido
El ejemplo que sigue utiliza la función random( ) para agregarle ruido de desenfoque a la
imagen. Para ello, imprime la imagen pixel por pixel pero el color lo toma de otro pixel
ligeramente vecino a este. Para trabajar con los pixeles de la imagen usa un tipo de datos de
Processing llamado PImage que permite levantar un jpg. (con la función loadImage( ) ),
imprimirla en pantalla con la instrucción image( ), así como leer el color de cada uno de sus
píxeles con la función get( ). El nivel de ruido depende de la posición vertical del mouse:
 
PImage imagen; // tipo PImage para cargar imágenes
void setup(){
size(200,300);
imagen = loadImage("rana.jpg"); //carga un jpg
background(0); //pinta de negro
image(imagen, 0, 0); //imprime la imagen
}
void draw(){
float des = (height-mouseY) / 20; //determina el nivel de desenfoque en función de la
posición vertical del mouse
for(int x=0 ; x<200 ; x++){ //recorre horizontalmente
for(int y=0 ; y<150 ; y++){ //recorre verticalmente
color este; //declara la variable este de tipo color
este = imagen.get( x+int( random(-des,des) ) , y+int( random(-des,des) ) ); //toma
el color de un pixel con un nivel de desenfoque
set( x , y+150 , este ); //imprime el color del pixel tomado
}
}
}
El desenfoque se produce por que en vez de tomar el color del pixel que le corresponde se lo desplaza ligeramente a
través de número pseudo-aleatorios, esto sucede en la instrucción:

este = imagen.get( x+int( random(-des,des) ) , y+int( random(-des,des) ) );

En donde imagen.get( x , y ) lee el color del pixel x,y. En este caso en vez de x se le pasa como parametro:

x+int( random(-des,des) )

Que combina la función int( ) que transforma los valores reales de la función
random( ) en valores enteros. Cuanto más grande sea el valor de la variable
llamada des, mayor será el desenfoque que produce.

La aleatoriedad como recurso expresivo


El ejemplo que sigue aprovecha el random( ) como un recurso expresivo. En cada
vuelta de animación, elige un pixel al azar de la imagen, captura su color y luego
imprime un rectángulo con una tamaño decidido al azar y con el mismo color (más
transparente) que el pixel original. Si presiona el mouse el procedimiento se
reinicia:

 PImage imagen; // tipo PImage para cargar imágenes


void setup(){
size(400,450);
imagen = loadImage("rana.jpg"); //carga un jpg
noStroke();
rectMode(CENTER);
background(0); //pinta de negro
image(imagen, 0, 0); //imprime la imagen
}
void draw(){
float des = (height-mouseY) / 20; //determina el nivel de desenfoque en función de la
posición vertical del mouse
color este; //declara la variable este de tipo color
int x = int( random(200) ); //toma una posición horizontal al azar
int y = int( random(150) ); //toma una posición vertical al azar
este = imagen.get( x , y ); //toma el color del pixel elegido
fill( red(este) , green(este) , blue(este) , 100 ); //usa ese color como relleno
dándoles cierta transparencia
stroke(este); //usa ese color de contorno
float lado = random(3,20); //elige el tamaño del cuadrado para pintar el pixel
rect( x * 2 , y * 2 +150, lado , lado ); //pinta el pixel duplicando el tamaño del
dibujo
}
void mousePressed(){
background(0); //pinta de negro
image(imagen, 0, 0); //imprime la imagen
}

Arreglos
Introducción
Como vimos en los apartados anteriores, las estructuras iterativas permiten repetir un proceso una gran cantidad de
veces, en contraste, cuando se desea realizar un tratamiento homogéneo sobre una gran cantidad de información, las
variables, como se han visto hasta aquí, son insuficientes. Esto es debido a que cuandosi desea repetir un procesos
sobre una gran cantidad de variables es necesario recurrir a estas haciendo referencia a diferentes nombres, lo que
imposibilita utilizar una estructura repetitiva. Por ejemplo, el siguiente es un programa para realizar un promedio de un
alumno:
 
float calificacion1 = 9.5;
float calificacion2 = 7;
float calificacion3 = 5;
float total = 0;
int cantidad = 3;
total += calificacion1;
total += calificacion2;
total += calificacion3;
float promedio = total/cantidad;

Si la cantidad de calificaciones a ser promediadas fuesen muchas (por ejemplo 500) el anterior procedimiento no sería
aplicable. En una caso como este sería deseable contar con algún tipo de variable que a partir de un único identificador
(nombre de la variable) permitiese acceder a gran cantidad de información para der el mismo tratamiento a toda esta
información.

Los arreglos
Los arreglos (ver definición en wikipedia) son variables que permiten acceder a una gran cantidad a partir de una único
identificador y un índice. Los arreglos pueden ser de varias dimensiones en función de la cantidad de índices que
utilizan. Los arreglos de una dimensión son llamados vectores, los de dos dimensiones se llaman matrices, los de tres
o más dimensiones se llaman tensores. Los arreglos además de ser inicializados, deben ser dimensionados,
asignándoles una extensión, es decir la cantidad de celdas de memoria que utilizará:
 
float[] calificacion; //inicializacion del arreglo
calificacion = new float[100]; //dimensión del arreglo
calificacion[0] = 9.5; //asignacion de la primer celda
calificacion[1] = 7.0; //asignacion de la segunda celda

También es posible dimensionar y asignar datos en un mismo paso, como se muestra en el siguiente ejemplo:
 
// inicializacion, dimensión
// y asignaciones del arreglo
float[] calificacion = { 9.5 , 7 , 6.5 , 8 , 10 };
float total = 0;
int cantidad = calificacion.length();
for( int i=0 ; i<cantidad ; i++ ){
• total += calificacion[ i ];
}
float promedio = total/cantidad;
println( "El promedio es " + promedio );

En la tercer línea del ejemplo anterior, se declara el arreglo al mismo tiempo que se le asignan 5 datos ( 9.5 , 7 , 6.5 , 8 y
10 ) lo que determina la extensión de este arreglo ( 5 ). La función length (en la quinta línea) retorna la cantidad de
celdas que tiene el arreglo, en este caso, obviamente 5. Las celdas en el arreglo se numeran desde el índice 0 (cero)
hasta la cantidad menos uno (4 en este caso), que son justamente los valores que adquiere la variable i en el ciclo for.

Un ejemplo interactivo
El ejemplo que sigue permite generar círculos con el mouse, haciendo click en el fondo
se genera un nuevo círculo, y cuando se hace click sobre un círculo ya creado, se le
modifica el color y se lo arrastra.
 
float[] x , y , tinta , radio ; //declaracion de los arreglos
// necesarios para dibujar los círculos: la posición -x,y-
// el color -la tinta- y el tamaño -radio-
int limite; //variable para definir el limite de los arreglos
int cantidad; //variable para contar los circulos
void setup(){
size(400,400);
// INICIALIZAR LA MEMORIA

limite = 50; //se define que la cantidad limite de circulos es de 50


cantidad = 0; //se inicia la cantidad de circulos en cero
x = new float[limite]; //declara los arreglos con 50 posiciones de memoria cada uno
y = new float[limite];
tinta = new float[limite];
radio = new float[limite];
colorMode(HSB);
noStroke();
smooth();
}
void draw(){
background(240);
if( mousePressed ){ //verifica si se presionó el mouse
boolean tocoAlguno = false; //se declara esta variable para verificar si el mouse toco
// algún círculo
// VERIFICA SI SE HIZO CLICK SOBRE UN CÍRCULO YA EXISTENTE
for( int i=0 ; i<cantidad ; i++ ){ //recorre los círculos existentes
if( dist( x[i] , y[i] , mouseX , mouseY ) < radio[i] ){ //revisa en cada círculo
// para ver si el cursor está dentro del círculo
//CAMBIAR EL ASPECTO DEL CÍRCULO SELECCIONADO
x[i] = mouseX; // entonces actualiza la posición del círculo en función del mouse
y[i] = mouseY;
tinta[i] = ( tinta[i] + 1 ) % 255; // incrementa la tinta
tocoAlguno = true; // pone la variable en "true" para especificar que un círculo
// fue tocado
break; // rompe el ciclo for
}
}

//SI NO TOCÓ NINGÚN CÍRCULO


if( ! tocoAlguno && cantidad<limite ){ // si no tocó ningún círculo
// y todavía existen lugares pendientes entonces crea uno nuevo
//ALMACENAR EN MEMORIA UN NUEVO CÍRCULO
x[cantidad] = mouseX; // crea el círculo en la posicion del mouse
y[cantidad] = mouseY;
tinta[cantidad] = random(255); // le asigna una tinta al azar
radio[cantidad] = random(20,80); // le asigna un tamaño al azar
cantidad++; // incrementa la cantidad de círculos
}
}
// DIBUJAR LOS CÍRCULOS ALMACENADOS EN MEMORIA
for( int i=0 ; i<cantidad ; i++ ){ // recorre cada círculo creado para dibujarlo
fill( tinta[i] , 255 , 255 , 100 );
ellipse( x[i] , y[i] , radio[i]*2 , radio[i]*2 );
}
}

Para poder realizar esta aplicación, se necesita algún tipo de memoria que guarde las posiciones, colores y tamaños de
cada uno de los círculos que son creados para luego poder dibujarlos en forma actualizada. La estructura general de
esta aplicación en pseudocodigo es la siguiente:
 
void setup(){
Inicializar la memoria
}
void draw(){
if( mousePressed ){
if( Hizo clik sobre un círculo ya existente ){
Cambiar el aspecto del círculo seleccionado
}
if( No toco ningún circulo ){
Almacenar en memoria un nuevo círculo
}
}
Dibujar los círculos almacenados en memoria
}

El esquema anterior no es código ejecutable, sino un esquema que combina código ejecutable y explicaciones literales
para mostrar la estructura del programa. Luego veremos que las explicaciones literales serán reemplazadas por código
ejecutable, de hecho, en el código fuente del ejemplo hay comentarios que indícan las partes correspondientes a estos
literales. Si revisamos con atención el esquema anterior veremos que la idea es crear y actualizar una memoria donde
se almacenan las posiciones, colores y tamaño de los círculos que hay en pantalla. Luego un parte de la estructura se
encarga de dibujar en cada ciclo del void draw() a los círculos que hay almacenados hasta el momento.
Cabe aclarar que la instrucción if( mousePressed ){ está preguntando "si el mouse está siendo precionado", dado
que mousePressed es una variable de estado que permite saber si el mouse está siendo presionado o no. Esta
variable es boolean y devuelve true cuando el mouse está siendo presionado, y false cuando no lo está.
La forma en que se implementa esta memoria es utilizando arreglos. Para la realización de esta aplicación es necesario
crear cuatro arreglos que sirven para almacenar la posición, color y tamaño de los círculos. Estos arreglos se declaran
fuera del void setup() y del void draw() para que sean globales, es decir, para que puedan ser visto desde cualquier
parte del algoritmo. Si por el contrario, fueran declarados dentro de alguna de estas estructuras (por ejemplo el void
setup() ) no podrían ser accedidos desde fuera de dicha estructura. También se declaran dos variables: limite y
cantidad, que son utilizadas para especificar la cantidad límite de círculos que se pueden crear (imite) y la cantidad
creada hasta el momento (cantidad). El código a continuación es el necesario para inicializar la memoria :
 
float[] x , y , tinta , radio ;
int limite;
int cantidad;
void setup(){
size(400,400);
limite = 50;
cantidad = 0;
x = float[limite];
y = new float[limite];
tinta = new float[limite];
radio = new float[limite];

La variable cantidad funciona de la siguiente manera: cuando inicia la aplicación la variable tiene valor igual a cero.
Cuando el usuario hace click, si no se ha tocado ningún círculo, se genera un nuevo círculo. Se le asigna la posición
tomando las coordenadas del cursor y cargándola en los arreglos x e y. El color y el tamaño se establecen asignandoles
valores al azar a los arreglos tinta y radio, respectivamente. Cuando el círculo que se agrega es el primero, el valor de
cantidad es cero y por lo tanto los valores del primer círculo se carga en la primer celda de los arreglos, es decir en la
que tiene índice igual a cero. Pero inmediatamente después se incrementa el valor de de la variable cantidad, esto se
hace con dos fines: para registrar la cantidad de círculos almacenados y para saber el siguiente lugar disponible para
cargar un círculo. El siguiente código es el que sirve para almacenar en memoria un nuevo círculo :
 
...
if( mousePressed ){
...
if( ! tocoAlguno && cantidad<limite ){
x[cantidad] = mouseX;
y[cantidad] = mouseY;
tinta[cantidad] = random(255);
radio[cantidad] = random(20,80);
cantidad++;
...

Para ilustrar lo que hace el anterior código, imaginemos el sguiente proceso: cuando la
aplicación se inicia por primera vez, la variable cantidad vale cero y aún no fue ingresado
ningún dato a los arreglos. El sguiente gráfico muestra los cuatro arreglos vacios y la
variable cantidad con el valor cero:

Cuando el usuario hace click y no se ha tocado ningún círculo,


entonces se ingresan los valores de la posición, color y tamaño en los arreglos, usando el
valor de cantidad como índice, es decir se carga el índice cero de cada uno de los
arreglos. Por lo que x[cantidad]=mouseX se traduce como x[0]=mouseX, y se carga el
valor de la posición horizontal del mouse en la primer celda (la celda con índice cero) de X:

Luego se incrementa en uno a la variable cantidad, por lo que pasa a valor uno. En este
momento la variable cantidad indica exactamente la cantidad de datos cargados por
arreglo, pero también indica el valor del siguiente índice donde se cargaran los nuevos
datos:

Cuando el usuario vuelve a hacer click, vuelve a cargar los datos en el índice que indica la
variable cantidad, pero en este caso x[cantidad]=mouseX se traduce como
x[1]=mouseX, dado que ahora el valor de cantidad es uno:

Luego vuelve a incrementar la variable cantidad que pasa a valer dos, y nuevamente muestra la cantidad de datos
cargados y el próximo índice a utilizar.
Dado que la variable cantidad sirve para saber, justamente, la cantidad de círculos almacenados hasta el momento,
esta información es útil para recorrer los arreglos con un ciclo for a la hora de imprimir los círculos en pantalla, como
muestra el código para dibujar los círculos almacenados en memoria :
 
...
for( int i=0 ; i<cantidad ; i++ ){
fill( tinta[i] , 255 , 255 , 100 );
ellipse( x[i] , y[i] , radio[i]*2 , radio[i]*2 );
}
...

En el código anterior la variable que recorre los índices de los arreglos, es la variable i del ciclo for. En este momento,
cómo cantidad vale dos, el ciclo for le asigna a la variable i los valores cero y uno, que son casualmente los índice
que estan cargados en los arreglos. Así en la instrucción ellipse( x[i] , y[i] , radio[i]*2 , radio[i]*2 ) la cuando la variable
i vale cero, se traduce como ellipse( x[0] , y[0] , radio[0]*2 , radio[0]*2 ). Y dado que
x[0], y[0] y radio[0] valen 56, 108 y 30, respectivamente, entonces la instrucción queda
finalmente así: ellipse( 56 , 108 , 30*2 , 30*2).
Por último, queda por ver cómo es que se selecciona un círculo ya existente. La forma en
que se realiza esto es recorrer uno por uno los círculos y verificar si la distancia entre el
mouse y el centro del círculo es menor al radio:

Para revisar la distancia, Processing tiene una función llamada dist(), a la que se le pasa 4
parámetros que son las posiciones X e Y de los dos puntos entre los que se quiere medir
la distancia:

Así para revisar uno por uno las distancia del mouse a cada uno de los centros de los
círculos, se usa un ciclo for que recorre con el índice i cada uno de los círculo y preguntar
por la distancia al mouse: dist( x[i] , y[i] , mouseX , mouseY ) < radio[i]
El código que sigue sirve para verificar si hizo clik sobre un círculo ya existente y en caso
de ser así, entonces cambiar el aspecto del cículo seleccionado :
 
...
boolean tocoAlguno = false;
for( int i=0 ; i<cantidad ; i++ ){
if( dist( x[i] , y[i] , mouseX , mouseY ) < radio[i] ){
x[i] = mouseX;
y[i] = mouseY;
tinta[i] = ( tinta[i] + 1 ) % 255;
tocoAlguno = true;
break;
}
}
...

Dado que deseamos modificar un círculo por vez, es necesario cortar el cíclo for una vez que se encuentra un cículo.
Esto lo hace la instrucción break. Esta instrucción interrumpe el ciclo for, por eso se ejecuta cuando el mouse cae
dentro de un círculo y se actualizan los datos del círculo seleccionado.
La variable tocoAlguno sirve para verificar si algún círculo fue tocado por el mouse, en principio se le asigna un valor
false, que sólo es cambiado si alguno de los círculos es tocado, en cuyo caso se le asigna el valor true. Esta variable
sirve para la parte que almacenar en memoria un nuevo círculo, dado que sólo crea un nuevo círculo si el mouse no
toco ninguno de los existentes, esto lo puede preguntar de la siguiente manera: if( ! tocoAlguno ){

Ejemplos
El siguiente ejemplo permite grabar la huella que se deja cuando se mueve el mouse. Para eso usa dos vectores
llamados X e Y que son recorridos por dos contadores llamados cont e i, que sirven para mover la cabeza grabadora y
la cabeza de reproducción, respectivamente:

boolean grabando; //variable que indica el estado


int[] x,y; //vectores donde se cargan las posiciones del
mouse
int cont,i;
int contColor;

void setup(){
size(400,400);
noStroke();
colorMode(HSB);

grabando = false; //se inicia en modo reproducción


x = new int[100000];
y = new int[100000];
cont = 0;
i = 0;
contColor = 0;
}

void draw(){
contColor = (contColor+1) % 256; //incrementa cíclicamente de 0 a 255
fill(0,0,0,10); //pinta el fondo de color
rect(0,0,width,height);//negro transparente

fill(contColor,255,255,60); //pone el color de relleno de los círculos

grabando = mousePressed; //si el mouse está siendo presionado pasa a modo grabación

if(grabando){
ellipse(mouseX,mouseY,10,10);
x[cont]=mouseX;//guarda un nuevo dato
y[cont]=mouseY;
cont++; //incrementa el puntero
}

ellipse(x[i],y[i],50,50);

i++; //con esta variable recorre el reproductor


if(i>=cont){
i=0;
}
}

El siguiente ejemplo permite dibujar rectánguloas presionando y arrastrando el mouse.

int estado,cont;
int[] x1=new int[1000];
int[] x2=new int[1000];
int[] y1=new int[1000];
int[] y2=new int[1000];
int actualX1,actualY1;

void setup(){
size(400,400);
rectMode(CORNERS);
estado=0;
cont=0;
}

void draw(){
background(0);
stroke(0,255,0);
noFill();

rect(375,1,398,25); //dibuja
line(375,1,398,25); //el boton de la esquina
line(375,25,398,1); //superio derecha

fill(0,255,0,30);

for(int i=1;i<=cont;i++){ //imprime todos los rectangulos ya grabados, de color


verde
rect(x1[i],y1[i],x2[i],y2[i]);
}
if(estado==1){ //si el botón del mouse está presionado (es decir que está
generando un rectangulo)
stroke(0,0,255); //pone color rojo para el que se está generando
fill(0,0,255,30);
rect(actualX1,actualY1,mouseX,mouseY);
}
}

void mousePressed(){
if(mouseX>357 && mouseY<25){//si el mouse fue presionado en el cuadrado de la esquina
entonces
cont=0; //borra todo
estado=0;
}
else{
estado=1; //cuando se presiona el boton estado pasa a 1 (generación)
actualX1=mouseX; //guarda los datos de la
actualY1=mouseY; //primer esquina del rectangulo
}
}

void mouseReleased(){
if(!(mouseX>357 && mouseY<25)){//si el mouse no fue presionado en el cuadrado de la
esquina entonces
estado=0;
cont++; //cuenta un nuevo rectangulo
x1[cont]=actualX1; //y agrega el nuevo rectangulo
y1[cont]=actualY1;
x2[cont]=mouseX;
y2[cont]=mouseY;
}
}

You might also like