INTRODUCCIÓN
A LA COMPUTACIÓN GRÁFICA
Los elementos de
estudio de esta unidad que explicaremos serán los siguientes:
Puntos: Se especifican a partir de su localización y color. Su
discretización es directa, como se mencionó con anterioridad.
Segmentos de recta: Son esenciales para la mayor parte de las
entidades. Se especifican a partir de un par de puntos que representan sus
extremos.
Circunferencias: En algunos casos representar entidades
curvadas con segmentos poligonales puede ser inadecuado o costoso, por lo que
en la prácticas las circunferencias o círculos se adoptan como primitivas. Se
especifican con la posición de su centro y su radio.
Polígonos: Son indispensables para representar entidades sólidas. Se
representan a partir de la secuencia de puntos que determina la poligonal de su
perímetro.
Para el momento de escoger un método de
discretización para una primitiva gráfica, es indispensable contar con
criterios que permitan evaluar y comparar las ventajas y desventajas de las
distintas alternativas.
Apariencia: Es la especificación más obvia, aunque no es fácil describirla en
términos formales. Normalmente se espera que un segmento de recta tenga una
“apariencia recta” más allá de que se hallan escogido los pixels
matemáticamente más adecuados. Tampoco debe tener discontinuidades. Debe pasar
por la discretización del primer y último punto del segmento. Debe ser
uniforme, etc.
Simetría e invariancia geométrica: Esta especificación se refiere a que un método
de discretización debe producir resultados equivalentes si se modifican algunas
propiedades geométricas de la primitiva que se está discretizando. Por ejemplo,
la discretización de un segmento no debe variar si dicho segmento se traslada a
otra localización en el espacio, o si es rotado, etc.
Simplicidad y velocidad de cómputo: Como los métodos tradicionales de
discretización de primitivas se desarrollaron hace tres décadas, en momentos en
que las posibilidades del hardware y software eran muy limitadas, los
resultados eran muy sensibles al uso de memoria u operaciones aritméticas
complejas. Por lo tanto, los métodos tienden a no depender de estructuras
complejas y a ser directamente implementables en hardware específico de baja
complejidad.
METODOS DE
DISCRETIZACIÓN
Los principales métodos para graficar las
primitivas básicas mediante la discretización:
Evaluar su ecuación diferencial a
diferencias finitas: Este
método, denominado DDA
(discrete diference analyzer) consiste en
plantear la ecuación diferencial de la primitiva a discretizar, y luego evaluar dicha expresión a intervalos adecuados.
Análisis del error: Estos métodos fueron desarrollados por Bressenham y se basan en analizar, dado un pixel que pertenece a la
discretización de la primitiva, cuál es el próximo pixel que minimiza una
determinada expresión que evalúa el error que comete la discretización.
Con los cuales graficaremos la recta, el
círculo, polígonos a continuación antes de eso una pequeña introducción a cada
una de los gráficos
1.- Introducción a
la primitiva línea
Es una
primitiva gráfica que esta especificada por dos puntos: sus extremos.
Cuando
hablamos de CG, lo que entendemos por linea es lo que en matemáticas entendemos
por segmento.
También
le podremos especificar algunas propiedades. Caracterización matemática En CG:
y =
mx + b P1 = (x1; y1), P2 = (x2; y2)
SEGMENTO DE LA
RECTA
El análisis de los métodos de discretización de
rectas parte de considerar el comportamiento esperado en determinados casos
particulares. Dichos casos surgen de suposiciones específicas que simplifican
el problema, pero que al mismo tiempo se pueden generalizar a todos los demás
casos por medio de simetrías. Dado un segmento de recta que va de (x0; y0) a
(x1; y1), se supone que:
Ø Dx = (x1 - x0) ³ 0
Ø Dy = (y1 - y0) ³ 0, y
Ø Dx ³ Dy.
Esto equivale a trabajar en el “octavo” del
espacio de pantalla sombreado en la
Figura 28, donde el origen es el pixel que
corresponde a la discretización del punto (x0;y0) y la zona sombreada a los
lugares donde puede ubicarse el punto (x1;y1 ).
Como ya se mencionó, los métodos DDA evalúan la
ecuación diferencial de la primitiva a intervalos finitos. En el caso
particular de los segmentos de recta, la ecuación diferencial es:
El método busca encontrar una secuencia de n +
1 puntos tales que (x0;y0) = (x0;y0); (x1;y1 ); … (xn;yn) = (x1;y1 ). La discretización de cada uno de
ellos son los pixeles de la discretización del segmento. Esta propiedad, si
bien es trivial, es de gran importancia porque determina que la discretización
de un segmento de recta es invariante frente a transformaciones afines. Esto
significa que es equivalente transformar los extremos del segmento y
discretizar el segmento transformado, o discretizar primero y transformar cada
punto obtenido. Sin embargo, la primera alternativa es mucho más eficiente.
e determina la “frecuencia” de muestreo del
segmento. Un valor muy pequeño determina que muchas muestras producirán puntos
que serán discretizados al mismo pixel. Por el contrario, un valor muy grande
determinaría que el segmento aparezca “punteado” en vez de ser continuo como
corresponde. Un valor práctico es elegir Dx = 1 y por lo tanto n = Dx, es decir, la discretización tiene tantos
pixeles como longitud tiene el segmento en la variable que más varía (más uno,
dado que la secuencia tiene n + 1 puntos). Al mismo tiempo es fácil ver que
En la Figura es posible ver el resultado de
discretizar un segmento particular por el método DDA. Obsérvese que los puntos
extremos (x0; y0) a (x1;y1) son en efecto puntos y por lo tanto están ubicados
en cualquier lugar dentro del pixel que corresponde a su discretización.
Un algoritmo sencillo escrito en lenguaje Java
que computa la discretización de un segmento de recta por el método DDA se
muestra en la Figura 30. Obsérvese que se computan las variables en punto
flotantes, y que además se requiere una división en punto flotante que
corresponde al cálculo de m.
Un pequeño paréntesis para explicar algunas
sentencias que pueden causar dudas:
Ø Sobre el parámetro Graphics g (línea 26),
corresponde al contexto gráfico de la ventana (algo así como un lienzo) sobre
el cual se dibuja.
Ø La llamada al método setColor (línea 34)
permite modificar el color actual con el cual se está dibujando, se toma el
color como un objeto de tipo Color que puede ser de los preterminados de Java o
creado a partir de los parámetros r, g, b. Esta llamada al método setColor
permite modificar el color del “lápiz” que dibuja sobre el contexto gráfico.
Ø Java no tiene una sentencia básica para dibujar
puntos (pixeles), en este caso se utiliza la sentencia g.drawRect (línea 35)
para dibujar un rectángulo con un ancho y alto de 0, que en su ejecución se
traduce a pintar un único pixel ubicado en el punto enviado como parámetro.
Ø En la misma sentencia g.drawRect (línea 35) se
utiliza el “casting” a enteros para lograr la discretización de las coordenadas
flotantes.
Segmento de recta por bresseham
En el algoritmo DDA para segmentos de recta es
necesario computar sumas entre las variables en punto flotantes, y además se
requiere una división en punto flotante para computar la pendiente. El mérito
del algoritmo que vamos a presentar consiste en que todas las operaciones se
realizan en aritmética entera por medio de operaciones sencillas, y por lo
tanto, su ejecución es más rápida y económica, y es de fácil implementación con
hardware específico.
El punto de partida del análisis es el
siguiente. Si la discretización de los puntos extremos del segmento debe
pertenecer a la discretización del segmento, entonces es conveniente efectuar
la llamada al algoritmo luego de discretizar los extremos. Esto significa que
(x0;y0) y (x1; y1 ),y
por lo tanto Dx y Dy son enteros.
Luego, si p es un pixel que pertenece a la
discretización del segmento, entonces en las condiciones particulares
mencionadas, el próximo pixel solamente puede ser el ubicado a la derecha (E o
“hacia el este”), o el ubicado en diagonal hacia la derecha y hacia abajo (D o
“en diagonal”) como se muestra en la Figura.
De esta manera todas las operaciones se
efectúan en aritmética entera, con su correspondiente agilización del tiempo de
procesamiento.
La implementación del algoritmo de Bressenham
para segmentos de recta se muestra en la Figura. Teniendo en cuenta que los
productos por 2 en aritmética entera se efectúan con un desplazamiento a
izquierda, es posible observar que el mismo utiliza operaciones elementales e
implementables con hardware específico muy sencillo.
Algoritmo
grafico de Primitiva línea por el método de bressenham
int dx = x1 - x0;
int dy = y1 - y0;
if (Math.abs(dx) > Math.abs(dy))
{
float m = (float) dy /
(float) dx;
float b = y0 - m * x0;
if(dx<0)
dx = -1;
else
dx = 1;
while (x0 != x1)
{
x0 += dx;
y0 = Math.round(m*x0 + b);
g.drawLine( x0, y0, x0, y0);
}
}
else
if (dy != 0)
{
float m = (float) dx /
(float) dy;
float b = x0 - m*y0;
if(dy<0)
dy = -1;
else
dy = 1;
while (y0 != y1)
{
y0 += dy;
x0 = Math.round(m * y0
+ b);
g.drawLine( x0, y0, x0, y0);
}
}
EJERCICIO
DE LA PRIMITIVA LINEA
2.- Discretización
de circunferencias
Como en el caso de los segmentos de recta, en
la discretización de circunferencias o círculos es posible trabajar un sólo
segmento de la circunferencia y se obtienen las demás por simetría. Igualmente
se dispone de algoritmos DDA y de Bressenham para el dibujo de circunferencias.
En este aparte se mostrará una adaptación del algoritmo DDA a partir de la
ecuación de la circunferencia, tomado de la página internet de Roberto Albornoz12.
Para poder realizar el dibujo de la
circunferencia usaremos las ecuaciones de la circunferencia en coordenadas
polares que son:
x = r * cosq
y = r *senq
Estas ecuaciones serán las que ocuparemos para
calcular cada punto (x,y) del círculo, donde el r será obviamente el radio de
círculo y q será el
ángulo que forma el radio con la parte positiva del eje x. En forma gráfica
sería así:


El ángulo deberá estar en radianes ya que las
funciones de seno y coseno que incluye Java, trabajan con los ángulos en
radianes. La fórmula para transformar grados a radianes es la siguiente:
Entonces para dibujar el círculo de un radio
determinado, solamente tenemos que hacer un ciclo desde 0 hasta 360, pero con
incrementos pequeños, calcular cada punto con las ecuaciones en coordenadas
polares e ir dibujando cada punto. El ciclo en vez de ir de 0 a 360 (ángulos en
grados) irá de 0 a 6.28 (360*3.14/180=6.28) ya que el ángulo debe estar en
radianes.
Dibujar el círculo punto a punto es una tarea
un poco lenta, debido a que se debe calcular en cada punto el seno y el coseno
del ángulo, y estas funcionas son muy lentas. Para solucionar esto se pueden
crear tablas predefinidas o precalculadas. En la siguiente figura se muestra el
código en Java que permitiría dibujar el círculo en una ventana.
3.- Discretización
de polígonos
Introducción
Se considera un polígono una figura cerrada,
formada a partir de varias líneas.
Para la discretización de polígonos se
considerarán 2 tipos de polígonos: los irregulares y los regulares, en
concordancia con lo mostrado por Steven R Davidson en su curso de gráficos
disponible en internet.
Es una primitiva
gráfica, que esta especificada por un conjunto ordenado de puntos.
Definición:
(Poligonal)
Dada una
secuencia finita de puntos en el plano
P =
fP1;
P2; : : : ; Png, una poligonal es la la unión de los segmentos de recta
determinados por puntos consecutivos de P.
Existen dos tipos de polígonos:
Irregulares
La graficación de polígonos irregulares se
realiza a partir de un conjunto de puntos que se unen secuencialmente, el
polígono se cierra al unir el primer y último puntos. A continuación se muestra
el código Java que dibujaría un polígono irregular a partir de un vector de
elementos de tipo Punto y el correspondiente número de puntos.
Cabe recordar que en Java, al igual que en C,
el índice de los vectores inicia en 0. Por tanto, la primera línea se dibuja
desde el primer punto (índice 0) hasta el segundo punto (índice 1), continúa
del segundo al tercero (índice 2), y así sucesivamente, hasta dibujar la línea
del penúltimo punto (índice N-2) hasta el último punto del vector (índice N-1).
Al finalizar el ciclo, dibuja la línea de cierre del polígono entre el último
punto (índice N-1) y el primero (índice 0).
Algoritmo
grafico de Primitiva de polígonos irregulares
Regulares
Un polígono regular se compone de aristas/lados
de igual longitud. Esto implica que el ángulo entre cada arista contigua es el
mismo. Si trazamos un segmento del centro a un vértice y otro segmento del
centro a otro vértice contiguo, entonces el ángulo entre estos dos segmentos es
un divisor de 2_ = 360°. En otras palabras, cada ángulo mencionado es inversamente
proporcional a la cantidad de lados del polígono regular.
Podemos usar la siguiente fórmula:
a = 2π / N, donde a es el ángulo, y N es
la cantidad de lados.
Crearemos polígonos regulares en base a una
circunferencia que circunscribe nuestro polígono regular. Esto implica, que el
centro de la circunferencia coincide con el centro geométrico de cualquier
polígono regular. Para esto, necesitamos usar algunas funciones
trigonométricas, junto con el ángulo ya calculado. El paso principal es
averiguar la coordenada del siguiente vértice de nuestro polígono.
Usaremos
las siguientes fórmulas:
x i = cx + r * cos( i*a )
y i = cy + r * sen( i*a )
i = 0,1,2,...,N-1,
r es el radio de la circunferencia, y
c = (cx, cy) es la coordenada del centro geométrico de la circunferencia
y del polígono.
Al agregar el centro a nuestra fórmula,
conseguimos mover el centro geométrico del origen (0,0) al que nosotros
deseemos. En la Figura se muestra el código que generaría los polígonos
regulares.
Algoritmo
grafico de Primitiva de polígonos regulares
Esto equivale a trabajar en el “octavo” del
espacio de pantalla sombreado en la
Figura 28, donde el origen es el pixel que
corresponde a la discretización del punto (x0;y0) y la zona sombreada a los
lugares donde puede ubicarse el punto (x1;y1 ).