Primitivas gráficas

Download Report

Transcript Primitivas gráficas

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
0
Máxima x – 1
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
y  m x  b
m es la pendiente y b la intersección con el eje y
y2  y1
m
x2  x1
b  y1  m  x1
Para cualquier intervalo Dx de x a lo largo de la recta,
se puede calcular el Dy correspondiente como:
Dy  m  Dx
Si la pendiente es positiva y menor que 1, se toman
variaciones de x iguales a 1 y se calcula y con:
yi 1  yi  m
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.
Trayectoria de la línea especificada
13
12
11
10
9
10
11
12
13
14
Trayectoria de la línea especificada
Sección de una pantalla de
despliegue donde se
desplegará un segmento
rectilineo con pendiente
negativa, comenzando desde
la posición (10, 12).
13
12
11
10
9
10
11
12
13
14
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.
y = mx + b
Sección de una retícula de la
pantalla donde se desplegará
una línea que pasará por:
x , y 
i
i
De aquí se tiene que:
y  m xi  1  b
y +2
i
y +1
i
y
i
x
i
x +1 x +2
i
i
Definimos:
d1  y  y i
 m x i  1  b  y i
d 2   y i  1  y
 y i  1  m x i  1  b
la diferencia es
d2  d1  2m xi  1  2 yi  2b  1
Definimos pi como:
pi  Dx ( d1  d 2 )
 2 Dy  xi  2 Dx  yi  c
donde c es:
c  2Dy  Dx 2b  1
Obtenemos pi+1 de pi como:
pi 1  2 Dy  xi 1  2 Dx  yi 1  c
Restando pi+1 y pi:
pi1  pi  2Dy xi1  xi   2Dx yi1  yi 
Simplificando:
pi1  pi  2Dy  2Dx yi1  yi 
El parámetro inicial es:
p1  2 Dy  Dx
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
pi 1  pi  2Dy
y en el segundo
pi1  pi  2Dy  Dx
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)
Función en C para dibujar rectas con
incx = 1;
cualquier pendiente.
else
if(deltax==0)
incx = 0;
else
incx = -1;
if(deltay>0)
incy = 1;
else
if(deltay==0)
incy = 0;
else
incy = -1;
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,
x,y
int n){
/*dibuja un polígono regular de n lados con
r a
centro en x,y inscrito en un círculo de
a  p/n
radio r y de color c*/
float PI = 3.1415926535;
float a = PI/2-PI/n;
int x1 = (int)(x-r*cos(a));
x – r cos(a), y + r sin(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;
}
}
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++){
x,y
d
x1 = (int)(x1+d*cos(a));
y1 = (int)(y1+d*sin(a));
a = a+da;
lineto(x1,y1);
}
lineto(x0,y0);
}
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:
y  yc  r 2   x  xc
x  xc2   y  yc2  r 2
r
yc
2
xc
Función en C
void PlotPoint(int xc,
int x, int y,int c)
{
putpixel(xc + x,yc +
putpixel(xc - x,yc +
putpixel(xc + x,yc putpixel(xc - x,yc putpixel(xc + y,yc +
putpixel(xc - y,yc +
putpixel(xc + y,yc putpixel(xc - y,yc }
int yc, void CircleSimple(int xc, int yc,
int r,int c){
int x,y;
double yr;
y,c);
x = 0;
y,c);
y = r;
y,c);
yr = r;
y,c);
PlotPoint(xc,yc,x,y,c);
x,c);
/* se cicla hasta trazar todo un
x,c);
octante */
x,c);
while (x < yr){
x,c);
x = x + 1;
yr = sqrt(r*r-x*x);
y = (int)round(yr);
PlotPoint(xc,yc,x,y,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).
x
y
i
x +1 x +2
i
i
i
y -1
i
y -2
i
2
2
2
x + y = r
Una medida de la diferencia de coordenadas puede definirse
como:
d1  y i2  y 2
 y i2  r 2   x i  1
d2  y   yi  1
2
y
i
y
2
d
2
y - 1
i
 r   xi  1   yi  1
2
d
2
2
x + 1
i
Definiendo pi como la diferencia de d1 y d2 tenemos
pi  d1  d 2
 2 x i  1  y   y i  1  2r 2
2
2
i
2
1
2
El valor de pi+1 es:


pi1  2  xi  1  1  y
2
2
i 1
  yi1  1  2r
2
2
Simplificando
pi1  pi  4xi  6  2 yi21  yi2   2 yi1  yi 
p1 se obtiene de (x1, y1) = (0, r)
p1  3  2 r
1. Seleccione la primera posición como
 x , y   0, r
1
1
2. Calcule el primer parámetro como
p1  3  2 r
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
pi 1  pi  4 xi  6
y en caso contrario
pi1  pi  4 xi  yi   10
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:
f circunferencia x, y   x 2  y 2  r 2
Un punto (x,y) arbitrario cumple con lo siguiente
 0, si  x , y  está dentro de la circunferencia

f circunferencia  x , y     0, si  x , y  está en la frontera de la circunferencia
  0, si  x , y  está fuera de la circunferencia

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
pk  f circunferencia  x k  1, y k  1 2
  x k  1   y k  1 2  r 2
2
2
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.
pk  f circunferencia  x k 1  1, y k 1  1 2


  x k  1  1   y k 1  1 2  r 2
2
2
o
pk 1  pk  2 xk  1   yk21  yk2    yk 1  yk   1
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:
2 yk 1  2 yk  2
2 xk 1  2 xk  2
El valor inicial es:
5
p0   r
4
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; };
#include <iostream>
#include <graphics.h>
Ejemplo
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)
x – 2*tamanio
y – 2*tamanio
Centro de la compuerta: x, y
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);
Algoritmo pastel
Algoritmo para dibujar un diagrama de pastel.
1. Iniciar ang = 0
2. Sum = suma de valores a representar
3. Para todos los valores hacer
4. Poner color del sector
5. Dibujar sector desde ang/suma*360 hasta
(ang + valor) /suma*360
6. Incrementar ang en valor
7. Fin para
Ejemplo, diagrama de pastel
#include <graphics.h>
void pastel(int n, float *a, int x, int y, int r){
float suma = 0,ang = 0;
int i;
for(i = 0; i<n; i++)
suma +=a[i];
for(i = 0; i<n; i++){
setfillstyle(1,i+1);
sector(x,y,(int)(ang/suma*360),(int)((ang+a[i])/suma*360),r,r);
ang += a[i];
}
}
main(){
float a[]={25.3,35.2,56.1,48.7,13.6};
initwindow(200,200);
pastel(5,a,100,100,60);
getch();
return 0;
}
Primitivas de texto en C
Despliega una cadena de texto en la posición del CP
void outtext (char *textstring);
Despliega una cadena en la coordenada x,y
void outtextxy (int x, int y, char *textstring);
Define el tipo de justificación para el texto
void settextjustify (int horiz, int vert);
Define la fuente, dirección y el tamaño del texto
void settextstyle (int font, int direction, int
charsize);
Define el tamaño del texto
void setusercharsize (int multx, int divx, int multy,
int divy);
Regresa el alto de una cadena de texto
int textheight (char *textstring);
Regresa el ancho de una cadena de texto
int textwidth (char *textstring);
Primitivas de texto en C cont.
Constantes de texto
Justificación vertical:
LEFT_TEXT, CENTER_TEXT, RIGHT_TEXT
Justificación horizontal:
BOTTOM_TEXT, VCENTER_TEXT, TOP_TEXT
Fuentes:
DEFAULT_FONT, TRIPLEX_FONT, SMALL_FONT,
SANS_SERIF_FONT, GOTHIC_FONT, SCRIPT_FONT,
SIMPLEX_FONT, TRIPLEX_SCR_FONT, COMPLEX_FONT,
EUROPEAN_FONT, BOLD_FONT
Primitivas de texto en C cont.
Tipos
struct textsettingstype
{
int font;
// la fuente en uso
int direction; // dirección del Texto
int charsize; // tamaño del carácter
int horiz;
// justificación Horizontal
int vert;
// justificación Vertical
};
void gettextsettings(struct textsettingstype
*texttypeinfo);
Primitivas de texto en C cont.
Otras formas de desplegar texto
Flujo de salida gráfico:
std::ostringstream bgiout;
Igual a outtext:
outstream(std::ostringstream& out=bgiout);
Igual a outtextxy:
outstreamxy(int x, int y, std::ostringstream&
out=bgiout);
Ejemplo
Demo justificación texto
ejemplo
/* outtext example */
#include <graphics.h>
int main(void){
/* request autodetection */
int midx, midy;
/* initialize graphics and local variables */
initwindow(300,100);
midx = getmaxx() / 2;
midy = getmaxy() / 2;
/* move the CP to the center of the screen */
moveto(midx, midy);
/* output text starting at the CP */
outtext("This ");
outtext("is ");
outtext("a ");
outtext("test.");
/* clean up */
getch();
closegraph();
return 0;
}
/* settextstyle example */
#include <graphics.h>
/* the names of the text styles supported */
char *fname[] = { "DEFAULT font", "TRIPLEX font",
"SMALL font",
"SANS SERIF_font",
"GOTHIC_font",
"SCRIPT font",
"SIMPLEX font", "TRIPLEX SCRIPT font",
"COMPLEX font", "EUROPEAN font",
"BOLD font"};
int main(void){
/* request autodetection */
int style, midx, midy;
int size = 1;
/* initialize graphics and local variables */
initwindow(600,200);
midx = getmaxx() / 2;
midy = getmaxy() / 2;
settextjustify(CENTER_TEXT, CENTER_TEXT);
for (style=DEFAULT_FONT; style<=BOLD_FONT; style++) {
cleardevice();
if (style == TRIPLEX_FONT)
size = 4;
/* select the text style */
settextstyle(style, HORIZ_DIR, size);
/* output a message */
outtextxy(midx, midy, fname[style]);
getch();
}
closegraph();
return 0;
}
Tarea
Escriba una función en C para
dibujar un diagrama de barras de
un conjunto de hasta 10 datos.
Incluya como parámetro un
arreglo de cadenas para las
leyendas.
Escriba una función en C para
dibujar un diagrama de pastel con
sectores resaltados de un conjunto
hasta de 10 datos. Incluya como
parámetro un arreglo de cadenas
para las leyendas.
Tarea
Haga una pequeña animación utilizando alguna de las técnicas
revisadas.
Atributos de las primitivas en bgi
• Atributos de línea
• Atributos de relleno
• Atributos de caracteres
Atributos de líneas
En bgi existen tres atributos para las líneas
color
grosor
patrón
Color
El color se establece con setcolor(int color).
Existen 16 colores predefinidos, del 0 al 15:
BLACK
BLUE
GREEN
CYAN
RED
MAGENTA
BROWN
LIGHTGRAY
DARKGRAY
LIGHTBLUE
LIGHTGREEN
LIGHTCYAN
LIGHTRED
LIGHTMAGENTA
YELLOW
WHITE
La función COLOR(r, g, b) permite obtener cualquier color dados los
valores las componentes de rojo, verde y azul.la función converttorgb(c)
convierte a RGB de Windows.
RED_VALUE(v) – regresa el valor de rojo de un color
GREEN_VALUE(v) – regresa el valor de verde de un color
BLUE_VALUE(v) – regresa el valor de azul de un color
IS_BGI_COLOR(v) – regresa verdadero si el color es BGI
IS_RGB_COLOR(v) – regresa verdadero si el color es RGB
Grosor y patrón
Existen dos grosores de línea predefinidos, pero puede usarse cualquier
valor:
NORM_WIDTH
1
THICK_WIDTH
3
Los patrones de línea son:
SOLID_LINE, DOTTED_LINE, CENTER_LINE,
DASHED_LINE, USERBIT_LINE
La función:
setlinestyle(int linestyle,unsigned upattern,int
thickness );
Establece el tipo de línea. El patrón definido por el usuario se establece con
el entero sin signo upattern, cada bit de este entero de 16 bits especifica si
se pinta o no un pixel.
Actividad
Defina los siguientes patrones de línea y dibuje
algunas líneas con estos patrones:
Patrones de relleno de áreas
Para relleno de áreas existen los siguientes patrones predefinidos:
EMPTY_FILL, SOLID_FILL, LINE_FILL, LTSLASH_FILL,
SLASH_FILL, BKSLASH_FILL, LTBKSLASH_FILL,
HATCH_FILL,
XHATCH_FILL, INTERLEAVE_FILL, WIDE_DOT_FILL,
CLOSE_DOT_FILL, USER_FILL
La función setfillstyle(int pattern,int color) define el
patrón de relleno y el color.
El relleno definido por el usuario se establece con setfillpattern(
char *upattern,int color) el patrón de 8x8 se define mediante un
arreglo de 8 caracteres. El siguiente ejemplo rellena con corazoncitos:
char pattern[] =
{0x66,0x99,0x81,0x81,0x42,0x24,0x18,0x00};
setfillpattern( pattern, 15 );
bar(200,200,300,300);
Actividad
Defina los siguientes patrones de línea y dibuje
algunas figuras con estos patrones:
Funciones de manejo de ventanas
Se pueden crear varias ventanas de despliegue. La
función initwindow(), regresa un entero que
permite identificar cada ventana.
Para establecer la ventana actual se utiliza
setcurrentwindow(int window);
Para determinar la ventana que está en uso se utiliza:
getcurrentwindow();
Actividad
Escriba un pequeño programa que cree dos ventanas y
deibuje algunas primitivas en cada una de ellas.
Manejo de imágenes
Se pueden manipular áreas de la pantalla mediante las siguientes funciones:
imagesize( int left, int top, int right, int bottom ); - determina el tamaño en bytes de
una región de la ventana.
getimage( int left, int top, int right, int bottom, void *bitmap ); - lee una región
rectangular de la pantalla y almacena su contenido en la variable bitmap, se debe
reservar espacio para almacenar la imagen.
putimage( int left, int top, void *bitmap, int op ); - despliega la imagen previamente
almacenada en bitmap. op puede ser: COPY_PUT, XOR_PUT, OR_PUT, AND_PUT,
NOT_PUT
readimagefile(const char* filename=NULL, int left=0, int top=0, int
right=INT_MAX, int bottom=INT_MAX); - lee un archivo de imagen en cualquier
formato bmp, gif, jpg, ico, emf y wmf y lo muestra en el recuadro especificado.
writeimagefile(const char* filename=NULL,int left=0, int top=0, int
right=INT_MAX, int bottom=INT_MAX, bool active=true, HWND hwnd=NULL); Escribe el recuadro de la imagen en un archivo bmp.
Si el nombre del archivo es NULL se abre ventana de diálogo.
Ejemplo de imágenes
#include <graphics.h>
main(){
initwindow(600,600);
setactivepage(0);
readimagefile("Creek.jpg",0,0,600,600);
setactivepage(1);
readimagefile("Desert Landscape.jpg",0,0,600,600);
setactivepage(2);
readimagefile("Forest.jpg",0,0,600,600);
setactivepage(3);
readimagefile("Humpback Whale.jpg",0,0,600,600);
int p=0;
char c;
while(true){
c = getch();
if(c == '1') p =0;
if(c == '2') p =1;
if(c == '3') p =2;
if(c == '4') p =3;
if(c == 27) return 0;
setvisualpage(p);
}
}
Demo de getimage putimage
void PutImageDemo(void){
static int r
= 20;
static int StartX = 100;
static int StartY = 50;
struct viewporttype vp;
int PauseTime, x, y, ulx, uly, lrx, lry, size, i, width, height, step;
void *Saucer;
int MaxX,MaxY;
MaxX = getmaxx();
MaxY = getmaxy();
outtextxy(getmaxx()/2,0, "GetImage / PutImage
Demonstration");
getviewsettings( &vp );
/* Draw Saucer */
setfillstyle(SOLID_FILL,getmaxcolor());
fillellipse(StartX, StartY, r, (r/3)+2);
ellipse(StartX, StartY-4, 190, 357, r, r/3);
line(StartX+7, StartY-6, StartX+10, StartY-12);
circle(StartX+10, StartY-12, 2);
line(StartX-7, StartY-6, StartX-10, StartY-12);
circle(StartX-10, StartY-12, 2);
getch();
/* Read saucer image */
ulx = StartX-(r+1);
uly = StartY-14;
lrx = StartX+(r+1);
lry = StartY+(r/3)+3;
width = lrx - ulx + 1;
height = lry - uly + 1;
size = imagesize(ulx, uly, lrx, lry);
Saucer = malloc(size);
getimage(ulx, uly, lrx, lry, Saucer);
putimage(ulx, uly, Saucer, XOR_PUT);
/* Plot some "stars" */
for ( i=0 ; i<5000; ++i )
putpixel(rand()%(MaxX), rand()%(MaxY), rand()%(
getmaxcolor()-1 )+1);
x = MaxX / 2;
y = MaxY / 2;
PauseTime = 70;
while ( !kbhit() ) {
putimage(x, y, Saucer, XOR_PUT);
/* draw image */
delay(PauseTime);
putimage(x, y, Saucer, XOR_PUT);
/* erase image */
step = rand()%( 2*r );
//mover
if ((step/2) % 2 != 0 ) step = -1 * step;
x = x + step;
step = rand()%( r );
if ((step/2) % 2 != 0 )
step = -1 * step;
y = y + step;
if (vp.left + x + width - 1 > vp.right) x = vp.right-vp.left-width + 1;
else if (x < 0) x = 0;
if (vp.top + y + height - 1 > vp.bottom) y = vp.bottom-vp.top-height + 1;
else if (y < 0) y = 0;
}
free( Saucer );
getch();
}
Actividad
Haga un programa que lea dos imágenes seleccionadas
por el usuario y las muestre en ventanas separadas.
Haga un programa que dibuje la siguiente figura y
copie y pegue 10 copias de la figura en posiciones
aleatorias de la pantalla.
Color rosa
r = 255, g = 170, b = 170
Animación simple
Una animación simple puede lograrse como sigue:
Dibujar
Esperar N ms
Borrar
Actualizar
Animación #1
main(){
initwindow(400,300);
int x=rand()%400,y = rand()%50, vx = 5,vy = 5;
while(true){
setcolor(WHITE);
setfillstyle(1,WHITE);
Dibujar
fillellipse(x,y,5,5);
delay(30);
Esperar N ms
setcolor(BLACK);
setfillstyle(1,BLACK);
fillellipse(x,y,5,5);
x += vx;
Borrar
y += vy;
if(x>400 || x<0) vx =-vx;
if(y>300 || y<0) vy =-vy;
Actualizar
}
getch();
return 0;
}
}
Actividad
Haga una animación que mueva 5 objetos a distintas
velocidades rebotando en la pantalla. Los objetos
deben dibujarse en diferentes colores.
Los objetos podrían ser, por ejemplo un cuadro, un
círculo hueco, un triángulo, etc.
Dibujo de un carro
(x – s, y – 2s)
(x – 2s, y – s)
(x + s, y – 2s)
(x + 2s, y – s)
(x – 3s, y – s)
(x + 3s, y – s)
(x – 3s, y)
(x – 2s, y + s/3)
(x, y)
(x + 3s, y)
(x + 2s, y + s/3)
Dibujo de un carro
void carro(int x, int y, int size){
moveto(x-3*size,y-size);
linerel(size,0);
linerel(size,-size);
linerel(2*size,0);
linerel(size,size);
linerel(size,0);
linerel(0,size);
linerel(-6*size,0);
linerel(0,-size);
circle(x-2*size,y+size/2,2*size/3);
circle(x+2*size,y+size/2,2*size/3);
}
(x, y)
Actividad
Usando la técnica anterior con linerel haga una
función para dibujar alguna de las siguientes figuras.
La figura debe poder dibujarse de cualquier tamaño y
en cualquier posición.
Animación con un fondo
Borrar pantalla
Dibujar fondo
Dibujar
Esperar N ms
Actualizar
void carro(int x, int y, int size){
moveto(x-3*size,y-(size));
linerel(size,0);
linerel(size,-size);
linerel(2*size,0);
linerel(size,size);
linerel(size,0);
linerel(0,size);
linerel(-6*size,0);
linerel(0,-size);
circle(x-2*size,y+size/2,2*size/3);
circle(x+2*size,y+size/2,2*size/3);
}
void fondo(){
int x = 0;
int d[] = {30,60,50,80,30,30,50,30};
int h[] = {70,100,140,30,80,30,60,70};
for(int i=0;i<9; i++){
setfillstyle(1,i+3);
bar(x,200,x+d[i],200-h[i]);
x += d[i];
}
}
main(){
initwindow(400,400);
int x=0,d=3;
char c;
while(true){
cleardevice();
setcolor(WHITE);
fondo();
carro(x,200,8);
delay(30);
x += d;
if(x <0 || x>400) d =-d;
if(kbhit()){
c = (char)getch();
switch(c){
case 27:return 0;
default: d =-d;
}
}
}
}
Dibujo de un carro relleno
Se requiere usar
void carro(int x, int y, int size){
fillpoly para
int p[16];
setcolor(WHITE);
rellenar el carro.
setfillstyle(SOLID_FILL,RED);
p[0] = x-3*size;
p[1] = y-size;
p[2] = x-2*size;
p[3] = y-size;
(x, y)
p[4] = x-size;
p[5] = y-2*size;
p[6] = x+size;
p[7] = y-2*size;
p[8] = x+2*size;
p[9] = y-size;
p[10] = x+3*size;
p[11] = y-size;
p[12] = x+3*size;
p[13] = y;
p[14] = x-3*size;
p[15] = y;
fillpoly(8,p);
setcolor(BLACK);
setfillstyle(SOLID_FILL,BLACK);
fillellipse(x-2*size,y+size/3,2*size/3,2*size/3);
fillellipse(x+2*size,y+size/3,2*size/3,2*size/3);
}
Actividad
Modifique la figura de la actividad anterior para que se
dibuje con un relleno.
Dibujo de edificios
void fondo(){
int x = 0;
int d[] = {30,60,50,80,30,30,50,30};
int h[] = {70,100,140,30,80,30,60,70};
for(int i=0;i<9; i++){
setfillstyle(1,i+3);
bar(x,200,x+d[i],200-h[i]);
x += d[i];
}
}
Fondo #1
while(true){
cleardevice();
setcolor(WHITE);
fondo();
carro(x,200,8);
delay(30);
x += d;
if(x <0 || x>400) d =-d;
if(kbhit()){
c = (char)getch();
switch(c){
case 27:return 0;
default: d =-d;
}
}
}
Borrar pantalla
Dibujar fondo
Dibujar
Esperar N ms
Actualizar
Mejora de animación con un fondo
Dibujar fondo
Dibujar
Esperar N ms
Borrar
Actualiza
Fondo #2
while(true){
setcolor(WHITE);
fondo();
carro(x,200,8);
setcolor(BLACK);
delay(30);
carro(x,200,8);
x += d;
if(x <0 || x>400) d =-d;
if(kbhit()){
c = (char)getch();
switch(c){
case 27:return 0;
default: d =-d;
}
}
}
Doble buffer
El doble buffer hace uso de dos ventanas de salida, una visible
y otra no visible. Las funciones en C son:
setvisualpage(int n); establece la página
visual
setactivepage(p); establece la página
activa
swapbuffers( ); intercambia la página
visual y activa
int getactivepage( ); obtiene la página
activa
int getvisualpage( ); obtiene la página
visible
Animación con doble buffer
Poner página
activa y visible
Dibujar fondo
Dibujar
Intercambiar
páginas
Actualiza
while(true){
//dibuja en la página oculta
setvisualpage(1-p);
setactivepage(p);
cleardevice();
fondo();
carro(x,200,8);
delay(10);
swapbuffers( );
p = 1-p;
x += d;
if(x <0 || x>400) d =-d;
if(kbhit()){
c = (char)getch();
switch(c){
case 27:return 0;
default: d =-d;
}
}
}
Poner página
activa y visible
Dibujar fondo
Dibujar
Intercambiar
páginas
Actualiza
Implementación en C
main(){
initwindow(400,400);
setactivepage(1);
/* lee la imagen desde un archivo y la
dibuja en la pantalla invisible*/
readimagefile("PGS_img01.jpg",0,0,400,400);
size = imagesize(0, 0, 400, 400);
/* reserva memoria para la imagen */
img = malloc(size);
/* guarda le imagen en memoria */
getimage(0,0,400,400,img);
// fondo();
int x=0,d=6,p=0,size=10;
char c;
while(true){
setcolor(WHITE);
//dibuja en la página oculta
setvisualpage(1-p);
setactivepage(p);
setbkcolor(WHITE);
cleardevice();
fondo();
carro(x,200,size);
delay(30);
swapbuffers( );
p = 1-p;
x += d;
if(x <0 || x>400) d =-d;
}
}