990 likes | 1.23k Views
PRIMITIVAS DE SALIDA. Curso de graficación I. Contenido. Dibujo de puntos Algoritmos comunes de trazo de rectas Algoritmos comunes de trazo de círculos Otras primitivas Bibliotecas gráficas en C y Java Uso de primitivas de biblioteca Principios de animación Mejora de la animación.
E N D
PRIMITIVAS DE SALIDA Curso de graficación I
Contenido • Dibujo de puntos • Algoritmos comunes de trazo de rectas • Algoritmos comunes de trazo de círculos • Otras primitivas • Bibliotecas gráficas en C y Java • Uso de primitivas de biblioteca • Principios de animación • Mejora de la animación
La pantalla gráfica Máxima x – 1 0 x = 0, y = 0 0 Máxima y – 1 x = Máxima x – 1 y = Máxima y – 1
Dibujo de puntos en C y Java C La función putpixel(int x, int y, int color) dibuja un punto en la coordenada x,y con el color especificado. Ejemplo: putpixel(50,25,7) dibuja un punto color gris en la coordenada 50,25. Java En Java se dibuja en un objeto de la clase Graphics. No tiene una función para dibujar puntos pero puede usarse: Graphics g; g.drawLine(50,25,50,25);
Ejemplo 1 #include <iostream> #include <graphics.h> using namespace std; int main(int argc, char *argv[]) { int i; initwindow(400, 300); for(i = 0; i< 1000; i++){ putpixel(rand()%400,rand()%300,rand()%15+1); } system("PAUSE"); closegraph(); return EXIT_SUCCESS; }
Trazo de líneas rectas paralelas a los ejes La línea recta es la más fácil de dibujar Las líneas rectas paralelas a los ejes se pueden trazar un un simple lazo for. El siguiente código traza un línea horizontal desde x a x+ancho. for(i = x; i < x+ancho; i++) putpixel(i,y,color); De forma similar se traza un línea vertical
Ejemplo #include <iostream> #include <graphics.h> using namespace std; void lineaH(int x1, int x2,int y, int color){ int dx; dx = x2>x1?x2-x1:x1-x2; for(int i=0;i<dx;i++) putpixel(x1+i,y,color); } int main(int argc, char *argv[]) { int i; initwindow(400, 300); for(i = 0; i< 1000; i++){ lineaH(rand()%100,rand()%300,rand()%300,rand()%15+1); } getch(); closegraph(); return EXIT_SUCCESS; }
Tarea Escriba funciones en C para dibujar a) una línea vertical y b) una línea diagonal a 45 grados, utilizando la primitiva para dibujar un punto. Ponga los parámetros adecuados en cada caso.
Dibujo de Líneas Rectas Una línea recta debe dibujarse como una sucesión de píxeles. Efecto de escalera que se produce cuando se genera una línea como una serie de píxeles.
Algoritmos para trazo de líneas rectas • Algoritmo DDA, algoritmo incremental básico con aritmética de punto flotante. • Algoritmo de Bresenham, algoritmo incremental complejo con sólo aritmética entera.
Algoritmo DDA Ecuación básica de la recta m es la pendiente y b la intersección con el eje y
Para cualquier intervalo Dx de x a lo largo de la recta, se puede calcular el Dy correspondiente como: Si la pendiente es positiva y menor que 1, se toman variaciones de x iguales a 1 y se calcula y con: Las rectas con pendiente mayor que 1, se invierten los papeles de x y de y.
void dda(int x1,int y1,int x2,int y2,int color){ int dx,dy,steps,k; float x_increment,y_increment,x,y; dx = x2-x1; dy = y2-y1; if(abs(dx)>abs(dy)) steps = abs(dx); else steps = abs(dy); if(steps==0) steps = 1; x_increment = (float)dx/steps; y_increment = (float)dy/steps; x = x1; y = y1; putpixel((int)x,(int)y,color); for(k = 1;k <=steps ;k++){ x = x+x_increment; y = y+y_increment; putpixel((int)x,(int)y,color); } }
Algoritmo de línea de Bresenham Sección de una pantalla de despliegue donde se desplegará un segmento rectilíneo, comenzando desde la posición (10, 10). Las posiciones de los pixeles se representan por las áreas rectangulares numeradas.
Sección de una pantalla de despliegue donde se desplegará un segmento rectilineo con pendiente negativa, comenzando desde la posición (10, 12). El siguiente pixel que se grafique en cada uno de estos ejemplos será aquel cuyo valor de y esta más próximo a la posición real de y sobre la recta.
Sección de una retícula de la pantalla donde se desplegará una línea que pasará por: De aquí se tiene que: Definimos:
la diferencia es Definimos pi como: donde c es: Obtenemos pi+1 de pi como:
Restando pi+1 y pi: Simplificando: El parámetro inicial es:
1. De como entrada los extremos de la línea. Almacene el punto del extremo izquierdo en (x1, y1) y el derecho en (x2, y2). 2. El primer punto que se selecciona para desplegar es el punto del extremo izquierdo(x1, y1). 3. Calcule Dx = x2 - x1, Dy = y2 - y1 y p1 = 2 Dy - Dx. Si p1 = 0, el siguiente punto será (x1 +1, y1), sino será (x1 +1, y1 +1). 4. Incremente x en 1. Se seleccionará yi o yi +1 dependiendo si pi 0 o pi 0. En el primer caso y en el segundo 5. Repita hasta que x llegue a x2.
void BresLine(int x1,int y1,int x2,int y2,int color){ int xerr,yerr,deltax,deltay,dist,incx,incy,i; xerr = 0; yerr = 0; deltax = x2-x1; deltay = y2-y1; if(deltax>0) incx = 1; else if(deltax==0) incx = 0; else incx = -1; if(deltay>0) incy = 1; else if(deltay==0) incy = 0; else incy = -1; Función en C para dibujar rectas con cualquier pendiente.
deltax = abs(deltax); deltay = abs(deltay); if(deltax>deltay) dist = deltax; else dist = deltay; for(i = 0; i<=dist+1;i++){ putpixel(x1,y1,color); xerr = xerr+deltax; yerr = yerr+deltay; if(xerr>dist){ xerr -= dist; x1 += incx; } if(yerr>dist){ yerr -= dist; y1 += incy; } } }
Primitivas básicas en C Define el color de la pluma void setcolor (int color); Regresa el color de la pluma actual int getcolor (void); Pone color de fondo void setbkcolor(int color); Regresa el color de fondo actual int getbkcolor(void); Borra el puerto de visión actual clearviewport (void);
Primitivas de líneas en C Dibuja línea entre (x1,y1) y (x2,y2) void line (int x1, int y1, int x2, int y2); Dibuja línea relativa al cursor gráfico void linerel (int dx, int dy); Dibuja línea desde el cursor gráfico a (x,y) void lineto (int x, int y); Mueve cursor gráfico en forma relativa void moverel (int dx, int dy); Mueve cursor gráfico en forma absoluta void moveto (int x, int y);
Polígono con line void poligono(int x, int y, int r,int c, int n){ /*dibuja un polígono regular de n lados con centro en x,y inscrito en un círculo de radio r y de color c*/ float PI = 3.1415926535; float a = PI/2-PI/n; int x1 = (int)(x-r*cos(a)); int y1 = (int)(y+r*sin(a)); putpixel(x,y,c); setcolor(c); for(int i = 2; i<=n+1;i++){ a = a+2*PI/n; int x2 = (int)(x-r*cos(a)); int y2 = (int)(y+r*sin(a)); line(x1,y1,x2,y2); x1 = x2; y1 = y2; } } x,y r a a = p/n x – r cos(a), y + r sin(a)
Polígono con linerel void poligono(int x,int y,int n, int d,int color){ int x0=x,y0=y,x1=x,y1=y,k; double a=0,da=2*3.14159265358979/n; moveto(x0,y0); for(k = 0;k <n-1 ;k++){ x1 = (int)(x1+d*cos(a)); y1 = (int)(y1+d*sin(a)); a = a+da; lineto(x1,y1); } lineto(x0,y0); } x,y d
Tarea Escriba una función que dibuje una estrella de 5 picos. Ponga como parámetros las coordenadas del centro, la distancia del centro a uno de los picos y el color. Ayuda: note que los picos son vértices de un pentágono. Distancia centro pico x, y
Proyectos Hacer las siguientes primitivas con funciones en C. Utilice las primitivas de línea de graphics.h.
Algoritmos de generación de circunferencias La ecuación de la circunferencia en coordenadas rectangulares es De ésta se puede despejar y como sigue:
Función en C void CircleSimple(int xc, int yc, int r,int c){ int x,y; double yr; x = 0; y = r; yr = r; PlotPoint(xc,yc,x,y,c); /* se cicla hasta trazar todo un octante */ while (x < yr){ x = x + 1; yr = sqrt(r*r-x*x); y = (int)round(yr); PlotPoint(xc,yc,x,y,c); } } void PlotPoint(int xc, int yc, int x, int y,int c) { putpixel(xc + x,yc + y,c); putpixel(xc - x,yc + y,c); putpixel(xc + x,yc - y,c); putpixel(xc - x,yc - y,c); putpixel(xc + y,yc + x,c); putpixel(xc - y,yc + x,c); putpixel(xc + y,yc - x,c); putpixel(xc - y,yc - x,c); }
Círculo básico en Java void CircleSimple(Graphics g, int xc, int yc, int r){ int x,y; double yr; x = 0; y = r; yr = r; PlotPoint(x,y);/* se cicla hasta trazar todo un octante */ while (x < yr){ x = x + 1; yr = Math.sqrt(r*r-x*x); y = (int)Math.round(yr); PlotPoint(x,y); } }
Algoritmo de circunferencia de Bresenham Se supone (xi, yi) la posición más próxima a la trayectoria, la siguiente posición es por tanto (xi+1, yi) o bien (xi+1, yi-1).
Una medida de la diferencia de coordenadas puede definirse como: Definiendo pi como la diferencia de d1 y d2 tenemos
El valor de pi+1 es: Simplificando p1 se obtiene de (x1, y1) = (0, r)
1. Seleccione la primera posición como • 2. Calcule el primer parámetro como • si pi <0, la siguiente posición es (xi+1, yi), si no es (xi+1, yi-1) • 3. Incremente x en 1. Seleccione pi+1 si pi <0 como • y en caso contrario • si pi+1 <0 el siguiente punto será(xi+2, yi+1). De lo contrario es (xi+2, yi+1 – 1). La coordenada y es yi+1=yi, si pi <0 o bien yi+1= yi–1 si pi 0. • 4. Repita el paso 3 hasta que x y y sean iguales.
Algoritmo de punto medio para la circunferencia El método de trazo del punto medio de la circunferencia se basa en la definición de la función circunferencia: Un punto (x,y) arbitrario cumple con lo siguiente
Para decidir entre el punto (xk+1, yk) y (xk+1, yk-1) se utiliza la fórmula anterior evaluada en el punto medio entre los dos pixeles Si pk<0 el punto está dentro de la circunferencia y el pixel (xk+1, yk) es el más próximo a la frontera. Sino, el punto está fuera y el más cercano es (xk+1, yk-1). Obtendremos una expresión recursiva para el siguiente parámetro de decisión cuando evaluamos la función de circunferencia en la posición xk +1 = xk +2.
o Si pk<0, el incremento es 2xk +1 + 1. Sino el incremento es 2xk – 2yk +1 +1. Los valores xk +1 y yk +1 se pueden calcular con: El valor inicial es:
Punto medio en C void CircleMidPoint(int xc, int yc, int r, int c){ int x, y, p; x = 0; y = r; p = 1 - r; PlotPoint(xc,yc,x,y,c); /* se cicla hasta trazar todo un octante */ while (x < y){ x = x + 1; if (p < 0) p = p + 2*x + 1; else { y = y - 1; p = p + 2*(x - y) + 1; } PlotPoint(xc,yc,x,y,c); } }
Punto medio en Java void CircleMidPoint(Graphics g, int xc, int yc, int r){ int x, y, p; x = 0; y = r; p = 1 - r; PlotPoint(g,xc,yc,x,y); /* se cicla hasta trazar todo un octante */ while (x < y){ x = x + 1; if (p < 0) p = p + 2*x + 1; else { y = y - 1; p = p + 2*(x - y) + 1; } PlotPoint(g,xc,yc,x,y); } }
Círculos en C Dibuja un círculo void circle (int x, int y, int r); Dibuja un arco de circulo Void arc (int x,int y,int stangle,int endangle,int radius ); Dibuja una elipse void ellipse(int x, int y, int stangle, int endangle, int xradius, int yradius); Regresa las coordenadas del último arco dibujado void getarccoords(struct arccoordstype *arccoords); Estructura utilizada por getarccoords struct arccoordstype { int x, y; int xstart, ystart, xend, yend; };
Ejemplo #include <iostream> #include <graphics.h> using namespace std; main(){ arccoordstype arco; initwindow(300,300); circle(100,100,50); ellipse(200,100,45,270,50,100); arc(200,200,0,135,50); getarccoords(&arco); cout << "x=" << arco.x << "\n"; cout << "y=" << arco.y << "\n"; cout << "xinicio=" << arco.xstart << "\n"; cout << "yinicio=" << arco.ystart << "\n"; cout << "xfin=" << arco.xend << "\n"; cout << "yfin=" << arco.yend << "\n"; getch(); return 0; }
Dibujo de una compuerta and Centro de la compuerta: x, y x – 2*tamanio y – 2*tamanio x + 2*tamanio y – 2*tamanio x – 4*tamanio y – tamanio Arco con centro en: x + 2*tamanio, y Radio de:2*tamanio de 0 a 90 grados. x – 2*tamanio y – tamanio Arco con centro en: x + 2*tamanio, y+1 Radio de:2*tamanio de 270 a 360 grados. x + 4*tamanio y + tamanio x + 6*tamanio, y x + 2*tamanio y + tamanio x + 4*tamanio, y x – 2*tamanio y + 2*tamanio x +2 *tamanio y +2 *tamanio
Dibujo de una compuerta and void dibujaAnd(int x, int y, int size){ int x1 = x-2*size; int y1 = y-2*size; line(x1,y1,x1,y1+4*size); line(x1,y1,x1+4*size,y1); line(x1,y1+4*size,x1+4*size,y1+4*size); line(x+4*size,y,x+5*size,y); line(x-2*size,y+size,x-3*size,y+size); line(x-2*size,y-size,x-3*size,y-size); arc(x+2*size,y,0,90,2*size); arc(x+2*size,y,270,360,2*size); }
Dibujo de una compuerta or Circulo con centro en: x-4*tqamanio, y Radio de:4*tamanio. viewport(x-2*tamanio,y-2*tamanio, x+6*tamanio,y+2*tamanio) Centro de la compuerta: x, y x – 2*tamanio y – 2*tamanio x,y – 2*tamanio Arco con centro en: x, y+2*tamanio Radio de:4*tamanio de 0 a 90 grados. viewport(x,y-2*tamanio,x+6*tamanio,y) x – 4*tamanio y – tamanio x – 2*tamanio y – tamanio Arco con centro en: x, y - 2*tamanio+1 Radio de:2*tamanio de 270 a 360 grados. viewport(x,y,x+6*tamanio,y+2*tamanio) x + 4*tamanio y + tamanio x + 4*tamanio*cos(30)+tamanio, y x +2*tamanio y +tamanio x + 4*tamanio*cos(30), y x – 2*tamanio y + 2*tamanio x, y +2 *tamanio
Función para dibujar compuerta or void dibujaOr(int x, int y, int size){ arccoordstype arco; int x1 = x-2*size; int y1 = y-2*size; int xp,yp; line(x1,y1,x1+2*size,y1); line(x1,y1+4*size,x1+2*size,y1+4*size); //arco superior delantero setviewport(x,y-2*size,x+4*size,y,true); arc(0,4*size,0,90,4*size); //arco inferior delantero setviewport(x,y,x+4*size,y+2*size+1,true); arc(0,-2*size+1,270,360,4*size); //arco trasero setviewport(x-2*size,y-2*size,x,y+2*size,true); xp = -(int)sqrt(4*size*4*size-4*size*size); circle(xp,2*size,4*size); setviewport(0,0,getmaxx(),getmaxy(),true);
//conexiones traseras xp = x1+xp+(int)sqrt(4*size*4*size-size*size); line(xp,y1+size,xp-size,y1+size); line(xp,y1+3*size,xp-size,y1+3*size); //conexione delantera xp = x+(int)(4*size*cos(30*pi/180)); yp = y-2*size+(int)(4*size*sin(30*pi/180)); line(xp,yp,xp+size,yp); }
Tarea 1. Basándose en las primitivas de compuertas and y or escriba funciones para dibujar estas compuertas con diferentes orientaciones: hacia arriba, hacia la izquierda y hacia abajo. 2. La primitiva drawOval(int x, int y, int w, int h) de Java dibuja una elipse enmarcada en un rectángulo como se muestra en la figura (las líneas punteadas no se dibujan). Defina una primitiva equivalente para dibujar una elipse en C utilizando la primitiva ellipse. x, y w h
Otras primitivas Rectángulos rellenos: Los rectángulos rellenos pueden generarse fácilmente haciendo un barrido de líneas de rastreo desde la primera coordenada y a la segunda. El siguiente código hace este trabajo: void Rectangulo(int x1,int y1,int x2,int y2){ int i; for(i = y1;i<=y2; i++) line(x1, i, x2, i); }
Relleno de polígonos: el relleno opera calculando los tramos que se hallan entre la arista de la izquierda y la derecha del polígono. El algoritmo requiere conservar una lista ordenada respecto a y de las aristas activas en cada fase del proceso. Recorte de círculos: Se puede recortar todo el círculo respecto a un rectángulo. Si el círculo lo intercepta, se divide en cuadrantes y se aplica la prueba de aceptación o rechazo trivial para cada uno. También se aceptar y rechazar a nivel de píxel.. Texto: el texto puede definirse mediante mapas de bits para cada conjunto de caracteres. Se dibuja usando la función CopyPixel del sistema.
Otras primitivas en C void bar (int left, int top, int right, int bottom);void bar3d (int left, int top, int right, int bottom, int depth, int topflag);void drawpoly (int numpoints, int *polypoints);void fillellipse (int x, int y, int xradius, int yradius);void fillpoly (int numpoints, int *polypoints);void floodfill (int x, int y, int border);void pieslice (int x, int y, int stangle, int endangle, int radius);void rectangle (int left, int top, int right, int bottom);void sector (int x, int y, int stangle, int endangle, int xradius, int yradius);void setfillpattern (char *upattern, int color); void setfillstyle (int pattern, int color); void setlinestyle (int linestyle, unsigned upattern, int thickness);