xdraw.c

   1 /**
   2  * xdraw.c
   3  *
   4  * @author Luis Alejandro Bernal Romero
   5  *
   6  * Este programa representa en una ventana xwindow la salida del
   7  * programa l-system. 
   8 
   9  * Para ejecutar digite lo siguiente en la línea de comando:
  10  *
  11  *   ./l-system01 hilbert.l | ./xdraw
  12  *
  13  * Para compilar:
  14  *
  15  *  gcc -Wall -pedantic -o xdraw xdraw.c -lm -lX11
  16  *
  17  * Por hacer:
  18  *
  19  * - Quitar los dos warnings de apuntadores
  20  *
  21  * - Hacer que la ventana se autoproporcione según los puntos máximos
  22  * y mínimos del dibujo.
  23  *
  24  * - Que la ventana se autorefresque. No lo hace, si se oculta la
  25  * ventana y se vuelve al poner al frente sale en blanco.
  26  *
  27  * - Escribir las versiones GTK, QT, EFL.
  28  *
  29  */
  30 
  31 #include <stdio.h>
  32 #include <stdlib.h>
  33 #include <ctype.h>
  34 #include <math.h>
  35 #include <unistd.h>
  36 
  37 #include <X11/Xlib.h>
  38 #include <X11/Xutil.h>
  39 
  40 #define TRUE 1
  41 #define FALSE 0
  42 
  43 #define MAX_CAD 100
  44 #define PI M_PI
  45 #define CERO 0.00000000001
  46 
  47 /* Valores por defecto. */
  48 
  49 #define COLOR_DEFECTO 2
  50 #define ANGULO_DEFECTO 90
  51 #define ANCHO_DEFECTO 3
  52 
  53 /* Variables del GUI. */
  54 Display         *el_display;
  55 Window          la_ventana;
  56 GC              el_gc;
  57 XEvent          el_evento;
  58 
  59 char el_nombre_del_icono[] = "l-system xdraw";
  60 char el_nombre_de_la_ventana[] = "l-system xdraw";
  61 
  62 /* Punto */
  63 struct punto{
  64   double x, y, z; /* Punto */
  65 };
  66 
  67 typedef struct punto Punto;
  68 
  69 void punto_inicializar(Punto *punto){
  70   punto->x = 0.0;
  71   punto->y = 0.0;
  72   punto->z = 0.0;
  73 }
  74 
  75 /* Poligono */
  76 
  77 #define MAX_PUNTOS      1000
  78 
  79 struct poligono{
  80   Punto arreglo[MAX_PUNTOS]; /* Vertices del poligono. */
  81   int   num;    /* Numero de vertices. */
  82 };
  83 
  84 typedef struct poligono Poligono;
  85 
  86 void poligono_inicializar(Poligono *poligono){
  87   poligono->num = 0;
  88 }
  89 
  90 void poligono_adicionar(Poligono *poligono, Punto *punto){
  91   poligono->arreglo[poligono->num].x = punto->x;
  92   poligono->arreglo[poligono->num].y = punto->y;
  93   poligono->arreglo[poligono->num].z = punto->z;
  94   poligono->num++;
  95 }
  96 
  97 void poligono_dibujar(Poligono *poligono){
  98   int i; /* Recorrer los vertices del poligono. */
  99 
 100   /* Dibujar perimetro. */
 101   for( i = 0; i < poligono->num - 1; i++){
 102       XDrawLine(el_evento.xexpose.display, el_evento.xexpose.window, el_gc,
 103                 poligono->arreglo[i].x,
 104                 poligono->arreglo[i].y,
 105                 
 106                 poligono->arreglo[i+1].x,
 107                 poligono->arreglo[i+1].y);
 108   }
 109   XDrawLine(el_evento.xexpose.display, el_evento.xexpose.window, el_gc,
 110             poligono->arreglo[i].x,
 111             poligono->arreglo[i].y,
 112             
 113             poligono->arreglo[0].x,
 114             poligono->arreglo[0].y);
 115 
 116   /* Rellenar poligono. */
 117 }
 118 
 119 /* Pila de poligonos. */
 120 #define MAX_POLIGONOS 10
 121 
 122 struct pila_poligonos{
 123   Poligono  arreglo[MAX_POLIGONOS]; 
 124   int   num;    /* Numero de poligonos en la pila. */
 125 };
 126 
 127 typedef struct pila_poligonos Pila_poligonos;
 128 
 129 void pila_poligonos_inicializar(Pila_poligonos *pila){
 130   pila->num = 0;
 131 }
 132 
 133 void pila_poligonos_adicionar(Pila_poligonos *pila){
 134   poligono_inicializar(&(pila->arreglo[pila->num]));    
 135   pila->num++;
 136 }
 137 
 138 void pila_poligonos_retirar(Pila_poligonos *pila){
 139   pila->num--;
 140 }
 141 
 142 Poligono *pila_poligonos_tope(Pila_poligonos *pila){
 143   return &(pila->arreglo[pila->num-1]); 
 144 }
 145 
 146 int esta_pila_poligonos_vacia(Pila_poligonos *pila){
 147   return pila->num <= 0;
 148 }
 149 
 150 int esta_pila_poligonos_llena(Pila_poligonos *pila){
 151   return pila->num >= MAX_POLIGONOS;
 152 }
 153 
 154 /* Estado. */
 155 #define MAX_ESTADOS 100000
 156 
 157 struct estado{
 158   Punto pos; /* Posicion x e y. */
 159   double angulo;        /* Angulo. */
 160   int color;    /* Color actual del dibujo. */
 161   double        ancho;  /* Ancho de la linea. */
 162 };
 163 
 164 typedef struct estado Estado;
 165 
 166 void estado_inicializar(Estado *estado){
 167   punto_inicializar(&estado->pos);
 168   estado->angulo        = 0.0;
 169   estado->color = 0.0;
 170   estado->ancho = 0.0;
 171 }
 172 
 173 
 174 struct pila_estados{
 175   Estado        arreglo[MAX_ESTADOS];   /* Arreglo de estados. */
 176   int           num;                    /* Numero de estados en la pila */
 177 };
 178 
 179 typedef struct pila_estados Pila_estados;
 180 
 181 void pila_inicializar(Pila_estados *pila){
 182   pila->num = 0;
 183 }
 184 
 185 void pila_adicionar(Pila_estados *pila, Estado *estado){
 186   pila->arreglo[pila->num].pos.x = estado->pos.x;
 187   pila->arreglo[pila->num].pos.y = estado->pos.y;
 188   pila->arreglo[pila->num].pos.z = estado->pos.z;
 189   pila->arreglo[pila->num].angulo = estado->angulo;
 190   pila->num++;
 191 }
 192 
 193 void pila_retirar(Pila_estados *pila, Estado *estado){
 194   pila->num--;
 195   estado->pos.x = pila->arreglo[pila->num].pos.x;
 196   estado->pos.y = pila->arreglo[pila->num].pos.y;
 197   estado->pos.z = pila->arreglo[pila->num].pos.z;
 198   estado->angulo = pila->arreglo[pila->num].angulo;
 199 }
 200 
 201 int esta_pila_llena(Pila_estados *pila){
 202   return pila->num >= MAX_ESTADOS;
 203 }
 204 
 205 int esta_pila_vacia(Pila_estados *pila){
 206   return pila->num <= 0;
 207 }
 208 
 209 /* Verificadores sintácticos. */
 210 
 211 int es_numero(char cad[]){
 212   for(; *cad != '\0'; cad++)
 213     if(!isdigit(*cad))
 214       return 0;
 215   return 1;
 216 }
 217 
 218 int es_numero_flotante(char cad[]){
 219   if(!isdigit(*cad))
 220     return 0;
 221   for(; isdigit(*cad); cad++){
 222   }
 223   if(*cad == '.'){
 224       cad++;
 225       if(!isdigit(*cad))
 226         return 0;
 227       for(; isdigit(*cad); cad++){
 228       }
 229   }
 230   if(*cad == 'e' || *cad == 'E'){
 231       cad++;
 232       if(!isdigit(*cad))
 233         return 0;
 234       for(; isdigit(*cad); cad++){
 235       }
 236   }
 237   if(*cad != '\0'){
 238     return 0;
 239   }
 240   return 1;
 241 }
 242 
 243 /* Parametros del dibujo. */
 244 Estado  estado_actual;          /* Estado actual. */
 245 double  delta_angulo = 90.0;    /* Incremento del angulo. */
 246 double  delta_pos = 5;          /* Incremento de la posicion. */
 247 
 248 /* Pilas del sistema.   */
 249 Pila_estados    pila_estados;   /* Pila que guarda estado anteriores. */
 250 Pila_poligonos  pila_poligonos; /* Pila de poligonos. */
 251 
 252 void procesar_comando(char ch){
 253   switch(ch){
 254   case 'F': { /* Avanzar trazando una linea. */
 255     double x_, y_; /*Nueva posicion */
 256         
 257     /* Calcular nuevo punto. */
 258     x_ = estado_actual.pos.x + delta_pos *
 259       cos(estado_actual.angulo*PI/180.0);
 260     y_ = estado_actual.pos.y + delta_pos *
 261       sin(estado_actual.angulo*PI/180.0);
 262 
 263     /* Dibujar linea. */
 264         
 265     XDrawLine(el_evento.xexpose.display, el_evento.xexpose.window, el_gc,
 266               rint(estado_actual.pos.x),rint(estado_actual.pos.y), 
 267               rint(x_), rint(y_));
 268     
 269     /* printf("(%g,%g,%g,%g)\n", pos.x, pos.y, x_, y_); */
 270 
 271     /* Asignar nueva posicion. */
 272 
 273     estado_actual.pos.x = x_; 
 274     estado_actual.pos.y = y_;
 275   }
 276     break;
 277   case 'f':{ /* Avanzar sin dibujar. */
 278     /* Calcular nuevo punto. */
 279     estado_actual.pos.x += delta_pos *
 280       cos(estado_actual.angulo * PI /180);
 281     estado_actual.pos.y += delta_pos *
 282       sin(estado_actual.angulo * PI /180);
 283     /* printf("(%g,%g)\n", pos.x, pos.y); */
 284   }
 285     break;
 286   case '+': /* Girar a la izquierda. */
 287     estado_actual.angulo -= delta_angulo;
 288     /* printf("angulo=%f\n", angulo); */
 289     break;
 290   case '-': /* Girar a la derecha.*/
 291     estado_actual.angulo += delta_angulo;
 292     /*printf("angulo=%f\n", angulo); */
 293     break;
 294   case '|': /* Girar 180 grados. */
 295     estado_actual.angulo += 180;
 296     break;
 297   case '[': /* Guardar estado actual en la pila. */
 298     if(!esta_pila_llena(&pila_estados)){
 299       pila_adicionar(&pila_estados,
 300                      &estado_actual);
 301     }
 302     else {
 303       fprintf(stderr, "Error: La pila"
 304               " esta llena\n");
 305       exit(3);
 306     }
 307     break;
 308   case ']': /* Retomar el ultimo estado de la pila */
 309     if(!esta_pila_vacia(&pila_estados)) {
 310       pila_retirar(&pila_estados,
 311                    &estado_actual);
 312     }
 313     else{
 314       fprintf(stderr, "Error: "
 315               "La pila esta vacia\n");
 316       exit(4);
 317     }
 318     break;
 319   case '{': /* Iniciar poligono. */
 320     if(!esta_pila_poligonos_llena(&pila_poligonos)){
 321       pila_poligonos_adicionar(&pila_poligonos);
 322     }
 323     else{
 324       fprintf(stderr, "Error: " "Muchos poligonos\n");
 325       exit(5);
 326     }
 327     break;
 328   case '}': /* Dibujar el poligono actual. */
 329     if(!esta_pila_poligonos_vacia(&pila_poligonos)){
 330       poligono_dibujar(pila_poligonos_tope(&pila_poligonos));
 331       pila_poligonos_retirar(&pila_poligonos);
 332     }
 333     else{
 334       fprintf(stderr, "Error:" 
 335               " no se abrio }\n");
 336       exit(6);
 337     }
 338     break;
 339   case '.': /* Adicionar la posicion actual como vertice del poligono. */
 340     if(!esta_pila_poligonos_vacia(&pila_poligonos)){
 341       poligono_adicionar(pila_poligonos_tope(&pila_poligonos), 
 342                          &estado_actual.pos);
 343     }
 344     else{
 345       fprintf(stderr, "Error: "
 346               " no se ha abierto {\n");
 347       exit(7);
 348     }
 349     break;
 350     /*
 351       case '\'': /* Incrementar el color.
 352       if(estado_actual.color + 1 < vga_getcolors()){
 353         estado_actual.color++;
 354         vga_setcolor(estado_actual.color);
 355       }
 356       else{
 357         fprintf(stderr, "Error: demasiados colores para"
 358                 " este modo de video\n");
 359          exit(8);
 360       }
 361       break;
 362       */
 363   case '!': /* Decrementar el diametro del segmento. */
 364     if(estado_actual.ancho > 1){
 365       estado_actual.ancho++;
 366     }
 367     break;
 368     }
 369 }
 370 
 371 int main(int argc, char *argv[]){
 372   FILE  *fp = stdin;            /* Archivo de donde se leen los comandos. */
 373   char  ch;                     /* Caracter que se lee del archivo. */
 374   
 375   char  cad[MAX_CAD+1];         /* Cadena para leer del delta del angulo. */
 376   int   i;                      /* Recorre cad. */
 377   
 378   KeySym                la_tecla;
 379   XSizeHints    el_hint;
 380   int           el_screen;
 381   unsigned long el_frente, 
 382     el_fondo;
 383   char          el_buffer[8];
 384   int           contador_teclas;
 385   int           terminar;
 386   
 387   
 388   /* Inicializar modo grafico */
 389 
 390   /* Establecimiento de la conexion. */
 391   el_display    = XOpenDisplay("");
 392   
 393   /* Preparacion y creacion de una ventana. */
 394   el_screen     = DefaultScreen(el_display);
 395   el_fondo      = WhitePixel( el_display, el_screen);
 396   el_frente     = BlackPixel( el_display, el_screen);
 397   el_hint.x     = 100;
 398   el_hint.y     = 100;
 399   el_hint.width = 500;
 400   el_hint.height        = 500;
 401   el_hint.flags = PPosition | PSize;
 402   la_ventana    = XCreateSimpleWindow ( el_display, DefaultRootWindow(el_display),
 403                                         el_hint.x, el_hint.y, el_hint.width, el_hint.height,
 404                                         7, el_frente, el_fondo);
 405   
 406   /* Notificacion a las demas aplicaciones. */
 407   XSetStandardProperties(el_display, la_ventana, el_nombre_de_la_ventana, 
 408                          el_nombre_del_icono, None, argv, argc, &el_hint);
 409   
 410   /* Creacion del contexto grafico. */
 411   el_gc = XCreateGC( el_display, la_ventana, 0, 0);
 412   XSetBackground( el_display, el_gc, el_fondo);
 413   XSetForeground( el_display, el_gc, el_frente);
 414   
 415   /* Seleccion del tipo de suceso de entrada a procesar. */
 416   XSelectInput(el_display, la_ventana, (KeyPressMask | ExposureMask));
 417   
 418   /* Visualizacion de las ventanas. */
 419   XMapRaised(el_display, la_ventana);
 420   
 421   /* Inicialicializaciones. */
 422   pila_inicializar(&pila_estados);
 423   pila_poligonos_inicializar(&pila_poligonos);
 424   estado_inicializar(&estado_actual);
 425   estado_actual.color = COLOR_DEFECTO;
 426   estado_actual.ancho = ANCHO_DEFECTO;
 427   
 428   /* Si se especifica nombre de archivo. */
 429   if( argc >= 2){
 430     if(es_numero(argv[1])){
 431       delta_pos = atoi(argv[1]);
 432     }
 433     else{
 434       /* Abrir archivo. */
 435       fp = fopen( argv[1], "r");
 436       if( fp == NULL){
 437         fprintf(stderr, "Error: No se puede abrir el"
 438                 " archivo \"%s\"\n", argv[1]);
 439         return 1;
 440       }
 441     }
 442   }
 443   
 444   /* Leer el delta del angulo. */
 445   for( i = 0; (ch = fgetc(fp)) != EOF && isdigit(ch); i++){
 446     cad[i] = ch;
 447   }
 448   if(ch == '.'){
 449     cad[i++] = ch;
 450     for(; (ch = fgetc(fp)) != EOF && isdigit(ch); i++){
 451       cad[i] = ch;
 452     }
 453   }
 454   cad[i] = '\0';
 455   if( i > 0){
 456     sscanf(cad,"%lf", &delta_angulo);
 457   }
 458   
 459   /* Punto inicial en la mitad de la pantalla. */
 460   estado_actual.pos.x = el_hint.width / 2;
 461   estado_actual.pos.y = el_hint.height / 2;
 462         
 463   /* Imprimir parametros del dibujo */
 464   /*
 465         printf("angulo=%f delta_angulo=%f\n", estado_actual.angulo,
 466                                         delta_angulo);
 467         printf("pos_x=%f pos_y=%f delta_pos=%f\n", estado_actual.pos.x,
 468                                                 estado_actual.pos.y,
 469                         delta_pos);
 470   */
 471   
 472   /* Ejecucion del ciclo principal. */
 473   terminar = FALSE;
 474   while( !terminar ){
 475     XNextEvent(el_display, &el_evento);
 476     switch(el_evento.type){
 477     case Expose:
 478       if(el_evento.xexpose.count == 0){
 479         /* Procesar comandos. */
 480         do{
 481           /* Saltar blancos, fin de linea. */
 482           while( isspace(ch) || ch == '\n' || ch == '\r'){
 483             ch = fgetc(fp);
 484           }
 485           
 486           /* Procesar comandos. */
 487           /* putchar(ch); */
 488           procesar_comando(ch);
 489         }while( (ch = fgetc(fp)) != EOF);
 490       }
 491       break;
 492     case MappingNotify:
 493       XRefreshKeyboardMapping(&el_evento);
 494       break;
 495     case KeyPress:
 496       contador_teclas = XLookupString(&el_evento, el_buffer, 8, &la_tecla, 0);
 497       if( (contador_teclas == 1) && (el_buffer[0] == 'q')){
 498                   terminar = TRUE;
 499       }
 500       break;
 501     }
 502   }
 503         
 504   /* Cerrar la ventana. */
 505   XFreeGC(el_display, el_gc);
 506   XDestroyWindow(el_display, la_ventana);
 507   XCloseDisplay(el_display);
 508         
 509   /* Cerrar el archivo. */
 510   if(fp != stdin){
 511     fclose(fp);
 512   }
 513   
 514   return 0;
 515 }

CategoryLenguajeC | CategoryProgramacion

LenguajeC/Programas/l-system/l-system01/xdraw.c (last edited 2008-04-20 14:39:32 by localhost)