Sunteți pe pagina 1din 84

Universidad Nacional Abierta y a Distancia – UNAD

Vicerrectoría Académica y de Investigación - VIACI


Escuela: Escuela De Ciencias Básicas Tecnología E Ingeniería Programa: Ingeniería de Sistemas
Curso: Computación Gráfica Código: 299210

COMPUTACION GRAFICA

UNIDAD 3 – TRABAJANDO CON UN API GRAFICA

Material adaptado Red de Tutores del curso Computación Gráfica.

UNAD 2017
Universidad Nacional Abierta y a Distancia – UNAD
Vicerrectoría Académica y de Investigación - VIACI
Escuela: Escuela De Ciencias Básicas Tecnología E Ingeniería Programa: Ingeniería de Sistemas
Curso: Computación Gráfica Código: 299210

CAPÍTULO 7 FUNDAMENTOS DEL API 2D DE JAVA

Lección 31 Características generales del API 2D de Java

31.1 Características generales del API 2D de Java

A continuación, se presentan algunas de las características del API 2D de Java, a partir de


la documentación proporcionada por Sun Microsystems para el J2SE.

El API 2D de Java mejora las capacidades de gráficos, texto e imágenes de la Abstract


Windowing Toolkit (AWT), haciendo posible el desarrollo de interfaces de usuario
mejoradas y nuevos tipos de aplicaciones Java. Además de sus mejoras en gráficos, letra
e imágenes, el API 2D de Java soporta mejoras para la definición y composición del color,
además de la detección de formas y texto en formas geométricas arbitrarias y un modelo
de dibujado (rendering) para impresoras y dispositivos de visualización.

El API 2D de Java también hace posible la creación de librerías gráficas avanzadas, tales
como librerías de CAD-CAM y de gráficos o librerías de efectos especiales para imágenes,
así como la creación de imágenes y de filtros para archivos gráficos.

Cuando se usa en conjunto con al Java Media Framework y otras APIs de Java Media, el
API 2D de Java puede utilizarse para crear y visualizar animaciones y otras presentaciones
multimedia. Los APIs de Java Animation y Java Media Framework le proporcionan al API
2D de Java el soporte para el renderizado.

31.1.1 Mejoras de gráficos, texto e imágenes

Las últimas versionas del AWT proporcionaron un paquete simple para construir páginas
comunes HTML, pero no contemplaban características completas suficientes para dibujar
gráficos complejos, texto e imágenes. Como un paquete de dibujo simplificado, el AWT
encapsuló casos específicos de conceptos de renderizado más general. El API 2D de Java
provee un paquete de renderizado más flexible y con amplias características que expanden
el AWT para soportar gráficos generales y operaciones de renderizado.

A través de la clase Graphics, es posible dibujar rectángulos, elipses y polígonos. El


Graphics2D incorpora el concepto de renderizado geométrico proporcionando un
mecanismo para dibujar virtualmente cualquier forma geométrica. Igualmente, con el API
Java 2D es posible dibujar líneas con estilos, de cualquier ancho y formas geométricas
rellenas con virtualmente cualquier textura.
Universidad Nacional Abierta y a Distancia – UNAD
Vicerrectoría Académica y de Investigación - VIACI
Escuela: Escuela De Ciencias Básicas Tecnología E Ingeniería Programa: Ingeniería de Sistemas
Curso: Computación Gráfica Código: 299210

Las formas geométricas se proporcionan a través de implementaciones de la interfaz


Shape, por ejemplo, las figuras Rectangle2D y Ellipse2D. Las curvas y los arcos también
son implementaciones específicas de la interfaz Shape.

Los rellenos y estilos de lápiz (denominado Filete en múltiples aplicaciones de dibujo) se


proporcionan a través de implementaciones de las interfaces Paint y Stroke, por ejemplo:
BasicStroke, GradientPaint, TexturePaint y Color.

La implementación AffineTransform define transformaciones lineales de coordenadas 2D,


incluyendo el escalado, rotación, traslación y recortado.

Las regiones de clipping se definen por las mismas implementaciones de la interface Shape
que se usan para definir regiones generales de clipping, por ejemplo, Rectangle2D y
GeneralPath.

Las composiciones de color se proporcionan por implementaciones de la interfaz


Composite, por ejemplo, AlphaComposite. Un objeto Font se define como una colección de
Glyphs, que a su vez está definida por Shapes individuales.

31.1.2 Modelo de Renderizado

El mecanismo de renderizado básico es el mismo que en las versiones anteriores del JDK.
El sistema de dibujo o renderizado controla cuándo y cómo dibuja un programa. Cuando
un componente necesita ser mostrado, se llama automáticamente a su método paint o
update dentro del contexto Graphics apropiado.

Como ya se mencionó, el API 2D de Java presenta java.awt.Graphics2D, un nuevo tipo de


objeto Graphics. Graphics2D desciende de la clase Graphics para roporcionar acceso a las
características avanzadas de renderizado del API 2D de Java.

Para usar las características del API 2D de Java, tenemos que forzar el objeto Graphics
pasado al método de dibujo de un componente a un objeto Graphics2D. Como se muestra
en el siguiente código:

public void Paint (Graphics g) {


Graphics2D g2 = (Graphics2D) g; ...
}
Al conjunto de atributos de estado asociados con un objeto Graphics2D se le conoce
como Contexto de Renderizado de Graphics2D. Para mostrar texto, formas o imágenes,
podemos configurar este contexto y luego llamar a uno de los métodos de renderizado de
la clase Graphics2D, como draw o fill. Cómo muestra la siguiente figura, el contexto de
renderizado de Graphics2D contiene varios atributos.
Universidad Nacional Abierta y a Distancia – UNAD
Vicerrectoría Académica y de Investigación - VIACI
Escuela: Escuela De Ciencias Básicas Tecnología E Ingeniería Programa: Ingeniería de Sistemas
Curso: Computación Gráfica Código: 299210

El estilo de lápiz que se aplica al exterior de una forma. Este atributo stroke
permite dibujar líneas con cualquier tamaño de punto y patrón de
sombreado y aplicar finalizadores y decoraciones a la línea.
Algunas aplicaciones de dibujo lo denominan filete.
El estilo de relleno que se aplica al interior de la forma. Este atributo paint
permite rellenar formas con colores sólidos, gradientes o patrones.

El estilo de composición se utiliza cuando los objetos dibujados se solapan


con objetos existentes.

La transformación que se aplica durante el dibujado para convertir el objeto


dibujado desde el espacio de usuario a las coordenadas de espacio del
dispositivo. También se pueden aplicar otras transformaciones opcionales
como la traducción, rotación escalado, recortado, a través de este atributo.
El Clip que restringe el dibujado al área dentro de los bordes de un Shape
se utiliza para definir el área de recorte. Se puede usar cualquier forma
para definir un clip.
La fuente se usa para convertir cadenas de texto.

Punto de Renderizado que especifican las preferencias en cuanto a


velocidad y calidad. Por ejemplo, es posible especificar que se desea usar
antialiasing, si está disponible.

Tomado de:
http://3.bp.blogspot.com/_ZZ6M_AOD6aQ/TTyfRUuyhBI/AAAAAAAAABQ/LubOHGKBY60/s1600/silla-ruedas-
perro-2.gif

Para configurar un atributo en el contexto de renderizado de Graphics2D, se usan los


métodos:

 setAttribute.
 setStroke
 setPaint
 setComposite
 setTransform
 setClip
 setFont
Universidad Nacional Abierta y a Distancia – UNAD
Vicerrectoría Académica y de Investigación - VIACI
Escuela: Escuela De Ciencias Básicas Tecnología E Ingeniería Programa: Ingeniería de Sistemas
Curso: Computación Gráfica Código: 299210

 setRenderingHints

Cuando se configura un atributo, se le pasa al objeto el atributo apropiado. Por ejemplo,


para cambiar el atributo paint a un relleno de gradiente azul-gris, deberíamos construir el
objeto GradientPaint y luego llamar a setPaint.

gp = new GradientPaint(0f,0f,blue,0f,30f,green);
g2.setPaint(gp);

Graphics2D contiene referencias a sus objetos atributos, no son clonados. Si se modifica


un objeto atributo que forma parte del contexto Graphics2D, es necesario llamar al método
set para notificarlo al contexto. La modificación de un atributo de un objeto durante el
renderizado puede causar comportamientos impredecibles.

31.1.3 Métodos de renderizado de Graphics2D

Graphics2D proporciona los siguientes métodos generales de dibujado que pueden usarse
para dibujar cualquier primitivo geométrico, texto o imagen.

 Draw: Dibuja el exterior de una forma geométrica primitiva usando los atributos
stroke y paint.
 Fill: Dibuja cualquier forma geométrica primitiva rellenado su interior con el color o
patrón especificado por el atributo paint.
 drawString: Dibuja cualquier cadena de texto. El atributo font se usa para convertir
la fuente a Glyphs que luego se rellenan con el color o patrón especificados por el
atributo paint.
 drawImage: Dibuja la imagen especificada.

Además, Graphics2D soporta los métodos de renderizado de Graphics para formas


particulares, como drawOval y fillRect.
Universidad Nacional Abierta y a Distancia – UNAD
Vicerrectoría Académica y de Investigación - VIACI
Escuela: Escuela De Ciencias Básicas Tecnología E Ingeniería Programa: Ingeniería de Sistemas
Curso: Computación Gráfica Código: 299210

Lección 32 Ubicación espacial, textos e imágenes

32.1 Sistema de coordenadas

El sistema 2D de Java mantiene dos sistemas de coordenadas:

• El espacio de usuario es un sistema de coordenadas lógicas independiente del


dispositivo. Las aplicaciones usan este sistema de coordenadas exclusivamente,
y este es el espacio en el que se especifican los gráficos primitivos del Java 2D.
• El espacio de dispositivo es el sistema de coordenadas para un dispositivo
específico de salida, como una pantalla, una ventana o una impresora. En un
ambiente multi-ventana con un escritorio virtual donde una ventana puede
expandirse más allá de la pantalla del dispositivo físico, este escritorio virtual se
adapta a todas las pantallas.

Aunque el sistema de coordenadas para una ventana o una pantalla podría ser muy distinto
que, para una impresora, estas diferencias son invisibles para los programas Java. Las
conversiones necesarias entre el espacio de usuario y el espacio de dispositivo se realizan
automáticamente durante el dibujado.

Espacio de usuario

Como se muestra en la figura siguiente, el origen del espacio de usuario se localiza en la


esquina superior izquierda del espacio, con los valores de x incrementando a la derecha y
los valores de y incrementando hacia abajo

Figura 1 Espacio de usuario

Tomado de: Autoría propia

El espacio del usuario representa una abstracción uniforme de todos los posibles sistemas
de coordenadas de dispositivos. El espacio de dispositivo para un dispositivo particular
Universidad Nacional Abierta y a Distancia – UNAD
Vicerrectoría Académica y de Investigación - VIACI
Escuela: Escuela De Ciencias Básicas Tecnología E Ingeniería Programa: Ingeniería de Sistemas
Curso: Computación Gráfica Código: 299210

podría tener el mismo origen y dirección del espacio del usuario, o podrían ser diferentes.
Sin embargo, las coordenadas del espacio del usuario son automáticamente transformadas
en las apropiadas para el espacio del dispositivo cuando se dibuja un objeto gráfico.
Frecuentemente, la plataforma subyacente o driver del dispositivo se utilizan para
desarrollar esta conversión.

Espacio de dispositivo

El API 2D de Java define tres niveles de información de configuración que se mantienen


para permitir la conversión desde un espacio de usuario a un espacio de dispositivo. Esta
información está encapsulada en tres clases:

• GraphicsEnvironment
• GraphicsDevice
• GraphicsConfiguration

Entre ellas, representan toda la información necesaria para localizar un dispositivo de


renderizado o fuente en la plataforma Java y para convertir las coordenadas del espacio
de usuario al espacio de dispositivo. Una aplicación puede tener acceso a esta información,
pero no necesita desarrollar modificaciones en ellas.

El GraphicsEnvironment describe la colección de dispositivos de renderizado disponible


para una aplicación Java en una plataforma particular. Los dispositivos de renderizado
incluyen pantallas, impresoras y búferes de imagen. El GraphicsEnvironment también
incluye una lista de todas las fuentes disponibles en una plataforma.

El GraphicsDevice describe un dispositivo de renderizado visible para la aplicación, tal como


una pantalla o impresora. Cada configuración posible del dispositivo se representa por una
GraphicsConfiguration. Por ejemplo, un dispositivo de visualización SVGA puede operar en
varios modos: 640*480*16 colores, 640*480*256 colores y 800*600*256 colores. La
pantalla SVGA está representada por un objeto GraphicsDevice y cada uno de los modos
es representado por un objeto GraphicsConfiguration.

Un GraphicsEnvironment puede contener uno o más GraphicsDevice, a su vez, cada


GraphicsDevice puede tener una o más GraphicsConfiguration.

Transformaciones

El API Java 2D ha unificado su modelo de transformación de coordenadas. Todas las


transformaciones de coordenadas, incluyendo transformaciones desde el espacio del
Universidad Nacional Abierta y a Distancia – UNAD
Vicerrectoría Académica y de Investigación - VIACI
Escuela: Escuela De Ciencias Básicas Tecnología E Ingeniería Programa: Ingeniería de Sistemas
Curso: Computación Gráfica Código: 299210

usuario al espacio del dispositivo, son representadas por objetos de la clase


AffineTransform, que define las reglas para manipular coordenadas usando matrices.

Es posible adicionar un AffineTransform al contexto gráfico para rotar, escalar, trasladar o


recortar una figura geométrica, texto o imagen cuando se esta renderizando. La
transformación adicional se aplica a cualquier objeto gráfico renderizado en ese contexto.
La transformación se realiza cuando el espacio de coordenadas de usuario se convierte en
espacio de coordenadas del dispositivo.

32.2 Fuentes

Una cadena se asume de manera normal, en términos de los caracteres que la conforman.
Cuando se dibuja una cadena, su apariencia está determinada por la letra o fuente que
está seleccionada. Sin embargo, las figuras que la fuente usa para mostrar la cadena no
siempre corresponden con caracteres individuales, por ejemplo, en publicidad profesional,
ciertas combinaciones de dos o más caracteres se reemplazan a menudo por una figura
simple denominada ligature.

Las figuras que una fuente usa para representar los caracteres en las cadenas se
denominan Glyphs. Una fuente puede representar un carácter como una a con tílde usando
varios glyphs, o representar ciertas combinaciones de caracteres como la fi de final con un
único glyph. En el API Java 2D, una glyph es simplemente un Shape que puede ser
manipulado y dibujado en la misma forma que cualquier otro objeto Shape.

Una fuente puede ser entendida como una colección glyphs. Una única fuente puede tener
muchas versiones, tales como heavy, médium, oblique, ghotic y regular. Estas diferentes
versiones son llamadas caras (faces). Todas las caras de una fuente tienen un diseño
tipográfico similar y pueden ser reconocidas como miembros de una misma familia. En
otras palabras, una colección de glyphs con una forma particular de estilo conforma una
font face, una colección de formas de font faces forman una font family, y una colección
de font families conforma el grupo de fuentes disponible en un GraphicsEnvironment
particular.

En el API Java 2D, las fuentes se especifican por un nombre que describe una particular
font face (por ejemplo: Helvetica Bold) Es diferente a como se asume en el JDK 1.1, en las
que las fuentes eran descritas por nombres lógicos que tomaban la forma de diferentes
font face dependiendo de las fuentes disponibles en la plataforma particular. Para lograr
compatibilidad el API Java 2D soporta la especificación de fuentes por su nombre lógico y
también por su nombre de font face.

Usando el API 2D de Java es posible componer y dibujar cadenas que contienen múltiples
fuentes, de diferentes familias, caras, tamaños e incluso lenguajes. La apariencia del texto
Universidad Nacional Abierta y a Distancia – UNAD
Vicerrectoría Académica y de Investigación - VIACI
Escuela: Escuela De Ciencias Básicas Tecnología E Ingeniería Programa: Ingeniería de Sistemas
Curso: Computación Gráfica Código: 299210

está separada lógicamente de las características del texto. Los objetos Font se utilizan para
describir la apariencia, y la información de características del texto se almacena en objetos
TextLayout y TextAttibuteSet. Esta posibilidad hace más fácil de usar la misma fuente en
texto con diferentes características.

32.3 Imágenes

Las imágenes son colecciones de píxeles organizados espacialmente. Un píxel define la


apariencia de una imagen en una ubicación simple. Un arreglo bidimensional de píxeles se
denomina una ráster.

La apariencia del píxel puede definirse directamente o como un índice en una tabla de color
para una imagen. En imágenes que contienen muchos colores (más de 256), los píxeles
usualmente representan directamente el color, alpha y otras características de cada
localización de la pantalla. Tales imágenes tienden a ser muchos más grandes que las
imágenes de color indexado (indexed-color images), pero ellas son más realistas.

En una imagen de color indexado, los colores en la imagen están limitados a los colores
especificados en una tabla de colores, a menudo, el resultado es que sólo es posible usar
unos pocos colores en la imagen. Sin embargo, un índice requiere menos almacenamiento
que un valor de color, por tanto, el resultado es que las imágenes de colores indexados
son más pequeñas. El formato de píxel es popular para las imágenes que contienen sólo
16 o 256 colores.

Las imágenes en el API 2D de java tiene dos componentes primarios:

• Los datos de la imagen original (los píxeles)


• La información necesaria para interpretar los píxeles.

Las reglas para interpretar los píxeles están encapsuladas en un objeto ColorModel (por
ejemplo, los valores podrían ser interpretados de dos formas, como colores directos o
indexados). Para que un píxel pueda ser mostrado, debe estar relacionado con un modelo
de color.

Una banda o canal (band) es un componente del espacio de color de una imagen. Por
ejemplo, el Rojo (Red), Verde (Green)y Azul (Blue) son las bandas o canales de una imagen
RGB. Un píxel en una imagen de modelo de color directo puede tomarse de una colección
de valores de las bandas para una localización en la pantalla.

El paquete java.awt.image contiene la implementación de varios ColorModel, incluyendo


representaciones de pixeles empaquetados o comprimidos y de componente.
Universidad Nacional Abierta y a Distancia – UNAD
Vicerrectoría Académica y de Investigación - VIACI
Escuela: Escuela De Ciencias Básicas Tecnología E Ingeniería Programa: Ingeniería de Sistemas
Curso: Computación Gráfica Código: 299210

Un objeto ColorSpace encapsula las reglas que gobiernan la forma como un conjunto de
valores numéricos que corresponden a un color particular. La implementación del
ColorSpace en el java.awt.color representa los espacios de color más popular, incluyendo
RGB y escala de grises. Es importante aclarar que un espacio de color no es una colección
de colores, el define las reglas como deberán ser interpretados los valores de colores
individuales.

Al separar el espacio de color (ColorSpace) del modelo de color (ColorModel) se


proporciona mayor flexibilidad para representar y convertir de una representación de color
a otra.

Lección 33 Rellenos, Filetes y Composiciones

33.1 Rellenos y Filetes

Como ya se había mencionado, con el API 2D de Java es posible usar diferentes estilos de
lápices (filetes) y patrones de relleno. Como el texto está en últimas representado por un
conjunto de glyphs, a las cadenas de texto también se les puede aplicar atributos de filete
y relleno.

Los estilos de lápices están


definidos por objetos que
implementan la interfaz
Stroke. El filete hace posible
especificar diferentes anchos y
Figura 2 Dibujo con diferentes tipos de filete patrones de diseño para líneas
Tomado de:
y curvas.
http://img.my.csdn.net/uploads/201206/13/1339601250_3155.jpg

Los patrones de rellenos están definidos por objetos que implementan la interfaz Paint.
La clase Color, que está disponible en versiones anteriores de AWT, es un tipo simple de
un objeto Saint usado para definir rellenos de colores sólidos. El API 2D de Java proporciona
dos implementaciones adicionales para Paint, TexturePaint y GradientPaint.
Universidad Nacional Abierta y a Distancia – UNAD
Vicerrectoría Académica y de Investigación - VIACI
Escuela: Escuela De Ciencias Básicas Tecnología E Ingeniería Programa: Ingeniería de Sistemas
Curso: Computación Gráfica Código: 299210

El TexturePaint define un
patrón de relleno utilizando un
simple fragmento de imagen
que se repite uniformemente.
El GradientPaint define un
relleno como un gradiente Figura 3 Relleno de gradiente y de textura
entre dos colores
Tomado de:
http://img.my.csdn.net/uploads/201206/13/1339601297_5930.jpg

En Java 2D, el renderizado de la línea exterior y el relleno de una figura son dos
operaciones separadas:

Usando el método draw se dibuja el contorno (línea exterior) de la figura usando el estilo
de lápiz especificado en el atributo Stroke y el patrón de relleno especificado por el atributo
Paint.

Usado el método fill se rellena el interior de la figura con el patrón especificado en el


atributo Paint.

Cuando se renderiza una cadena de texto, el atributo actual de Paint se aplica a los glyphs
que forman la cadena. Sin embargo, drawString actualmente rellena los glyphs que están
siendo renderizados. Para modificar el filete del contorno de los glyphs en una cadena de
texto, es necesario enviar el contorno y renderizarlos como figuras usando el método
draw.

33.2 Composiciones (composites)

Cuando se renderiza un objeto que se sobrepone con otro objeto existente, es necesario
determinar como se deben combinar los colores del nuevo objeto von los colores que ya
están ocupando el área donde se está dibujando. El API 2D de Java encapsula reglas para
combinar los colores en el objeto Composite.

Los sistemas de renderizado primitivo proporcionan solamente operadores boléanos


básicos para combinar los colores. Por ejemplo, una regla de composición booleana puede
definir los valores de color de la fuente y el destino a partir de operaciones de And, OR y
XOR. Este enfoque tiene varios inconvenientes, como lo poco intuitivo para el ser humano,
además que este tipo de composiciones no permite la composición de colores en diferentes
espacios de color, además de no considerar el caso de las imágenes de color indexado, ya
que el resultado de la operación booleana de dos valores de píxel en una imagen es la
composición de dos índices, no de dos colores.

El API 2D de Java evita estos inconvenientes al implementar reglas de mezcla alfa (alpha-
blending) que tienen en cuenta la información acerca del modelo de color al hacer las
Universidad Nacional Abierta y a Distancia – UNAD
Vicerrectoría Académica y de Investigación - VIACI
Escuela: Escuela De Ciencias Básicas Tecnología E Ingeniería Programa: Ingeniería de Sistemas
Curso: Computación Gráfica Código: 299210

composiciones. El objeto alphaComposite incluye el modelo del color de los colores fuente
y destino.

Lección 34 Los paquetes del API 2D de Java

Las clases del API Java 2D está organizada en los siguientes paquetes:

• java.awt
• java.awt.geom
• java.awt.font
• java.awt.color
• java.awt.image
• java.awt.image.renderable
• java.awt.print

El paquete java.awt contiene algunas clases e interfaces del API Java 2D, obviamente no
todas las clases del java.awt son clases del Java 2D.

AlphaComposite BasicStroke Color


Composite CompositeContext Font
GradientPaint Graphics2D GraphicsConfiguration
GraphicsDevice GraphicsEnvironment Paint
PaintContext Rectangle Shape
Stroke TexturePaint Transparency

El paquete java.awt.geom contiene clases e interfaces relacionadas con la definición de


primitivas geométricas.

AffineTransform Arc2D Arc2D.Double


Arc2D.Float Area CubicCurve2D
CubicCurve2D.Double CubicCurve2D.Float Dimension2D
Ellipse2D Ellipse2D.Double Ellipse2D.Float
FlatteningPathIterator GeneralPath Line2D
Line2D.Double Line2D.Flota PathIterator
Point2D Point2D.Double Point2D.Float
Universidad Nacional Abierta y a Distancia – UNAD
Vicerrectoría Académica y de Investigación - VIACI
Escuela: Escuela De Ciencias Básicas Tecnología E Ingeniería Programa: Ingeniería de Sistemas
Curso: Computación Gráfica Código: 299210

QuadCurve2D QuadCurve2D.Double QuadCurve2D.Float


Rectangle2D Rectangle2D.Double Rectangle2D.Float
RectangularShape RoundRectangle2D RoundRectangle2D.Double
RoundRectangle2D.Float

Muchas de las primitivas geométricas tienen sus correspondientes implementaciones .Float


y .Double. Las implementaciones de doble precisión proporcionan mayor precisión de
renderizado, pero a expensas del desempeño en algunas plataformas

El paquete java.awt.font contiene clases e interfaces que se utilizan para proporcionar


características al texto y la definición de fuentes

FontRenderContext GlyphJustificationInfo GlyphMetrics


GlyphVector GraphicAttribute ImageGraphicAttribute
LineBreakMeasurer LineMetrics MultipleMaster
OpenType ShapeGrapicAttribute TextAttribute
TextHitInfo TextLayout TransformAttribute

El paquete java.awt.color contiene clases e interfaces para la definición de espacios de


color y perfiles de color.

ColorSpace ICC_ColorSpace ICC_Profile


ICC_ProfileGray ICC_ProfileRGB

Los paquetes java.awt.image y java.awt.image.renderable contienen clases e


interfaces para la definición y renderizado de imágenes
AffineTransformOp BandCombineOp BandedSampleModel
BufferedImage BufferedImageFilter BufferedImageOp
ByteLookupTable ColorConvertOp ColorModel
ComponentColorModel ComponentSampleModel ConvolveOp
ContextualRenderedImageFactory DataBuffer
DataBufferByte DataBufferInt DataBufferShort
DataBufferUShort DirectColorModel IndexColorModel
Universidad Nacional Abierta y a Distancia – UNAD
Vicerrectoría Académica y de Investigación - VIACI
Escuela: Escuela De Ciencias Básicas Tecnología E Ingeniería Programa: Ingeniería de Sistemas
Curso: Computación Gráfica Código: 299210

Kernel LookupOp LookupTable


MultiPixelPackedSampleModel PackedColorModel
ParameterBlock PixelInterleavedSampleModel Ráster
RasterOp RenderableImage RenderableImageOp
RenderContext RenderableImageProducer RenderedImageFactory
RenderedImage RescaleOp SampleModel
ShortLookupTable TileObserver WritableRaster
WritableRenderedImage SinglePixelPackedSampleMod
el

El API Java 2D mejora las siguientes clases heredadas de la clase image de AWT
• ColorModel
• DirectColorModel
• IndexColorModel

Estas clases de modelo de color recogen las características del java.awt.image para
compatibilidad, y para mantener consistencia, las nuevas clases del modelo de color
también están localizadas en el paquete java.awt.image.

El paquete java.awt.print contiene clases e interfaces que hacen posible la impresión de


todos los objetos gráficos basados en Java 2D, como texto, gráficos e imágenes.

Book Pageable PageFormat


Paper Printable PrinterGraphics
PrinterJob

Antes de comenzar en serio con los componentes gráficos que proporciona el API 2D de
java, es necesario, hacer una pequeña revisión de la clase Graphics, superclase de
Graphics2D y revisar algunos conceptos básicos acerca del contexto gráfico, que
posteriormente permitirán comprender mucho mejor los ejemplos que se presentarán.

Lección 35 La clase Graphics


Universidad Nacional Abierta y a Distancia – UNAD
Vicerrectoría Académica y de Investigación - VIACI
Escuela: Escuela De Ciencias Básicas Tecnología E Ingeniería Programa: Ingeniería de Sistemas
Curso: Computación Gráfica Código: 299210

La clase Graphics es la clase base abstracta que proporciona toda, o al menos la mayoría,
de la funcionalidad para poder pintar tanto sobre componentes como sobre imágenes fuera
de pantalla.

Un objeto Graphics encapsula la siguiente información que será necesaria a la hora de las
operaciones básicas de pintado

• El objeto de tipo Component sobre el que se pinta


• Un origen de traslación para coordenadas de pintado y clipping
• La región actual ocupada por el componente
• El color actual
• La fuente de caracteres actual
• La operación lógica actual para utilizar con pixeles (XOR o Paint)
• La actual alteración de color XOR

Un objeto Graphics describe un contexto gráfico. Un contexto gráfico define una zona de
recorte, una zona a la que va a afectar; cualquier operación gráfica que se realice
modificará solamente los pixeles que se encuentren dentro de los límites de la zona de
recorte actual y el componente que fue utilizado para crear el objeto Graphics.

Cuando se pinta o escribe, ese dibujo o escritura se realiza en el color actual, utilizando el
modo de dibujo actual y la fuente de caracteres actual.

Hay muchas otras clases, como la clase Rectangle y la clase Polygon, que utilizan como
soporte a las operaciones que se pueden realizar con la clase Graphics.

Para poder revisar esta clase, quizá una de las mejores formas sea a través de sus
múltiples métodos, intentando agruparlos por funcionalidad, que es lo que se ha intentado
aquí, aunque si el lector quiere una referencia completa y una descripción de los métodos
de esta clase deberá recurrir a la documentación que JavaSoft proporciona sobre el AWT.

Hay que empezar hablando del constructor de la clase Graphics, que no tiene argumentos;
aunque Graphics es una clase abstracta, por lo que las aplicaciones no pueden llamar a
este constructor directamente. Se puede obtener un objeto de tipo Graphics a partir de
otro objeto Graphics llamando al método getGraphics() sobre un componente. También se
puede recibir un objeto Graphics como parámetro cuando se van a sobreescribir los
métodos paint() o update().
Universidad Nacional Abierta y a Distancia – UNAD
Vicerrectoría Académica y de Investigación - VIACI
Escuela: Escuela De Ciencias Básicas Tecnología E Ingeniería Programa: Ingeniería de Sistemas
Curso: Computación Gráfica Código: 299210

35.1 Métodos generales de la clase Graphics

En esta categoría estarían incluidos los métodos útiles en general, sin una asignación
específica de funcionalidad con respecto a acciones determinadas de dibujo. A
continuación, se enumeran algunos de los métodos considerados generales, para seguir
con la descripción y uso de algunos de ellos en aplicaciones de ejemplo.

clearRect( int,int,int,int ), se le pasa un rectángulo y borra la zona con el color que se


haya establecido de fondo para la superficie donde se está pintando.

copyArea( int,int,int,int,int,int ), copia la zona rectangular del componente que se indica


en los primeros cuatro parámetros, en otra posición del contexto gráfico desplazada las
distancia indicada en los dos últimos parámetros.

create(), crea un nuevo objeto de tipo Graphics que es copia del objeto Graphics que ha
invocado al método.

dispose(), elimina el contexto gráfico sobre el cual es invocado y devuelve al sistema


todos los recursos que estaba utilizando, incluyendo todos los recursos, no solamente la
memoria. Un objeto Graphics no se puede utilizar después de haber llamado a este
método; y es importante que se eliminen estos objetos manualmente, bien sea creados
directamente desde un componente o a partir de otro objeto Graphics, cuando ya no se
necesiten, en lugar de esperar a que se finalice la ejecución.

finalice(), elimina el contexto gráfico cuando ya no hay ninguna referencia sobre él.

getColor(), devuelve el color actual fijado para el contexto gráfico.

setColor( Color ), fija el color del contexto gráfico al color que se pasa como parámetro,
todas las operaciones gráfica siguientes que utilicen este contexto gráfico, utilizarán el
color que se especifica en este método.

setPaintMode(), fija la forma de pintar del contexto gráfico de modo que se sustituya lo
que había con lo nuevo. Cualquier operación de pintado sobreescribirá lo que hubiese en
la zona de destino con el color actual.

setXORMode( Color ), fija la forma de pintar del contexto gráfico a una alternancia entre
en color actual y el color de la zona de destino.

toString(), devuelve un objeto de tipo String representando el valor del objeto Graphics.

translate( int,int ), traslada el origen del contexto gráfico al punto que se pasa en los dos
parámetros en el sistema de coordenadas que se esté utilizando.
Universidad Nacional Abierta y a Distancia – UNAD
Vicerrectoría Académica y de Investigación - VIACI
Escuela: Escuela De Ciencias Básicas Tecnología E Ingeniería Programa: Ingeniería de Sistemas
Curso: Computación Gráfica Código: 299210

35.2 Obtener un contexto gráfico

La verdad es que se han escrito varias veces las palabras contexto gráfico, y no se ha
proporcionado al lector una explicación concreta de lo que significan estos términos. Hay
varias definiciones, para unos significa que la aplicación ha conseguido la habilidad para
pintar o colocar imágenes sobre un componente que tiene la característica de soportar el
pintado o visualización de imágenes. Otros autores prefieren decir que cada objeto
Graphics representa una determinada superficie de dibujo, luego ese objeto Graphics
define un contexto gráfico a través del cual se pueden manipular todas las actividades
gráficas sobre esa superficie. Y otros autores indican que un objeto Graphics es la superficie
última sobre la que se pueden colocar líneas, figuras y texto, por lo cual puede recibir
también el nombre de contexto gráfico al aunar información sobre la zona de dibujo, más
la fuente de caracteres, color y cualquier otro factor.

Ahora que ya se sabe lo que es un contexto gráfico, hay que ver cómo se consigue crear
uno. Para empezar, esto no puede hacerse instanciando directamente un objeto de tipo
Graphics, ya que la clase Graphics es abstracta y no puede ser instanciada por el código
de la aplicación, así que hay que recurrir a formas indirectas para conseguir el contexto
gráfico.

Uno de estos caminos indirectos para obtener un contexto gráfico es invocar el método
getGraphics() sobre otro objeto. Sin embargo, este método devuelve un contexto gráfico
de una imagen, es decir, que solamente funciona para objetos de tipo Image creados en
memoria a través del método createImage(), de la clase Component. Esta es una técnica
utilizada normalmente cuando se están usando imágenes que se crean en memoria y luego
se transfieren a la pantalla, es decir, se está pintando en el doble buffer.

Hay otros dos caminos para obtener un contexto gráfico y, son sorprendentemente
simples, porque se hace automáticamente, y es cuando se sobreescriben los métodos
paint() y update(), en los cuales Java pasa como parámetro el contexto gráfico del objeto
al que pertenece el método.

Normalmente, el método paint() se sobreescribe cuando se quiere colocar algún tipo de


material gráfico sobre la pantalla, y el método update() se sobreescribe en circunstancias
especiales, como puede ser el caso de una animación o que se vaya a utilizar doble buffer.
Lo normal es pues la presentación de información gráfica colocando el código encargado
de ello en el método sobreescrito paint() y luego invocando al método repaint() para indicar
al sistema que presente ese material en pantalla; aunque el método paint() también puede
ser invocado por causas externas, sin control alguno por parte de la aplicación, como puede
ser el redimensionamiento de la ventana en la que se está presentando la información
gráfica.

Hay que tener en cuenta que el método repaint() pide al sistema que redibuje el
componente tan pronto como sea posible, pero esto lo hará el método update() que se
Universidad Nacional Abierta y a Distancia – UNAD
Vicerrectoría Académica y de Investigación - VIACI
Escuela: Escuela De Ciencias Básicas Tecnología E Ingeniería Programa: Ingeniería de Sistemas
Curso: Computación Gráfica Código: 299210

llame a continuación. No hay una relación uno a uno entre las llamadas a repaint() y
update(), por lo que es posible que múltiples llamadas a repaint() puedan recogerse en
una sola llamada a update().

El método update() es invocado automáticamente cuando se pide repintar un Componente.


Si el componente no es ligero (lightweight), la implementación por defecto de update()
borra el contexto gráfico rellenando el fondo en el color que se haya asignado como color
de fondo, fijando de nuevo el color al color del primer plano y llamando a paint(). Si no se
sobreescribe update() para hacer una animación, se verá siempre un parpadeo en el
refresco del componente por causa de este borrado del fondo.

En síntesis, el método paint() es el que ofrece el sistema para poder pintar lo que se quiera
sobre un determinado componente. En la clase base Component, este método no hace
absolutamente nada. Normalmente, en el caso de applets, se sobreescribe para hacer
presentar un rectángulo relleno con el color de fondo.

Veamos un primer ejemplo básico de obtención del contexto gráfico y pintado de una
cadena de texto en un objeto Frame en la siguiente figura. Notará que se utiliza la clase
Frame del AWT y no la JFrame del Swing, ya que se quieren asegurar la compatibilidad

Figura 4 Primer ejemplo de dibujo utilizando Java 2D

Tomado de: Autoria propia

Observe que se está convirtiendo el contexto gráfico original g en un contexto gráfico 2D


denominado g2, que es el que finalmente se utiliza para dibujar la cadena.
Universidad Nacional Abierta y a Distancia – UNAD
Vicerrectoría Académica y de Investigación - VIACI
Escuela: Escuela De Ciencias Básicas Tecnología E Ingeniería Programa: Ingeniería de Sistemas
Curso: Computación Gráfica Código: 299210

CAPÍTULO 8 API 3D de JAVA

Lección 36 Figuras básicas en Java 2D (Shape)

Las clases del paquete java.awt.geom definen gráficos primitivos comunes, como puntos,
líneas, curvas, arcos, rectángulos y elipses.

Las clases en el paquete java.awt.geom son:

Arc2D Ellipse2D QuadCurve2D


Area GeneralPath Rectangle2D
CubicCurve2D Line2D RectangularShape
Dimension2D Point2D RoundRectangle2D

Excepto para Point2D y Dimension2D, cada una de las otras clases geométricas
implementa el interfaz Shape, que proporciona un conjunto de métodos comunes para
describir e inspeccionar objetos geométricos bi-dimensionales.

Con estas clases podemos crear de forma virtual cualquier forma geométrica y dibujarla a
través de Graphics2D llamando al método draw o al método fill.

36.1 Formas Rectangulares

Los primitivos Rectangle2D, RoundRectangle2D, Arc2D, y Ellipse2D descienden de la clase


RectangularShape, que define métodos para objetos Shape que pueden ser descritos por
una caja rectangular. La geometría de un RectangularShape puede ser extrapolada desde
un rectángulo que encierra completamente el exterior de la forma, como se muestra en la
siguiente figura.
Universidad Nacional Abierta y a Distancia – UNAD
Vicerrectoría Académica y de Investigación - VIACI
Escuela: Escuela De Ciencias Básicas Tecnología E Ingeniería Programa: Ingeniería de Sistemas
Curso: Computación Gráfica Código: 299210

Figura 5 Formas rectangulares

Tomado de: http://www.oracle.com/ocom/groups/public/@otn/documents/digitalasset/148635.gif

36.2 GeneralPath

La clase GeneralPath permite crear una curva arbitraria especificando una serie de
posiciones a lo largo de los límites de la forma.

Estas posiciones pueden ser


conectadas por segmentos de
línea, curvas cuadráticas o
curvas cúbicas.
Esta figura puede ser creada
Figura 6 Forma GeneralPath
con 3 segmentos de línea y una
Tomado de: curva cúbica.
http://programacion.net/cursos_descargas/2d/images/PolyApp.gif

El siguiente ejemplo muestra el uso de algunos de estos objetos gráficos y además de las
opciones para relleno y filete. El código original corresponde en un demo proporcionado en
el tutorial de Java 2D de la documentación del J2SE.
Universidad Nacional Abierta y a Distancia – UNAD
Vicerrectoría Académica y de Investigación - VIACI
Escuela: Escuela De Ciencias Básicas Tecnología E Ingeniería Programa: Ingeniería de Sistemas
Curso: Computación Gráfica Código: 299210

Figura 7 Ejecución del renderizado de figuras primitivas

Tomado de: http://www.jtech.ua.es/apuntes/ajdm2010/sesiones/imagenes/graficos/primitivas.gif

El código comentado se muestra a continuación. Como se dará cuenta es bastante extenso,


por lo que se recomienda seguirlo cuidadosamente. Una vez lo ha implementado y
comprendido, intente realizar modificaciones en los parámetros de dibujo de las diferentes
figuras.

/*
* Este es un ejemplo sobre el dibujo de Shapes, proporcionado por la
* documentación de Java en la versión 1.2.
*/
import java.awt.*; import java.awt.event.*; import java.awt.geom.*; import javax.swing.*;

/*
* La clase se crea como hija de la clase Applet. Si se define como hija
* directa de la clase Frame, se tiene problemas al redimensionar el
* Frame, ya que no se redibujan automáticamente las figuras.
*/
public class ShapesDemo2D extends JApplet {
final static int maxCharHeight = 15;
final static int minFontSize = 6;
final static Color bg = Color.white;
final static Color fg = Color.black;
final static Color red = Color.red;
final static Color white = Color.white;

//Definición de los tipos de filete


final static BasicStroke stroke = new BasicStroke(2.0f);
final static BasicStroke wideStroke = new BasicStroke(8.0f);
final static float dash1[] = {10.0f};
final static BasicStroke dashed = new BasicStroke(1.0f, BasicStroke.CAP_BUTT,
BasicStroke.JOIN_MITER, 10.0f, dash1, 0.0f);
Dimension totalSize;
FontMetrics fontMetrics;
Universidad Nacional Abierta y a Distancia – UNAD
Vicerrectoría Académica y de Investigación - VIACI
Escuela: Escuela De Ciencias Básicas Tecnología E Ingeniería Programa: Ingeniería de Sistemas
Curso: Computación Gráfica Código: 299210

public void init() {


//Initialize drawing colors
setBackground(bg);
setForeground(fg);
}

/* Permite redimensionar el tamaño de la letra a partir de un objeto de tipo Fontmetrics


* dependiendo del tamaño del contexto gráfico, si se amplía el tamaño de la ventana, la
* letra se ampliará, si se disminuye el tamaño del contexto la letra disminuirá
*/
FontMetrics pickFont(Graphics2D g2, String longString, int xSpace) {
boolean fontFits = false;
Font font = g2.getFont();
FontMetrics fontMetrics = g2.getFontMetrics();
int size = font.getSize();
String name = font.getName();
int style = font.getStyle();

while ( !fontFits ) {
if ( (fontMetrics.getHeight() <= maxCharHeight) && (fontMetrics.stringWidth(longString) <= xSpace) )
{
fontFits = true;
}
else {
if ( size <= minFontSize ) {
fontFits = true;
}
else {
g2.setFont(font = new Font(name, style, --size));
fontMetrics = g2.getFontMetrics();
}
}
}
return fontMetrics;
}

public void paint(Graphics g) {


Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);

/* Toma las dimensiones del contexto y lo divide para saber el ancho y alto de
* cada una de las celdas de la cuadrícula donde dibujará
*/
Dimension d = getSize(); int gridWidth = d.width / 6; int gridHeight = d.height / 2;

//Obtiene el tamaño de la letra a partir de la cadena más larga a escribir


Universidad Nacional Abierta y a Distancia – UNAD
Vicerrectoría Académica y de Investigación - VIACI
Escuela: Escuela De Ciencias Básicas Tecnología E Ingeniería Programa: Ingeniería de Sistemas
Curso: Computación Gráfica Código: 299210

fontMetrics = pickFont(g2, "GeneralPath con relleno y contorno", gridWidth);

//Dibuja el cuadrado general que sirve de fondo al applet Color


fg3D = Color.lightGray;
g2.setPaint(fg3D);
g2.draw3DRect(0, 0, d.width - 1, d.height - 1, true);
g2.draw3DRect(3, 3, d.width - 7, d.height - 7, false); g2.setPaint(fg);

int x = 5; int y = 7;
int rectWidth = gridWidth - 2*x;
int stringY = gridHeight - 3 - fontMetrics.getDescent();
int rectHeight = stringY - fontMetrics.getMaxAscent() - y - 2;

// Dibuja una línea con su respectivo texto inferior


g2.draw(new Line2D.Double(x, y+rectHeight-1, x + rectWidth, y)); g2.drawString("Line2D", x, stringY);
x += gridWidth;

// Asigna un filete, dibuja el rectángulo y debajo su respectivo texto


g2.setStroke(stroke);
g2.draw(new Rectangle2D.Double(x+5, y+5, rectWidth-5, rectHeight-5)); g2.drawString("Rectangle
2D", x, stringY);
x += gridWidth;

/* Asigna el filete como punteado, dibuja un rectángulo con


* bordes redondeados y su texto inferior
* Los parámetros de creación del objeto correspoden al valor en x e y inicial
* x e y final y el radio de la circunferencia que define las puntas redondeadas.
*/
g2.setStroke(dashed);
g2.draw(new RoundRectangle2D.Double(x+20, y+20, rectWidth-40, rectHeight-40, 40, 40));
g2.drawString("RoundRectangle2D", x, stringY); x += gridWidth;

/* Asigna el filete, dibuja un arco con 7 parámetros de construcción.


* Ellos son: el rectángulo que enmarca el arco tiene esquina superior izquierda en
* en x,y,el valor máximo en x, el valor máximo en y. Los siguientes dos parámetros
* corresponde a los ángulos de inicio y fin del arco, en este caso 60 y 135 grados.
* Finalmente el último parámetro corresponde al tipo de arco, los posibles valores son
* OPEN, CHORD, PIE.
* Debajo escribe el texto correspondiente
*/
g2.setStroke(wideStroke);
g2.draw(new Arc2D.Double(x, y, rectWidth, rectHeight, 60, 135, Arc2D.OPEN));
g2.drawString("Arc2D", x, stringY);
x += gridWidth;

// Asigna el filete, dibuja una elipse y el texto inferior correspondiente


g2.setStroke(stroke); g2.draw(new Ellipse2D.Double(x, y, rectWidth, rectHeight));
g2.drawString("Ellipse2D", x, stringY); x += gridWidth;
Universidad Nacional Abierta y a Distancia – UNAD
Vicerrectoría Académica y de Investigación - VIACI
Escuela: Escuela De Ciencias Básicas Tecnología E Ingeniería Programa: Ingeniería de Sistemas
Curso: Computación Gráfica Código: 299210

/* Asigna el filete, crea unos vectores con las coordenadas de los puntos del polígono,
* crea el objeto GeneralPath (polygon) trazando lineas entre las coordenadas
* y finalmente cierra el poligono. Dibuja el polígono y el texto inferior
* correspondiente.
*/
g2.setStroke(stroke);
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);
g2.drawString("GeneralPath", x, stringY);

// Modifica los valores de coordenadas x e y para dibujar la segunda fila


x = 5;
y += gridHeight; stringY += gridHeight;

/* Realiza los mismo pasos que para el polígono anterior, lo que varía es
* que en este caso no se cierra el polígono
*/
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);
g2.drawString("GeneralPath (Abierto)", x, stringY); x += gridWidth;

/* Asigna el color de relleno a azul. Rellena un objeto rectángulo y lo dibuja. Nuevamente


* asigna el color, en este caso al negro y dibuja el texto inferior correspondiente
*/
g2.setPaint(Color.blue);
g2.fill(new Rectangle2D.Double(x, y, rectWidth, rectHeight));
g2.setPaint(fg);
g2.drawString("Rectangle2D con relleno", x, stringY); x += gridWidth;

/* Define el objeto gradiente para rellenar el rectángulo redondeado, partiendo


* del color rojo hasta el color amarillo. Ese objeto GradientPaint se envía como
* color de relleno mediante el setPaint. Se dibuja el rectángulo redondeado.
* Se restaura el color de dibujo al negro y se dibuja el texto inferior.
*/
GradientPaint relleno = new GradientPaint(x,y,red,x+rectWidth, y,Color.yellow); g2.setPaint(relleno);
g2.fill(new RoundRectangle2D.Double(x, y, rectWidth, rectHeight, 10, 10));
g2.setPaint(fg);
Universidad Nacional Abierta y a Distancia – UNAD
Vicerrectoría Académica y de Investigación - VIACI
Escuela: Escuela De Ciencias Básicas Tecnología E Ingeniería Programa: Ingeniería de Sistemas
Curso: Computación Gráfica Código: 299210

g2.drawString("RoundRectangle2D con gradiente", x, stringY); x += gridWidth;

// Define el color de relleno en rojo y dibuja el arco.


g2.setPaint(red);
g2.fill(new Arc2D.Double(x, y, rectWidth, rectHeight, 90, 135, Arc2D.PIE)); g2.setPaint(fg);
g2.drawString("Arc2D con relleno", x, stringY); x += gridWidth;

// Define un relleno de gradiente de rojo a blanco y dibuja la elipse rellena.


relleno = new GradientPaint(x,y,red,x+rectWidth, y,white); g2.setPaint(relleno);
g2.fill (new Ellipse2D.Double(x, y, rectWidth, rectHeight)); g2.setPaint(fg);
g2.drawString("Ellipse2D con gradiente", x, stringY); x += gridWidth;

/* Define los arreglos de las coordenadas para el polígono. Crea el polígono uniendo
* los puntos con líneas. Asigna el color rojo y dibuja el polígono relleno.
* Retorna el valor de la pintura a negro y dibuja el polígono mediante draw, lo
* que origina que se sibuje el filete del polígono.
*/
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(Color.yellow); g2.fill(filledPolygon); g2.setPaint(fg);
g2.setStroke(wideStroke); g2.draw(filledPolygon);
g2.drawString("GeneralPath con relleno y contorno", x, stringY);
}

//Clase que se ejecuta public static void main(String s[]) {


//Crea el Frame
JFrame f = new JFrame("Demo de Figuras Primitivas"); f.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {System.exit(0);}
});

//Crea el applet de acuerdo a la clase ShapesDemo2D


JApplet applet = new ShapesDemo2D();
//Agrega el objeto applet al Frame
f.getContentPane().add("Center", applet); applet.init();
f.pack();
f.setSize(new Dimension(550,300)); f.show();
}
Universidad Nacional Abierta y a Distancia – UNAD
Vicerrectoría Académica y de Investigación - VIACI
Escuela: Escuela De Ciencias Básicas Tecnología E Ingeniería Programa: Ingeniería de Sistemas
Curso: Computación Gráfica Código: 299210

36.3 QuadCurve2D y CubicCurve2D

La clase QuadCurve2D permite crear segmentos de curvas cuadráticos. Una curva


cuadrática está definida por dos puntos finales y un punto de control.

La clase CubicCurve2D permite crear segmentos de curvas cúbicos. Una curva cúbica está
definida por dos puntos finales y dos puntos de control, los segmentos de curvas cúbicos
también se conocen como curvas de Bézier. Las siguientes figuras muestran ejemplos de
curvas cuadráticas y cúbicas.

Figura 8 Formas Curvas

Tomado de: http://study-and-dev.com/blog/wp-content/uploads/mediawiki/images/pro_swing_-


_chast_1/swing_1_14.png

El siguiente código crea una curva cuadrática con dos puntos finales y un punto de control.
Las posiciones de los puntos se seleccionan con respecto al tamaño de la ventana.

import java.awt.*; import java.awt.event.*; import java.awt.geom.*; import javax.swing.*;

public class EjemploQuad extends JApplet {


public void init() {
setBackground(Color.white);
setForeground(Color.black);
}

public void paint(Graphics g) {


Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
Dimension d = getSize(); int w = d.width;
int h = d.height;

//Crea el objeto de tipo QuadCurve2D


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

//Crea los objetos que definen los puntos de inicio, final y control
Universidad Nacional Abierta y a Distancia – UNAD
Vicerrectoría Académica y de Investigación - VIACI
Escuela: Escuela De Ciencias Básicas Tecnología E Ingeniería Programa: Ingeniería de Sistemas
Curso: Computación Gráfica Código: 299210

Point2D.Double inicio, fin, control;


inicio = new Point2D.Double();
fin = new Point2D.Double();
control = new Point2D.Double();

//Le asigna coordenadas a los puntos en x e y a partir del tamaño de la ventana


inicio.setLocation(w/2-100, h/2+50);
fin.setLocation(w/2+100, h/2+50);
control.setLocation((int)(inicio.x)+100, (int)(inicio.y)-100);

quad.setCurve(inicio, control, fin); //Construye la curva

//Define color y filete


g2.setPaint(Color.magenta);
g2.setStroke(new BasicStroke(2.0f));

//Dibuja la curva
g2.draw(quad);

//Modifica el color para dibujar los puntos como rectángulos


g2.setPaint(Color.black);
g2.fill(new Rectangle2D.Double(inicio.x, inicio.y,3,3));
g2.drawString("Inicio", (int) inicio.x+5,(int) inicio.y+5);
g2.fill(new Rectangle2D.Double(fin.x, fin.y,3,3));
g2.drawString("Fin",(int) fin.x+5, (int)fin.y+5);
g2.fill(new Rectangle2D.Double(control.x, control.y,3,3));
g2.drawString("Control",(int)control.x+5, (int)control.y+5);
}

//Clase que se ejecuta


public static void main(String s[]) {
//Crea el Frame
JFrame f = new JFrame("Dibujando un QuadCurve2D");
f.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e)
{System.exit(0);} } );

//Crea el applet de acuerdo a la clase ShapesDemo2D


JApplet applet = new EjemploQuad();
//Agrega el objeto applet al Frame
f.getContentPane().add("Center", applet);
applet.init();
f.pack();
f.setSize(new Dimension(400,300));
f.show();
}
}
Universidad Nacional Abierta y a Distancia – UNAD
Vicerrectoría Académica y de Investigación - VIACI
Escuela: Escuela De Ciencias Básicas Tecnología E Ingeniería Programa: Ingeniería de Sistemas
Curso: Computación Gráfica Código: 299210

La ejecución de este código proporciona la siguiente ventana gráfica:

Intente implementar una


aplicación que dibuje una curva
cúbica, dibuje también los puntos
de referencia para la curva,
mediante rectángulos rellenos.
Aplique diferentes tipos de filete,
Figura 9 Ejecución del dibujo de una curva cuadrática
a partir de lo ya visto.
Tomado de:
https://www.kirupa.com/canvas/images/quadratic_curve_144.p
ng

Lección 37 Áreas

Con la clase Area se pueden realizar operaciones boolenas, como uniones, intersecciones
y substracciones, sobre dos objetos Shape cualquiera. Esta técnica, permite crear
rápidamente objetos Shape complejos sin tener que describir cada línea de segmento o
cada curva, este proceso se denomina construir un área geométrica (CAG). Una Area
soporta las siguientes operaciones booleanas.

unión Sustracción

Intersección Or-Exclusivo (XOR)

Tomado de: http://programacion.net/articulo/graficos_con_java_2d_111/15

En el siguiente ejemplo, tomado del tutorial de gráficos del sitio web de Programación en
castellano, se crea un Area que dibuja una pera a partir de objetos elipses y operaciones
de unión, sustracción e intersección. La ejecución proporciona la siguiente ventana gráfica.
Universidad Nacional Abierta y a Distancia – UNAD
Vicerrectoría Académica y de Investigación - VIACI
Escuela: Escuela De Ciencias Básicas Tecnología E Ingeniería Programa: Ingeniería de Sistemas
Curso: Computación Gráfica Código: 299210

Figura 10 Formación de una pera a partir de operaciones de área

Tomado de: http://programacion.net/cursos_descargas/2d/images/2D-51.gif

El código que se requiere para el renderizado de este gráfico se presenta a continuación.

import java.awt.*;
import java.awt.event.*;
import java.awt.font.*;
import java.awt.geom.*;
import java.applet.*;
import javax.swing.*;

/*
* Este applet dibuja una pera, usando métodos de Constructive Area Geometry (CSG)
* para adición, sustracción e intersección.
*/
public class Pera extends Applet {
Ellipse2D.Double circle, oval, leaf, stem;
Area circ, ov, leaf1, leaf2, st1, st2;

public void init() {


circle = new Ellipse2D.Double();
oval = new Ellipse2D.Double();
leaf = new Ellipse2D.Double();
stem = new Ellipse2D.Double();
circ = new Area(circle);
ov = new Area(oval);
leaf1 = new Area(leaf);
leaf2 = new Area(leaf);
st1 = new Area(stem);
st2 = new Area(stem);
setBackground(Color.white);
Universidad Nacional Abierta y a Distancia – UNAD
Vicerrectoría Académica y de Investigación - VIACI
Escuela: Escuela De Ciencias Básicas Tecnología E Ingeniería Programa: Ingeniería de Sistemas
Curso: Computación Gráfica Código: 299210

public void paint (Graphics g) {


Graphics2D g2 = (Graphics2D) g;

//Toma las dimensiones del contexto gráfico, en este caso el Frame


Dimension d = getSize();
int w = d.width;
int h = d.height;
double ew = w/2;
double eh = h/2;
g2.setColor(Color.green);

/* Crea la primera hoja a partir de la intersección de dos objetos Area, creados


* a partir de una elipse
*/
leaf.setFrame(ew-16, eh-29, 15.0, 15.0);
leaf1 = new Area(leaf);
leaf.setFrame(ew-14, eh-47, 30.0, 30.0);
leaf2 = new Area(leaf);
leaf1.intersect(leaf2);
g2.fill(leaf1);

// Crea la segund hoja.


leaf.setFrame(ew+1, eh-29, 15.0, 15.0);
leaf1 = new Area(leaf);
leaf2.intersect(leaf1);
g2.fill(leaf2);
g2.setColor(Color.black);

/* Crea el pedazo de tronco a partir del llenado del Area resultante de la sustracción de
* dos objetos Area creados a partir de una elipse.
*/
stem.setFrame(ew, eh-42, 40.0, 40.0);
st1 = new Area(stem);
stem.setFrame(ew+3, eh-47, 50.0, 50.0);
st2 = new Area(stem);
st1.subtract(st2); g2.fill(st1);
g2.setColor(Color.yellow);

/* Crea el cuerpo de la pera llenado el Area resultante de la unión de dos objetos


* Area, creados de una elipse un circulo.
*/
circle.setFrame(ew-25, eh, 50.0, 50.0);
oval.setFrame(ew-19, eh-20, 40.0, 70.0);
circ = new Area(circle);
ov = new Area(oval);
circ.add(ov);
Universidad Nacional Abierta y a Distancia – UNAD
Vicerrectoría Académica y de Investigación - VIACI
Escuela: Escuela De Ciencias Básicas Tecnología E Ingeniería Programa: Ingeniería de Sistemas
Curso: Computación Gráfica Código: 299210

g2.fill(circ);
}

public static void main(String s[]) {


JFrame f = new JFrame("Pera");
f.addWindowListener(
new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
}
);
Applet applet = new Pera();
f.getContentPane().add("Center", applet);
applet.init();
f.pack();
f.setSize(new Dimension(150,200));
f.show();
}
}

Lección 38 Texto y Fuentes

Es posible mostrar una cadena de texto con cualquier tipo de letra disponible en el sistema,
en cualquier tamaño y en el estilo que se seleccione. Para determinar las fuentes que están
disponibles en el sistema es necesario llamar el método
GrpahicsEnvironment.getAvailableFontFamilyNames. Este método retorna un arreglo de
cadenas que contiene los nombres de las familias de las fuentes disponibles, cualquiera de
estas cadenas, además del tamaño y el estilo, pueden ser utilizados como argumentos
para crear un nuevo objeto Font.

El siguiente ejemplo, muestra una


aplicación donde es posible
seleccionar el tipo de fuente, tamaño
y estilo a partir de 3 objetos combo y
observar las modificaciones en la
cadena dibujada. El ejemplo es
tomado del Tutorial de Java 2D de
Sun Microsystems. La ejecución del
Figura 11 Ejemplo de dibujo de fuentes programa genera una pantalla como
Tomado de: Autoría propia
la que se muestra al lado.
Universidad Nacional Abierta y a Distancia – UNAD
Vicerrectoría Académica y de Investigación - VIACI
Escuela: Escuela De Ciencias Básicas Tecnología E Ingeniería Programa: Ingeniería de Sistemas
Curso: Computación Gráfica Código: 299210

Para construir el ejemplo, es necesario utilizar el siguiente código que permite obtener los
datos de las fuentes instaladas en el sistema y guardarlos en un objeto Vector, que
posteriormente puede pasarse a un combo que despliegue los nombres de las fuentes:

GraphicsEnvironment gEnv = GraphicsEnvironment.getLocalGraphicsEnvironment();


String envcmbFuente[] = gEnv.getAvailableFontFamilyNames();
Vector vector = new Vector();
for ( int i = 1; i < envcmbFuente.length; i++ ) {
vector.addElement(envcmbFuente[i]);
}
cmbFuente = new JComboBox( vector );
cmbFuente.setMaximumRowCount( 9 );
cmbFuente.addItemListener(this);
nuevafuente = envcmbFuente[0];
pnlLetra.add(cmbFuente);

A continuación, se crea un objeto Font con un estilo Font.PLAIN y un tamaño de 10. Los
otros estilos disponibles son ITALIC, BOLD y BOLD+ITALIC.

Font thisFont;
...
thisFont = new Font("Arial", Font.PLAIN, 10);

Posteriormente es posible crear un nuevo objeto Font a partir de un nombre de fuente,


estilo y tamaño, que pueden seleccionarse de distintos combos. Al seleccionarse el tamaño
el valor de item es de tipo cadena, por lo que se debe convertir a entero para poder crear
la nueva fuente.

public void cambiarFuente(String nf, int nest, String ntam){


Integer nuevoTam = new Integer(ntam);
int tam = nuevoTam.intValue();
thisFont = new Font(nf, nest, tam);
repaint();
}

Para controlar la fuente que se utiliza para dibujar el texto, es necesario enviar los atributos
de la fuente al contexto Graphics2D antes de renderizar. Los atributos de la fuente se
envían pasando un objeto Font al método setFont. En este ejemplo, los atributos son
envidos al construir el nuevo objeto Font y la cadena se dibuja en el centro del componente
usando esta fuente. Cada vez que se modifiquen los atributos, se construye un nuevo
objeto Font y se envía al contexto Graphics 2D en el metodo Paint() para que sean
Universidad Nacional Abierta y a Distancia – UNAD
Vicerrectoría Académica y de Investigación - VIACI
Escuela: Escuela De Ciencias Básicas Tecnología E Ingeniería Programa: Ingeniería de Sistemas
Curso: Computación Gráfica Código: 299210

redibujados. El método getFontMetrics permite medir la longitud en píxeles de la cadena


considerando los nuevos atributos, de manera que siempre se dibuje en el centro del
componente.

g2.setFont(thisFont);
String cadena = "Seleccione una fuente, tamaño y estilo para modificarme";
FontMetrics medida = g2.getFontMetrics();
int ancho = medida.stringWidth( cadena );
int alto = medida.getHeight();

//Dibuja la cadena en el centro del panel correspondiente


g2.drawString( cadena, w/2-ancho/2, h/2-alto/2 );

El código completo del ejemplo, comentado se muestra a continuación:

/*
* Ejemplo de selección de fuentes. Construido para el Tutorial
* de Java2D de Sun Microsystems.
*/
import java.lang.Integer;
import java.awt.*;
import java.awt.font.*;
import java.awt.geom.*;
import java.awt.event.*;
import javax.swing.*;
import java.util.Vector;

public class FontSelection extends JApplet implements ItemListener {


JLabel lblFuente, lblTamano, lblEstilo;
pnlLetra fontC;
JComboBox cmbFuente, cmbTamano, cmbEstilo;
int i = 0;
String nuevafuente = "Fuente sin seleccionar";
int nuevoestilo = 0;
String nuevotam = "10";

public void init() {


getContentPane().setLayout( new BorderLayout() );
JPanel pnlSuperior = new JPanel();
JPanel pnlLetra = new JPanel();
JPanel pnlTamano = new JPanel();
JPanel pnlEstilo = new JPanel();
JPanel pnlEstiloTamano = new JPanel();

//Se asignan las distribuciones para cada panel


pnlSuperior.setLayout( new BorderLayout() );
pnlLetra.setLayout( new GridLayout( 2, 1 ) );
Universidad Nacional Abierta y a Distancia – UNAD
Vicerrectoría Académica y de Investigación - VIACI
Escuela: Escuela De Ciencias Básicas Tecnología E Ingeniería Programa: Ingeniería de Sistemas
Curso: Computación Gráfica Código: 299210

pnlTamano.setLayout( new GridLayout( 2, 1 ) );


pnlEstilo.setLayout( new GridLayout( 2, 1 ) );
pnlEstiloTamano.setLayout( new BorderLayout() );

//Incluye cada panel dentro de los correspondientes para visualizar mejor


//la distribución de la aplicación
pnlSuperior.add( BorderLayout.WEST, pnlLetra );
pnlEstiloTamano.add( BorderLayout.WEST, pnlTamano );
pnlEstiloTamano.add( BorderLayout.CENTER, pnlEstilo );
pnlSuperior.add( BorderLayout.CENTER, pnlEstiloTamano );
getContentPane().add( BorderLayout.NORTH, pnlSuperior );

//Asigna características a la etiqueta de texto Fuentes


lblFuente = new JLabel();
lblFuente.setText("Fuentes");
Font newFont = getFont().deriveFont(1);
lblFuente.setFont(newFont);
lblFuente.setHorizontalAlignment(JLabel.CENTER);
pnlLetra.add(lblFuente);

//Asigna características a la etiqueta de texto Tamaño


lblTamano = new JLabel();
lblTamano.setText("Tamaño");
lblTamano.setFont(newFont);
lblTamano.setHorizontalAlignment(JLabel.CENTER);
pnlTamano.add(lblTamano);

//Asigna características a la etiqueta de texto Estilo


lblEstilo = new JLabel();
lblEstilo.setText("Estilo");
lblEstilo.setFont(newFont);
lblEstilo.setHorizontalAlignment(JLabel.CENTER);
pnlEstilo.add(lblEstilo);

/*Se obtienen las fuentes disponibles en el contexto gráfico


*se asignan al objeto vector que posteriomente es enviado al combo
*de Fuentes. Se asigna un máximo de items para mostrar en el combo de 9 fila
*y se predetermina como fuente inicial, la primera fuente ubicada (indice 0).
*Finalmente se agrega el combo al panel correspondiente.
*/
GraphicsEnvironment gEnv = GraphicsEnvironment.getLocalGraphicsEnvironment();
String envcmbFuente[] = gEnv.getAvailableFontFamilyNames();
Vector vector = new Vector();
for ( int i = 1; i < envcmbFuente.length; i++ ) {
vector.addElement(envcmbFuente[i]);
}
cmbFuente = new JComboBox( vector );
cmbFuente.setMaximumRowCount( 9 );
Universidad Nacional Abierta y a Distancia – UNAD
Vicerrectoría Académica y de Investigación - VIACI
Escuela: Escuela De Ciencias Básicas Tecnología E Ingeniería Programa: Ingeniería de Sistemas
Curso: Computación Gráfica Código: 299210

cmbFuente.addItemListener(this);
nuevafuente = envcmbFuente[0];
pnlLetra.add(cmbFuente);

/*Se asignan los valores para el combo de tamaño, los posibles tamaños serán 10,
*12,14,16,18. Se define como máximo número de filas a mostrar 9. Se agrega el combo
*al panel correspondiente.
*/
cmbTamano = new JComboBox( new Object[]{ "10", "12", "14", "16", "18"} );
cmbTamano.setMaximumRowCount( 9 );
cmbTamano.addItemListener(this);
pnlTamano.add(cmbTamano);

/*Se arma el combo de estilo a partir de los estilos predeterminados.se siguen los mismo
*pasos que para los combos anteriores y finalmente se incluye el combo en el panel
*correspondiente.
*/
cmbEstilo = new JComboBox( new Object[]{ "PLAIN", "BOLD", "ITALIC", "BOLD & ITALIC"} );
cmbEstilo.setMaximumRowCount( 9 );
cmbEstilo.addItemListener(this);
cmbTamano.setMaximumRowCount( 9 );
pnlEstilo.add(cmbEstilo);

/*Se especifican las caracteristicas del Panel que va a contener el texto.


*/
fontC = new pnlLetra();
fontC.setBackground(Color.white);
getContentPane().add( BorderLayout.CENTER, fontC);
}

/* El siguiente método detecta cuando se ha realizado la modificación de item


* en alguno de los combos.
*/
public void itemStateChanged(ItemEvent e) {
if ( e.getStateChange() != ItemEvent.SELECTED ) {
return;
}
Object combomodif = e.getSource(); //Obtiene el objeto combo que cambió de item

//Compara con cada uno de los combos posibles


if ( combomodif == cmbFuente ) {
nuevafuente = (String)cmbFuente.getSelectedItem();
}
else if (
combomodif == cmbEstilo ) { i = cmbEstilo.getSelectedIndex(); nuevoestilo = i;
}
else {
Universidad Nacional Abierta y a Distancia – UNAD
Vicerrectoría Académica y de Investigación - VIACI
Escuela: Escuela De Ciencias Básicas Tecnología E Ingeniería Programa: Ingeniería de Sistemas
Curso: Computación Gráfica Código: 299210

nuevotam = (String)cmbTamano.getSelectedItem();
}

//Cambia la fuente del contexto, de acuerdo con los nuevos atributos seleccionados en los combo
fontC.cambiarFuente(nuevafuente, nuevoestilo, nuevotam);
}

public static void main(String s[]) {


JFrame f = new JFrame("Ejemplo de renderizado de texto"); f.addWindowListener(new
WindowAdapter() {
public void windowClosing(WindowEvent e) {System.exit(0);}
});
JApplet Seleccion = new FontSelection();
f.getContentPane().add(Seleccion, BorderLayout.CENTER);
Seleccion.init();
f.setSize(new Dimension(550,250));
f.setVisible(true);
}
}

class pnlLetra extends JPanel {


Font thisFont;
public pnlLetra(){
thisFont = new Font("Arial", Font.PLAIN, 10);
}

// Este método es el que modifica la fuente de acuerdo con los nuevos parámetros
public void cambiarFuente(String nf, int nest, String ntam){
Integer nuevoTam = new Integer(ntam); int tam = nuevoTam.intValue();
thisFont = new Font(nf, nest, tam); repaint();
}

public void paintComponent (Graphics g) {


super.paintComponent( g );
Graphics2D g2 = (Graphics2D) g; int w = getWidth();
int h = getHeight();
g2.setColor(Color.darkGray);
g2.setFont(thisFont);
String cadena = "Seleccione una fuente, tamaño y estilo para modificarme";
FontMetrics medida = g2.getFontMetrics();
int ancho = medida.stringWidth( cadena );
int alto = medida.getHeight();
//Dibuja la cadena en el centro del panel correspondiente
g2.drawString( cadena, w/2-ancho/2, h/2-alto/2 );
}
}
Universidad Nacional Abierta y a Distancia – UNAD
Vicerrectoría Académica y de Investigación - VIACI
Escuela: Escuela De Ciencias Básicas Tecnología E Ingeniería Programa: Ingeniería de Sistemas
Curso: Computación Gráfica Código: 299210

Se recomienda revisar el ejemplo y plantear una solución para cuando el texto no cabe en
una línea y se requiere separarlo, como en el caso de un párrafo.

Lección 39 Imágenes

El API 2D de Java implementa un nuevo modelo de imagen que permite la manipulación


de imágenes de resolución fija almacenadas en memoria. La clase BufferedImage es una
nueva clase Image en el paquete java.awt.image, que puede usarse para manipular
datos de una imagen recuperados desde un archivo o una URL. Por ejemplo, se puede usar
un BufferedImage para implementar doble búfer. Las clases BufferedImage y
BufferedImageOp también permiten realizar una gran variedad de operaciones de filtrado
de imágenes como blur o sharpen. El modelo de imagen productor/consumidor
proporcionado en las versiones anteriores del JDK se mantiene por razones de
compatibilidad.

39.1 El modelo de imágenes de modo inmediato y el BufferedImage

El modelo de imágenes en "modo inmediato" permite manipular y mostrar imágenes de


pixeles mapeados cuyos datos están almacenados en memoria. Es posible acceder a los
datos de la imagen en una gran variedad de formatos y usar varios tipos de operaciones
de filtrado para manipular los datos.

BufferedImage es la clase clave del API del modo-inmediato. Esta clase maneja una imagen
en memoria y proporciona métodos para almacenar, interpretar y dibujar cada dato de
pixel. Un BufferedImage puede ser renderizado en un contexto Graphics o en un contexto
Graphics2D.

Un BufferedImage es
esencialmente un Image
con un búfer de datos
accesible. Un
BufferedImage tiene un
ColorModel y un Ráster de Figura 12 Clase BufferedImage (Sun Microsystems)

los datos de la imagen. Tomado de:


http://devel.archefire.org/programming/languages/java/tutorial/figure
s/2d/2D-53.gif
Universidad Nacional Abierta y a Distancia – UNAD
Vicerrectoría Académica y de Investigación - VIACI
Escuela: Escuela De Ciencias Básicas Tecnología E Ingeniería Programa: Ingeniería de Sistemas
Curso: Computación Gráfica Código: 299210

El ColorModel proporciona una interpretación de color de los datos de los píxeles de la


imagen. El Ráster representa las coordenadas rectangulares de la imagen, mantiene los
datos de la imagen en memoria, y proporciona un mecanismo para crear múltiples
subimagenes de un sólo búfer de imagen. El Ráster también proporciona métodos para
acceder a píxeles específicos dentro de la imagen.

39.2 Filtrado de un BufferedImage

El API Java 2D define varias operaciones de filtrado para objetos BufferedImage. Cada
operación de proceso de imágenes está incluida en una clase que implementa la interfaz
BufferedImageOp. La manipulación de imágenes se realiza en el método filter. La clase
BufferedImageOp en el API Java 2D soporta:

• Transformación afin
• Escalado
• Modificación de Aspecto
• Combinación Linear de Bandas
• Conversión de color
• Convolución.

Para filtrar un BufferedImage usando una de las clases de operación de imagense debe:

1. Constuir una instancia de una de las clases BufferedImageOp:


AffineTransformOp, BandCombineOp, ColorConvertOp, ConvolveOp, LookupOp ,
o RescaleOp.
2. Llamar al método de operación filter, pasando el BufferedImage que se desea
filtrar y el BufferedImage donde se quiere almacenar el resultado.

El siguiente ejemplo, tomado del Tutorial de Java 2D de Sun Microsystems ilustra el uso
de cuatro operaciones de filtrado de imagenes: low-pass, sharpen, lookup, y rescale. Se
hicieron algunas modificaciones, pues se presentaban errores al cargar los archivos de
imagen. El resultado de la ejecución es la pantalla que se muestra en la Figura 13.

El filtro sharpen se realiza usando un ConvolveOp. Convolución es el proceso de hacer más


pesado el valor de cada pixel en una imagen con los valores de los pixeles vecinos. La
mayoría de los algoritmos de filtrado espacial están basados en las operaciones de
convolución.
Universidad Nacional Abierta y a Distancia – UNAD
Vicerrectoría Académica y de Investigación - VIACI
Escuela: Escuela De Ciencias Básicas Tecnología E Ingeniería Programa: Ingeniería de Sistemas
Curso: Computación Gráfica Código: 299210

Para construir y aplicar este tipo de filtrado al BufferedImage, este ejemplo usa un código
similar al del siguiente fragmento.

public static final float[] SHARPEN3x3 = {


0.f, -1.f, 0.f,
-1.f, 5.0f, -1.f,
0.f, -1.f, 0.f};

BufferedImage dstbimg = new BufferedImage(iw,ih,BufferedImage.TYPE_INT_RGB);


Kernel kernel = new Kernel(3,3,SHARPEN3x3);
ConvolveOp cop = new ConvolveOp(kernel, ConvolveOp.EDGE_NO_OP, null);
cop.filter(srcbimg,dstbimg);

Figura 13 Ejemplo de tratamiento de imágenes

Tomado de: Autoria propia

El objeto Kernel define matemáticamente cómo se ve afectada la salida de cada pixel en


su área inmediata. La definición del Kernel determina el resultado del filtro.
Universidad Nacional Abierta y a Distancia – UNAD
Vicerrectoría Académica y de Investigación - VIACI
Escuela: Escuela De Ciencias Básicas Tecnología E Ingeniería Programa: Ingeniería de Sistemas
Curso: Computación Gráfica Código: 299210

El código completo de la aplicación, que contiene los cuatro filtros aplicados a las imágenes
es el siguiente:

/*
* Ejemplo de aplicación de filtros utilizando BufferedImage y BufferedImageOp.
* Versión modificada del ejemplo del Tutorial de Java 2D de Sun Microsystems.
*/
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.awt.image.*;
import java.awt.geom.AffineTransform;
import java.awt.font.TextLayout;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.awt.event.WindowAdapter;
import java.applet.*;
import java.net.URL;
public class ImageOps extends Applet {
private BufferedImage vectorbi[];
public static final float[] SHARPEN3x3_3 = {
0.f, -1.f, 0.f,
-1.f, 5.f, -1.f,
0.f, -1.f, 0.f};
public void init() {
setBackground(Color.white);

vectorbi = new BufferedImage[4];


String nombresimg[] = { "canocristales01.jpg", "canocristales01.jpg", "rioapaporis01.jpg",
"rioapaporis01.jpg"};
for ( int i = 0; i < vectorbi.length; i++ ) {
//Obtiene la imagen a partir del nombre de archivo correspondiente
Image imagen = Toolkit.getDefaultToolkit().getImage(nombresimg[i]);

/* El objeto MediaTracker, optimiza el proceso de cargado de la imagen al bloquear la tarea hasta


que
* la imagen esté totalmente cargada, con lo que se elimina el parpadeo que se produce al ir
* presentándose en la pantalla partes de esa imagen que no está totalmente cargada.
*/
try {
MediaTracker tracker = new MediaTracker(this); tracker.addImage(imagen, 0);
tracker.waitForID(0);
}
catch ( Exception e ) {
}
int iancho = imagen.getWidth(this);
Universidad Nacional Abierta y a Distancia – UNAD
Vicerrectoría Académica y de Investigación - VIACI
Escuela: Escuela De Ciencias Básicas Tecnología E Ingeniería Programa: Ingeniería de Sistemas
Curso: Computación Gráfica Código: 299210

int ialto = imagen.getHeight(this);


vectorbi[i] = new BufferedImage(iancho, ialto, BufferedImage.TYPE_INT_RGB);

//Crea un contexto gráfico a partir de la imagen


Graphics2D completa = vectorbi[i].createGraphics();
//Dibuja en el contexto la imagen
completa.drawImage(imagen,0,0,this);
}
}

public void paint(Graphics g) {


Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2.setRenderingHint(RenderingHints.KEY_RENDERING,
RenderingHints.VALUE_RÉNDER_QUALITY);

//Tamaño del applet para calcular los tamaños de imagen y sus posiciones
int anchoap = getSize().width;
int altoap = getSize().height;
g2.setColor(Color.black);
float[][] datos = {{0.1f, 0.1f, 0.1f, // Matriz del Filtro
0.1f, 0.2f, 0.1f,
0.1f, 0.1f, 0.1f}, SHARPEN3x3_3};

String Descrip[] = { "Convolve LowPass", "Convolve Sharpen", "LookupOp", "RescaleOp"};


for ( int i = 0; i < vectorbi.length; i++ ) {
int iancho = vectorbi[i].getWidth(this);
int ialto = vectorbi[i].getHeight(this);
int x = 0, y = 0;

AffineTransform transformacion = new AffineTransform();


transformacion.scale((anchoap-14)/2.0/iancho, (altoap-34)/2.0/ialto);

BufferedImageOp bitrans = null;


//BufferedImage donde quedará la modificada
BufferedImage biorig = new BufferedImage(iancho, ialto, BufferedImage.TYPE_INT_RGB);
//BufferedImage original

switch ( i ) {
case 0 :
case 1 :
x = i==0?5:anchoap/2+3;
y = 15;
Kernel kernel = new Kernel(3,3,datos[i]);
ConvolveOp cop = new ConvolveOp(kernel, ConvolveOp.EDGE_NO_OP, null);
Universidad Nacional Abierta y a Distancia – UNAD
Vicerrectoría Académica y de Investigación - VIACI
Escuela: Escuela De Ciencias Básicas Tecnología E Ingeniería Programa: Ingeniería de Sistemas
Curso: Computación Gráfica Código: 299210

cop.filter(vectorbi[i],biorig);
bitrans = new AffineTransformOp(transformacion,
AffineTransformOp.TYPE_NEAREST_NEIGHBOR);
break;

case 2 :
x = 5;
y = altoap/2+15;
byte chlut[] = new byte[256];
for ( int j=0;j<200 ;j++ ) {
chlut[j]=(byte)(256-j);
}
ByteLookupTable blut=new ByteLookupTable(0,chlut);
LookupOp lop = new LookupOp(blut, null);
lop.filter(vectorbi[i],biorig);
bitrans = new AffineTransformOp(transformacion,AffineTransformOp.TYPE_BILINEAR);
break;

case 3 :
x = anchoap/2+3;
y = altoap/2+15;
RescaleOp rop = new RescaleOp(1.1f,20.0f, null);
rop.filter(vectorbi[i],biorig);
bitrans = new AffineTransformOp(transformacion,AffineTransformOp.TYPE_BILINEAR);
}

//Dibuja la imagen en el contexto gráfico en la correspondiente x e y.


g2.drawImage(biorig,bitrans,x,y);

//Dibuja el texto
TextLayout texto = new TextLayout(Descrip[i], g2.getFont(),g2.getFontRenderContext());
texto.draw(g2, (float) x, (float) y-4);
}
}

public static void main(String s[]) {


JFrame f = new JFrame("Tratamiento de imágenes");
f.addWindowListener(
new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
}
);

Applet elapplet = new ImageOps();


Universidad Nacional Abierta y a Distancia – UNAD
Vicerrectoría Académica y de Investigación - VIACI
Escuela: Escuela De Ciencias Básicas Tecnología E Ingeniería Programa: Ingeniería de Sistemas
Curso: Computación Gráfica Código: 299210

f.getContentPane().add("Center", elapplet);
elapplet.init();
f.pack();
f.setSize(new Dimension(610,450));
f.show();
}
}

Lección 40 Técnica de Doble Búfer

Cuando un gráfico es complejo o se usa repetidamente, se puede reducir el tiempo que


tarda en mostrarse renderizándolo primero en un búfer fuera de pantalla y luego copiando
el búfer en la pantalla. Esta técnica, llamada doble búfer, se usa frecuentemente para
animaciones.

Nota!!! Cuando dibujamos sobre un componente Swing, éste utiliza automáticamente el


doble búfer

Un BufferedImage puede usarse fácilmente como un búfer fuera de pantalla. Para crear un
BufferedImage cuyo espacio, color, profundidad y distribución de pixeles

corresponden exactamente a la ventana en la que serán dibujados, se llama al método


createImage del componente. Si se necesita un control sobre el tipo de la imagen fuera de
la pantalla o su transparencia, se puede construir directamente un objeto BufferedImage
y usarlo como un búfer fuera de pantalla.

Para dibujar dentro de una imagen almacenada, se llama al método


BufferedImage.createGraphics para obtener el objeto Graphics2D; luego se llama a los
métodos de dibujo apropiados del Graphics2D. Todo el API de dibujo de Java 2D puede
usarse cuando se dibuja sobre un BufferedImage que está siendo utilizado como un búfer
fuera de pantalla.

Cuando esté listo para copiar el BufferedImage en la pantalla, simplemente se llama al


método drawImage sobre el contexto Graphics2D del componente y se le pasa el
BufferedImage.

El siguiente ejemplo permite al usuario arrastrar un rectángulo sobre la ventana del applet.
En lugar de dibujar el rectángulo en cada posición del cursor, para proporcionar información
al usuario, se usa un BufferedImage como búfer fuera de la pantalla. Cuando se arrastra
el rectángulo, es renderizado dentro del BufferedImage en cada nueva posición y el
BufferedImage se copia en la pantalla. El ejemplo fue tomado del Tutorial de Sun
Microsystems además de ilustrar el uso del doble búfer le puede servir para ilustrar un
posible proceso de animación. Lea atentamente el código comentado.
Universidad Nacional Abierta y a Distancia – UNAD
Vicerrectoría Académica y de Investigación - VIACI
Escuela: Escuela De Ciencias Básicas Tecnología E Ingeniería Programa: Ingeniería de Sistemas
Curso: Computación Gráfica Código: 299210

Figura 14 Ejecución del ejemplo de doble búfer

Tomado de: Autoria propia

import java.awt.*;
import java.awt.event.*;
import java.applet.Applet;
import java.awt.image.*;

public class BufferedShapeMover extends Applet{


static protected Label lblTexto;

public void init(){


//Define la organización del applet
setLayout(new BorderLayout());
add(new BSMCanvas());
lblTexto = new Label("Arrastre el rectángulo dentro del área");
add("South", lblTexto);
}

public static void main(String s[]) {


Frame f = new Frame("Ejemplo de uso de doble búfer");
f.addWindowListener(
new WindowAdapter() {
public void windowClosing(WindowEvent e) {System.exit(0);}
}
);
Applet applet = new BufferedShapeMover();
f.add("Center", applet);
applet.init();
f.pack();
f.setSize(new Dimension(550,250));
Universidad Nacional Abierta y a Distancia – UNAD
Vicerrectoría Académica y de Investigación - VIACI
Escuela: Escuela De Ciencias Básicas Tecnología E Ingeniería Programa: Ingeniería de Sistemas
Curso: Computación Gráfica Código: 299210

f.show();
}
}

class BSMCanvas extends Canvas implements MouseListener, MouseMotionListener{


Rectangle rect = new Rectangle(0, 0, 100, 50);
BufferedImage bi;
Graphics2D contexto;

/* Toma las coordenas de la última vez que el usuario presiono el mouse y se ejecutó
* el evento mousePressed.
*/
int ult_x, ult_y;
boolean primeraVez = true;
TexturePaint texturaRelleno, texturaFilete;
Rectangle area;

/* Esta variable es True si el usuario dió clic o movio el mouse fuera del area del rectangulo,
* falso de lo contrario
*/
boolean estaFuera = false;

//Esta es la clase que define el fondo donde actua el rectángulo


public BSMCanvas(){
setBackground(Color.white);
addMouseMotionListener(this);
addMouseListener(this);

// Crea el patrón para el relleno


bi = new BufferedImage(5, 5, BufferedImage.TYPE_INT_RGB);
contexto = bi.createGraphics();
contexto.setColor(Color.blue);
contexto.fillRect(0, 0, 7, 7);
contexto.setColor(Color.cyan);
contexto.fillOval(0, 0, 2, 2);
Rectangle r = new Rectangle(0,0,5,5);
texturaRelleno = new TexturePaint(bi, r);
contexto.dispose();

//Crea el patrón para el filete


bi = new BufferedImage(5, 5, BufferedImage.TYPE_INT_RGB);
contexto = bi.createGraphics();
contexto.setColor(Color.cyan);
contexto.fillRect(0, 0, 7, 7);
contexto.setColor(Color.blue);
contexto.fillOval(0, 0, 2, 2);
Universidad Nacional Abierta y a Distancia – UNAD
Vicerrectoría Académica y de Investigación - VIACI
Escuela: Escuela De Ciencias Básicas Tecnología E Ingeniería Programa: Ingeniería de Sistemas
Curso: Computación Gráfica Código: 299210

r = new Rectangle(0,0,5,5);

texturaFilete = new TexturePaint(bi, r);


contexto.dispose();
}

// Maneja el evento cuando se ha dado clic a un botón del mouse.


public void mousePressed(MouseEvent e){
ult_x = rect.x - e.getX();
ult_y = rect.y - e.getY();

// Chequea si el usuario dio clic dentro del rectangulo y se mantiene allí


if(rect.contains(e.getX(), e.getY())){
updateLocation(e);
}
else {
BufferedShapeMover.lblTexto.setText("Posicione el cursor en el rectángulo y luego arrastre");
estaFuera = true;
}
}

// Maneja el evento cuando el usuario arrastra el mouse miesntras mantiene presionado el botón.
public void mouseDragged(MouseEvent e){
if(!estaFuera){
updateLocation(e);
}
else {
BufferedShapeMover.lblTexto.setText("Posicione el cursor en el rectángulo y luego arrastre");
}
}

// Maneja el evento cuando el usuario suelta el boton del mouse


public void mouseReleased(MouseEvent e){
/* Chequea si el cursor está dentro del rectángulo cuando el usuario suelta el botón del mouse
* e.getX y e.getY proporcionan las coordenadas donde se soltó el botón
*/
if(rect.contains(e.getX(), e.getY())){
updateLocation(e);
}
else {
BufferedShapeMover.lblTexto.setText("Posicione el cursor en el rectángulo y luego arrastre");
estaFuera = false;
}
}

// Este método es requerido por el MouseListener, no se implementa.


public void mouseMoved(MouseEvent e){}
Universidad Nacional Abierta y a Distancia – UNAD
Vicerrectoría Académica y de Investigación - VIACI
Escuela: Escuela De Ciencias Básicas Tecnología E Ingeniería Programa: Ingeniería de Sistemas
Curso: Computación Gráfica Código: 299210

// Estos métodos son requeridos por el MouseMotionListener no se implementa.


public void mouseClicked(MouseEvent e){}
public void mouseExited(MouseEvent e){}
public void mouseEntered(MouseEvent e){}

// Este método es el que actualiza la localización del rectángulo


public void updateLocation(MouseEvent e){
rect.setLocation(ult_x + e.getX(), ult_y + e.getY());
/* Si el método chequearRect retorna verdadero actualiza el contenido del texto para que
* muestre la localización actual del rectángulo, de lo contrario muestr un mensaje
*/
if (chequearRect()) {
BufferedShapeMover.lblTexto.setText("Rectángulo localizado en " + rect.getX() + ", " + rect.getY());
}
else {
BufferedShapeMover.lblTexto.setText("Por favor no intente arrastrar el rectángulo" + " fuera del
área");
}
repaint();
}

public void paint(Graphics g){


update(g);
}

public void update(Graphics g){


Graphics2D g2 = (Graphics2D)g;

if(primeraVez){
Dimension dim = getSize();
int ancho = dim.width;
int alto = dim.height;
area = new Rectangle(dim);
bi = (BufferedImage)createImage(ancho, alto);
contexto = bi.createGraphics();
rect.setLocation(ancho/2-50, alto/2-25);
contexto.setStroke(new BasicStroke(10.0f));
primeraVez = false;
}

// Pone en blanco el rectángulo que se dibujó con anterioridad


contexto.setColor(Color.white);
contexto.clearRect(0, 0, area.width, area.height);

// Dibuja y rellena el rectángulo en la nueva posición del búfer


contexto.setPaint(texturaFilete);
contexto.draw(rect);
contexto.setPaint(texturaRelleno);
Universidad Nacional Abierta y a Distancia – UNAD
Vicerrectoría Académica y de Investigación - VIACI
Escuela: Escuela De Ciencias Básicas Tecnología E Ingeniería Programa: Ingeniería de Sistemas
Curso: Computación Gráfica Código: 299210

contexto.fill(rect);

// Dibuja la imagen del búfer en la pantalla.


g2.drawImage(bi, 0, 0, this);
}

/* Esta función chequea si el rectángulo se encuentra dentro de la ventana del applet.


* Si no se encuentra dentro del applet, el se redibuja de forma que quede al lado del
* margen de la ventana.
*/
boolean chequearRect(){
if (area == null) {
return false;
}

if(area.contains(rect.x, rect.y, 100, 50)){


return true;
}
int nuevo_x = rect.x; int nuevo_y = rect.y;

if((rect.x+100)>area.width){
nuevo_x = area.width-99;
}

if(rect.x < 0){


nuevo_x = -1;
}

if((rect.y+50)>area.height){
nuevo_y = area.height-49;
}

if(rect.y < 0){


nuevo_y = -1;
}
rect.setLocation(nuevo_x, nuevo_y);
return false;
}
}
Universidad Nacional Abierta y a Distancia – UNAD
Vicerrectoría Académica y de Investigación - VIACI
Escuela: Escuela De Ciencias Básicas Tecnología E Ingeniería Programa: Ingeniería de Sistemas
Curso: Computación Gráfica Código: 299210

CAPÍTULO 9 API 3D de JAVA

A continuación, se presenta un tutorial introductorio al API 3D de Java, tomado de la


traducción realizada por Juan Antonio Palos al Tutorial de Sun Microsystems. Sólo
contempla la etapa de reconocimiento del modelamiento inicial con el API 3D de Java, se
espera que el estudiante profundice su estudio a partir de sus necesidades e intereses
individuales.

El API Java 3D es una interface para escribir programas que muestran e interactúan con
gráficos tridimensionales. Java 3D es una extensión estándar del JDK 2 de Java. El API
Java 3D proporciona una colección de constructores de alto-nivel para crear y manipular
geometrías 3D y estructuras para dibujar esta geometría. Java 3D proporciona las
funciones para creación de imágenes, visualizaciones, animaciones y programas de
aplicaciones gráficas 3D interactivas.

Lección 41 Lo básico de Java 3D

El API 3D de Java es un árbol de clases Java que sirven como interfaz para sistemas de
renderizado de gráficos tridimensionales y un sistema de sonido. El programador trabaja
con constructores de alto nivel para crear y manipular objetos geométricos en 3D. Estos
objetos geométricos residen en un universo virtual, que luego es renderizado. El API está
diseñado con flexibilidad para crear universos virtuales precisos de una ámplia variedad de
tamaños, desde astronómicos a subatómicos.

A pesar de toda esta funcionalidad, el API es sencillo de usar. Los detalles de renderizado
se manejan automáticamente. Aprovechándose de los Threads Java, el renderizador Java
3D es capaz de renderizar en paralelo. El renderizador también puede optimizarse
automáticamente para mejorar el rendimiento del renderizado.

Un programa Java 3D crea ejemplares de objetos Java 3D y los sitúa en una estructura de
datos de escenario gráfico. Este escenario gráfico es una composición de objetos 3D en
una estructura de árbol que especifica completamente el contenido de un universo virtual,
y cómo va a ser renderizado.

Los programas Java 3D pueden escribirse para ser ejecutados como aplicaciones solitarias
o como applets en navegadores que hayan sido extendidos para soportar Java 3D, o ámbos
Universidad Nacional Abierta y a Distancia – UNAD
Vicerrectoría Académica y de Investigación - VIACI
Escuela: Escuela De Ciencias Básicas Tecnología E Ingeniería Programa: Ingeniería de Sistemas
Curso: Computación Gráfica Código: 299210

Lección 42 Empezar con Java 3D

Todo programa Java 3D está, al menos parcialmente, ensamblado por objetos del árbol de
clases Java 3D. Esta colección de objetos describe un universo virtual, que va a ser
renderizado. El API define unas 100 clases presentadas en el paquete javax.media.j3d.

Hay cientos de campos y métodos en las clases del API Java 3D. Sin embargo, un sencillo
universo virtual que incluya animación puede construirse con unas pocas clases. Esta
sección describe un conjunto mínimo de objetos y sus interacciones para renderizar un
universo virtual.

Esta sección incluye el desarrollo de un sencillo pero completo programa Java 3D, llamado
HelloJava3Dd.java, que muestra un cubo giratorio. El programa de ejemplo se desarrolla
de forma incremental, y se presenta en varias versiones, para demostrar cada parte del
proceso de programación Java 3D.

Además del paquete corazón de Java 3D, se usan otros paquetes para escribir programas
Java 3D. Uno de estos paquetes es com.sun.j3d.utils al que normalmente se hace
referencia como clases de utilidades de Java 3D. El paquete de las clases corazón incluye
sólo las clases de menor nivel necesarias en la programación Java 3D.

Las clases de utilidades son adiciones convenientes y poderosas al corazón. Estas clases
se dividen en cuatro categorías: cargadores de contenidos, ayudas a la construcción del
escenario gráfico, clases de geometría y utilidades de conveniencia.

Al utilizar las clases de utilidades se reduce significativamente el número de líneas de


código en un programa Java 3D. Además de las clases de los paquetes corazón y de
utilidades de Java 3D, todo programa 3D usa clases de los paquetes java.awt y
javax.vecmath.

En el resto del texto, el término objeto visual se utilizará para hacer referencia a un "objeto
del escenario gráfico" (por ejemplo, un cubo o una esfera). El término objeto sólo se usará
para referirse a un ejemplar de una clase. El término contenido se usará para referirnos a
objetos visuales en un escenario gráfico como un todo.

42.1 Construir un Escenario Gráfico

Un universo virtual Java 3D se crea desde un escenario gráfico. Un escenario gráfico se


crea usando ejemplares de clases Java 3D. El escenario gráfico está ensamblado desde
objetos que definen la geometría, los sonidos, las luces, la localización, la orientación y la
apariencia de los objetos visuales y sonoros.
Universidad Nacional Abierta y a Distancia – UNAD
Vicerrectoría Académica y de Investigación - VIACI
Escuela: Escuela De Ciencias Básicas Tecnología E Ingeniería Programa: Ingeniería de Sistemas
Curso: Computación Gráfica Código: 299210

Una definición común de un escenario gráfico es una estructura de datos compuesta de


nodos y arcos. Un nodo es un elemento dato y un arco es una relación entre elementos
datos. Los nodos en un escenario gráfico son los ejemplares de las clases Java 3D. Los
arcos representan dos tipos de relaciones entre ejemplares Java 3D.

La relación más común es padre-hijo. Un nodo Group puede tener cualquier número de
hijos, pero sólo un padre. Un nodo hoja sólo puede tener un padre y no puede tener hijos.
La otra relación es una referencia. Una referencia asocia un objeto NodeComponent con
un nodo del escenario gráfico. Los objetos NodeComponent definen la geometría y los
atributos de apariencia usados para renderizar los objetos visuales.

Un escenario gráfico Java 3D está construido de objetos nodos con relaciones padre-hijo
formando una estructura de árbol. En una estructura de árbol, un nodo es la raíz. Se puede
acceder a otros nodos siguiendo los arcos desde la raíz. Los nodos de un árbol no forman
bucles. Un escenario gráfico está formado desde los árboles con raíces en los objetos
Locale. Los NodeComponents y las referencias a arcos no forman parte del escenario
gráfico.

Sólo existe un camino desde la raíz de un árbol a cada una de las hojas; por lo tanto, sólo
hay un camino desde la raíz hasta el escenario gráfico de cada nodo hoja. El camino desde
la raíz de un escenario gráfico hasta una hoja especificada es el camino al escenario gráfico
del nodo hoja. Como un camino de un escenario gráfico trata exactamente con una sola
hoja, hay un camino de escenario gráfico para cada hoja en el escenario.

Todo camino de escenario gráfico en un escenario gráfico Java 3D especifica


completamente la información de estado de su hoja. Esta información incluye, la
localización, la orientación y el tamaño del objeto visual. Consecuentemente, los atributos
visuales de cada objeto visual dependen sólo de su camino de escenario gráfico. El
renderizador Java 3D se aprovecha de este hecho y renderiza las hojas en el orden que él
determina más eficiente. El programador Java 3D normalmente no tiene control sobre el
orden de renderizado de los objetos.

Las representaciones gráficas de un escenario gráfico pueden servir como herramienta de


diseño y/o documentación para los programas Java 3D. Los escenarios gráficos se dibujan
usando símbolos gráficos estándar como se ve en la Figura 15. Los programas Java 3D
podrían tener más objetos que los que hay en su escenario gráfico.

Para diseñar un universo virtual Java 3D se dibuja un escenario gráfico usando un conjunto
de símbolos estándar. Después de completar el diseño, este escenario gráfico es la
especificación para el programa. Después de completar el programa, el mismo escenario
gráfico es una representación concisa del programa (asumiendo que se siguió la
especificación)
Universidad Nacional Abierta y a Distancia – UNAD
Vicerrectoría Académica y de Investigación - VIACI
Escuela: Escuela De Ciencias Básicas Tecnología E Ingeniería Programa: Ingeniería de Sistemas
Curso: Computación Gráfica Código: 299210

Figura 15 Notación utilizada para la representación de un escenario gráfico

Tomado de: http://programacion.net/cursos_descargas/3d/images/java3d_1.gif

Cada uno de los símbolos mostrados al lado izquierdo de la Figura 15 representa un sólo
objeto cuando se usa en un escenario gráfico. Los dos primeros símbolos representan
objetos de clases específicas: VirtualUniverse y Locale. Lo siguientes tres símbolos de la
izquierda representan objetos de las clases Group, Leaf, y NodeComponent. Estos tres
símbolos normalmente tienen anotaciones para indicar la subclase del objeto específico. El
último símbolo se usa para representar otras clases de objetos.

El símbolo de la flecha sólida representa una relación padre-hijo entre dos objetos.

La flecha punteada es una referencia a otro objeto. Los objetos referenciados pueden ser
compartidos entre diferentes ramas de un escenario gráfico. En la Figura 16, se puede
observar un sencillo escenario gráfico.
Universidad Nacional Abierta y a Distancia – UNAD
Vicerrectoría Académica y de Investigación - VIACI
Escuela: Escuela De Ciencias Básicas Tecnología E Ingeniería Programa: Ingeniería de Sistemas
Curso: Computación Gráfica Código: 299210

Figura 16 Ejemplo de escenario gráfico

Tomadode: http://programacion.net/cursos_descargas/3d/images/java3d_2.gif

Es posible crear un escenario gráfico ilegal. Se puede ver uno en la Figura 17. Este
escenario es ilegal porque viola las propiedades de un DAG. El problema son los dos objetos
TransformGroup(TG) que tienen al mismo objeto Shape3D como hijo. Recuerda que una
hoja sólo puede tener un padre. En otras palabras, sólo puede haber un camino desde el
objeto Locale hasta la hoja (o un camino desde la hoja hasta el objeto Locale).

Figura 17 Ejemplo de escenario gráfico ilegal

Tomado de: http://programacion.net/cursos_descargas/3d/images/java3d_3.gif


Universidad Nacional Abierta y a Distancia – UNAD
Vicerrectoría Académica y de Investigación - VIACI
Escuela: Escuela De Ciencias Básicas Tecnología E Ingeniería Programa: Ingeniería de Sistemas
Curso: Computación Gráfica Código: 299210

Es posible pensar que la estructura mostrada en la Figura 17 define tres objetos visuales
en un universo virtual. Pero el escenario gráfico define dos objetos visuales que re-usan el
objeto visual (Shape3D) del lado derecho de la figura. Conceptualmente, cada objeto
TransformGroup que apadrina al ejemplar compartido de Shape3D podría situar una
imagen en el objeto visual en diferentes localizaciones. Sin embargo, es un escenario
gráfico ilegal porque el arco padre- hijo no forma un árbol. En este ejemplo, el resultado
es que el objeto Shape3D tiene más de un padre.

Las explicaciones del árbol y de las estructuras DAG son correctas. Sin embargo, el sistema
de ejecución Java 3D reporta el error en términos de la relación hijo- padre. Un resultado
de la limitación de la estructura de árbol es que cada objeto Shape3D está limitado a un
sólo padre. Para el ejemplo de la Figura 17, se lanzará una excepción 'multiple parent' en
el momento de la ejecución. La Figura 18, con un padre para cada objeto Shape3D,
muestra una posible solución para este escenario gráfico.

Figura 18 Posible solución al escenario gráfico ilegal

Tomado de: http://programacion.net/cursos_descargas/3d/images/java3d_4.gif

Es posible pensar que la estructura mostrada en la Figura 18 define tres objetos visuales
en un universo virtual. Pero el escenario gráfico define dos objetos visuales que re-usan el
objeto visual (Shape3D) del lado derecho de la figura. Conceptualmente, cada objeto
TransformGroup que apadrina al ejemplar compartido de Shape3D podría situar una
imagen en el objeto visual en diferentes localizaciones. Sin embargo, es un escenario
gráfico ilegal porque el arco padre- hijo no forma un árbol. En este ejemplo, el resultado
es que el objeto Shape3D tiene más de un padre.
Universidad Nacional Abierta y a Distancia – UNAD
Vicerrectoría Académica y de Investigación - VIACI
Escuela: Escuela De Ciencias Básicas Tecnología E Ingeniería Programa: Ingeniería de Sistemas
Curso: Computación Gráfica Código: 299210

Las explicaciones del árbol y de las estructuras DAG son correctas. Sin embargo, el sistema
de ejecución Java 3D reporta el error en términos de la relación hijo- padre. Un resultado
de la limitación de la estructura de árbol es que cada objeto Shape3D está limitado a un
sólo padre. Para el ejemplo de la Figura 18, se lanzará una excepción 'multiple parent' en
el momento de la ejecución. La Figura 19, con un padre para cada objeto Shape3D,
muestra una posible solución para este escenario gráfico.

Figura 19 Posible solución al escenario gráfico ilegal

Tomado de: http://programacion.net/cursos_descargas/3d/images/java3d_4.gif

Cada escenario gráfico tiene un sólo VirtualUniverse. Este objeto tiene una lista de objetos
Locale. Un objeto Locale proporciona una referencia a un punto en el universo virtual. Se
puede pensar en los objetos Locale como marcas de tierra que determinan la localización
de los objetos visuales en el universo virtual.

Es técnicamente posible para un programa Java 3D tener más de un objeto VirtualUniverse,


y así definir más de un universo virtual. Sin embargo, no hay ninguna forma de
comunicación entre los universos virtuales. Además, un objeto de un escenario gráfico no
puede existir en más de un universo virtual. Es altamente recomendable usar uno y sólo
un ejemplar de VirtualUniverse en cada programa Java 3D.

Mientras que un objeto VirtualUniverse podría referenciar muchos objetos Locale, la


mayoría de los programas Java 3D tiene un sólo objeto Locale. Cada objetoLocale puede
servir de raíz para varios sub-gráficos del escenario gráfico. Por ejemplo, si se hace
referencia a la Figura 16 se podrá observar las dos ramas sub-gráficas que salen desde el
objeto Locale.
Universidad Nacional Abierta y a Distancia – UNAD
Vicerrectoría Académica y de Investigación - VIACI
Escuela: Escuela De Ciencias Básicas Tecnología E Ingeniería Programa: Ingeniería de Sistemas
Curso: Computación Gráfica Código: 299210

Un objeto BranchGroup es la raíz de un sub-gráfico, o rama gráfica. Hay dos categorías de


escenarios sub-gráficos: la rama de vista gráfica y la rama de contenido gráfico. La rama
de contenido gráfico especifica el contenido del universo virtual - geometría, apariencia,
comportamiento, localización, sonidos y luces. La rama de vista gráfica especifica los
parámetros de visualización, como la posición de visualización y la dirección. Juntas, las
dos ramas especifican la mayoría del trabajo que el renderizador tiene que hacer.

42.2 Árbol de Clases de Alto Nivel del API Java 3D

En la Figura 20 se pueden ver los tres primeros niveles del árbol de clases del API Java
3D. En esta parte del árbol aparecen las clases VirtualUniverse, Locale, Group, y Leaf.

Figura 20 Árbol de clases del API Java 3D

Tomado de: http://programacion.net/cursos_descargas/3d/images/java3d_5.gif

SceneGraphObject es la superclase de casi todas las clases corazón y de utilidad de Java


3D. Tiene dos subclases: Node y NodeComponent. Las subclases de Node proporcionan la
Universidad Nacional Abierta y a Distancia – UNAD
Vicerrectoría Académica y de Investigación - VIACI
Escuela: Escuela De Ciencias Básicas Tecnología E Ingeniería Programa: Ingeniería de Sistemas
Curso: Computación Gráfica Código: 299210

mayoría de los objetos de un escenario gráfico. Un objeto Node es un objeto nodo Group
o un objeto nodo Leaf.

Clase Node

La clase Node es una superclase abstracta de las clases Group y Leaf. Esta clase define
algunos de los métodos importantes de sus subclases. Las subclases de Node componen
escenarios gráficos.

Clase Group

La clase Group es la superclase usada en especificación de localización y orientación de


objetos visuales en el universo virtual. Dos de las subclases de Group son: BranchGroup y
TransformGroup. En la representación gráfica de un escenario gráfico, los simbolos de
Group (círculos) normalmente se anotan con BG para BranchGroups, TG para
TransformGroups, etc. La Figura 70 muestra algunos ejemplos de esto.

Clase Leaf

La clase Leaf es la superclase usada para especificar la forma, el sonido y comportamiento


de los objetos visuales en el universo virtual. Algunas de las subclases de Leaf son:
Shape3D, Light, Behavior, y Sound. Estos objetos podrían no tener hijos, pero podrían
referenciar a NodeComponents.

Clase NodeComponent

La clase NodeComponent es la superclase usada para especificar la geometría, la


apariencia, la textura y las propiedades de material de un nodo Shape3D (Leaf). Los
NodeComponents no forman parte del escenario gráfico, pero son referenciados por él. Un
NodeComponent podría ser referenciado por más de un objeto Shape3D.

42.3 Receta para Escribir Programas Java 3D

Las subclases de SceneGraphObject son los ladrillos que se ensamblan en los escenarios
gráficos. La línea básica de desarrollo de un programa Java 3D consiste en siete pasos (a
los que la especificación del API Java 3D se referiere como un Receta) presentados a
Universidad Nacional Abierta y a Distancia – UNAD
Vicerrectoría Académica y de Investigación - VIACI
Escuela: Escuela De Ciencias Básicas Tecnología E Ingeniería Programa: Ingeniería de Sistemas
Curso: Computación Gráfica Código: 299210

continuación. Esta receta puede usarse para ensamblar muchos programas útiles de Java
3D.

• Crear un Objeto Canvas3D


• Crear un objeto VirtualUniverse
• Crear un objeto Locale, adjuntarlo al objeto VirtualUniverse
• Construir la rama de vista gráfica
• Crear un objeto View
• Crear un objeto ViewPlatform
• Crear un objeto PhysicalBody
• Crear un objeto PhysicalEnvironment
• Adjuntar los objetos ViewPlatform, PhysicalBody, PhysicalEnvironment, y Canvas3D
al objeto View
• Construir la(s) rama(s) gráfica(s) de contenido
• Compilar la(s) rama(s) gráfica(s)
• Insertar los subgráficos dentro del objeto Locale

Esta receta ignora algunos detalles, pero ilustra el concepto fundamental para toda la
programación Java 3D: crear la rama gráfica del escenario gráfico es la programación
principal. En vez de ampliar esta receta, los siguientes párrafos explican una forma sencilla
de construir un escenario gráfico muy similar con menos programación.

Los programas Java 3D escritos usando la receta básica tienen ramas de vista gráfica con
idéntica estructura. La regularidad de la estructura de las ramas de vista gráfica tambien
se encuentra en la clase de utilidad SimpleUniverse. Los ejemplares de esta clase realizan
los pasos 2, 3 y 4 de la receta básica. Usando la clase SimpleUniverse en programación
Java 3D se reduce significativamente el tiempo y el esfuerzo necesario para crear las ramas
de vista gráfica. Consecuentemente, el programador tiene más tiempo para concentrarse
en el contenido. Esto es de lo que se trata el escribir programas Java 3D.

La clase SimpleUniverse es un buen punto de inicio en la programación Java 3D, porque


permite al programador ignorar las ramas de vista gráfica. Sin embargo, usar
SimpleUniverse no permite tener varias vistas de un universo virtual.

La clase SimpleUniverse se usa en todos los ejemplos de programación de este tutorial.

La clase SimpleUniverse

El constructor de SimpleUniverse crea un escenario gráfico que incluye un objeto


VirtualUniverse y Locale, y una rama de vista gráfica completa. Esta rama gráfica creada
usa un ejemplar de las clases de conveniencia ViewingPlatform y Viewer en lugar de las
Universidad Nacional Abierta y a Distancia – UNAD
Vicerrectoría Académica y de Investigación - VIACI
Escuela: Escuela De Ciencias Básicas Tecnología E Ingeniería Programa: Ingeniería de Sistemas
Curso: Computación Gráfica Código: 299210

clases corazón usadas para crear una rama de vista gráfica. Observe que SimpleUniverse
sólo usa indirectamente los objetos View y ViewPlatform del corazón Java 3D. Los objetos
SimpleUniverse suministran la funcionalidad de todos los objetos que hay dentro del
recuadro azul de la Figura 21.

Figura 21 Universo virtual mínimo proporcionado por la clase SimpleUniverse (en azul)

Tomado de: http://programacion.net/cursos_descargas/3d/images/java3d_6.gif

El paquete com.sun.j3d.utils.universe contiene SimpleUniverse, ViewingPlatform, y


clases Viewer de conveniencia.

Al usar los objetos SimpleUniverse la receta básica se simplifica:

• Crear un objeto Canvas3D


• Crear un objeto SimpleUniverse que referencia al objeto Canvas3D anterior
• Personalizar el objeto SimpleUniverse
• Construir la rama de contenido
• Compilar la rama de contenido gráfico
• Insertar la rama de contenido gráfico dentro del objeto Locale de SimpleUniverse

Constructores de SimpleUniverse

Paquete: com.sun.j3d.utils.universe
Universidad Nacional Abierta y a Distancia – UNAD
Vicerrectoría Académica y de Investigación - VIACI
Escuela: Escuela De Ciencias Básicas Tecnología E Ingeniería Programa: Ingeniería de Sistemas
Curso: Computación Gráfica Código: 299210

Esta clase configura un entorno de usuario mínimo para obtener rápida y fácilmente un
programa Java 3D y ejecutarlo.

Esta clase de utilidad crea todos los objetos necesarios para la rama de vista gráfica.
Especificamente crea los objetos Locale, VirtualUniverse, ViewingPlatform, y Viewer (todos
con sus valores por defecto). Los objetos tienen las relaciones apropiadas para formar la
rama de vista gráfica.

SimpleUniverse proporciona toda la funcionalidad necesaria para muchas aplicaciones Java


3D básicas. Viewer y ViewingPlatform son clases de conveniencia. estas clases usan las
clases View y ViewPlatform del corazón Java.

 SimpleUniverse() Construye un sencillo universo virtual.


 SimpleUniverse(Canvas3D canvas3D) Construye un sencillo universo virtual con
una referencia al objeto Canvas3D nombrado.

El objeto SimpleUniverse crea una rama de vista gráfica completa para un universo virtual.
Esta rama incluye un plato de imagen. Un plato de imagen es el rectángulo conceptual
donde se proyecta el contenido para formar la imagen renderizada. El objeto Canvas3D,
que proporciona una imagen en una ventana de nuestra pantalla, puede ser el plato de
imagen.

La Figura 22 muestra la relación entre el plato de imagen, la posición del ojo, y el universo
virtual. La posición del ojo está detrás del plato de imagen. Los objetos visuales delante
del plato de imagen son renderizados en el plato de imagen. El renderizado puede ser
como una proyección de los objetos visuales sobre el plato de imagen. Esta idea se ilustra
con los cuatro proyectores de la imagen (líneas punteadas).

Figura 22 Representación del Plato de imagen y el ojo visor en el universo virtual

Tomado de: http://programacion.net/cursos_descargas/3d/images/java3d_7.gif


Universidad Nacional Abierta y a Distancia – UNAD
Vicerrectoría Académica y de Investigación - VIACI
Escuela: Escuela De Ciencias Básicas Tecnología E Ingeniería Programa: Ingeniería de Sistemas
Curso: Computación Gráfica Código: 299210

Por defecto, el plato de imagen está centrado en el origen de SimpleUniverse. La


orientación por defecto es mirando hacia abajo el eje Z. Desde esta posición, el eje X es
una línea horizontal que atraviesa el plato de imagen con los valores positivos hacia la
derecha. El eje Y es una línea vertical que atraviesa el centro del plato de imagen, con los
valores positivos arriba. Consecuentemente, el punto (0,0,0) es el centro del plato de
imagen.

Los típicos programas Java 3D mueven la vista hacía atrás (z positivo) para hacer que los
objetos se acerquen, al origen dentro de la vista. La clase SimpleUniverse tiene un
miembro que es un objeto de la clase ViewingPlatform. Esta clase tiene un método
setNominalViewingTransform que selecciona la posición del ojo para que esté centrado en
(0, 0, 2.41) buscando en dirección z negativa hacia el origen.

El Método ViewingPlatform setNominalViewingTransform()

Paquete: com.sun.j3d.utils.universe

La clase ViewingPlatform se usa para configurar la rama de vista gráfica de un escenario


gráfico Java 3D en un objeto SimpleUniverse. Este método normalmente se usa en
conjunción con el método getViewingPlatform de la clase SimpleUniverse.

void setNominalViewingTransform()

Selecciona la distancia nominal de la vista a una distancia de aproximadamente 2,42


metros en la vista de transformación de un SimpleUniverse. Desde esta distancia y con el
campo de vista por defecto, los objetos con 2 metros de altura o de anchura generalmente
entran en el plato de imagen.

Después de crear los objetos Canvas3D y SimpleUniverse, el siguiente paso es la creacción


de la rama de contenido gráfico. La regularidad de estructura encontrada en la rama de
vista gráfica no existe para la rama de contenido gráfico. La rama de contenido varía de
un programa a otro haciendo imposible obtener los detalles de su construcción en una
receta. Esto también significa que no hay una clase de "contenido sencillo" para ningún
universo que podamos querer ensamblar.

Después de crear la rama de contenido gráfico, se inserta dentro del universo usando el
método addBranchGraph de SimpleUniverse. Este método toma un ejemplar de
BranchGroup como único argumento. Este BranchGroup se añade como hijo del objeto
Locale creado por SimpleUniverse.

Algunos de los métodos de SimpleUniverse correspondiente al paquete:


com.sun.j3d.utils.universe, se muestran a continuación:
Universidad Nacional Abierta y a Distancia – UNAD
Vicerrectoría Académica y de Investigación - VIACI
Escuela: Escuela De Ciencias Básicas Tecnología E Ingeniería Programa: Ingeniería de Sistemas
Curso: Computación Gráfica Código: 299210

 void addBranchGraph(BranchGroup bg) Se usa para añadir Nodos al objeto


Locale del escenario gráfico creado por el SimpleUniverse. Se usa para añadir una
rama de contenido gráfico al universo virtual.
 ViewingPlatform getViewingPlatform() Se usa para recuperar el objeto
ViewingPlatform del SimpleUniverse ejemplarizado. Este método se usa con el
método setNominalViewingTransform() de ViewingPlatform para ajustar la
localización de la posición de vista.

42.4 Alguna Terminología Java 3D

Insertar una rama gráfica dentro de un Locale la hace viva, y consecuentemente, cada
uno de los objetos de esa rama gráfica también están vivos. Hay algunas consecuencias
cuando un objeto se convierte en vivo. Los objetos vivos estan sujetos a
renderización. Los parámetros de los objetos vivos no pueden ser modificados a menos
que la capacidad correspondiente haya sido seleccionada especificamente antes de que el
objeto esté vivo.

Los objetos BranchGroup pueden ser compilados. Compilar un BranchGroup lo convierte


a él y a todos sus ancestros en una forma más eficiente para el renderizado. Compilar los
objetos BranchGroup está recomendado como el último paso antes de hacerlo
vivir. Es mejor compilar solo los objetos BranchGroup insertados dentro de objetos Locale

El método BranchGroup compile() compila la fuente BranchGroup asociada con este


objeto creado y coloca en memoria caché el escenario gráfico compilado.

Los conceptos de compilado y vivo se implementan en la clase SceneGraphObject. Abajo


se pueden ver los dos métodos de la clase SceneGraphObject que se relacionan con estos
conceptos.

SceneGraphObject es la superclase usada para crear un escenario gráfico incluyendo


Group, Leaf, y NodeComponent. SceneGraphObject proporciona varios métodos y campos
comunes para sus subclases:

 boolean isCompiled(): Devuelve una bandera indicando si el nodo forma parte


de un escenario gráfico que ha sido compilado.
 boolean isLive(): Devuelve una bandera que indica si el nodo forma parte de un
escenario gráfico vivo.
Observe que no hay un paso "Empezar a renderizar" en ninguna de las recetas anteriores.
El renderizador Java 3D empieza a funcionar en un bucle infinito cuando una rama gráfica
que contiene un ejemplar de View se vuelve vivo en un universo virtual. Una vez arrancado,
el renderizador Java 3D realiza las operaciones mostradas en el siguiente listado:
Universidad Nacional Abierta y a Distancia – UNAD
Vicerrectoría Académica y de Investigación - VIACI
Escuela: Escuela De Ciencias Básicas Tecnología E Ingeniería Programa: Ingeniería de Sistemas
Curso: Computación Gráfica Código: 299210

while(true) {
Procesos de entrada
If (petición de salida) break
Realiza comportamientos
Atraviesa el escenario gráfico
y renderiza los objetos visuales
}
Limpieza y salida

Las secciones anteriores explicaban la construcción de un sencillo universo virtual sin una
rama de contenido gráfico. La creación de esta rama es el objetivo de las siguientes
secciones.

Lección 43 Un Ejemplo de la aplicación de la receta

El programa Java 3D típico empieza definiendo una nueva clase que extiende la clase
Applet. El ejemplo HelloJava3Da.java es una clase definida para extender la clase Applet.
Los programas Java 3D podrían escribirse como aplicaciones, pero usar applets ofrece una
forma más sencilla de producir una aplicación con ventanas.

La clase principal de un programa Java 3D normalmente define un método para construir


la rama de contenido gráfico. En el ejemplo HelloJava3Da dicho método está definido como
createSceneGraph(). Los pasos de la receta sencilla se implementan en el constructor de
la clase HelloJava3Da, que se muestra en la Figura 23.

Figura 23 Fragmento del código de HelloJava3Da.java

Tomado de: Autoria propia


Universidad Nacional Abierta y a Distancia – UNAD
Vicerrectoría Académica y de Investigación - VIACI
Escuela: Escuela De Ciencias Básicas Tecnología E Ingeniería Programa: Ingeniería de Sistemas
Curso: Computación Gráfica Código: 299210

El paso 1, crear un objeto Canvas3D, se completa en la línea 23.

El paso 2, crear un objeto SimpleUniverse, se hace en la línea 31.

El paso 2a, personalizar el objeto SimpleUniverse, se realiza en la línea 35.

El paso 3, construir la rama de contenido, se realiza en la llamada al método


createSceneGraph() de la línea 27.

El paso 4, compilar la rama de contenido gráfico, se hace en la línea 28. Finalmente, el


paso 5, insertar la rama de contenido gráfico en el objeto Locale del SimpleUniverse, se
completa en la línea 37.

El paso 3 de esta sencilla receta es crear la rama de contenido gráfico. Esta rama se crea
en el fragmento de código que se muestra en la Figura 24

Probablemente sea la rama de contenido


gráfico más sencilla posible. Contiene un
objeto gráfico estático, un ColorCube que se
observa en la línea 45. Éste está localizado
Figura 24 Fragmento para la creación de la rama de contenido en el origen del sistema de coordenadas del
gráfico
universo virtual, el valor del lado del cubo
Tomado de: Autoria propia es de 0.4, considerando que el tamaño total
del applet es 1.0

La clase HelloJava3Da está derivada de Applet pero el programa puede ejecutarse como
una aplicación con el uso de la clase MainFrame. La clase Applet se usa como clase base
para hacer más fácil la escritura de un programa Java 3D que se ejecuta en una ventana.
MainFrame proporciona un marco AWT (ventana) para un applet permitiendo que el applet
se ejecute como una aplicación.

El tamaño de la ventana de la
aplicación resultante se
especifica en la construcción Figura 25 Método main que crea la ventana invocando
de la clase MainFrame Tomado de: Autoria propia

Los tres fragmentos de código anteriores (Figura 23, Figura 24 y Figura 78) forman un
programa Java 3D completo cuando se usan las sentencias import adecuadas. A
continuación, se pueden ver las sentencias import necesarias para compilar la clase
HelloJava3Da. Las clases más comunmente usadas en Java 3D se encuentran en los
paquetes javax.media.j3d, o javax.vecmath.
Universidad Nacional Abierta y a Distancia – UNAD
Vicerrectoría Académica y de Investigación - VIACI
Escuela: Escuela De Ciencias Básicas Tecnología E Ingeniería Programa: Ingeniería de Sistemas
Curso: Computación Gráfica Código: 299210

En este ejemplo, sólo la clase de utilidad


ColorCube se encuentra en el paquete
com.sun.j3d.utils.geometry. La mayoría de
los programas Java 3D tienen las
sentencias import mostradas en el
Figura 26 Sentencias import para HelloJava3Da.java fragmento de la Figura 26
Tomado de: Autoria propia

En el programa de ejemplo HelloJava3Da.java, sólo se sitúo un objeto gráfico en una única


localización. En la Figura 27 se observa el escenario gráfico resultante:

Figura 27 Escenario gráfico de HelloJava3Da.java

Tomado de: http://programacion.net/cursos_descargas/3d/images/java3d_8.gif

La imagen que proporciona la ejecución del código completo se muestra en la Figura 28.

Figura 28 Ejecución de HelloJava3Da.java

Tomado de: http://programacion.net/cursos_descargas/3d/images/java3d_9.gif


Universidad Nacional Abierta y a Distancia – UNAD
Vicerrectoría Académica y de Investigación - VIACI
Escuela: Escuela De Ciencias Básicas Tecnología E Ingeniería Programa: Ingeniería de Sistemas
Curso: Computación Gráfica Código: 299210

Como no se explica cada línea de código del ejemplo HelloJava3Da, las ideas básicas de
ensamblar un programa Java 3D deberían estar claras habiendo leído el ejemplo. La
siguiente sección presenta cada una de las clases usadas en el programa.

43.1 Clases Java 3D Usadas en HelloJava3Da

Para añadir un poco de entendimiento del API Java 3D y el ejemplo HelloJava3Da aquí se
presenta una síntesis de las clases del API Java 3D usadas en HelloJava3Da.

Clase BranchGroup

Los objetos de este tipo se usan para formar escenarios gráficos. Los ejemplares de
BranchGroup son la raíz de los sub-gráficos. Los objetos BranchGroup son los únicos que
pueden ser hijos de los objetos Locale. Los objetos BranchGroup pueden tener varios hijos.
Los hijos de un objeto BranchGroup pueden ser otros objetos Group o Leaf.

El constructor por defecto de BranchGroup es:

 BranchGroup() Los ejemplares de BranchGroup sirven como raíz para las ramas
del escenario gráfico; los objetos BranchGroup son los únicos objetos que pueden
insertarse en un conjunto de objetos Locale.

Clase Canvas3D

La clase Canvas3D deriva de la clase Canvas del AWT. Por lo menos un objeto Canvas3D
debe ser referenciado en la rama de vista gráfica del escenario gráfico.

El constructor de Canvas3D es:

 Canvas3D(GraphicsConfiguration graphicsconfiguration) Construye e


inicializa un nuevo objeto Canvas3D que el Java 3D puede renderizar dando un
objeto GraphicsConfiguration válido. Es una extensión de la clase Canvas del AWT.

Clase Transform3D

Los objetos Transform3D representan transformaciones de geometrías 3D como una


traslación o una rotación. Estos objetos normalmente sólo se usan en la creacción de un
objeto TransformGroup. Primero, se construye el objeto Transform3D, posiblemente desde
Universidad Nacional Abierta y a Distancia – UNAD
Vicerrectoría Académica y de Investigación - VIACI
Escuela: Escuela De Ciencias Básicas Tecnología E Ingeniería Programa: Ingeniería de Sistemas
Curso: Computación Gráfica Código: 299210

una combinación de objetos Transform3D. Luego se construye el objeto TransformGroup


usando el objeto Transform3D.

Un objeto de transformación generalizado se representa internamente como una matriz de


4x4 doubles de punto flotante. La representación matemática es la mejor forma. Un objeto
Transform3D no se usa en un escenario gráfico. Se usa para especificar la transformación
de un objeto TransformGroup.

El constructor por defecto de Transform3D

 Transform3D() Construye un objeto Transform3D que representa la matriz de


identidad (no la transformación).
Un objeto Transform3D puede representar una traslación, una rotación, un escalado, o una
combinación de éstas. Cuando se especifica una rotación, el ángulo se expresa en radianes.
Una rotación completa es 2 PI radianes. Una forma de especificar ángulos es usar la
constante Math.PI. Otra forma es especificar los valores directamente. Algunas
aproximaciones son: 45º es 0.785, 90º es 1.57, y 180º es 3.14.

A continuación, se presenta una lista parcial de métodos de Transform3D

 void rotX(double angle) Selecciona el valor de esta transformación a una rotación


en contra del sentido del reloj sobre el eje-x. El ángulo se especifica en radianes.
 void rotY(double angle) Selecciona el valor de esta transformación a una rotación
en contra del sentido del reloj sobre el eje-y. El ángulo se especifica en radianes.
 void rotZ(double angle) Selecciona el valor de esta transformación a una rotación
en contra del sentido del reloj sobre el eje-z. El ángulo se especifica en radianes.
 void set(Vector3f translate) Selecciona el valor transacional de esta matriz al
valor del parámetro Vector3f, y selecciona los otros componentes de la matriz como
si ésta transformación fuera una matriz idéntica.

Clase TransformGroup

Como una subclase de la clase Group, los ejemplares de TransformGroup se usan en la


creacción de escenarios gráficos y tienen una colección de objetos nodos como hijos. Los
objetos TransformGroup contienen transformaciones geométricas como traslaciones y
rotaciones. La transformación normalmente se crea en un objeto Transform3D, que no es
un objeto del escenario gráfico.

Los contructores de TransformGroup son:

 TransformGroup() Construye e inicializa un TransformGroup usando una identidad


de transformación.
 TransformGroup(Transform3D t1) Construye e inicializa un TransformGroup
Universidad Nacional Abierta y a Distancia – UNAD
Vicerrectoría Académica y de Investigación - VIACI
Escuela: Escuela De Ciencias Básicas Tecnología E Ingeniería Programa: Ingeniería de Sistemas
Curso: Computación Gráfica Código: 299210

desde un objeto Transform3D t1 pasado como parámetro.

La transformación contenida en un objeto Transform3D se copia a un objeto


TransformGroup o cuando se crea el TransformGroup, o usando el método
setTransform(). Así:

 void setTransform(Transform3D t1) Selecciona el componente de


transformación de este TransformGroup a partir del valor de de la transformación
pasada en el parámetro t1.

Clase Vector3f

Vector3f es una clase matemática que se encuentra en el paquete javax.vecmath para


especificar un vector usando tres valores de punto flotante para las coordenadas x, y, e z.
Los objetos Vector se usan frecuentemente para especificar traslaciones de
geometrías. Los objetos Vector3f no se usan directamente en la construcción de un
escenario gráfico. Se usan para especificar las traslaciones, superficies normales, u otras
cosas.

A continuación, se muestran los constructores de Vector3f

 Vector3f(): Construye e inicializa un Vector3f a (0,0,0).


 Vector3f(float x, float y, float z): Construye e inicializa un Vector3f desde las
coordenadas x, y, z especificadas.

Clase ColorCube

ColorCube es una clase de utilidad que se encuentra en el paquete


com.sun.j3d.utils.geometry que define la geometría y colores de un cubo centrado en
el origen y con diferentes colores en cada cara, ColorCube extiende la clase Shape3D, por
lo tanto, es un nodo hoja. Si un cubo sin rotar se sitúa en el origen (como en HelloJava3Da),
se verá la cara roja desde la localización de visión nominal. Los otros colores son azul,
magenta, amarillo, verde y cian.

Los coonstructores de ColorCube son:

 ColorCube() Construye un cubo de color del tamaño por defecto. Por defecto, una
esquina está situada a 1 unidad de cada uno de los ejes desde el origen, resultando
un cubo que está centrado en el origen y tiene 2 unidades de alto, de ancho y de
profundo.
 ColorCube(double scale) Construye un cubo de color escalado por el valor
Universidad Nacional Abierta y a Distancia – UNAD
Vicerrectoría Académica y de Investigación - VIACI
Escuela: Escuela De Ciencias Básicas Tecnología E Ingeniería Programa: Ingeniería de Sistemas
Curso: Computación Gráfica Código: 299210

especificado. El tamaño por defecto es 2 unidades de lado. El ColorCube resultante


tiene esquinas en (scale, scale, scale) y (-scale, -scale, -scale).

Lección 44 Rotación de objetos

Una simple rotación del cubo puede hacer que se vea más de una de sus caras. El primer
paso es crear la transformación deseada usando un objeto Transform3D.

El fragmento de código de la Figura 29 incorpora un objeto TransformGroup en el escenario


gráfico para rotar el cubo sobre el eje x. Primero se crea la transformación de rotación
usando el objeto rotate de Transform3D, en la linea 24.

La rotación se especifica usando el


método rotX() de la línea 27.
Entonces se crea el objeto
TransformGroup en la línea 31 para
contener la transformación de
rotación.
Dos parámetros especifican la
rotación: el eje de revolución, y el
ángulo de rotación.
Figura 29 Fragmento de código para rotar un objeto

Tomado de: Autoria propia

El eje se elige seleccionando el método apropiado (rotX, rotY o rotZ). El ángulo de rotación
es el valor que se le pasa como argumento. Como el ángulo de rotación se especifica en
radianes, el valor PI/4 es 1/8 de una rotación completa, o 45 grados. Solamente las líneas
24 y 27 ejecutan la rotación en un eje.

Después de crear el objeto Transform3D, rotate, se usa en la creacción del objeto


TransformGroup objRotate (línea 31). El objeto Transform3D se usa en el escenario gráfico.
Entonces el objeto objRotate hace que ColorCube sea su hijo (línea 34). A su vez, el
objeto objRoot hace a objRotate como su hijo (línea 33).

La rama de contenido gráfico ahora incluye un objeto TransformGroup en el camino del


escenario gráfico hacia el objeto ColorCube. Cada uno de los caminos del escenario gráfico
es necesario. El objeto BranchGroup es el único que puede ser hijo de un Locale.
Universidad Nacional Abierta y a Distancia – UNAD
Vicerrectoría Académica y de Investigación - VIACI
Escuela: Escuela De Ciencias Básicas Tecnología E Ingeniería Programa: Ingeniería de Sistemas
Curso: Computación Gráfica Código: 299210

El objeto TransformGroup es el único que


puede cambiar la localización, la orientación,
o el tamaño de un objeto visual. En este caso
el objeto TransformGroup cambia la
orientación. Por supuesto, el objeto
ColorCube es necesario para suministrar el
objeto visual. A continuación, se puede
observar el escenario gráfico producido por
el fragmento de la Figura 30. Figura 30 Escenario gráfico para la rotación del cubo

Tomado de:
http://programacion.net/cursos_descargas/3d/i
mages/java3d_10.gif

El resultado de la ejecución de la rotación en un eje y al modificar el eje se puede observar


en la siguiente secuencia gráfica.

Figura 31 Resultado de rotar el cubo en X Figura 32 Resultado de rotar el cubo en Y Figura 33 Resultado de rotar el cubo en Z

Tomado de: http://programacion.net/cursos_descargas/3d/images/java3d_15.gif

44.1 Combinación de transformaciones

Frecuentemente un objeto visual se traslada y se rota, o se rota sobre dos ejes. En


cualquier caso, se especifican dos transformaciones diferentes para un sólo objeto visual.
Las dos transformaciones pueden combinarse en una matriz de transformaciones y
contenerse en un sólo objeto TransformGroup. Para el ejemplo se pedirá revisar
nuevamente el código de la Figura 29, correspondiente al programa HelloJava3Db.java.
Hasta el momento nos habíamos fijado solamente en las líneas 24 y 27 para rotar el objeto
visual en un solo eje, al incluir las demás líneas se obtendrá una combinación de rotaciones.
Universidad Nacional Abierta y a Distancia – UNAD
Vicerrectoría Académica y de Investigación - VIACI
Escuela: Escuela De Ciencias Básicas Tecnología E Ingeniería Programa: Ingeniería de Sistemas
Curso: Computación Gráfica Código: 299210

Para crear estas dos rotaciones simultáneas se requiere combinar dos objetos Transform3D
de rotación. El ejemplo rota el cubo sobre los ejes x e y. Se crean dos objetos Transform3D,
uno por cada rotación (líneas 24 y 25). Las rotaciones individuales se especifican para los
dos objetos TransformGroup (líneas 27 y 28). Luego las rotaciones se combinan mediante
la multiplicación de los objetos Transform3D (línea 29). La combinación de las dos
transformaciones se carga en el objeto TransformGroup (línea 31).

El código completo del ejemplo HelloJava3Db.java es el siguiente:

/* @(#)HelloJava3Db.java 1.1 00/09/22 13:55


* Copyright (c) 1996-2000 Sun Microsystems, Inc. All Rights Reserved.
* HelloJava3Db dibuja un cubo simple rotado 45° en x y 36° en y
*/
import java.applet.Applet;
import java.awt.BorderLayout;
import java.awt.Frame;
import java.awt.event.*;
import java.awt.GraphicsConfiguration;
import com.sun.j3d.utils.applet.MainFrame;
import com.sun.j3d.utils.geometry.*;
import com.sun.j3d.utils.universe.*;
import javax.media.j3d.*;
import javax.vecmath.*;

public class HelloJava3Db extends Applet {


public BranchGroup createSceneGraph() {
// Crea la raíz del árbol
BranchGroup objRoot = new BranchGroup();

// El objeto rotate contiene la matriz de transformación


Transform3D rotate = new Transform3D();
Transform3D tempRotate = new Transform3D();

rotate.rotX(Math.PI/4.0d);
tempRotate.rotY(Math.PI/5.0d);
rotate.mul(tempRotate);

TransformGroup objRotate = new TransformGroup(rotate);

objRoot.addChild(objRotate); objRotate.addChild(new ColorCube(0.4));

// Compila la escena gráfica


objRoot.compile();
return objRoot;
} // Fin del método CreateSceneGraph que crea la escena
Universidad Nacional Abierta y a Distancia – UNAD
Vicerrectoría Académica y de Investigación - VIACI
Escuela: Escuela De Ciencias Básicas Tecnología E Ingeniería Programa: Ingeniería de Sistemas
Curso: Computación Gráfica Código: 299210

// Crea una escena simple relacionada con el universo virtual


public HelloJava3Db() {
setLayout(new BorderLayout());
GraphicsConfiguration config = SimpleUniverse.getPreferredConfiguration();

Canvas3D canvas3D = new Canvas3D(config);


add("Center", canvas3D);

BranchGroup scene = createSceneGraph();


SimpleUniverse simpleU = new SimpleUniverse(canvas3D);
simpleU.getViewingPlatform().setNominalViewingTransform();

simpleU.addBranchGraph(scene);
} // Fin del constructor HelloJava3Db

public static void main(String[] args) {


Frame frame = new MainFrame(new HelloJava3Db(), 256, 256);
} // Fin del método main
} // Fin de la clase HelloJava3Db

En la Figura 34 se puede ver el escenario gráfico creado en HelloJava3Db.java. La rama


de vista gráfica es la misma producida en HelloJava3Da, que está construida por un
SimpleUniverse y representada por una gran estrella. La rama de contenido gráfico ahora
incluye un TransformGroup en el camino del escenario gráfico hacia el objeto ColorCube.
En la Figura 35 se puede observar el resultado de la ejecución.

Figura 35 Ejecución de HelloJava3Db con rotación en X e Y


Figura 34 Escenario gráfico para varias transformación
Tomado de:
Tomado de: http://programacion.net/cursos_descargas/3d/imag
http://programacion.net/cursos_descargas/3d/imag es/java3d_17.gif
es/java3d_14.gif
Universidad Nacional Abierta y a Distancia – UNAD
Vicerrectoría Académica y de Investigación - VIACI
Escuela: Escuela De Ciencias Básicas Tecnología E Ingeniería Programa: Ingeniería de Sistemas
Curso: Computación Gráfica Código: 299210

44.2 Capacidades y Rendimiento

El escenario gráfico construido por un programa Java 3D podría usarse directamente para
renderizar. Sin embargo, la representación no es muy eficiente. La flexibilidad construida
dentro de cada objeto escenario gráfico (que no se van a discutir en este tutorial) crean
una representación sub-optima del universo virtual. Para mejorar el rendimiento de la
renderización se usa una representación más eficiente del universo virtual.

Java 3D tiene una representación interna para un universo virtual y los métodos para hacer
la conversión. Hay dos formas para hacer que el sistema Java 3D haga la conversión de la
representación interna. Una forma es compilar todas las ramas gráficas. La otra forma es
insertar una rama gráfica en un universo virtual para darle vida.

Compilar Contenidos

El objeto BranchGroup tiene un método compilador. Llamando a este método se convierte


la rama gráfica completa que hay debajo del BranchGroup a la representación interna de
Java 3D de la rama gráfica. Además de la conversión, la representación interna podría
optimizarse de una o varias maneras.

Las posibles optimizaciones no se especifican en el API Java 3D. Sin embargo, se puede
ganar en eficiencia de varias formas. Una de las posibles optimizaciones es combinar
TransformGroups con caminos de escenario gráfico. Por ejemplo, si un escenario gráfico
tiene dos objetos TransformGroup en una relación padre-hijo pueden ser representados
por un objeto TransformGroup. Otra posibilidad es combinar objetos Shape3D que tienen
una relación estática física. Estos tipos de optimizaciones se hacen posibles cuando las
capacidades no se configuran.

La Figura 36 presenta una representación conceptual de la conversión a una representación


más eficiente. El escenario gráfico del lado izquierdo es compilado y transformado en la
representación interna mostrada en el lado derecho. La figura sólo representa el concepto
de representación interna, no como Java 3D realmente lo hace.
Universidad Nacional Abierta y a Distancia – UNAD
Vicerrectoría Académica y de Investigación - VIACI
Escuela: Escuela De Ciencias Básicas Tecnología E Ingeniería Programa: Ingeniería de Sistemas
Curso: Computación Gráfica Código: 299210

Figura 36 Representación conceptual del proceso de compilar un escenario gráfico

Tomado de: http://programacion.net/cursos_descargas/3d/images/java3d_13.gif

Capacidades

Una vez que una rama gráfica empieza a vivir o es compilada el sistema de renderizado
Java 3D la convierte a una representación interna más eficiente. El efecto más importante
de esta conversión es la mejora del rendimiento de renderizado.

Pero también tiene otros efectos, uno de ellos es fijar el valor de transformaciones y otros
objetos en el escenario gráfico. A menos que especificamente se le proporcionen al
programa, este no tendrá la capacidad de cambiar los valores de los objetos del escenario
gráfico una vez que estén vivos.

Hay casos en que un programa necesita la capacidad de cambiar estos valores después de
que estén vivos. Por ejemplo, cambiar el valor de un objeto TransformGroup crea
animaciones. Para que esto suceda, la transforamción debe poder cambiar después de
estar viva. La lista de parámetros a los que se puede acceder, y de qué forma, se llama
capacidades del objeto.

Cada SceneGraphObject tiene un conjunto de bits de capacidad. Los valores de estos bits
determinan que capacidades existen para el objeto después de compilarlo o de darle vida.
El conjunto de capacidades varía con la clase. SceneGraphObject es la superclase de casi
cualquier clase usada para crear un escenario gráfico, incluyendo Group, Leaf, y
NodeComponent.

A continuación, se presenta la lista parcial de métodos de SceneGraphObject.

 void clearCapability(int bit): Borra el bit de capacidad especificado.


 boolean getCapability(int bit): Recupera el bit de capcidad especificado.
Universidad Nacional Abierta y a Distancia – UNAD
Vicerrectoría Académica y de Investigación - VIACI
Escuela: Escuela De Ciencias Básicas Tecnología E Ingeniería Programa: Ingeniería de Sistemas
Curso: Computación Gráfica Código: 299210

 void setCapability(int bit): Configura el bit de capacidad especificado.


Como ejemplo, para poder leer el valor de la transformación representada por un objeto
TransformGroup, esta capacidad debe activarse antes de compilarlo o darle vida. De forma
similar, para poder cambiar el valor de la transformación en un objeto TransformGroup,
su capacidad de escribir transformación debe configurarse antes de compilarlo o darle vida.
Intentar hacer un cambio en un objeto vivo o compilado para el que la propiedad adecuada
no se ha configurado resultará en una excepción.

En la siguiente sección, las animaciones se crean usando una transformación de rotación


que varía con el tiempo. Para que esto sea posible, el objeto TransformGroup debe tener
su capacidad ALLOW_TRANSFORM_WRITE activada antes de que sea compilado o se le
de vida.

A continuación, se presenta la lista parcial de capacidades de TransformGroup. Las dos


capacidades listadas aquí son las únicas definidas por TransformGroup. Éste hereda varias
capacidades de sus clases ancestros: Group y Node. La configuración de capacidades se
puede seleccionar, eliminar o recuperar usando los métodos definidos en
SceneGraphObject.

 ALLOW_TRANSFORM_READ Especifica que el nodo TransformGroup permite


acceder a la información de transformación de su objeto.
 ALLOW_TRANSFORM_WRITE Especifica que el nodo TransformGroup permite
escribir la información de transformación de su objeto.

Las capacidades también controlan el acceso a otros aspectos de un objeto


TransformGroup. Los objetos TransformGroup heredan configuración de capacidades de
sus clases ancestros: Group y Node. En el siguiente bloque de referencia se pueden ver
ver algunas de esas capacidades.

 Lista Parcial de Capacidades de Group: TransformGroup hereda varios bits de


capacidades de sus clases ancestros.
o ALLOW_CHILDREN_EXTEND Permite que se puedan añadir hijos al nodo
Group después de que esté compilado o vivo.
o ALLOW_CHILDREN_READ: Permite que se puedan leer las referencias a los
hijos del nodo Group después de que esté compilado o vivo.
o ALLOW_CHILDREN_WRITE: Permite que se puedan escribir las referencias
a los hijos del nodo Group después de que esté compilado o vivo.
Universidad Nacional Abierta y a Distancia – UNAD
Vicerrectoría Académica y de Investigación - VIACI
Escuela: Escuela De Ciencias Básicas Tecnología E Ingeniería Programa: Ingeniería de Sistemas
Curso: Computación Gráfica Código: 299210

Lección 45 Añadir Comportamiento de Animación

En Java 3D, Behavior es una clase para especificar animaciones o interacciones con
objetos visuales. El comportamiento puede cambiar virtualmente cualquier atributo de un
objeto visual. Un programador puede usar varios comportamientos predefinidos o
especificar un comportamiento personalizado. Una vez que se ha especificado un
comportamiento para un objeto visual, el sistema Java 3D actualiza automáticamente la
posición, la orientación, el color, u otros atributos del objeto visual.

La distinción entre animación e interacción es si el comportamiento es activado


en respuesta al paso del tiempo o en respuesta a actividades del usuario,
respectivamente.

Cada objeto visual del universo virtual puede tener su propio comportamiento predefinido.
De hecho, un objeto visual puede tener varios comportamientos. Para especificar un
comportamiento para un objeto visual, el programador crea objetos que especifiquen el
comportamiento, añade el objeto visual al escenario gráfico y hace las referencias
apropiadas entre los objetos del escenario gráfico y los objetos Behavior.

En un universo virtual con muchos comportamientos, se necesita una significante potencia


de cálculo para calcular los comportamientos. Como tanto el renderizador como el
comportamiento usan el mismo procesador, es posible que la potencia de cálculo que
necesita el comportamiento degrade el rendimiento del renderizado.

Java 3D permite al programador manejar este problema especificando un límite espacial


para que el comportamiento tenga lugar. Este límite se llama región programada. Un
comportamiento no está activo a menos que el volumen de activación de ViewPlatform
interseccione con una región programada del Behavior. En otras palabras, si nadie en el
bosque ve el árbol caer, éste no cae. La característica de región programada hace más
eficiente a Java 3D en el manejo de universos virtuales con muchos comportamientos.

Un Interpolator es uno de las muchas clases de comportamientos predefinidos en el


paquete corazón de Java 3D. Basado en una función de tiempo, el objeto Interpolator
manipula los parámetros de un objeto del escenario gráfico. Por ejemplo, para el
RotationInterpolator, manipula la rotación especificada por un TransformGroup para
afectar la rotación de los objetos visuales que son ancestros de TransformGroup.

La siguiente lista enumera los pasos que se requieren para especificar una animación con
un objeto Interpolator. Los siguientes pasos forman una receta para crear un
comportamiento de animación con interpolación:

• Crear un TransformGroup fuente.


• Selecciona la capacidad ALLOW_TRANSFORM_WRITE.
• Crear un objeto Alpha (función de tiempo en Java 3D).
• Especifica los parámetros de tiempo para el alpha.
Universidad Nacional Abierta y a Distancia – UNAD
Vicerrectoría Académica y de Investigación - VIACI
Escuela: Escuela De Ciencias Básicas Tecnología E Ingeniería Programa: Ingeniería de Sistemas
Curso: Computación Gráfica Código: 299210

• Crear el objeto Interpolator. Tiene referencias con los objetos Alpha y


TransformGroup.
• Personalizar los parámetros del comportamiento.
• Especificar la región programada.
• Configurar la región programada para el comportamiento.
• Hacer el comportamiento como hijo del TransformGroup

45.1 Ejemplo de Comportamiento: HelloJava3Dc

El fragmento de código de la Figura 37 muestra un ejemplo completo del uso de las clases
interpoladoras para crear una animación. La animación creada con este código es una
rotación continúa con un tiempo de rotación total de 4 segundos.

Figura 37 Código para la creación de la escena con comportamiento RotationInterpolator

Tomado de: Autoría propia

El paso 1 de la receta es crear el objeto TransformGroup para modificarlo durante la


ejecución. El objeto TransformGroup fuente de un interpolador debe tener activada la
capacidad de escritura. El objeto TransformGroup llamado objSpin se crea en la línea
25. La capacidad de escritura de objSpin se selecciona en la línea 26.

El paso 2 es crear un objeto Alpha para dirigir la interpolación. Los dos parámetros
especificados en la línea 34 del fragmento de código son el número de interacciones del
bucle y el tiempo de un ciclo. El valor de "-1" especifica un bucle contínuo. El tiempo se
especifica en milisegundos por lo que el valor de 4000 significa 4 segundos. Por lo tanto,
el comportamiento es rotar cada cuatro segundos.
Universidad Nacional Abierta y a Distancia – UNAD
Vicerrectoría Académica y de Investigación - VIACI
Escuela: Escuela De Ciencias Básicas Tecnología E Ingeniería Programa: Ingeniería de Sistemas
Curso: Computación Gráfica Código: 299210

El paso 3 de la receta es crear el objeto Interpolator. El objeto RotationInterpolator


se crea en la línea 36. El interpolador debe tener referencias a la transformación fuente y
al objeto alpha. Esto se consigue en el constructor. En este ejemplo se usa el
comportamiento por defecto del RotationInterpolator para hacer una rotación completa
sobre el eje y.

El paso 4 es especificar una región programada. Se usa un objeto BoundingSphere con


sus valores por defecto. El objeto BoundingSphere se crea en la línea 40. La esfera se
configura como los límites del comportamiento en la línea 41.

El paso final, el 5, hace del comportamiento un hijo del TransformGroup. Esto se


consigue en la línea 42.

Este fragmento de código se usa con otros fragmentos anteriores para crear el programa
de ejemplo HelloJava3Dc.java. Al ejecutar la aplicación veremos cómo se renderiza el
ColorCube con un comportamiento de rotación cada cuatro segundos.

El programa HelloJava3Dc
crea el escenario gráfico de
la Figura 38. El objeto
rotation es tanto hijo del
TransformGroup como una
referencia a él. Aunque esta
relación parece violar las
restricciones de bucles
dentro del escenaio gráfico,
no lo hace. Recuerda que los
Figura 38 Escenario gráfico incluyendo comportamiento
arcos de referencia (flecha
Tomado de: punteada) no son parte del
http://programacion.net/cursos_descargas/3d/images/java3d_14.gif escenario gráfico. La línea

punteada desde el Behavior


hacia el TransformGroup es
esta referencia.

La ejecución del ejemplo HelloJava3Dc proporciona la siguiente ventana gráfica:


Universidad Nacional Abierta y a Distancia – UNAD
Vicerrectoría Académica y de Investigación - VIACI
Escuela: Escuela De Ciencias Básicas Tecnología E Ingeniería Programa: Ingeniería de Sistemas
Curso: Computación Gráfica Código: 299210

Figura 39 Ejecución del ejemplo HelloJava3Dc.java

Tomado de: http://programacion.net/cursos_descargas/3d/images/java3d_15.gif

45.2 Clases que intervienen para programar el comportamiento de animación

Una acción de comportamiento puede ser cambiar la localización (PositionInterpolator),


la orientación (RotationInterpolator), el tamaño (ScaleInterpolator), el color
(ColorInterpolator), o la transpariencia (TransparencyInterpolator) de un objeto
visual. Como se mencionó antes, los Interpolators son clases de comportamiento
predefinidas. Todos los comportamientos mencionados son posibles sin usar un
Interpolator; sin embargo, los interpolators hacen mucho más sencilla la cracción de
comportamientos. Las clases Interpolators existen para proporcionar otras acciones,
incluyendo combinaciones de estas acciones.

Clase RotationInterpolator

Esta clase se usa para especificar un comportamiento de rotación de un objeto visual o de


un grupo de objetos visuales. Un objeto RotationIterpolator cambia un objeto
TransformGroup a una rotación especififca en repuesta a un valor de un objeto Alpha.
Como el valor de este objeto cambia cada vez, la rotación también cambia. Un objeto
RotationInterpolator es flexible en la especificación del eje de rotación, el ángulo de inicio
y el ángulo final.

Para rotaciones constantes sencillas, el objeto RotationInterpolator tiene el siguiente


constructor que puede usarse para eso:

• RotationInterpolator(Alpha alpha, TransformGroup target) Este


constructor usa valores por defecto de algunos parámetros del interpolador para
Universidad Nacional Abierta y a Distancia – UNAD
Vicerrectoría Académica y de Investigación - VIACI
Escuela: Escuela De Ciencias Básicas Tecnología E Ingeniería Programa: Ingeniería de Sistemas
Curso: Computación Gráfica Código: 299210

construir una rotación completa sobre el eje y, usando el TransformGroup


especificado. Los parámetros son:
• alpha: la función de variación de tiempo para referencia.
• target: el objeto TransformGroup a modificar.

El objeto TransformGroup de un interpolador debe tener la capacidad de escritura activada.

Mapear una acción en el tiempo se hace usando un objeto Alpha. La especificación de este
objeto puede ser compleja.

Clase Alpha

Los objetos de la clase Alpha se usan para crear una función que varía en el tiempo. La
clase Alpha produce un valor entre cero y uno, inclusives. El valor que produce depende
de la hora y de los parámetros del objeto Alpha. Los objetos Alpha se usan comúnmente
con un comportamiento Interpolator para proporcionar animaciones de objetos visuales.

Alpha tiene diez parámetros, haciendo la programación tremendamente flexible. Sin entrar
en detalles de cada parámetro, saber que un ejemplar de Alpha puede combinarse
fácilmente con un comportamiento para proporcionar rotaciones sencillas, movimientos de
péndulo, y eventos de una vez, como la apertura de puertas o el lanzamiento de cohetes.

La clase Alpha proporciona objetos para convertir la hora en un valor alpha (un valor entre
0 y 1). El objeto Alpha es efectivamente una función de tiempo que genera valores alpha
entre cero y uno. La función "f(t)" y las características del objeto Alpha están determinadas
por parámetros definidos por el usuario:

Algunos constructores para el objeto Alpha son:

• Alpha(): Bucle continuo con un periodo de un segundo.


• Alpha(int loopCount, long increasingAlphaDuration): Este constructor
toma sólo loopCount e increasingAlphaDuration como parámetros y asigna los
valores por defecto a todos los demás parámetros, resultando un objeto Alpha
que produce valores desde cero a uno crecientes. Esto se repite el número de
veces especificado por loopCount. Si loopCount es -1, el objeto alpha se repite
indefinidamente. El tiempo que tarde en ir desde cero hasta uno está
especificando en el segundo parámetro usando una escala de milisegundos.
Los parámetros:

• loopCount: número de veces que se ejecuta este objeto alpha; un


valor de -1 especifica un bucle indefinido.
• increasingAlphaDuration: tiempo en milisegundos que tarda el
objeto alpha en ir de cero a uno.
Universidad Nacional Abierta y a Distancia – UNAD
Vicerrectoría Académica y de Investigación - VIACI
Escuela: Escuela De Ciencias Básicas Tecnología E Ingeniería Programa: Ingeniería de Sistemas
Curso: Computación Gráfica Código: 299210

Región Programada

Como se mencionó anteriormente, cada comportamiento tiene unos límites programados.


Estos límites se configuran usando el método setSchedulingBounds de la clase
Behavior.

Hay varias formas de especificar una región programada, la más sencilla es crear un objeto
BoundingSphere. Otras opciones incluyen BoundingBox y BoundingPolytope.

La sintaxis del método setShedulingBounds se presenta a continuación:

• void setSchedulingBounds(Bounds region): Selecciona la región


programada del Behavior a unos límites especificados por el parámetro región.

Clase BoundingSphere

Especificar un límite esférico se consigue especificando un punto central y un radio para la


esfera. El uso normal de este tipo de límites es usar el centro a (0, 0, 0). Entonces el radio
se selecciona lo suficientemente grande como para contener el objeto visual, incluyendo
todas las posibles localizaciones del objeto.

Algunos de los constructores de BoundingSphere son:

• BoundingSphere(): Este constructor crea una límite esférico centrado en el


origen (0, 0, 0) con un radio de 1.
• BoundingSphere(Point3d center, double radius): Construye e inicializa un
BoundingSphere usando el punto central y el radio especificados.

45.3 Ejemplo de combinación de Transformación y


Comportamiento: HelloJava3Dd

Como se puede suponer, es posible combinar comportamientos con las transformaciones


de rotación de los ejemplos anteriores. HelloJava3Dd.java hace esto. En la rama de
contenido gráfico, hay objetos llamados objRotate y objSpin, que distinguen entre la
rotación estática y el comportamiento de rotación (bucle continuo) del objeto Cube
respectivamente. El código completo de la aplicación que permite dibujar la escena se
presenta a continuación.

/* @(#)HelloJava3Dd.java 1.1 00/09/22 13:55


* Copyright (c) 1996-2000 Sun Microsystems, Inc. All Rights Reserved.
* Este ejemplo presenta la animación continua de un cubo rotado
*/
Universidad Nacional Abierta y a Distancia – UNAD
Vicerrectoría Académica y de Investigación - VIACI
Escuela: Escuela De Ciencias Básicas Tecnología E Ingeniería Programa: Ingeniería de Sistemas
Curso: Computación Gráfica Código: 299210

import java.applet.Applet;
import java.awt.BorderLayout;
import java.awt.Frame;
import java.awt.event.*;
import java.awt.GraphicsConfiguration;
import com.sun.j3d.utils.applet.MainFrame;
import com.sun.j3d.utils.geometry.ColorCube;
import com.sun.j3d.utils.universe.*;
import javax.media.j3d.*;
import javax.vecmath.*;

public class HelloJava3Dd extends Applet {


public BranchGroup createSceneGraph() {
// Crea la raiz de la escena
BranchGroup objRoot = new BranchGroup();

// Estas son las líneas que permiten la rotación


// combinada en los ejes X e Z.
Transform3D rotate = new Transform3D();
Transform3D tempRotate = new Transform3D();
rotate.rotX(Math.PI/4.0d);
tempRotate.rotZ(Math.PI/5.0d);
rotate.mul(tempRotate);
TransformGroup objRotate = new TransformGroup(rotate);

// Estas son las líneas que permiten el Behavior o


// animación de rotación continua, observada en HelloJava3Dc
TransformGroup objSpin = new TransformGroup();
objSpin.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
objRoot.addChild(objRotate); objRotate.addChild(objSpin);

// Crea el ColorCube y lo agrega a la escena


objSpin.addChild(new ColorCube(0.4));

// Crea el objeto Behavior para desarrollar la animación deseada


// que consiste en un rotación continua sobre el eje Y cada 4 sg
Transform3D yAxis = new Transform3D();
Alpha rotationAlpha = new Alpha(-1, 4000);

RotationInterpolator rotator =
new RotationInterpolator(rotationAlpha,
objSpin, yAxis,
0.0f, (float) Math.PI*2.0f);

// Se especifica el área activa de la escena como una Esfera


BoundingSphere bounds = new BoundingSphere();
rotator.setSchedulingBounds(bounds);
objSpin.addChild(rotator);
Universidad Nacional Abierta y a Distancia – UNAD
Vicerrectoría Académica y de Investigación - VIACI
Escuela: Escuela De Ciencias Básicas Tecnología E Ingeniería Programa: Ingeniería de Sistemas
Curso: Computación Gráfica Código: 299210

return objRoot;
} // Fin del método CreateSceneGraph

public HelloJava3Dd() {
setLayout(new BorderLayout());
GraphicsConfiguration config = SimpleUniverse.getPreferredConfiguration();
Canvas3D canvas3D = new Canvas3D(config);
add("Center", canvas3D);
BranchGroup scene = createSceneGraph();
scene.compile();
SimpleUniverse simpleU = new SimpleUniverse(canvas3D);
simpleU.getViewingPlatform().setNominalViewingTransform();
simpleU.addBranchGraph(scene);
} // Fin del constructor de HelloJava3Dd

public static void main(String[] args) {


Frame frame = new MainFrame(new HelloJava3Dd(), 256, 256);
} // Fin del método main
} // Fin de la clase HelloJava3Dd

La representación gráfica de la escena y la ventana generada se muestran en las


siguientes figuras:

Figura 40 Escena gráfica que combina transformación y Figura 41 Ejecución del ejemplo HelloJava3Dd.java
comportamiento
Tomado de:
Tomado de: http://programacion.net/cursos_descargas/3d/imag
http://programacion.net/cursos_descargas/3d/imag es/java3d_17.gif
es/java3d_14.gif
Universidad Nacional Abierta y a Distancia – UNAD
Vicerrectoría Académica y de Investigación - VIACI
Escuela: Escuela De Ciencias Básicas Tecnología E Ingeniería Programa: Ingeniería de Sistemas
Curso: Computación Gráfica Código: 299210

Referencias Bibliográficas

Developer.com. (2007). Understanding Transforms in Java 3D. Obtenido de


http://www.developer.com/java/other/article.php/3717101/Understanding-
Transforms-in-Java-3D.htm

Foley, J., Van Dam, A., Feiner, S., & Huges, J. (1996). Computer graphics: principles and
practice. Addison Wesley.

fukinotou11d. (2015). 3D Models in Java 3D: Beginners Only_1 Color Cube and
Coordinate Systems (with Source Code). Obtenido de
https://www.youtube.com/watch?v=bAA6NRW3D4s

Java.net. (2000). Java 3D API. Obtenido de


http://download.java.net/media/java3d/javadoc/1.5.0/

Oracle Inc. (2005). Package javax.media.j3d. Obtenido de


http://docs.oracle.com/cd/E17802_01/j2se/javase/technologies/desktop/java3d/fo
rDevelopers/j3dapi/index.html

Oracle Inc. (2017). Java SE Documentation. Obtenido de


http://www.oracle.com/technetwork/java/javase/documentation/index.html

Panama Hitek. (2014). Creación y manipulación de objetos en tercera dimensión con


Java 3D. Obtenido de https://www.youtube.com/watch?v=DO6gthIB4Ds

Programacion.net. (2010). Java 3D. Obtenido de


http://programacion.net/articulo/java_3d_169/2

SUN Microsystems. (2000). The Java 3D™ API Specification. Obtenido de


http://docs.oracle.com/cd/E19869-01/806-5414-10/806-5414-10.pdf

S-ar putea să vă placă și