Universidad Simón Bolívar Computación gráfica I Sep – Dic 2011 Algoritmos para dibujo de líneas Realizado por: ● Natalya Blanco ● Rubén Arévalo Contenido • Líneas • Algoritmo DDA • Algoritmo Breseham • Algoritmo Xiaolin Wu o Antialiasing Líneas • La Recta es una sucesión infinita o continua de puntos alineados en una sola dirección. • Es una de las primitivas básicas en Computación Gráfica • Viene dada por la ecuación Y=mX+b , donde m es la pendiente de la recta y b es el corte con el eje Y. • B A Figura 1 Líneas • Para dibujar la recta hay que hallar todos los puntos medios entre el inicial y el final. • El problema es que la ubicación de cada pixel se representa con un entero y las posiciones halladas mediante la ecuación son valores reales. • Por lo tanto, se necesitan formas eficientes de dibujar la recta lo más parecida posible a la realidad, a pesar de las limitaciones que las pantallas de píxeles nos pongan. Transformar primitivas en pixeles Las coordenadas de los píxeles deben estar lo más cerca posible de una línea recta real Un algoritmo debe cumplir con: • La secuencia de píxeles debe ser lo más recta que se pueda. • Las líneas deben tener el mismo grosor e intensidad sin importar el grado de inclinación • Las líneas deben dibujarse lo más rápido posible Transformar línea a pixel Figura 2 – Tomada de www2.dis.ulpgc.es/~ii-fgc/Tema%202%20-%20Primitivas%202D.pdf Algoritmo Ineficiente Algoritmo: Se calcula m (pendiente) Calculo de b (pto de corte en el eje Y) Para x=x0 hasta x=xn y = mx + b Dibujar pixel (x,redondear(y)) Se necesita una multiplicación flotante, una suma y un redondeo por cada paso Analizador diferencial digital Algoritmo DDA Busca determinar los valores enteros correspondientes más próximos a la trayectoria de la línea para la otra coordenada. Para una pendiente positiva, |m| ≤ 1, se realiza el muestreo de x en intervalos y se calcula el valor sucesivo de y con la siguiente ecuación: Yk+1 = Yk +m El subíndice k crece con razón 1 hasta alcanzar el valor final, y m toma valores entre 0 y 1 reales, los valores de y calculados deben ser redondeados. Si la pendiente es negativa, se utiliza un caso análogo con la siguiente ecuación: Xk+1 = Xk + 1/m Algoritmo DDA Pseudo Código Función DDA_Line (int X0, y0, x1, y1) Dx = x1 - x0 Dy = y1 – y0 Si |Dx| > |Dy| entonces pasos = |Dx| Si no pasos = |Dy| xinc = Dx / pasos yinc = Dy / pasos x = x0 y = y0 Dibujar Pixel (redondear(x), redondear(y)) Para k=1 hasta k = pasos x = x + xinc y = y + yinc Dibujar Pixel (redondear(x), redondear(y)) Problemas DDA • Presenta errores de acumulación • Redondeo lento Mejora Separar los incrementos m y 1/m en parte entera y fraccionaria, para reducir a operaciones de enteros Código DDA - JAVA void Line(Display* display, Window win, GC gc, int x0, int y0, int x1, int y1){ float x, y, xs, ys; int dx, dy, steps; dx = x1 – x0; dy = y1 – y0; x = x0; y = y0; if (abs(dx) > abs(dy)) steps = abs(dx); else steps = abs(dy); if (steps == 0) { XdrawPoint(display,win,gc,round(x),round(y)); fprintf(stderr,”this line is a point”); Return; } xs = dx/steps; ys = dy/steps; for (i = 0; i <= steps; i++){ XdrawPoint(display,win,gc,round(x),round(y)); x = x + xs; y = y + ys; } } Tomado de: Alfredo Weitzenfeld – Gráfica la Línea. Recuperado de http://www.docstoc.com/docs/273281/Graficos-Lineas-Circulos?term=linea-algoritmo-completo-bresenham# Algoritmo Breseham Calcula cuál de dos píxeles es el más cercano a la trayectoria de una línea. El pixel (Xk, Yk) se divide en (Xk+1, Yk) y (Xk+1, Yk+1) y hay que decidir cuál pintar, cualculando la distancia vertical entre el centro de cada pixel y la línea real. Figura 3 – Tomada de www2.dis.ulpgc.es/~ii-fgc/Tema%202%20-%20Primitivas%202D.pdf Algoritmo Bresenham Pseudo Código Función Bresenham (int X0, y0, x1, y1) // para el caso 0 < m < 1, siendo x0 < x1 Dibujar Pixel (x0, y0) Calculamos: A=2∆y B=2∆y-2∆x Obtener el valor para p0 = 2∆y-∆x Para cada Xk sobre la línea si pk < 0 Dibujar Pixel (xk+1, yk) pk+1 = pk + A si pk > 0 Dibujar Pixel (xk+1, yk+1) pk+1 = pk + B • Si m > 1: intercambiamos x e y • Si m < 0: el cambio es similar Código Bresenham public void Bresenham(Graphics g,int x0, int y0, int x1, int y1) int x, y, dx, dy, p, incE, incNE, sx, sy; dx = (x1 - x0); dy = (y1 - y0); /* Se determina el punto para comenzar, y para terminar */ if (dy < 0) { dy = -dy; Sy = -1; } else sy = 1; if (dx < 0) { dx = -dx; Sx = -1; } else sx = 1; x = x0; y = y0; g.drawLine( x0, y0, x0, y0); Código Bresenham – Cont. /* se itera hasta el final de la línea */ if(dx>dy){ p = 2*dy - dx; incE = 2*dy; incNE = 2*(dy-dx); while (x != x1){ x = x + sx; if (p < 0){ p = p + incE; } else { y = y + sy; p = p + incNE; } g.drawLine( x0, y0, x0, y0); } }else{ p = 2*dx - dy; incE = 2*dx; incNE = 2*(dx-dy); while (y != y1){ y = y + sy; if (p < 0){ p = p + incE; } else { x = x + sx; p = p + incNE; } g.drawLine( x0, y0, x0, y0); }}} Anti-Aliasing Aliasing es la apariencia de ”escaleras” o ”escalones” que se forman debido a la discretización de lo píxeles. Propuesta Hardware: - Mayor resolución - Píxeles más pequeños Figura 4 – tomada de www.cimat.mx/~cesteves/cursos/cg/pdf/Antialiasing.pdf Algoritmo Xiaolin Wu Mejora del algoritmo de Bresenham, para dibujar rectas en dispositivos de gráficos rasterizados de manera que se reduzca el aliasing. Esta basado en dibujar parejas de píxeles a lo largo del trazado de la línea con diferentes intensidades, en función de la a la recta real. Pseudo código Xiaolin Wu función plot(x, y, c) es Dibujar el pixel en (x, y) con brillo c (donde 0 ≤ c ≤ 1) función ipart(x) es Retornar parte entera de x función redondear(x) es Retornar ipart(x + 0.5) función fpart(x) es Retorna parte fraccional de x función rfpart(x) es Retorna 1 - fpart(x) Pseudo código (Cont.) función dibujarLinea(x1,y1,x2,y2) es dx = x2 - x1 dy = y2 - y1 Si abs(dx) < abs(dy) entonces intercambiar x1, y1 intercambiar x2, y2 intercambiar dx, dy Si x2 < x1 intercambiar x1, x2 intercambiar y1, y2 gradiente = dy / dx xend = redondear(x1) yend = y1 + gradiente * (xend - x1) xgap = rfpart(x1 + 0.5) xpxl1 = xend ypxl1 = ipart(yend) dibujar(xpxl1, ypxl1, rfpart(yend) * xgap) dibujar(xpxl1, ypxl1 + 1, fpart(yend) * xgap) intery = yend + gradiente Pseudo código – (Cont.) xend = redondear(x2) yend = y2 + gradiente * (xend - x2) xgap = fpart(x2 + 0.5) xpxl2 = xend ypxl2 = ipart (yend) dibujar (xpxl2, ypxl2, rfpart (yend) * xgap) dibujar(xpxl2, ypxl2 + 1, fpart (yend) * xgap) // ciclo principal for x from xpxl1 + 1 to xpxl2 - 1 do dibujar(x, ipart (intery), rfpart (intery)) dibujar(x, ipart (intery) + 1, fpart (intery)) intery = intery + gradiente fin Referencias • Tema 2 - Primitivas 2D. Recuperado Noviembre 8, 2011 de www2.dis.ulpgc.es/~ii-fgc/Tema%202%20-%20Primitivas%202D.pdf • Algoritmo DDA Analizador Diferencial Digital. Recuperado Noviembre 8, 2011 de http://maiki69.tripod.com/DDA.htm • Rosetta Code - Xiaolin Wu's Line Algorithm . Recuperado Noviembre 8, 2011 de http://rosettacode.org/wiki/Xiaolin_Wu%27s_line_algorithm • Medellín Anaya, Héctor E. Algoritmo basado en la ecuación de la recta. Recuperado Noviembre 8, 2011 de http://galia.fc.uaslp.mx/~medellin/Applets/LineasRectas/Recta.htm • Algoritmo DDA . Recuperado Noviembre 8, 2011 http://sites.google.com/site/proyectosroboticos/algoritmo-dda • Gómez, Francisco (Febrero 16, 2011) - Una breve introducción a Antialiasing. Recuperado Noviembre 8, 2011 de www.cimat.mx/~cesteves/cursos/cg/pdf/Antialiasing.pdf de