Gráficos con Java 2D

Cambiando el punteado y los atributos de dibujo en el contexto de Graphics2D, antes del dibujo, podemos f�cilmente aplicar estilos divertidos de l�neas y patrones de relleno para gr�ficos primitivos. Por ejemplo, podemos dibujar una l�nea punteada creando el objeto Stroke apropiado y llamando a setStroke para a�adirlo al contexto Graphics2D antes de dibujar la l�nea. De forma similar, podemos aplicar un relleno de gradiente a un Shape creando un objeto GradientPaint y a�adiendo al contexto Graphics2D llamando a setPaint antes de dibujar la Shape.

El siguiente applet demuestra c�mo podemos dibujar formas geom�tricas usando los m�todos Graphics2D draw y fill.

Pulsa sobre la imagen para ejecutar el  applet.

Esta es una imagen del GUI del applet. Para ajecutar el applet, pulsa sobre ella. El applet aparecer� en una nueva ventana del navegador.

ShapesDemo2D.java contiene el c�digo completo de este applet.

Cada una de las formas dibujadas por el applet est� construida de geometr�as y est� dibujada a trav�s de Graphics2D. Las variables rectHeight y rectWidth de este ejemplo definen las dimensiones del espacio en que se dibuja cada forma, en pixels. La variables x e y cambian para cada forma para que sean dibujadas en formaci�n de parrilla.

�
// draw Line2D.Double
g2.draw(new Line2D.Double(x, y+rectHeight-1,
                          x + rectWidth, y));
�
// draw Rectangle2D.Double
g2.setStroke(stroke);
g2.draw(new Rectangle2D.Double(x, y,
                               rectWidth,
                               rectHeight));
�
// draw RoundRectangle2D.Double
g2.setStroke(dashed);
g2.draw(new RoundRectangle2D.Double(x, y,
                                   rectWidth,
                                   rectHeight,
                                   10, 10));
�
// draw Arc2D.Double
g2.setStroke(wideStroke);
g2.draw(new Arc2D.Double(x, y,
                         rectWidth,
                         rectHeight,
                         90, 135,
                         Arc2D.OPEN));
�
// draw Ellipse2D.Double
g2.setStroke(stroke);
g2.draw(new Ellipse2D.Double(x, y,
                             rectWidth,
                             rectHeight));
�
// draw GeneralPath (polygon)
int x1Points[] = {x, x+rectWidth,
                  x, x+rectWidth};
int y1Points[] = {y, y+rectHeight,
                  y+rectHeight, y};
GeneralPath polygon = new
	 GeneralPath(GeneralPath.WIND_EVEN_ODD,
		     x1Points.length);
polygon.moveTo(x1Points[0], y1Points[0]);

for (int index = 1;
     index < x1Points.length;
     index++) {
        polygon.lineTo(x1Points[index],
                       y1Points[index]);
};

polygon.closePath();
g2.draw(polygon);
�
// draw GeneralPath (polyline)
int x2Points[] = {x, x+rectWidth, x,
                  x+rectWidth};
int y2Points[] = {y, y+rectHeight,
                  y+rectHeight, y};
GeneralPath polyline = new
         GeneralPath(GeneralPath.WIND_EVEN_ODD,
           	     x2Points.length);

polyline.moveTo (x2Points[0], y2Points[0]);

for (int index = 1;
     index < x2Points.length;
     index++) {
 	 polyline.lineTo(x2Points[index],
         y2Points[index]);
};

g2.draw(polyline);
�
// fill Rectangle2D.Double (red)
g2.setPaint(red);
g2.fill(new Rectangle2D.Double(x, y,
        rectWidth, rectHeight));
�
// fill RoundRectangle2D.Double
g2.setPaint(redtowhite);
g2.fill(new RoundRectangle2D.Double(x, y,
                                   rectWidth,
                                   rectHeight,
                                   10, 10));
�
// fill Arc2D
g2.setPaint(red);
g2.fill(new Arc2D.Double(x, y, rectWidth,
                         rectHeight, 90,
                         135, Arc2D.OPEN));
�
// fill Ellipse2D.Double
g2.setPaint(redtowhite);
g2.fill (new Ellipse2D.Double(x, y,
                              rectWidth,
                              rectHeight));
�
// fill and stroke GeneralPath
int x3Points[] = {x, x+rectWidth, x,
                  x+rectWidth};
int y3Points[] = {y, y+rectHeight,
                  y+rectHeight, y};

GeneralPath filledPolygon = new
         GeneralPath(GeneralPath.WIND_EVEN_ODD,
		     x3Points.length);
filledPolygon.moveTo(x3Points[0],
                     y3Points[0]);

for (int index = 1;
     index < x3Points.length;
     index++) 	{
	filledPolygon.lineTo(x3Points[index],
                             y3Points[index]);

};
filledPolygon.closePath();
g2.setPaint(red);
g2.fill(filledPolygon);

Observa que este ejemplo usa implementaciones de doble precision de las clases geom�tricas. Donde sea posible, las implementaciones de los float y doble precisi�n de cada geom�trico est�n proporcionados por clases internas.

.�Dibujar Curvas

Los applets Cubic y Quad demuestran como crear curvas c�bicas y cuadr�ticas usando CubicCurve2D y QuadCurve2D. Estos applets tambi�n demuestran como se dibujan las curvas con respecto al posicionamiento de los puntos de control permitiendonos mover interactivamente tanto los puntos de control como los puntos finales.

.�Ejemplo: Quad

El applet Quad demuestra una curva cuadr�tica, que es un segmento de curva que tiene dos puntos finales y un �nico punto de control. El punto de control determina la forma de la curva controlando tanto el punto de control como los vectores tangenciales de los puntos finales.

Pulsa sobre la imagen para ejecutar  el applet.

Esta es una imagen del GUI del applet. Para ajecutar el applet, pulsa sobre ella. El applet aparecer� en una nueva ventana del navegador.

Quad.java contiene el c�digo completo de este applet.

Primero se crea una nueva curva cuadr�tica con dos puntos finales y un punto de control y las posiciones de los puntos se seleccionan con respecto al tama�o de la ventana.

QuadCurve2D.Double quad = new QuadCurve2D.Double();

Point2D.Double start, end, control;
start = new Point2D.Double();
one = new Point2D.Double();
control = new Point2D.Double();

quad.setCurve(start, one, control);

start.setLocation(w/2-50, h/2);
end.setLocation(w/2+50, h/2);
control.setLocation((int)(start.x)+50, (int)(start.y)-50);

Cada vez que el usuario mueva uno de los puntos, la curva se resetear�.

quad.setCurve(start, control, end);

.�Ejemplo: Cubic

El ejemplo Cubic muestra una curva c�bica, que es un segmento de curva que tiene dos puntos finales y dos puntos de control. Cada punto de control determina la forma de la curva mediante el control de uno de los vectores tangenciales de un punto final. En el ejemplo Cubic, las cruces coloreadas se dibujan donde se encuentran los puntos de control y los puntos finales. El punto de control azul controla el punto final rojo y el punto de control verde controla el punto final magenta.

Pulsa sobre la imagen para ejecutar  el applet.

Esta es una imagen del GUI del applet. Para ajecutar el applet, pulsa sobre ella. El applet aparecer� en una nueva ventana del navegador.

Cubic.java contiene el c�digo completo de este applet.

Una curva c�bica se crea con dos puntos finales y dos puntos de control y las localizaciones de los puntos se seleccionan con respecto al tama�o de la ventana.

CubicCurve2D.Double cubic = new CubicCurve2D.Double();

Point2D.Double start, end, one, two;
start = new Point2D.Double();
one = new Point2D.Double();
two = new Point2D.Double();
end = new Point2D.Double();

cubic.setCurve(start, one, two, end);

...
start.setLocation(w/2-50, h/2);
end.setLocation(w/2+50, h/2);
one.setLocation((int)(start.x)+25, (int)(start.y)-25);
two.setLocation((int)(end.x)-25, (int)(end.y)+25);

Como en el ejemplo Quad, la curva es reseteada cada vez que se mueven los puntos.

cubic.setCurve(start, one, two, end);

.�Dibujar formas arbitrarias

El ejemplo ShapesDemo usa GeneralPath para hacer pol�gonos en forma de cristales, pero tambien podemos usar GeneralPath para hacer formas arbitrarias tanto con l�neas rectas como curvas.

.�Ejemplo: Odd_Shape

El ejemplo Odd_Shape usa GeneralPath para crear formas arbitrarias en la secci�n Formas.

Pulsa sobre la imagen para ejecutar  el applet.

Esta es una imagen del GUI del applet. Para ajecutar el applet, pulsa sobre ella. El applet aparecer� en una nueva ventana del navegador.

Odd_Shape.java contiene el c�digo completo de este applet.

El siguiente c�digo crea un nuevo GeneralPath y a�ade el primer punto al path.

GeneralPath oddShape = new GeneralPath();
...
x = w/2 + 50;
y = h/2 - 25;

x2 = x;
y2 = y;

oddShape.moveTo(x, y);

Despu�s de a�adir el primer punto al path, se a�aden tres l�neas rectas.

x -= 100;
oddShape.lineTo(x, y);
y += 50;
oddShape.lineTo(x, y);
x += 100;
oddShape.lineTo(x, y);

Finalmente, se a�ade una curva c�bica.

x += 10;
y -= 10;
x1 = x - 20;
y1 = y - 20;
oddShape.curveTo(x, y, x1, y1, x2, y2);

.�Definir Estilos de l�nea divertidos y Patrones de relleno.

Probablemente habr�s observado en el ejemplo anterior algunas de las formas tienen l�neas punteadas o est�n rellenas con gradientes de dos colores. Usando las clases Stroke y Paint de Java 2D, podemos f�cilmente definir estilos de l�nea divertidos y patrones de relleno.

.�Estilos de L�nea

Los estilos de l�nea est�n definidos por el atributo stroke en el contexto Graphics2D. Para seleccionar el atributo stroke podemos crear un objeto BasicStroke y pasarlo dentro del m�todo Graphics2D setStroke.

Un objeto BasicStroke contiene informaci�n sobre la anchura de la l�nea, estilo de uniones, estilos finales, y estilo de punteado. Esta informaci�n se usa cuando se dibuja un Shape con el m�todo draw.

La anchura de l�nea es la longitud de la l�nea medida perpendicularmente a su trayectoria. La anchura de la l�nea se especificada como un valor float en las unidades de coordenadas de usuario, que es equivalente a 1/72 pulgadas cuando se utiliza la transformaci�n por defecto.

El estilo de uni�n es la decoraci�n que se aplica cuando se encuentran dos segmentos de l�nea. BasicStroke soporta tres estilos de uni�n:.

JOIN_BEVEL

JOIN_MITER

JOIN_ROUND

El estilo de finales es la decoraci�n que se aplica cuando un segmento de l�nea termina. BasicStroke soporta tres estilos de finalizaci�n:

CAP_BUTT

CAP_ROUND

CAP_SQUARE

El estilo de punteado define el patr�n de las secciones opacas y transparentes aplicadas a lo largo de la longitud de la l�nea. Este estilo est� definido por un array de punteado y una fase de punteado. El array de punteado define el patr�n de punteado. Los elementos alternativos en el array representan la longitud del punteado y el espacio entre punteados en unidades de coordenadas de usuario.. El elemento 0 representa el primer punteado, el elemento 1 el primer espacio, etc. La fase de punteado es un desplazamiento en el patr�n de punteado, tambi�n especificado en unidades de coordenadas de usuario. La fase de punteado indica que parte del patr�n de punteado se aplica al principio de la l�nea.

.�Patr�n de Relleno

Los patrones de rellenos est�n definidos por el atributo paint en el contexto Graphics2D. Para seleccionar el atributo paint, se crea un ejemplar de un objeto que implemente el interface Paint y se pasa dentro del m�todo Graphics2D setPaint.

Tres clases implementan el interface Paint: Color, GradientPaint, y TexturePaint . GradientPaint y TexturePaint son nuevas en el JDK 1.2.

Para crear un GradientPaint, se especifica una posici�n inicial y un color y una posici�n final y otro color. El gradiente cambia proporcionalmente desde un color al otro a lo largo de la l�nea que conecta las dos posiciones.

El patr�n para una TexturePaint esta definido por un BufferedImage. Para crear un TexturePaint, se especifica una imagen que contiene el patr�n y un rect�ngulo que se usa para replicar y anclar el patr�n.

.�Ejemplo: StrokeAndFill

El applet StrokeAndFill permite al usuario seleccionar un gr�fico primitivo, un estilo de l�nea, un estilo de dibujo y o bien puntear el exterior del objeto, rellenarlo con el dibujo seleccionado, o puntear el objeto en blanco y rellenar el dibujo con el dibujo seleccionado.

Pulsa sobre la imagen para ejecutar el  applet.

Esta es una imagen del GUI del applet. Para ajecutar el applet, pulsa sobre ella. El applet aparecer� en una nueva ventana del navegador.

StrokeAndFill.java contiene el c�digo completo de este applet.

Los primitivos son inicializados e introducidos en un array de objetos Shape. El siguiente c�digo crea un Rectangle y un Ellipse2D.Double y los introduce en el array shapes.

shapes[0] = new Rectangle(0, 0, 100, 100);
shapes[1] = new Ellipse2D.Double(0.0, 0.0, 100.0, 100.0);

Para crear un objeto Shape desde una cadena de texto, primero debemos crear un objeto TextLayout desde el texto de la cadena.

TextLayout textTl = new TextLayout("Text",
	  new Font("Helvetica", 1, 96),
	  new FontRenderContext(null, false, false));

Las siguientes l�neas transforman el TextLayout para que sea centrado en el origen y luego introduce el objeto Shape resultante de la llamda a getOutline dentro del array shapes.

AffineTransform textAt = new AffineTransform();
textAt.translate(0,
    (float)textTl.getBounds().getHeight());
shapes[2] = textTl.getOutline(textAt);

Podemos elegir un primitivo accediendo al �ndice apropiado dentro del array shapes.

Shape shape =
    shapes[Transform.primitive.getSelectedIndex()];

C�mo se realiza el dibujo dependen de las opciones elegidas.

  • Cuando el usuario elige stroke, se llama a Graphics2D.draw para realizar el dibujo, Si se elige text como primitivo, las l�neas son recuperadas y el dibujo se hace con el m�todo draw.
  • Cuando el usuario elige fill, se llama a Graphics2D.fill o Graphics2D.drawString para realizar el dibujado.
  • Cuando el usuario elige stroke and fill, se llama a fill o drawString para rellenar el Shape, y luego se llama a draw para dibujar la l�nea exterior.
Nota:

Para rellenar y puntear un gr�fico primitivo, necesitamos hacer dos llamadas separadas a m�todos: fill o drawString para rellenar el interior, y draw para dibujar el exterior.

Los tres estilos de l�nea usados en este ejemplo -- ancho, estrecho y punteado -- son ejemplares de BasicStroke.

// Sets the Stroke.
...
case 0 : g2.setStroke(new BasicStroke(3.0f)); break;
case 1 : g2.setStroke(new BasicStroke(8.0f)); break;
case 2 : float dash[] = {10.0f};
         g2.setStroke(new BasicStroke(3.0f,
             BasicStroke.CAP_BUTT,
             BasicStroke.JOIN_MITER,
             10.0f, dash, 0.0f));
         break;

El estilo de punteado de este ejemplo tiene 10 unidades de punteado alternados con 10 unidades de espacio. El principio del patr�n del punteado se aplica al principio de la l�nea -- la fase de punteado es 0.0.

En este ejemplo se usan tres estilos de dibujo -- s�lido, gradiente y polka. El dibujo de color s�lido es un ejemplar de Color, el gradiente un ejemplar de GradientPaint, y el patr�n un ejemplar de TexturePaint.

// Sets the Paint.
...
case 0 : g2.setPaint(Color.blue); break;
case 1 : g2.setPaint(new GradientPaint(0, 0,
                          Color.lightGray,
                          w-250, h, Color.blue, false));
         break;
case 2 : BufferedImage bi = new BufferedImage(5, 5,
                                BufferedImage.TYPE_INT_RGB);
         Graphics2D big = bi.createGraphics();
         big.setColor(Color.blue);
         big.fillRect(0, 0, 5, 5);
         big.setColor(Color.lightGray);
         big.fillOval(0, 0, 5, 5);
         Rectangle r = new Rectangle(0,0,5,5);
         g2.setPaint(new TexturePaint(bi, r));
         break;

COMPARTE ESTE ARTÍCULO

COMPARTIR EN FACEBOOK
COMPARTIR EN TWITTER
COMPARTIR EN LINKEDIN
COMPARTIR EN WHATSAPP
ARTÍCULO ANTERIOR

SIGUIENTE ARTÍCULO