Documente Academic
Documente Profesional
Documente Cultură
A la hora de desarrollar un programa grfico se debe tener en cuenta los siguientes cuatro puntos: 1. Especificar el fichero o librera graphics.h # include<graphics.h>
Funciones de Graphics.h
Esta librera se encuentra los prototipos de las Funciones que manipulan la parte grfica en el entorno de MS-DOS. Arc bar bar3d circle cleardevice clearviewport closegraph detectgraph drawpoly ellipse fillellipse fillpoly floodfill getarccoords getaspectratio getbkcolor getcolor getdefaultpalette getdrivername getfillpattern getfillsettings getgraphmode getimage getlinesettings getmaxcolor getmaxmode getmaxx getmaxy getmodename getmoderange getpalette getpalettesize getpixel gettextsettings getviewsettings getx gety graphdefaults grapherrormsg graphfreemem graphgetmem graphresult imagesize initgraph installuserdriver installuserfont line linerel lineto moverel moveto outtext outtextxy pieslice putimage putpixel rectangle registerbgidriver registerbgifont restorecrtmode sector setactivepage setallpalette setaspectratio setbkcolor setfillpattern setfillstyle setgraphbufsize setgraphmode setlinestyle setpalette setrgbpalette settextjustify settextstyle setusercharsize setviewport setvisualpage setwritemode textheight textwidth
Es necesario conocer hacerca de los macros y estructuras, entre las estructuras tenemos: arccoordstype fillsettingstype Entre los macros se encuentran: colores drivers enlazar errores fuentes lnea modos put_op trama linesettingstype palettetype textsettingstype viewporttype
Antes de comenzar a programar en modo grafico debemos estudiar lo que son los macros, que son instrucciones que nos ayudaran a realizar de una manera ms efectiva nuestros grficos.
Colores :
Colores de Fondo
Constante BLACK BLUE GREEN CYAN RED MAGENTA BROWN LIGHTGRAY DARKGRAY LIGHTBLUE LIGHTGREEN LIGHTCYAN LIGHTRED LIGHTMAGENTA YELLOW WHITE Valor 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 Significado Negro Azul Verde Can Rojo Magenta Marrn Gris Claro Gris Oscuro Azul Claro Verde Claro Can Claro Rojo Claro Magenta Claro Amarillo Blanco
Modo de 16 Colores
Constante BLACK BLUE GREEN CYAN RED MAGENTA BROWN LIGHTGRAY DARKGRAY LIGHTBLUE LIGHTGREEN LIGHTCYAN LIGHTRED LIGHTMAGENTA YELLOW WHITE 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 Valor Significado Negro Azul Verde Can Rojo Magenta Marrn Gris Claro Gris Oscuro Azul Claro Verde Claro Can Claro Rojo Claro Magenta Claro Amarillo Blanco
Nmero Paleta 0 1 2 3
Valor asignado: 1 2 3 Nota: Color 0 se reserva para el color de fondo y se asigna con lo funcin setbkcolor, pero los dems colores son fijos. Estas constantes se usan con setcolor.
Nota: Estas constantes se usan con las Funciones setpalette y setallpalette.el cual veremos en captulos posteriores
Fuentes:
Tramas:
Tramas predefinidas
Nota: Todos los tipos de tramas menos EMPTY_FILL usan el color de relleno seleccionado; EMPTY_FILL usa el color de fondo para rellenar.
Driver:
Dispositivos Grficos
Dispositivo/Constante DETECT CGA MCGA EGA EGA64 EGAMONO IBM8514 HERCMONO ATT400 VGA PC3270 Valor 0 1 2 3 4 5 6 7 8 9 10
Lneas:
Estilos de Lneas
Constante SOLID_LINE DOTTED_LINE CENTER_LINE DASHED_LINE USERBIT_LINE Valor 0 1 2 3 4 Significado Lnea continua _______ Lnea hecha con puntos .. Lnea centrada Lnea discontinua _._._._. Lnea definida por el usuario
Nota: El grosor es definido escribiendo NORM_WIDTH para rallas normales y THICK_WIDTH para lneas mas gruesos
Modos de Escritura
Valor 0 1
Significado Pxeles de la lnea sobrescriben los pxeles existentes Pxel de la pantalla son el Resulta do de la operacin OR de los pxeles existentes y los de la lnea
Modos:
Modos Grficos
Dispositivo CGA Modo/Constante CGAC0 CGAC1 CGAC2 CGAC3 CGAHI MCGAC0 MCGAC1 MCGAC2 MCGAC3 MCGAMED MCGAHI EGALO EGAHI A64LO EGA64HI AMONOHI VGALO VGAMED VGAHI ATT400C0 ATT400C1 ATT400C2 ATT400C3 ATT400MED ATT400HI HERCMONOHI PC3270HI IBM8514LO IBM8514HI Cdigo 0 1 2 3 4 0 1 2 3 4 5 0 1 0 1 3 0 1 2 0 1 2 3 4 5 0 0 0 1 Resolucin 320X200 320X200 320X200 320X200 640X200 320X200 320X200 320X200 320X200 640X200 640X480 640X200 640x350 640X200 640X350 640x200 640X200 640x350 640X480 320x200 320x200 320x200 320x200 640x400 640x400 720X348 720X350 640X480 1024X768 Paleta 4 Clores 4 Clores 4 Clores 4 Clores 2 Clores 4 Clores 4 Clores 4 Clores 4 Clores 2 Clores 2 Clores 16 Colores 16 Colores 16 Colores 4 Colores 2 Colores 16 Colores 16 Colores 16 Colores 4 Colores 4 Colores 4 Colores 4 Colores 2 Colores 2 Colores 2 Colores 2 Colores 256 Colores 256 Colores Pagina 1 1 1 1 1 1 1 1 1 1 1 4 2 1 1
MCGA
1* / 2**
2 2 1 1 1 1 1 1 1 2 1
HERC
Errores:
Put_op:
Operaciones con putimage
Constante COPY_PUT XOR_PUT OR_PUT AND_PUT NOT_PUT Valor 0 1 2 3 4 Significado Sobrescribir los pxeles existentes Operacin OR Exclusivo con los pxeles Operacin OR Inclusivo con los pxeles Operacin AND con los pxels Invertir la imagen
Nota: Estas operaciones se usan exclusivamente con la funcin putimage. El cual veremos en captulos posteriores.
1. Mtodo de inicializacin del modo grafico a prueba de errores. Juan Carlos Gutirrez Barquero____________________________________________ 9
#include <graphics.h> # include<process.h> # include <conio.h> void main() { int driver = VGA; int modo = VGAHI; int resultado; initgraph(&driver,&modo,"c:\\tc20\\bin"); resultado=graphresult(); if(resultado!=grOk) { getch(); exit(0); } getch(); } cuerpo del programa
Rasterop: Es una operacin grafica que copia el rea de una imagen para luego
dibujarla en cualquier regin de la pantalla.
Texto Grfico: Sirve para escribir texto en modo grafico, utilizando diferentes
fuentes. Figuras geomtricas: LINEAS. void far line(int x1, int y1, int x2, int y2); Esta funcin es usada para conectar dos puntos con una lnea recta. El primer punto es especificado por los argumentos x1 e y1. El segundo punto es especificado por los argumentos x2 e y2. La lnea se dibuja usando el estilo de lnea actual, el grosor, y el color actual. La posicin del cursor grfico no es afectada por la funcin line.
Ejemplo:
11
#include <graphics.h> #include <conio.h> void main() { int driver = EGA,modo = EGAHI; initgraph( &driver, &modo, "c:\\tc20\\bin" ); line( 20, 40, 350, 100 ); line( 400, 30, 50, 250 ); getch(); closegraph(); } CIRCULOS. void far circle(int x, int y, int radio); Esta funcin se utiliza para dibujar un crculo. Los argumentos x e y definen el centro del crculo, mientras que el argumento radio define el radio del crculo. El crculo no es rellenado pero es dibujado usando el color actual.
El grosor de la circunferencia puede ser establecido por la funcin setlinestyle; sin embargo, el estilo de la lnea es ignorado por la funcin circle. La funcin circle no retorna ningn valor. Ejemplo: #include <graphics.h> #include <conio.h> void main() { int driver = EGA; int modo = EGAHI; initgraph( &driver, &modo, "C:\\tc20\\BIN" ); circle( 300, 200, 80 ); getch(); /* Pausa */ closegraph(); }
12
RECTANGULOS.
void far rectangle(int izquierda,int superior, int derecha, int inferior); Esta funcin dibujar un rectngulo sin rellenar su interior usando el color actual. La esquina superior izquierda del rectngulo est definida por los argumentos izquierdos y superiores. Estos argumentos corresponden a los valores x e y de la esquina superior izquierda. Similarmente, los argumentos derecha e inferior definen la esquina inferior derecha del rectngulo. El permetro del rectngulo es dibujado usando el estilo y grosor de lnea actuales.
La funcin rectangle() no retorna ningn valor. Ejemplo: #include <graphics.h> #include <conio.h> void main() { int driver = EGA,modo = EGAHI; initgraph( &driver, &modo, "C:\\tc20\\bin" ); rectangle( 20, 20, 400, 300 ); getch(); /* Pausa */ closegraph(); }
ARCOS
void far arc(int x, int y,int comienzo_angulo, int final_angulo, int radio); Esta funcin crear un arco circular. El arco tiene como centro el punto especificado por los argumentos x e y, y es dibujado con el radio especificado: radio. El arco no est rellanado, pero es dibujado usando el color actual. El arco comienza al ngulo especificado por el argumento comienzo_angulo y es dibujado en la direccin contraria al de las agujas del reloj hasta llegar al ngulo especificado por el argumento final_angulo. La funcin arc usa el este (extendindose hacia la derecha del centro del arco en la direccin horizontal) como su punto de 0 grados. La funcin setlinestyle puede usarse para establecer el grosor del arco. La funcin arc, sin embargo, ignorar el argumento trama de la funcin setlinestyle.
13
La funcin arc no retorna ningn valor. Ejemplo: #include <graphics.h> #include <conio.h> void main() { int driver = EGA,modo = EGAHI,radio; initgraph( &driver, &modo, "C:\\tc20\\bin" ); for( radio = 25; radio < 175; radio += 25 ) arc( 320, 175, 45, 135, radio ); getch(); /* Pausa */ closegraph(); }
PIXELES.
void far putpixel(int x, int y, int color); Esta funcin es usada para colocar a un pxel en una posicin en particular la cual es cuestionada por los argumentos x e y. El argumento color especfico el valor del color del pxel. La funcin putpixel no retorna ningn valor. Ejemplo: #include <graphics.h> #include <conio.h> void main() { int driver = EGA,modo = EGAHI,t; initgraph( &driver, &modo, c:\\tc20\\bin ); for( t=0; t<200; t++ ) putpixel( 100+t, 50+t, t%16 ); getch(); closegraph(); }
ELIPSES.
14
void far ellipse(int x, int y, int comienzo_angulo, int final_angulo, int x_radio, int y_radio); Esta funcin es usada para dibujar un arco elptico en el color actual. El arco elptico est centrado en el punto especificado por los argumentos x e y. Ya que el arco es elptico el argumento x_radio especifica el radio horizontal y el argumento y_radio especifica el radio vertical. El arco elptico comienza con el ngulo especificado por el argumento comienzo_angulo y se extiende en un sentido contrario a las agujas del reloj al ngulo especificado por el argumento final_angulo. La funcin ellipse considera este - el eje horizontal a la derecha del centro del elipse - ser 0 grados. El arco elptico es dibujado con el grosor de lnea actual como es establecido por la funcin setlinestyle. Sin embargo, el estilo de lnea es ignorado por la funcin ellipse. La funcin ellipse no retorna ningn valor. Ejemplo:
#include <graphics.h> #include <conio.h> void main() { int driver = EGA,modo = EGAHI; initgraph( &driver, &modo, "C:\\tc20\\bin" ); ellipse( 300, 150, 45, 225, 100, 50 ); getch(); /* Pausa */ closegraph();
15
#include <graphics.h> #include <conio.h> void main() { int driver = EGA; int modo = EGAHI; initgraph( &driver, &modo, C:\\TC20\\BIN ); setbkcolor( 4 ); circle( 300, 150, 50 ); getch(); /* Pausa */ closegraph(); getch(); } Funcin getbkcolor. int far getbkcolor(void); Esta funcin es usada para obtener el valor del color de fondo actual. El color de fondo, por defecto, es el color 0. Sin embargo, este valor puede cambiar con una llamada a la funcin setbkcolor. Existen varios valores para ciertos colores de fondo. La funcin getbkcolor retorna el valor del color de fondo actual. Ejemplo: #include <graphics.h> #include <conio.h> #include <stdio.h> void main() { int driver = EGA,modo = EGAHI,color; initgraph( &driver, &modo, "C:\\tc20\\BIN" ); setbkcolor( 4 ); circle( 300, 150, 50 ); color = getbkcolor(); getch(); /* Pausa */ closegraph(); printf( "Color de fondo: %d\n", color ); getch(); } void far setcolor(int color) Esta funcin coloca el atributo color es decir escoge un color entre 0 y 15 o su equivalente en ingls (ver pagina 3 Modo de 16 colores) todo lo que se dibuje despus de esta instruccin tendr el color establecido por la funcin setcolor el valor de esta es funcin es WHITE. Esta funcin no devuelve ningn valor.
16
17
18
Rellenos
Es el proceso de rellenar una regin de la pantalla con un patrn o color. Turbo C utiliza dos mtodos para definir la regin de rellenos. El primero relleno de polgonos, usa la lista de vrtices del polgono para calcular la geometra del interior, El segundo relleno es por el mtodo de inundacin, busca desde un punto inicial llamado la semilla en todas las direcciones para encontrar una frontera que encierre la regio. La frontera se reconoce como el valor del pxel que tiene. Antes de estudiar los dos mtodos estudiaremos la funcin setfillstyle que ser de gran importancia a la hora de realizar los dos tipos de rellenado y bar que es una funcin similar a rectangle.
Funcin bar
void far bar(int izquierda, int superior, int derecha, int inferior); Esta funcin dibujar una barra rectangular y rellenada de dos dimensiones. La esquina superior izquierda de la barra rectangular est definida por los argumentos izquierdos y superiores. Estos argumentos corresponden a los valores x e y de la esquina superior izquierda. Similarmente, los argumentos derecha e inferior definen la esquina inferior derecha de la barra. La barra no tiene borde, pero es rellenada con la trama de relleno actual y el color de relleno como es establecido por la funcin setlinestyle. La funcin bar no retorna ningn valor. Ejemplo: #include <graphics.h> #include <conio.h> void main() { int driver = EGA,modo = EGAHI, x, y, color,fill; initgraph( &driver, &modo, "C:\\tc20\\BIN" ); x = 20; y = 20; color = 1; fill = 1; do { setfillstyle( fill, color ); bar( x, y, x+40, 320 ); x += 40; y += 10; color = (color+1) % 16; fill = (fill+1) % 12; } while( x < 620 ); getch(); /* Pausa */ closegraph(); } El patrn de relleno se define con las Funcines setfillstyle y setfillpattern
19
Esta funcin es usada para seleccionar una trama predefinida y un color de relleno. El argumento trama especifica la trama predefinida, mientras que el argumento color especifica el color de relleno. Existen trece valores ya definidos para tramas. Sin embargo, la trama USER_FILL (valor 12) no debera usarse para asignar una trama definida por el usuario. En su lugar, se debera usar la funcin setfillpattern. La funcin setfillstyle no retorna ningn valor.
Ejemplo: #include <graphics.h> #include <conio.h> void main() { int driver = EGA,modo = EGAHI; initgraph( &driver, &modo, "c:\\tc20\\bin" ); setfillstyle( LTSLASH_FILL, 6 ); bar( 50, 50, 350, 300 ); getch(); /* Pausa */ closegraph(); } LTSLASH_FILL es un estilo de relleno si desea estudiarlos se encuentran en el libro(Ver pagina # 5 ).
Funcin setfillpattern
void far setfillpattern(char far *trama, int color); Esta funcin es usada para seleccionar una trama de relleno definido por el usuario. El argumento *trama apunta a una serie de ocho bytes que representa una trama de relleno de bits de 8 x 8. Cada byte representa una fila de ocho bits, donde cada bit est encendido o no (1 0). Un bit de 0 indica que el pxel correspondiente ser asignado el color de relleno actual. Un bit de 0 indica que el pxel correspondiente no ser alterado. El argumento color especifica el color de relleno que ser usado para la trama.
20
/*Este programa te muestra los diferentes colores con una misma trama trata de modificarlo para que obtengas todas las tramas con todos los colores*/
21
22
23
La funcin moverel no retorna ningn valor. Ejemplo: #include <graphics.h> #include <conio.h> void main() { int driver = EGA,modo = EGAHI; initgraph( &driver, &modo, "C:\\tc20\\bin" ); moveto( 20, 20 ); linerel( 20, 40 ); moverel( 50, 50 ); linerel( 40, 30 ); getch(); closegraph(); } Funcin linerel. void far linerel(int dx, int dy); Esta funcin es usada para dibujar una lnea recta a una distancia y direccin predeterminadas desde la posicin actual del cursor grfico. El argumento dx especifica el nmero relativo de pxels para atravesar en la direccin horizontal. El argumento dy especifica el nmero relativo de pxels para atravesar en la direccin vertical. Estos argumentos pueden ser tanto valores positivos como negativos. La lnea se dibuja usando el estilo de lnea actual, el grosor, y el color actual desde la posicin actual del cursor grfico a travs de la distancia relativa especificada. Cuando la lnea est terminada, la posicin del cursor grfico es actualizado al ltimo punto de la lnea. La funcin linerel no retorna ningn valor. Ejemplo: #include <graphics.h> #include <conio.h> void main() { int driver = EGA,modo = EGAHI; initgraph( &driver, &modo, "C:\\tc20\\bin" ); moveto( 20, 20 ); linerel( 20, 40 ); linerel( 40, 30 ); getch(); closegraph(); } Funcin getx.
24
25
Funcin bar3d
void far bar3d(int izquierda, int superior,int derecha, int inferior, int profundidad, int banderin_tapa);
Esta funcin crear una barra rectangular y rellenada de tres dimensiones. La esquina superior izquierda de la barra rectangular ms frontal est definida por los argumentos izquierdos y superiores. Estos argumentos corresponden a los valores x e y de la esquina superior izquierda del rectngulo ms frontal. Similarmente, los argumentos derecha e inferior definen la esquina inferior derecha del rectngulo ms frontal. La barra tiene borde, en todas las tres dimensiones, rellenada con el color y estilo de lnea actuales. El rectngulo ms frontal es rellenado usando la trama de relleno actual y el color de relleno como es establecido por la funcin setlinestyle. El argumento banderin_tapa es usado para especificar si es o no es posible apilar varias barras encima de cada una. Si banderin_tapa tiene un valor distinto a cero, entonces la barra est "tapada". Si banderin_tapa tiene un valor de cero, entonces la barra no est "tapada", permitiendo otras barras ser apiladas encima de sta. La funcin bar3d no retorna ningn valor. Ejemplo: #include <graphics.h> #include <conio.h> void main() { int driver = EGA,modo = EGAHI,color, relleno; color = 10; relleno = 11; initgraph(&driver,&modo,"c:\\tc20\\bin"); setfillstyle( relleno, color ); bar3d( 100, 50, 300, 150, 25, 1 ); getch(); /* Pausa */ closegraph(); getch(); }
26
Esta funcin es usada para rellenar la pantalla actual del usuario con el color de fondo actual. El color de fondo puede ser establecido con la funcin setbkcolor. La posicin del cursor grfico es la esquina superior izquierda de la pantalla actual del usuario. Esta posicin es (0,0) segn la pantalla actual del usuario. La funcin clearviewport no retorna ningn valor. Ejemplo: #include <graphics.h> #include <conio.h> void main() { int a = EGA,b = EGAHI,color; initgraph( &a, &b, "C:\\tc20\\BIN" ); setviewport( 150, 150, 350, 350, 0 ); for( color = 0; color<16; color++ ) { circle( 100, 100, 60 ); getch(); setbkcolor( color ); clearviewport(); } getch(); /* Pausa */ closegraph(); } Funcin closegraph void far closegraph(void); Esta funcin es usada para cerrar el sistema grfico como es iniciada por la funcin initgraph. La funcin closegraph libera toda la memoria usada por el sistema grfico y luego restaura el modo de vdeo al modo de texto que estaba en uso anteriormente a la llamada a la funcin initgraph. La funcin closegraph no retorna ningn valor. Ejemplo: #include <graphics.h> #include <conio.h> void main() { int driver = EGA,modo = EGAHI; initgraph( &driver, &modo, "C:\\tc20\\BIN); circle( 300, 200, 80 ); getch(); /* Pausa */ closegraph(); getch(); } Funcin detectgraph
27
28
29
Esta funcin es usada para recoger las coordenadas del centro, y los puntos del comienzo y final de la ltima llamada con xito a la funcin arc. El argumento *coordenadas_arco apunta a la estructura de tipo arccoordstype que guarda la informacin recogida. La sintaxis de la estructura arccoordstype es: struct arccoordstype { int x, y; int xstart, ystart; int xend, yend; }; Los miembros x e y definen el centro del arco. Los miembros xstart e ystart definen las coordenadas x e y del punto de comienzo del arco. Similarmente, los miembros xend e yend definen las coordenadas x e y del punto de final del arco. La funcin getarccoords no retorna ningn valor. Ejemplo: #include <graphics.h> #include <conio.h> void main() { int driver = EGA; int modo = EGAHI,radio; struct arccoordstype info_arco; initgraph( &driver, &modo, "C:\\tc20\\BIN" ); for( radio=25; radio<=100; radio+=25 ) { arc( 300, 150, 45, 315, radio ); getarccoords( &info_arco ); moveto( info_arco.xstart, info_arco.ystart ); lineto( info_arco.xend, info_arco.yend ); } getch(); /* Pausa */ closegraph(); getch(); } Funcin getaspectratio void far getaspectratio(int far *x_proporcion,int far *y_proporcion); Esta funcin es usada para obtener la proporcin anchura-altura del modo grfico actual. La proporcin anchura-altura puede definirse como la proporcin de la anchura del pxel del modo grfico y la altura del pxel. Esta proporcin, usando los modos grficos existentes, es siempre menor o igual que 1. El valor para determinar la proporcin anchura-altura con respecto al eje horizontal es retornado en el argumento *x_proporcion. Similarmente, el valor para el eje vertical es retornado en el argumento *y_proporcion. El argumento *y_proporcion es asignado 10000, el cual es retornado cuando se llama a la funcin getaspectratio. El argumento *x_proporcion es casi siempre menor que el valor de *y_proporcion. Esto es debido al hecho de que la mayora de los
30
31
Funcin getdefaultpalette struct palettetype far *getdefaultpalette(void); Esta funcin es usada para obtener una estructura que define la paleta segn el dispositivo en la inicializacin - esto es, cuando se llama a initgraph. La estructura palettetype se define de la siguiente manera: #define MAXCOLORS 15 struct palettetype { unsigned char size; signed char colors[MAXCOLORS+1]; } El campo size indica el tamao de la paleta. El campo colors contiene los valores numricos que representan los colores que ofrece el dispositivo en su paleta de colores. La funcin getdefaultpalette retorna un puntero a una estructura del tipo palettetype. Ejemplo: #include <graphics.h> #include <conio.h> #include <stdio.h> void main() { int driver = EGA; int modo = EGAHI; struct palettetype *palette = NULL; int i; initgraph( &driver, &modo, "C:\\tc20\\BIN" ); palette = getpalettetype(); circle( 300, 150, 50 ); getch(); /* Pausa */ closegraph(); printf( "Paleta\n\nTamao: %d\nColores: %d", palette->size, palette->colors[0] ); for( i=1; i<palette->size; i++ ) printf( ", %d", palette->colors[i] ); printf( "\n" ); getch(); }
32
Esta funcin es usada para obtener una cadena de caracteres que contiene el nombre del dispositivo grfico actual. Esta funcin debera ser llamada despus de que un dispositivo haya sido definido e inicializado esto es, despus de llamar a initgraph. La funcin getdrivername retorna una cadena de caracteres conteniendo el nombre del dispositivo grfico. Ejemplo: #include <graphics.h> #include <conio.h> #include <stdio.h> #include <string.h> void main() { int driver = EGA, modo = EGAHI; char *nombre; initgraph( &driver, &modo, "C:\\tc20\\BIN" ); strcpy( nombre, getdrivername() ); circle( 300, 150, 50 ); getch(); /* Pausa */ closegraph(); printf( "Nombre del dispositivo grfico: %s\n", nombre ); getch();} Funcin getfillpattern void far getfillpattern(char far *trama); Esta funcin es usada para obtener una trama de relleno definido por el usuario, como es definida por la funcin setfillpattern, y la guarda en memoria. El argumento *trama es un puntero a una serie de ocho bytes que representa una trama de relleno de bits de 8 x 8. Cada byte representa una fila de ocho bits, donde cada bit est encendido o no (1 0). Un bit de 0 indica que el pxel correspondiente ser asignado el color de relleno actual. Un bit de 0 indica que el pxel correspondiente no ser alterado. La funcin getfillpattern no retorna ningn valor, directamente. Ejemplo: #include <graphics.h> #include <conio.h> void main() { int driver = EGA; int modo = EGAHI; char trama1[8] = { 0x33, 0xEE, 0x33, 0xEE, 0x33, 0xEE, 0x33, 0xEE }; char trama2[8] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; initgraph( &driver, &modo, "C:\\tc20\\bin" ); getfillpattern( trama2 ); bar( 50, 50, 150, 150 ); setfillpattern( trama1, 9 );
33
34
Esta funcin es usada para obtener el valor del modo grfico actual. El dispositivo actual debe ser considerado cuando se interprete el valor de retorno. Esta funcin slo debera ser llamada despus de que el sistema grfico haya sido inicializado con la funcin initgraph. Existen varios valores para los modos de cada dispositivo. La funcin getgraphmode retorna el modo grfico como es establecido por initgraph o setgraphmode. Ejemplo: #include <graphics.h> #include <conio.h> #include <stdio.h> void main() { int driver = EGA, modo = EGAHI,modo; initgraph( &driver, &modo, "C:\\tc20\\BIN" ); modo = getgraphmode(); bar( 50, 50, 350, 300 ); getch(); /* Pausa */ closegraph(); printf( "Modo grfico: %d\n", modo ); getch(); } Funcin getlinesettings void far getlinesettings(struct linesettingstype far *info); Esta funcin obtiene la informacin actual para las lneas. Esta informacin es guardada en una estructura de tipo linesettingstype que es apuntado por el argumento *info. El estilo de lnea, trama, y grosor actuales son guardados en esta estructura. La sintaxis para la estructura linesettingstype: struct linesettingstype { int linestyle; unsigned upattern; int thickness; } El campo linestyle es el estilo de la lnea recta. El campo upattern es la trama de la lnea del usuario solamente cuando el campo linestyle es igual a USERBIT_LINE, 4. Cuando esto sea el caso, el miembro upattern contiene una trama de lnea definido por el usuario de 16 bits. Un bit 1 en esta trama indica que el pxel correspondiente ser asignado el color actual. Un bit 0 indica que el pxel correspondiente no ser alterado. El campo thickness es el grosor de la lnea. Existen varios valores para los diferentes estilos y grosores de lneas rectas. La funcin getlinesettings no retorna ningn valor, directamente. Ejemplo:
35
#include <graphics.h> #include <conio.h> #include <stdio.h> void main() { int driver = EGA; int modo = EGAHI; struct linesettingstype info; initgraph( &driver, &modo, "C:\\tc20\\bin" ); setlinestyle( DOTTED_LINE, 0xFF33, THICK_WIDTH ); circle( 350, 250, 50 ); getlinesettings( &info ); getch(); /* Pausa */ closegraph(); printf( "Lneas rectas.\nEstilo: %d\tTrama: %X\tGrosor: %d\n", info.linestyle, info.upattern, info.thickness ); getch(); } Funcin getmaxcolor int far getmaxcolor(void); Esta funcin es usada para obtener el valor ms alto de color en la paleta actual. La paleta en uso depende del dispositivo y modo inicializados. Para los modos de 16 colores, el valor de retorno es 15. Similarmente, para los modos de dos colores, el valor de retorno es 1. La funcin getmaxcolor retorna el valor mximo del color en la paleta en uso. Ejemplo: #include <graphics.h> #include <conio.h> #include <stdio.h> void main() { int driver =EGA,modo =EGAH,color_max; initgraph( &driver, &modo, "C:\\tc20\\BIN" ); color_max = getmaxcolor(); closegraph(); printf( "Color m ximo: %d\n", color_max ); getch(); }
36
Esta funcin es usada para obtener el nombre del modo grfico especificado por el argumento num_modo. La funcin getmodename retorna el nombre del modo grfico que est contenido en todos los dispositivos grficos. Ejemplo: #include <graphics.h> #include <conio.h> #include <stdio.h> #include <string.h> void main() { int driver = IBM8514; int modo = IBM8514HI,i; char *nombre; int num_modo; initgraph( &driver, &modo,"C:\\TC20\\BIN"); num_modo = getgraphmode(); strcpy(nombre,getmodename(num_modo)); closegraph(); for(i=0;nombre[i];i++) printf("%c",nombre[i]); getch(); } Funcin getmoderange void far getmoderange(int driver, int far *modo_bajo, int far *modo_alto); Esta funcin es usada para obtener los valores altos y bajos del modo grfico del dispositivo especificado por el argumento driver. El valor ms bajo del modo es retornado en *modo_bajo, y el valor ms alto del modo es retornado en *modo_alto. Si el dispositivo especificado es invlido, el valor de -1 es retornado en ambos argumentos: *modo_bajo y *modo_alto. Sin embargo, si el argumento driver es asignado -1, los modos alto y bajo del dispositivo actual son retornados. La funcin getmoderange no retorna ningn valor, directamente. Ejemplo: #include <graphics.h> #include <conio.h> #include <stdio.h> void main() { int driver = EGA; int modo = EGAHI; int modo_bajo, modo_alto; initgraph( &driver, &modo, C:\\TC20\\BIN ); getmoderange( driver, &modo_bajo, &modo_alto ); closegraph();
37
38
Esta funcin es usada para obtener el nmero de entradas de paleta vlidas para la paleta actual, considerando el modo grfico en uso. La funcin getpalettesize retorna el nmero de colores en la paleta actual. Para modos de 16 colores, la funcin getpalettesize retorna 16. Ejemplo: #include <graphics.h> #include <conio.h> #include <stdio.h> void main() { int driver = EGA; int modo = EGAHI; int num_colores; initgraph( &driver, &modo, C:\\TC20\\BIN ); num_colores = getpalettesize(); closegraph(); printf( "Paleta\n\nNmero de colores: %d\n", num_colores ); getch(); } Funcin getpixel unsigned far getpixel(int x, int y); Esta funcin es usada para obtener el valor del color del pxel especificado por los argumentos x e y. Estos argumentos especifican las coordenadas de la pantalla del pxel a ser evaluado. Cuando se evala el valor del color retornado, el modo grfico en uso debe ser considerado. Existen varios valores para describir colores. La funcin getpixel retorna el nmero del color del pxel especificado. Ejemplo: #include <graphics.h> #include <conio.h> #include <stdio.h> void main() { int driver = EGA, modo = EGAHI, x, y, color; initgraph( &driver, &modo, C:\\TC20\\BIN ); x = 300; y = 100; setfillstyle( SOLID_FILL, 2 ); fillellipse( 300, 160, 50, 150 ); color = getpixel( x, y ); getch(); closegraph(); printf( "Colores\n\nEl color del pxel (%d,%d): %d\n", x, y, color ); getch();
39
40
struct viewporttype { int left, top; int right, bottom; int clip; }; La funcin getviewsettings no retorna ningn valor, directamente. Ejemplo: #include <graphics.h> # include<conio.h> #include <stdio.h> void main() { int driver = VGA, modo = VGAHI; struct viewporttype info; initgraph( &driver, &modo, "C:\\TC20\\BIN" ); getviewsettings( &info ); closegraph(); printf( "\t\t\t\tPantalla\n\nIzquierda: %d\tSuperior: %d\tDerecha: %d\t" "Inferior: %d\tBandern: %d\n", info.left, info.top, info.right, info.bottom, info.clip ); getch(); } Funcin graphdefaults void far graphdefaults(void); Esta funcin es usada para reiniciar todos los datos grficos a sus valores originales, o por defecto. La funcin graphdefaults reinicia la pantalla del usuario para que cubra la pantalla entera, mueve el cursor a la posicin (0,0), y reinicia la paleta actual a sus colores por defecto. Tambin reinicia el color de fondo y el actual a sus valores por defecto, reinicia el estilo y trama de relleno a sus valores por defecto, y reinicia la fuente y justificacin de texto. La funcin graphdefaults no retorna ningn valor. Ejemplo: #include <graphics.h> #include <conio.h> void main() { int driver = VGA; int modo = VGAHI; initgraph( &driver, &modo, "C:\\TC20\\BIN" ); setcolor( 4 ); setviewport( 250, 150, 350, 250, 1 ); graphdefaults(); circle( 300, 200, 50 );
41
42
43
44
45
Ejemplo:
46
#include <graphics.h> #include <conio.h> # include <dos.h> #include <stdio.h> void main() { int driver = EGA; int modo = EGAHI,i; initgraph( &driver, &modo, "C:\\TC20\\BIN" ); setcolor(BLUE); i=1; do{ delay(30000); rectangle(10+i,10,100+i,100); setfillstyle(i,BLUE); floodfill(20,20,BLUE); i++; }while(!kbhit()); } Funcin outtext void far outtext(char far *cadena_texto); Esta funcin es usada para mostrar una cadena de caracteres. El argumento *cadena_texto define la cadena de texto a ser mostrado. La cadena es mostrado donde est el cursor grfico actualmente usando el color actual y fuente, direccin, valores, y justificaciones de texto. La posicin del cursor permanece sin ser cambiado al menos que la justificacin horizontal actual es LEFT_TEXT y la orientacin del texto es HORIZ_DIR. Cuando esto sea el caso, la posicin del cursor es colocada horizontalmente a la anchura del pxel de la cadena de texto. Adems, cuando se use la fuente por defecto, cualquier texto que se extiende a fuera del rea grfica actual es truncado. Aunque la funcin outtext est diseada para texto sin formato, texto con formato puede ser mostrada a travs del uso de un bfer de caracteres y la funcin sprintf. La funcin outtext no retorna ningn valor. Ejemplo: #include <graphics.h> #include <conio.h> #include <stdio.h> void main() { int driver = EGA; int modo = EGAHI; char mensaje[40]; char nombre[25]; printf( "Escribe tu nombre: " ); scanf( "%s", nombre ); sprintf( mensaje, "Hola %s!", nombre ); initgraph( &driver, &modo, C:\\TC20\\BIN ); outtext( mensaje );
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
initgraph( &driver, &modo, "C:\\TC20\\BIN" ); outtextxy(10,10,mensaje); anchura = textwidth( mensaje ); altura = textheight( mensaje ); getch(); closegraph(); printf( "El mensaje: \"%s\" tiene de anchura: %d y altura: %d\n", mensaje, anchura, altura ); printf( "Pulsa una tecla para continuar...\n" ); getch(); } Funcin textwidth int far textwidth(char far *texto); Esta funcin es usada para determinar la anchura, en pxeles, de la cadena de texto especificada por el argumento *texto. La anchura del texto se determina usando la fuente actual y el tamao del carcter. La funcin textwidth retorna la anchura, en pxeles, del texto especificado por el argumento. Ejemplo: #include <graphics.h> #include <conio.h> #include <stdio.h> void main() { int driver = EGA; int modo = EGAHI; int anchura, altura; char mensaje[5] = "Hola"; initgraph( &driver, &modo, "C:\\TC20\\BIN" ); outtextxy(10,10,mensaje); anchura = textwidth( mensaje ); altura = textheight( mensaje ); getch(); closegraph(); printf( "El mensaje: \"%s\" tiene de anchura: %d y altura: %d\n", mensaje, anchura, altura ); printf( "Pulsa una tecla para continuar...\n" ); getch(); }
63
Los miembros x e y definen el centro del arco. Los miembros xstart e ystart definen las coordenadas x e y del punto de comienzo del arco. Similarmente, los miembros xend e yend definen las coordenadas x e y del punto de final del arco. Esta estructura se usa como parmetro en la funcin getarccoords, que se usa para recoger las coordenadas del centro, y los puntos del comienzo y final de la ltima llamada con xito a la funcin arc.
Ejemplo: #include <graphics.h> #include <conio.h> void main() { int driver = EGA,modo = EGAHI,radio; struct arccoordstype info_arco; initgraph( &driver, &modo, "C:\\tc20\\BIN" ); for( radio=25; radio<=100; radio+=25 ) { arc( 300, 150, 45, 315, radio ); getarccoords( &info_arco ); moveto( info_arco.xstart, info_arco.ystart ); lineto( info_arco.xend, info_arco.yend ); } getch(); /* Pausa */ closegraph(); } Estructura fillsettingstype struct fillsettingstype { int pattern; int color; };
Esta estructura se usa para obtener la informacin de tramas de relleno, mediante getfillsettings. El campo pattern es la trama y el campo color es el color de relleno de la trama. Existen trece valores ya definidos para tramas.
64
Esta estructura se usa para obtener la informacin actual para las lneas mediante la funcin getlinesettings. El campo linestyle es el estilo de la lnea recta. El campo upattern es la trama de la lnea del usuario solamente cuando el campo linestyle es igual a USERBIT_LINE, 4. Cuando esto sea el caso, el miembro upattern contiene una trama de lnea definido por el usuario de 16 bits. Un bit 1 en esta trama indica que el pxel correspondiente ser asignado el color actual. Un bit 0 indica que el pxel correspondiente no ser alterado. El campo thickness es el grosor de la lnea. Existen varios valores para los diferentes estilos y grosores de lneas rectas.
Ejemplo: #include <graphics.h> #include <conio.h> #include <stdio.h> void main() { int gdriver = EGA; int gmodo = EGAHI; struct linesettingstype info; initgraph( &gdriver, &gmodo, "C:\\tc20\\BIN" ); setlinestyle( DOTTED_LINE, 0xFF33, THICK_WIDTH ); circle( 350, 250, 50 ); getlinesettings( &info ); getch(); /* Pausa */
65
Estructura palettetype
#define MAXCOLORS 15 struct palettetype { unsigned char size; signed char colors[MAXCOLORS+1]; }; Esta estructura se usa para obtener una los datos que definen la paleta segn cada dispositivo. El campo size indica el tamao de la paleta. El campo colors contiene los valores numricos que representan los colores que ofrece el dispositivo en su paleta de colores.
Ejemplo: #include <graphics.h> #include <conio.h> #include <stdio.h&t; void main() { int driver = EGA,modo = EGAHI,i; struct palettetype *palette = NULL; initgraph( &driver, &modo, "C:\\tc20\\BIN" ); palette = getpalettetype(); circle( 300, 150, 50 ); getch(); /* Pausa */ closegraph(); printf( "Paleta\n\nTamao: %d\nColores: %d", palette->size, palette->colors[0] ); for( i=1; i<palette->size; i++ ) printf( ", %d", palette->colors[i] ); printf( "\n" ); getch(); } Estructura textsettingstype struct textsettingstype { int font; int direction; int charsize; int horiz; int vert; };
66
Ejemplo:
#include <graphics.h> #include <stdio.h> void main() { int driver = EGA,modo = EGAHI; struct textsettingstype info; initgraph( &driver, &modo, "C:\\tc20\\BIN" ); gettextsettings( &info ); closegraph(); printf( "Texto\n\nFuente: %d\tSentido: %d\tTamao: %d\n" "Justificacin:\nHorizontal: %d, Vertical: %d\n", info.font, info.direction, info.charsize, info.horiz, info.vert); getch(); } Estructura viewporttype
struct viewporttype { int left, top; int right, bottom; int clip; }; Esta estructura se usa para obtener informacin acerca del rea grfica actual mediante la funcin getviewsettings. Esta estructura contiene informacin acerca de las esquinas superior izquierda e inferior derecha, tambin como el bandern de recorte del rea grfica.
Ejemplo: #include <graphics.h> #include <conio.h> #include <stdio.h> void main() { int driver =IBM8514LO,modo=IBM8514HI; struct viewporttype info; initgraph( &driver, &modo, "C:\\tc20\\BIN" ); getviewsettings( &info ); closegraph(); printf( "Pantalla\n\nIzquierda: %d\tSuperior: %d\tDerecha: %d\t" "Inferior: %d\tBandern: %d\n", info.left, info.top, info.right, info.bottom, info.clip); getch(); }
67
Estructura time
struct viewporttype { int left, top; int right, bottom; int clip; }; Esta estructura se usa para obtener informacin acerca del rea grfica actual mediante la funcin getviewsettings. Esta estructura contiene informacin acerca de las esquinas superior izquierda e inferior derecha, tambin como el bandern de recorte del rea grfica.
Ejemplo: #include <graphics.h> #include <conio.h> #include <stdio.h> void main() { int driver =IBM8514LO,modo=IBM8514HI; struct viewporttype info; initgraph( &driver, &modo, "C:\\tc20\\BIN" ); getviewsettings( &info ); closegraph(); printf( "Pantalla\n\nIzquierda: %d\tSuperior: %d\tDerecha: %d\t" "Inferior: %d\tBandern: %d\n", info.left, info.top, info.right, info.bottom, info.clip); getch(); }
Funciones de Rasterop.
Las funciones del rasterop, son auellas que realizar la accion de mover una imagen ya sea transportando una imagen o copiandola. Las funciones pertenecientes al rasterop son: 1. 2. 3. 4. imagesize malloc getimage putimage
Las cuatro complementan la operacin de mover una imagen almacenndola en una variable temporal de tipo buffer. Procederemos a explicar cada una de ellas para realizar buestros ejercicios de movimiento.
68
69
70
/*En este ejemplo solo conseguimos el tamao de la imagen y guardamos la imagen en un buffer*/ Funcin putimage void far putimage(int izquierda , int superior, void far *image, int accin); Esta funcin coloca una imagen que fue previamente guardada con la funcin getimage en la pantalla. La esquina superior izquierda donde ser colocada la imagen est definida por los argumentos izquierda y superior. Estos argumentos representan las coordenadas x e y de la esquina superior izquierda, respectivamente. El argumento *image apunta al bfer de memoria donde la imagen est guardada. La imagen se coloca en la pantalla con la accin definida en el argumento accin. Los valores y consonantes usados por el argumento accion se describen a continuacin ya que pudieron haberlos olvidado: Constante COPY_PUT XOR_PUT OR_PUT AND_PUT NOT_PUT Valor 0 1 2 3 4 Significado Sobrescribir los pxeles existentes Operacin OR Exclusivo con los pxeles Operacin OR Inclusivo con los pxeles Operacin AND con los pxels Invertir la imagen
La funcin putimage no retorna ningn valor. Ejemplo: #include <graphics.h> #include <conio.h> #include <stdlib.h> void main() { int driver = EGA,modo = EGAHI, imagentam; void *imagen; initgraph( &driver, &modo, C:\\tc20\\BIN ); setfillstyle( SLASH_FILL, 5 ); bar( 50, 50, 350, 300 ); imagentam = imagesize( 50, 50, 100, 100 ); imagen = malloc( imagentam ); getimage( 50, 50, 100, 100, imagen ); putimage( 400, 50, imagen, COPY_PUT ); getch(); putimage( 400, 110, imagen, COPY_PUT ); getch(); /* Pausa */ closegraph(); free( imagen ); getch(); } Este es el pequeo ejemplo del rasterop
71
Otros ejemplo de Rasterop. 1. Un crculo que realiza un movimiento iliptico. # include <conio.h> # include <graphics.h> # include <math.h> # include <dos.h> void inicializar(void); void cuerpo(void); void main(void) { inicializar(); cuerpo(); } void inicializar(void) { int drive=DETECT,modo; initgraph(&drive,&modo,"c:\\tc20\\bin"); } void cuerpo() { double x,y; while(!kbhit()) { x=-180; while(x<=180 && !kbhit()) { y=sqrt(15000*(1-((x*x)/32400))); circle(x+310,240-y,20); delay(15000); x+=1; cleardevice(); } x=180; while(x>=-180 && !kbhit()) { y=-1*sqrt(15000*(1-((x*x)/32400))); circle(x+310,240-y,20); delay(15000); x-=1; cleardevice(); } }
72
Bismarck Salvador Traa Lpez__________________________________________ UNI getch(); } Realice un programa que muestre el movimiento de la tierra alrededor de la tierra y que mustre los meses del ao conforme valla avanzando la image.
# include <conio.h> # include <stdio.h> # include <stdlib.h> # include <graphics.h> # include <math.h> # include <dos.h> # include <process.h> void inicializar(void); void main() { float y2,y1,x,x2; void far *buffer; system("cls"); inicializar(); buffer=malloc(imagesize(0,20,20,20)); do { outtextxy(150,50,"MOVIMIENTO DE ROTACION DE LA TIERRA al rededor del sol"); x2=-300; while(x2<=300 && !kbhit()) { putpixel(random(639),random(480),WHITE); putpixel(random(639),random(480),YELLOW); if((x2>=-300)&&(x2<-200)) { rectangle(480,440,600,460); setfillstyle(1,BLUE); floodfill(485,450,WHITE); outtextxy(500,450,"Enero"); } else { if((x2>=-200)&&(x2<-100)) { setcolor(BLUE);outtextxy(500,450,"Enero"); setcolor(RED); rectangle(480,440,600,460); setfillstyle(1,GREEN); floodfill(485,450,BLUE); outtextxy(500,450,"Febrero"); } else {
73
74
75
76
La funcin itoa
int itoa(int value, char *string, int radix); La funcin itoa convierte un entero a cadena, recibe los siguientes parmetros: int value = es el valor que vas a convertir char *string = es una arreglo de caracteres o un puntero que apunte a char, aqu se colocar el valor entero convertido. int radix = quiere decir el sistema en el que est el valor entero, ejemplo para enteros decimales debe ser 10, para enteros hexadecimale debe ser 16, para octales debe ser 8. Esta funcin es comnmente usada con outtextxy(), en el siguiente ejemplo deseo mostrar en pantalla grfica el valor de una variable entera para lo cual tengo que convertirla a cadena.
77
Las funciones rand() y random() son similares, ambas devuelve un valor seudo-aleatorio, la primera no recibe parmetros y el rango del valores est entre 0 y RAND_MAX este usualmente es 32767, el rango de valores para random() esta entre 0 y (valor_final 1). El ejemplo siguiente simulara una cantidad de estrellas: #include <graphics.h> #include <conio.h> #include <stdlib.h> void main(void) { int adaptador=DETECT,modo; initgraph(&adaptador,&modo,"c:\\tc20\\bin"); while(!kbhit()) { putpixel(rand(),rand(),random(16)); } } Otra manera de realizar programas en modo grafico con gran efectiidad es utilizando la librera mouse.h; esta funcin no esta definida dentro de la ayuda de tc20 pero esta dentro del archivo BGI o include veremos cada una de las funciones asi como tambin como las funciones contenidas dentro de ella.
78
La funcin mver
Void mver (void) La funcin mver muestra el puntero del ratn no es necesario en viar ningn parmetro. La funcin mver no retorna ningn valor. Ejemplo #include<graphics.h> #include<conio.h> #include<mouse.h> void main(){ int adaptador=DETECT,modo; initgraph(&adaptador,&modo,"c:\\tc20\\BIN"); do{ mver(); }while(!kbhit()); closegraph(); getch(); }
79
La funcin mxpos
int mxpos (int modo) Dice la posicin de la coordenada x en la cual se encuentra el ratn. Es necesario enviarunvalor para especificar el modo en cual sera usado. 1 es para modo grfico. 8 es para modo texto La funcin mxpos regresa la posicin horizontal de un entero que seria la posicin del ratn en x. Ejemplo #include <graphics.h> #include <conio.h> #include <mouse.h> #include <stdlib.h> void main(void) { int adaptador=DETECT,modo; int x,y; char *strx, *stry; initgraph(&adaptador,&modo,"c:\\tc20\\bin"); setbkcolor(BLUE);
80
La funcin mypos
int mypos (int modo) Dice la posicin de la coordenada y en la cual se encuentra el ratn. Es necesario enviarunvalor para especificar el modo en cual sera usado. 1 es para modo grfico. 8 es para modo texto La funcin mypos regresa la posicin horizontal de un entero que seria la posicin del ratn en y. Ejemplo #include <graphics.h> #include <conio.h> #include <mouse.h> #include <stdlib.h> void main(void) { int adaptador=DETECT,modo; int x,y; char *strx, *stry; initgraph(&adaptador,&modo,"c:\\tc20\\bin"); setbkcolor(BLUE); while(!kbhit()) { setfillstyle(SOLID_FILL,BLUE); mver(); x=mxpos(1); y=mypos(1);
81
La funcin msituar
void msituar(int modo, int x, int y) Esta funcin permite situar al curcor en una posicin especfica para su utilizacin es necesario enviar tres parmetros modo, x,y. Modo: 1 para modo grfico. 8 para modo texto. X: posicin horizontal. Y: posicin vertical. La funcin no retorna ningn valor. Ejemplo #include<graphics.h> #include<conio.h> #include<mouse.h> void main(){ int adaptador=DETECT,modo; initgraph(&adaptador,&modo,"c:\\tc20\\BIN"); msituar(1,310,240); /*Coloca el cursor en el centro de la pantalla*/ do{ mver(); }while(!kbhit()); closegraph(); getch(); }
82
La funcin mlimit
void mlimit(int modo, int x1, int y1, int x2, int y2) Esta funcin limita el espacio de movilizacin del cursor (ratn), en esta funcin es necesario enviar cinco parmetros modo,x1,y1,x2,y2.
83
84
Ejemplos de la de la VGA.
/*Este programa te muestra las figuras geometricas*/ # include<stdio.h> # include <dos.h> # include <stdlib.h> # include<graphics.h> # include<stdlib.h> # include<conio.h> void inicializar(void); void cuadro(void); void main(void) { inicializar(); cuadro(); restorecrtmode(); } void inicializar(void) { int adaptor=DETECT,modo,codigo;
85
86
/******************triangulo2****************************/ /* q eje x w eje y*/ outtextxy(q-100,w-90,"Triangulo Rectangulo 3 lados diferentes"); outtextxy(q-57,w-20,"h"); outtextxy(q-20,w+40,"a"); outtextxy(q+10,w-30,"b"); outtextxy(q-80,w-30,"c"); settextstyle(SMALL_FONT,HORIZ_DIR,5); outtextxy(q-45,w+60,"S=-\/ p(p-a)(p-b)(p-c)'"); line(q-15,w+60,q+110,w+60); outtextxy(q-30,w+75,"P=(a+b+c)/2"); settextstyle(SMALL_FONT,HORIZ_DIR,4); /*outtextxy(q-5,w+70,"(b x h)/2");*/ outtextxy(i-60,j-90,"Tri ngulo rectangulo"); outtextxy(i-60,j-90,"Tri ngulo rectangulo"); outtextxy(i-60,j-90,"Tri ngulo rectangulo"); setlinestyle(DOTTED_LINE,3,NORM_WIDTH); line(q-50,w-60,q-50,w+40); setlinestyle(SOLID_LINE,15,NORM_WIDTH); line(q-50,w+40,q+80,w+40); line(q+80,w+40,q-50,w-60); line(q-50,w+40,q-100,w+40); line(q-100,w+40,q-50,w-60); /*******************triangulo escaleno*****************************/ /*t es eje x k es eje y*/ outtextxy(t-60,k-90,"Triangulo Escaleno"); outtextxy(t-67,k-20,"h"); outtextxy(t,k+40,"b"); outtextxy(t-5,k+70,"S=(b x h)/2"); line(t-60,k-60,t-25,k+40); /*line que corta al triangulo o cat opu*/ line(t-25,k+40,t+100,k+40); /*cat ady.*/ line(t+100,k+40,t-60,k-60); /*hipoten.*/ setlinestyle(DOTTED_LINE,8,NORM_WIDTH); line(a+20,s-60,a+20,s+40); /*Triangulo isosceles*/ line(t-60,k-60,t-60,k+40); line(t-60,k+40,t+100,k+40); setlinestyle(SOLID_LINE,21,NORM_WIDTH); /*********************triangulo isosceles***************************/ outtextxy(a-40,s-90,"Triangulo Isosceles"); outtextxy(a+10,s-20,"h"); outtextxy(a+10,s+40,"b"); outtextxy(a-5,s+70,"S=(b x h)/2"); line(a+20,s-60,a-60,s+40); /*cat opt.*/ line(a-60,s+40,a+100,s+40); /*cat ady*/ line(a+100,s+40,a+20,s-60); /*hip*/ getch(); } if(paginas==2)
87
88
89
# include <conio.h> # include <dos.h> # include <process.h> # include <stdlib.h> # include <graphics.h> # define WHITE 15 void marco(int *,int *,int *,int *,int *); void estrellas(int *,int *); void ambiente(void); void ambientedos(void); void montana(void); void cometas(void); void main() { /*INICIALIZAR EL MODO GRAFICO DE MANERA RAPIDA*/ int a=DETECT,b; int x1=0,y1=0,x2=640,y2=480,color=6; int y=0, x=0; initgraph(&a,&b,"c:\\tc20\\bin"); system("cls"); ambiente(); ambientedos(); marco(&x1,&y1,&x2,&y2,&color); estrellas(&x,&y); montana(); cometas(); getch(); } void ambiente(void) { int x=50,y=480; setbkcolor(BLUE); setcolor(LIGHTGRAY); rectangle(0,0,639,479); moveto(x,y); setcolor(LIGHTGRAY); lineto(100,450); lineto(150,400); lineto(210,370); lineto(0,370); setfillstyle(SOLID_FILL,GREEN); floodfill(1,470,LIGHTGRAY); } void ambientedos(void) {
90
91
92
93
94
Este programa muestra el movimiento de una pelota. # include<stdio.h> # include <dos.h> # include <stdlib.h> # include<graphics.h> # include<conio.h> void inicializar(void); void juego_visual(void); void fondo_de_la_pantalla(void); void mover(void); void main(void) { inicializar(); juego_visual(); cleardevice(); fondo_de_la_pantalla(); mover(); getch(); restorecrtmode(); } void inicializar(void) { int adaptor=DETECT,modo,codigo; printf("desea seguir viendo los graficos"); initgraph(&adaptor,&modo,"c:\\tc20\\bin"); if((codigo=graphresult())!=0) { printf("%s",grapherrormsg(codigo)); exit(1); } } void juego_visual(void)
95
96
Cuando aparecieron los primeros computadores exista una memoria de solo 640 Kb (memoria convencional) y el procesador que dominaba en aquella poca era el 8086 y 8088 el cual poda direccionar hasta 1 Mb de memoria, ya que el microprocesador era de 16 bits. Aadieron a este diferentes reas de memoria, para la BIOS, el video, cartuchos ROM, etc. Hoy en da la configuracin de todo PC est organizada en bloques de 64 kb. Organizacin de la memoria de un PC A000: corresponde a la memoria de la pantalla en los modos grficos de las tarjetas EGA y VGA. B000: Es para las tarjetas de video monocromo MDA y Hercules. Tambin sirve tarjeta CGA. Se utiliza como alojamiento de los modos alfanumricos. para la
C000: Se depositan algunas rutinas BIOS, que no forman parte del ncleo original de esta. D000: Para cartuchos ROM. No se suele utilizar. E000: Igual que D000. F000: Aqu se guardan todas la rutinas (funciones) de la ROM-BIOS.
97
El Procesador . Para hacer la programacin del sistema, hay que conocer algunos conceptos que juegan un papel importante, trminos como por ejemplo los registros, a los que hay que conocer si se quieren manejar las interrupciones, ya sean a nivel DOS o BIOS. Los registros . Los registros son muy importantes para el ordenador, sirven para ayudar al funcionamiento de las instrucciones. Una definicin un poco ms acertada, sera decir que los registros son como variables internas con las que el computador realiza operaciones, y lleva el control de los programas. El tamao de estos registros en un 286 es de 16 bits, pero a partir del 386 estos registros son de 32 bits. Cada uno de estos registros se divide en dos partes de 8 bits cada una (esto es as, por que el DOS trabaja en modo Real, y no puede direccionar ms de 16 bits). Por ejemplo, el registro AX, se divide en AH y AL (H de High y L de Low). Podemos distinguir cinco tipos de registros diferentes: Registros Generales: Hay cuatro: AX, BX, CX, y DX. Son unos registros de 16 bits que se usan como almacenamiento temporal, para realizar operaciones aritmticas, cada uno de estos se divide en dos partes, la parte alta (AH), y la baja (AL), donde H significa High y L de Low. Tienen un propsito general para el programador. Registros de direccin (Puntero / Indice): SP, BP, SI y DI. Los utilizamos para formar direcciones de 20 bits, junto con los registros de segmento CS, DS, SS, y ES. Registros de segmento: CS, DS, SS y ES. Con ellos referenciamos direcciones de memoria. Registro de Puntero de Instruccin: IP (Instruction Pointer). Este lo usa el PC para acordarse en que punto se ha quedado a partir de la base CS. Va cambiando su valor cada vez que saltamos a un punto del programa. Registro de Bandera (Flag): Sirve para saber el estado y tener el control del procesador. Con este registro podremos saber, si por ejemplo despus de una suma, el valor excede de 65535 y por tanto no cabe en 16 bits. Estos bits, que pueden valer 0 o 1, indican varias cosas segn su valor. Las interrupciones . Las interrupciones, tal y como indica su nombre, tienen como funcin interrumpir en medio de un procedimiento, ejecutar un trozo de cdigo y continuar con lo que se estaba haciendo. De esta manera la CPU se ahorra de ir preguntado todo el rato a los diferentes perifricos si necesitan su ayuda (polling). Hay de varios tipos, las que son ejecutadas por el hardware, las del Sistema Operativo y las iniciadas por el sistema (BIOS). Dentro de estas hay las enmascarable, y las no enmascarables (NMI). El B.I.O.S ( Basic Input Output System) tiene una serie de interrupciones, para que cuando utilicemos alguna de ellas sepamos donde se encuentra. Para eso utilizaremos
98
99
100
101
102
Lo que hemos hecho con esta funcin es simplemente llamar a la interrupcin 10h con los parmetros necesarios para iniciar el modo 13h. Otra rutina que nos ser de mucha utilidad ser la que regresa al modo texto, esta funcin es similar al anterior, la nica diferencia es que al registro AL se le debe pasar el valor 03h. Podramos crear una funcin general para que realice los cambios de modos de video, esto quedara as: void SetMode(char mode) { union REGS r; r.h.ah=0; r.h.al=mode; int86(0x10, &r, &r); } Otra manera seria: void SetMCGA(void) { _AX=0x0013 ; geninterrupt(0x10) ; } Para volver al modo texto usamos la misma interrupcin 10h, slo que el servicio 03h : void SetText(void) { _AX=0x0003 ; geninterrupt(0x10) ; } y crear dos constantes con la directiva #define, es decir: #define TEXTO 0x03 #define GRAFICO 0x13 de esta manera para iniciar el modo 13h, llamaramos a la funcin SetMode de la siguiente forma SetMode(GRAFICO); y para volver al modo texto simplemente: SetMode(TEXTO); Veamos de la primera forma: #include <dos.h> para la funcion int86() # include <stdio.h> para la funcion printf() #include <conio.h> para la funcion getch()
103
104
getch(); ModoTexto(); printf("Regreso a modo VGA"); getch(); } Un Ejemplo: Este es un ejemplo sencillo elaborado en el modo 13h (320*200) a 256 colores que realiza el efecto del fuego. El programa fue compilado con Turbo C Nota.- El programa debe ser compilado con alguno de estos modelos: COMPACT,LARGE o HUGE para que pueda funcionar correctamente. #include <dos.h> para MK_FP,poke,ouportb,geninterrupt #include <stdlib.h> para random() #include <conio.h> para kbhit() typedef unsigned char byte; byte far* Video= (byte far*)MK_FP(0xA000,0x000); void Setrgbpalette(byte c,byte r,byte g,byte b) { outportb(0x3c8,c); outportb(0x3c9,r); outportb(0x3c9,g); outportb(0x3c9,b); } void Modo13h(void) { _AL=0x13; _AH=0; geninterrupt(0x10); } void ModoTexto(void) { _AL=0x03; _AH=0; geninterrupt(0x10); } void main(void) { int x,y,c; Modo13h(); for(x=1;x<=32;x++){
105
106
107
108
struct valor_rgb { unsigned char azul; unsigned char verde; unsigned char rojo; unsigned char reservado; }; void modo_video(unsigned char modo); void setpal(char col,char r,char g,char b); /*void putpixel(unsigned int x, unsigned int y, unsigned char color);*/ /*-------------------------------------------------------------------------*/ char verifica(char *fname); void mostrar_pal(void); void carga(void); void menu(void); void presentacion(void); void info_general(void); void paleta(void); void mostrar_imagen(void); void cambiar_pal(struct valor_rgb *pal); void despedida(void); struct cabecera bmp_cab; struct info_general bmp_info; struct valor_rgb *rgb; FILE *f; char fname[50]; int main() { presentacion(); fclose(f); free(rgb); /* liberamos la memoria utilizada */ return 0; } void carga(void) { register int i; /* leemos la cabecera del archivo */ fread( &bmp_cab, sizeof(struct cabecera), 1, f); /* leemos la informacion general del archivo */ fread( &bmp_info, sizeof(struct info_general), 1, f); /*leemos todos los colores que existen en la imagen */ if (!bmp_info.num_color) /* si se usan todos los colores */
109
110
111
getch(); } void cambiar_pal(struct valor_rgb *pal) { register int i; for (i = 0; i < 256; i++) setpal( i, pal[i-VAR].rojo / 4, pal[i-VAR].verde / 4, pal[i-VAR].azul / 4); } void paleta(void) { register int i,j; char opcion; clrscr(); printf("\n %10s %10s %10s %10s\n\n","Color","Rojo","Verde","Azul"); for (i = 0, j = 1; i <= (bmp_info.num_color); i++, j++) { if (j == 20 || i == (bmp_info.num_color) ) { j = 0; i--; gotoxy(1,25); printf(" Presione [ESC] para salir o cualquier tecla para continuar...."); opcion = getch(); if (opcion == KB_ESC) break; if (i+1 == (bmp_info.num_color)) break; clrscr(); printf("\n %10s %10s %10s %10s\n\n","Color","Rojo","Verde","Azul"); continue; } printf("\n %10d %10d %10d %10d", i, rgb[i].rojo, rgb[i].verde, rgb[i].azul); } } void mostrar_imagen(void) { register int x,y; char *linea; int resto; unsigned long int posicion; posicion = ftell(f); /* tomamos la posicion del puntero del archivo */
112
113
114
115
116
117
118
119
120
void Inicio(void); void Salir(void); void Juego(void); void Avanza(void); void Crece(void); void Libera(void); void Pinta_serpiente(void); void Pinta_rapido(void); int Choque(void); void Pinta_pantalla(void); int Es_punto(int x,int y); void Lee_record(void); void Escribe_record(void);
121
122
123
Lee_record(); t=77;/*ponemos una tecla (para que empiece yendo hacia la derecha)*/ superado=0; vel=v*300; Crece(); /*creamos la cabeza*/ cabeza->x=bordeiz+radio; /*la colocamos*/ cabeza->y=bordeab-radio; Crece(); /*ponemos otras dos bolitas de cuerpo*/ Crece(); Pinta_pantalla(); gotoxy(35,15); printf("ADELANTE"); delay(10000); cleardevice(); do { /*si no hay objeto, cogemos una pos aleatoria*/ if(obj==0) { do{ do{ x2=(((rand()%((bordede/(radio*2))-1)+1))*radio*2)-radio; }while(x2>bordede-radio || x2<bordeiz+radio); do{ y2=(((rand()%((bordeab/(radio*2))-1)+1))*radio*2)-radio; }while(y2>bordeab-radio || y2<bordear+radio); }while(Es_punto(x2,y2)); obj=1; } /*si se pulsa una tecla*/ if(kbhit()) { a=t; /*se guarda la anterior*/ t=getch(); /* y se coge*/ } if(Choque()) { printf("%c",pito); /*si se choca, pierde*/ Salir(); }
124
Pinta_pantalla(); if(obj==1) /*si hay objeto, lo pintamos de otro color*/ { setfillstyle(1,12); fillellipse(x2,y2,radio-2,radio-2); setfillstyle(1,c); } switch(t) /*evalua la tecla*/ { case 72: case '5': Avanza(); cabeza->y=cabeza->y-mov; break; /*arriba */ case 75: case '1': Avanza(); cabeza->x=cabeza->x-mov; break; /*izquierda */ case 77: case '3': Avanza(); cabeza->x=cabeza->x+mov; break; /*derecha */ case 80: case '2': Avanza(); cabeza->y=cabeza->y+mov; break; /*abajo*/ case 's': case 'S': /*si quiere salir, liberamos mem, cerramos el modo grafico y exit*/ Libera(); closegraph(); Escribe_record(); exit(2); break; case 'p':/*pausa*/
125
126
127
xa=ultimo->x; ya=ultimo->y; /*nos quedamos con la posicion de la cola*/ /*corremos cada bola a la pos de la bola anterior*/ while(indice!=cabeza) { indice->x=indice->ant->x; indice->y=indice->ant->y; indice=indice->ant; } } void Pinta_serpiente(void) { int i=0; indice=cabeza; setfillstyle(1,colorcabeza); fillellipse(indice->x,indice->y,radio,radio); setfillstyle(1,c); i++; indice=indice->sig; /*sin comentarios*/ while(i<longitud) { fillellipse(indice->x,indice->y,radio,radio); i++; indice=indice->sig; } } /*Como hemos comprobado en anteriores versiones, al pintar la serpiente entera*/ /*, si esta media mucho, se ralentizaba el juego mogollon, y sabemos que, al pintar*/ /*una bola y moverla, se queda su estela pintada, no?, coo pues pintemos solo*/ /*la primera, segunda y ultima bolita, y asi, mida lo que mida la serpiente,*/ /*solo pintaremos 3 bolas, y no se ralentiza casi nada.*/ void Pinta_rapido(void) { setfillstyle(1,colorcabeza); fillellipse(cabeza->x,cabeza->y,radio,radio); setfillstyle(1,c); fillellipse(cabeza->sig->x,cabeza->sig->y,radio,radio); fillellipse(ultimo->x,ultimo->y,radio,radio);
128
129
void Libera(void) { struct bola *aux; indice=cabeza; /*no hace falta comentario*/ cabeza=ultimo=NULL; while(indice!=ultimo) { aux=indice; indice=indice->sig; free(aux); } aux=indice; free(aux); longitud=0; } void Pinta_pantalla(void) { gotoxy(1,1); printf(" Serpiente v1 Desarrollado por Abdul Ruiz Chaos\n\r"); gotoxy(10,2); printf("Nivel : %1d Punt.Max. : %4d Puntuacion :%4d Longitud : %4d",m,max,puntos,longitud); Pinta_rapido(); /* dibujamos la serp */ /*"borramos" la ultima bola*/ /*este metodo es mas util, porque usando un cleardevice(), la pantalla vibraba mucho*/ setfillstyle(1,colorfondo); fillellipse(xa,ya,radio,radio); setfillstyle(1,c); /* dibujamos los bordes de la pantalla */ setcolor(15); rectangle(bordeiz-1,bordear-1,bordede+1,bordeab+1); setcolor(0); } int Es_punto(int x,int y) { indice=cabeza->sig;
130
131
La Geometra fue estudiada desde la antigua Grecia y Egipto. Constituan una herramienta muy importante para resolver problemas prcticos. El primer algoritmo que pueda considerarse completo es la construccin Eucldea, porque fue el primero que satisfizo todos los requerimientos: es correcto, no ambiguo y tiene un final. Este algoritmo adems da una coleccin de instrucciones y reglas, posee un conjunto de primitivas asociadas. Ya en 1902 se describi un conjunto de pasos para contar como realizar sobre papel una serie de primitivas Eucldeas. Se hablaba por entonces ya del trmino complejidad, no computacional pero s de dificultad para medir la complicacin de su realizacin. Se puede decir que fue una aproximacin a lo que entendemos hoy por .complejidad temporal.. No se hablaba del problema en funcin del conjunto de entrada, pero s intentaban reducirse el nmero de pasos a realizar para resolver un problema. Poco a poco se fueron dando cuenta de que todo problema posee un esfuerzo mnimo de realizacin, lo que nosotros llamamos .complejidad del algoritmo.. Ya en 1672 se demostr que cualquier construccin que pudiera realizarse slo con regla y comps podra hacerse usando slo comps. El concepto de lnea se ampli pasando a ser el lugar geomtrico compuesto por la unin de los puntos de corte de dos arcos realizados con un comps. La Geometra ha tenido momentos de especial realce, por ejemplo el crecimiento del anlisis real, la Geometra mtrica y la teora de la convexidad, han supuesto las herramientas matem ticas para el diseo de algoritmos rpidos. Por un lado la distancia es un tema esencial en conceptos geomtricos y la teora de la convexidad es analizada para obtener propiedades globales. La Geometra Algortmica est basada en caracterizaciones de objetos geomtricos en trminos de propiedades de subconjuntos finitos. Un tratamiento algortmico implica eliminar el trmino infinito. Hoy da la Geometra Computacional se utiliza como herramienta bsica, no slo en disciplinas inmediatamente relacionadas con la Geometra. A partir de finales de los aos 60 y 70, el incremento del uso de la computadoras en investigacin y desarrollo, propicia usar estas mquinas para resolver problemas clsicos que siempre fueron resueltos a base de reglas y comps. Pero la memoria de las mquinas y el tiempo de ejecucin de stas, la mayora de las veces compartido, exigi de pronto el conseguir mtodos que no slo funcionaran, sino que intentaran optimizar al mximo dos recuerdos muy importantes, sobre todo por aquel entonces: la memoria y el tiempo de CPU. Hoy por hoy a pesar de utilizar mquinas ms potentes, tambin se plantea en
132
Existen distintas formas de medir algoritmos o de clasificarlos. Un algoritmo fcil de entender, codificar y depurar es preferible a otro que realice lo mismo pero que no cumpla estas carcter sticas. Algo similar ocurre con respecto a la eficiencia; un algoritmo es eficiente cuando usa adecuadamente los recursos del ordenador y lo hace con la mayor rapidez posible. Los recursos son siempre referidos al tiempo de ejecucin y al tiempo de CPU que necesita para ejecutarse. Para optar por escribir un tipo de algoritmo que cumpla con las especificaciones anteriores tambi n es necesario saber cuantas veces va a ejecutarse dicho algoritmo y con qu cantidad de datos. As, un algoritmo poco eficiente con pocos datos es preferible utilizarlo a otro que necesite gran cantidad de tiempo en disearse. Por el contrario es beneficioso en muchas ocasiones realizar un buen diseo a pesar de utilizar gran cantidad de esfuerzo y emplear estructuras de datos complejas, si se consigue finalmente un mtodo de resolucin que realice buenos tiempos de ejecucin para entradas grandes de datos. Por otra parte, cuando nuestro algoritmo pretende resolver un problema clsico, como puede ser en Geometra Computacional, se da por supuesto que tiene que ser eficiente con grantes cantidades de datos y adems hay que suponer que dicho algoritmo va a ser ampliamente utilizado. Por tanto, nuestro propsito es no slo entender y utilizar algoritmos que funcionen en Geometra Computacional sino que tambin sean eficientes. Para medir dicha eficiencia, hay que tener en cuenta ciertos parmetros: Dependencia de los datos de entrada del programa. Calidad del cdigo que genera el compilador en el programa objeto. Las instrucciones y arquitectura de las computadoras. Tiempo de ejecucin de dicho programa.
Como entrar en detalles de compiladores diferentes y de distintas arquitecturas es muy amplio y adems es absolutamente cambiante, basta decir que cuanto ms rpido mejor. Lo que haremos ser estudiar los algoritmos en funcin de la entrada, bsicamente de su tamao, y adems en la complejidad o tiempo que emplea el algoritmo para su ejecucin. Obviamente un algoritmo, o programa puesto que se est ejecutando, va a ser ms rpido si tiene que procesar diez datos que si tiene que realizar lo mismo con una entrada de tamao cien.
133
Vamos a denominar T(n) al tiempo de ejecucin de un programa con tamao n. Para no especi ficar el tiempo en segundos, puesto que depende excesivamente de la mquina empleada, se usar una funcin expresada en trminos de n. Por ejemplo, T(n) = cn2, siendo c una constante. En muchas ocasiones es necesario referirse al tiempo de ejecucin esperado del algoritmo en el peor de los casos para una entrada de tamao n. De esta forma se puede acotar el problema con una cota superior que nos permita conocer el margen en el que nos podemos mover. El caso medio tambin puede ser interesante en casos donde se conozca que el peor caso se produce con una probabilidad muy pequea. Cuando decimos que el tiempo de ejecucin T(n) de un programa es O(n2) significa que existen constantes enteras positivas c tales que T(n) fi cn2. Por tanto es lo que llamamos cota superior que nos identifica el peor caso. En el caso genrico decimos que T(n) es O( f (n)). Tambin existen cotas inferiores para hablar del tiempo de ejecucin. Es una cota inferior o lo que es lo mismo: el algoritmo se ejecutar al menos en el tiempo que la funcin g(n) indica. Se dice que T(n) es (g(n)) cuando existe una constante c tal que T(n) fi cg(n). Cuanto menor sea la representacin grfica de la funcin f (n), ms rpido se ejecutar el algoritmo para un conjunto de entrada de tamao dado. Pero esto no siempre es verdadero para todo n, es decir, en ocasiones el tiempo de ejecucin se refiere a grandes cantidades de informacin y por tanto, n tiende a infinito. As O(n2) es mejor que O(n3); O(n) es mejor que O(n2) pero peor que O(nlogn). Por ejemplo un programa con tiempo O(100n) es ms lento para n menor que 20 que otro que se ejecute en tiempo O(5n2). En algoritmos tpicos de Geometra Computacional lo que se busca sobre todo son ejecuciones en tiempo lineal O(n), o en O(nlog n). A menos que un algoritmo tenga una velocidad de crecimiento baja, O(n) o O(nlogn), un crecimiento modesto en la rapidez de la computadora no infiuir gran cosa en el tamao del problema. A pesar de todo lo expuesto anteriormente, si un algoritmo va a ser utilizado pocas veces, el costo de escritura de una algoritmo eficiente puede que no merezca la pena. Tampoco es necesario si siempre va a recibir un conjunto de entrada pequeo. En algunas ocasiones un algoritmo puede permitirse el lujo de ser algo ms lento si a cambio es ms didctico. Por otro lado, si la eficiencia a nivel de tiempo en CPU implica un alto coste en cantidad de almacenamiento o porque se encuentre en dispositivos de memoria masiva. Por ltimo, en algoritmos numricos es tan importante la precisin de los clculos como la eficiencia de stos. Para calcular la eficiencia de un algoritmo hay que tener en cuenta ciertos casos:
134
Bismarck Salvador Traa Lpez__________________________________________ UNI Si T1(n) y T2(n) son tiempos de ejecucin de dos fragmentos de
programa, el tiempo totalser de T1(n)+T2(n). Sin embargo, se considera nicamente el ms lento de los dos y eltiempo de ejecucin vendr dado por tanto por O(max( f (n);g(n)) , siendo O( f (n)) eltiempo para T1(n) y O(g(n)) para T2(n). Tambin existen simplificaciones, por ejemplo,O(c f (n)) se considera siempre O( f (n)).
multiplicadas por el orden del conjunto de instrucciones del cuerpo del bucle. Si tenemos dos bucles de n ciclos, uno dentro de otro, se considera tiempo cuadrtico (suponiendo que el cuerpo del bucle tuviera un tiempo contante). Cuando se hacen llamadas a procedimientos no recursivos, se suman todos los tiempos de ejecuci n segn las pautas anteriores, pero en procesos recursivos se trabaja de forma distinta. Supongamos la siguiente funcin:
Para n > 2, tenemos que T(n) = c +T(n 1). El trmino T(n 1) se sustituye por n 1: T(n1) = c+T(n2), sustituyendo tenemos que T(n) = c+c+T(n2). Siguiendo este proceso hasta el trmino i entonces T(n) = ic+T(ni). Cuando i = n1, T(n) = nc+T(1) = ncfi= O(n). En el siguiente ejemplo tenemos a un algoritmo recursivo. Para el caso general, n >1, el proceso divide el problema en dos mitades de aproximadamente el mismo tamao. Cuando ste proceso de divisin termina necesita un tiempo lineal para unir los resultados de las dos mitades. Este mtodo es muy habitual en los problemas resueltos con el mtodo Divide y Vencers.
135
1.3.
En este apartado entraremos en contacto con mtodos para la resolucin de algunos de los problemas ms elementales en Geometra. Nos servir igualmente para recordar conceptos a nivel computacional. Los algoritmos aparecern mayormente escritos en lenguaje Pascal, a no ser que alguno de ellos aparezca, no por razones prcticas sino didcticas. 1.3.1. Introduccin A nivel de tratamiento de la informacin, en Geometra Computacional es clara la preferencia por los tipos de datos enteros, lo que se denomina aritmtica entera. La razn es obvia, el ordenador debe transformar todo dato de la recta real en un tipo de dato de una computadora que tiene un espacio finito de almacenamiento. Los datos enteros s garantizan su transformacin ntegra a un tipo de dato almacenado en memoria, siempre que ste sea menor que una valor dado. Sin embargo, los datos reales o en coma flotante pierden casi siempre cierta precisin al ser guardados. Cuando una variable de tipo real nace en la ejecucin de un programa y a su vez es utilizada como entrada para crear otras nuevas, este proceso repetido puede hacer que el dato se aleje del valor correcto. Por esta razn, y siempre que sea posible, es preferible hacer uso de la aritmtica entera. Por ejemplo, para saber si dos segmentos intersecan basta utilizar aritmtica entera, sin embargo si queremos saber exactamente el lugar de interseccin, s era necesario realizar algn clculo en coma flotante. 1.3.2. Algunos tipos de datos simples Los datos geomtricos, a la hora de ser procesados por un ordenador, son reemplazados por lo que denominamos tipos de datos. Muchos conceptos tpicamente matemticos se denominan de forma anloga cuando se representan internamente, as usamos el concepto de variable o de constante. Los tipos de datos identifican el tipo de cada una de estas posibles variables o constantes. Los tipos de datos que cualquier lenguaje de programacin soporta cubren el espectro ms habitual, sin embargo, los de tipo geomtrico deben ser definidos explcitamente por el programador. En este curso utilizaremos varios de estos tipos de datos. Por ejemplo, el tipo de dato TipoPunto, TipoPoligono, etc. En las clases de prcticas se definirn muchos de ellos, ahora identificaremos los anteriores en Pascal para poder trabajar con ellos a lo largo de este tema:
136
137
El clculo del rea de un polgono convexo es bien sencillo, basta con calcular el rea de todos los tringulos que se pueden formar lanzando diagonales desde cualquier vrtice, hasta el resto de los vrtices del polgono convexo.
Si el polgono no es convexo, el rea puede calcularse sumando las reas de los tringulos resultantes o incluso restando los de aquellos que no tengan superficie, como en el siguiente ejemplo:
El rea del polgono puede calcularse de dos modos: Area (abd) + area (bcd) Area(abc) area(adc)
Este mismo principio puede extenderse a cualquier polgono, indistintamente del tipo y nmero de vrtices que tuviera. Veamos el siguiente ejemplo: se ha elegido un punto cualquiera p, interior o exterior al polgono y se han trazado diagonales a todos sus vrtices. Los vrtices de ste han sido enumerados del o al n1 en orden inverso a las agujas del reloj. Este dato es muy importante, porque va a ser siempre el mecanismo utilizado para numerar los vrtices cuando trabajemos con polgonos. El nmero de tringulos obtenidos ser de n1, siempre partiendo del punto p y siguiendo con dos vrtices sucesivos del modo siguiente:
138
El tringulo p01 se traza en sentido inverso a las agujas del reloj, lo que implicar siempre que el rea de dicho tringulo es positiva. Se ha sealado utilizando un smbolo + cuando el clculo se realiza en el sentido antihorario y con cuando el rea es negativa. Cuando el recorrido de los vrtices del tringulo siempre en la forma pvivi+1, sea en sentido horario, por ejemplo el tringulo p67, el rea correspondiente se resta. El resultado final, como podemos observar en la figura, es que todas las reas de los tringulos no contenidas en el interior del polgonos son sumadas y restadas una vez con resultado igual a cero, es decir, el resultado finalmente es el deseado. Por tanto, podemos hacer uso de la funcin AreaTriangulo2 tantas veces como tringulos se vayan formando con el proceso anterior, sumando unas veces las reas y otras restndose automticamente segn sea la salida de dicha funcin. Como de cada tringulo se calcula el doble de su rea, finalmente ser necesario dividir por dos el resultado final. Como el punto P puede ser cualquier punto, sea interior o no al polgono, podemos optar por tomar al punto del polgono s[0], o lo que es lo mismo computacionalmente, a s[0]. El resultado lo podemos escribir a continuacin: Veamos el cdigo: int AreaPolygoni(tpointi s, int n) { float suma; int i; suma=0; for(i=1;i<n-1;i++) suma=suma+Area2(s[0],s[i],s[i+1]); return suma; } 1.3.4. Interseccin de segmentos Una de las operaciones elementales en Geometra Computacional es la interseccin de segmentos, clculo vlido para otros muchos problemas. Sin
139
El tringulo imaginario abc se dibuja en orden inverso a la agujas del reloj, lo que automticamente nos est indicando que el punto c est a la izquierda de ab. Es necesario observar que no es lo mismo el segmento ab que el segmento ba computacionalmente hablando. El rea del tringulo bac es negativa porque el punto c est a la derecha del segmento ba. El subprograma correspondiente nicamente necesita realizar una llamada a la funcin AreaTriangulo2 anteriormente vista. Aprovechamos un clculo en principio de distinta ndole, para determinar la posicin de un punto con respecto a un segmento. Veamos el codigo: bool Left(tpointi a, tpointi b, tpointi c) { Return Area2(a,b,c)fi0; /*Si areamayor que cero retorna TRUE */ } No es difcil entender que este mismo principio sirve para determinar si el punto c est justamente a la derecha (la funcin anterior nos devuelve un valor f alse). o si el rea del tringulo abc es igual a cero, lo que indica que los tres puntos son colineales:
140
Veamos el codigo en C: bool Collineal(tpointi a, tpoint b, tpoint c) { return Area2(a,b,c)==0; } Debemos insistir en que el cdigo anterior da por supuesto que todos los clculos se realizan nicamente utilizando aritmtica de enteros. No quiere decir sto que no pueda migrarse dicho cdigo a operaciones en coma fiotante, pero en ese caso jams debera realizarse una operacin como esta i f a = 0 ::::, puesto que no siempre el valor que nosotros consideramos como cero (o cualquier otro valor concreto) lo entienda as un tipo de dato en coma fiotante. Para solventar este problema es ms conveniente establecer un margen de error permitido, y operar as: i f abs(a) < 0;001 :::, o lo que es lo mismo, si el valor absoluto de la variable real a es menor que un valor prximo a cero. Para saber si dos segmentos ab y cd intersectan, deberamos saber si: 1. no son colineales 2. si d est a la izquierda de ab y c est a la derecha (o al revs) y adems 3. si a est a la derecha de cd y b lo est a la izquierda (o al revs) Nos podemos dar cuenta en la figura de que si no se cumple algunas de estas premisas no tenemos garanta de que ambos segmentos intersecten.
El cdigo debe tener en cuenta todos los casos citados anteriormente. La operacin vlida para implementar el .al revs., es la operacin XOR(a;b) cuya tabla de verdad da el valor verdadero cuando a y b son distintos.
141
bool Intersect(tpointi a, tpoint b, tpointi c, tpointi d) { If (IntersectProp(a,b,c,d)) Return TRUE; /*Hay interseccin propia*/ else If(Between (a,b,c) || Between (a,b,d) || Between (c,d,a) || Between (c,d,b) Return TRUE; /*Hay interseccion impropia*/ else return FALSE; /*No hay interseccion*/ } El inconveniente del mtodo es la redundancia. Ahora realizaremos una nueva versin del algoritmo utilizando la primitiva Entre, que ser capaz de saber si un punto c est o no en el segmento ab. Para ellos veremos si la coordenada x de c cae en el intervalo determinado por la coordenada x de a y b. Lo mismo debe hacerse para la ordenada. Veamos el codigo en C: boll Between (tpoint a, tpointi b, tpoint c) { If(!Collineal(a,b,c)) Return FALSE; If(a[x]!=b[x]) return ( (a[x]<=c[x]) && (c[x]<=b[x]) || (a[x]>=c[x] ) && (c[x]>=b[x]) ); else return ( (a[y]<=c[y]) && (c[y]<=b[y]) || (a[y]>=c[y] ) && (c[y]>=b[y]) ); } Esta versin del algoritmo adems cuenta con al ventaja de poder trabajar con las intersecciones de forma propia o impropia. Una interseccin impropia ocurre cuando un extremo de uno de los segmentos est justo en en alguna posicin del otro. La siguiente funcin en Pascal detecta primero si existe la posibilidad de colinealidad con la funcin Entre. Posteriormente hace el mismo proceso que IntersectaSegmento. Veamos el cdigo: bool IntersecImprop(tpoint a, tpoint b, tpointi c, tpointi d) { If( Between (a,b,c) || Between (a,b,d) || Between (c,d,a) || Between (c,d,b) ) return TRUE; else return(Left(a,b,c) || Left(a,b,d) && Left(c,d,a) || Left(c,d,b) ) }
142
Ahora veremos la function propia en C: bool IntersecProp (tpoint a tpoint b, tpointi c, tpointi d) { If( Collineal(a,b,c) || Collineal (a,b,d) || Collineal (c,d,a) || Collineal (c,d,b) ) return FALSE; return (Xor(Left (a,b,c), Left (a,b,d)) && Xor (Left(c,d,a),Left (c,d,b))); } bool Xor (bool x, bool y) { return !x^!y; } 1.3.5. Clculo de diagonales El clculo de una diagonal tiene como objetivo la triangulacin de polgonos. Una diagonal es aquel segmento que une dos vrtices del polgono de forma que no intersecte con ningn otro eje de dicho polgono y adems sea interno al polgono. Para saber si existe o no interseccin puede utilizarse el proceso anterior, pero para saber si es o no interno necesitamos realizar un procesamiento adicional. Este clculo puede realizarse en tiempo constante porque si una diagonal es interior a un polgono P en su vecindario (vrtices prximos), tambin lo es para todo el polgono, no siendo necesario un procesamiento completo del polgono P. Diremos que un segmento s es interno a P si y slo si es interno al cono cuyo vrtice es vi y cuyos lados pasan a travs de vi1 y vi+1. Existen dos casos, el caso convexo en el que el resto del polgono est en la parte de menor ngulo y el caso cncavo en cuyo caso el ngulo es mayor que La siguiente funcin . determina si el vector que une los vrtices i y j del polgono P es interior o no al polgono. Veamos el codigo: Esta funcin verifica si un vertice es convexo boll InCone(int i, int n, tpoligoni P) { int i1,inl; i1=(i+1)%n; inl=(i+n-1)%n; if(LeftOn(P[inl],P[i],P[i1])) /**/ return (Left(P[i],P[j],P[inl]) && Left (P[j],P[i],P[i1])); else return (!(LeftOn[P[i],P[i1]P[i1]) && LeftOn(P[j],P[i+,P[inl])); }
143
bool LeftOn (tpointi a, tpoint b,tpoint c) { return Area2(a,b,c)fi0; } Vemos en la figura siguiente los dos casos comentados anteriormente. El caso convexo ocurre cuando el vrtice vi+1 est a la izquierda del eje trazado por vi1vi. En este caso, lo vemos en la figura de la izquierda, para que se trate de un eje interno debe ocurrir que vi1 est a la izquierda de viv j y que vi+1 lo est a la izquierda. El caso cncavo aparece a la derecha.
Por tanto, una diagonal es aquel segmento interior que est dentro del polgono. Pero el segmento i j es una diagonal si no intersecta con ninguna otro de las aristas del polgono. Este clculo necesita forzosamente un tiempo de ejecucin lineal. La funcin DiagonalfiIE se encargar de realizar este chequeo, y que ser invocado por la funcin Diagonal cuyo cdigo resulta bastante evidente: el segmento i j es una diagonal del polgono P de tamao n si es interior y adems no intersecta con ninguna arista. Veamos el cdigo: Es/*ta function verifica la possible diagonal entre dos vertices.*/ bool Diagonal (int i, int j,int n,tpolygoni P) { return(InCode(i,j,n,P) && Diagonaie(i,j,n,P)()); } /*Esta function verifica si una diagonal se intersecta con una arista del poligono */ bool Diagonalie (int i, int j, int n, tpoligono p) { Int k,k1; for(k=0; k<n; k++) { K1=(k+1)%n; if( !( ( k==i) || ( K1==i ) || ( k==j) || ( k1==j ) ) )
144
} return TRUE;
/*Esta function remueve el triangulo formado por la diagonal y la arista asociada ala diagonal, para lo cual reasigna las etiquetas del polgono.*/ void ClipEar1 (int i, int n, tpoligoni p, int labels [ ]) { Int k; for(k=I; k<n-1 ; k++) { point assign (p[k+1]); labels[k] = labels [k+1]; } } /*Esta funccion obtiene los vrtices de la possible diagonal */ void TriRecurse(int n, tpoligoni P, int labels []) { int i,i1,i2; if(n>3) for(i=0; i<n;i++) { i1=(i+1)%n; i2=(i+2)%n; if (Diagonal(i,i2,n,p)) { printf("%d %d ln",labels[i2]); ClipEar1(i1,n,p,labels); TriRecurse(n-1,P,labels); break; } /*Cierre del if*/ } /*Cierre del for*/ } /**Cierre de la funcion/ 1.3.6. Un ejemplo completo: triangulacin de un polgono La triangulacin de polgonos es un clculo muy importante en muchas aplicaciones de Geometr a Computacional. Permite, aparte de otras muchas aplicaciones, dividir un polgono con posible cierta complejidad, en un conjunto de tringulos fciles de procesar. Veremos que el siguiente mtodo puede ser perfectamente vlido para lograr la triangulacin de cualquier polgono P de tamao n. Sin embargo, y a pesar
145
146
147
Las secuencias ms usuales son las listas enlazadas y los arrays. Las primeras forman una sucesin de nodos o elementos informativos unidos unos a otros mediante punteros. El tiempo de acceso es lineal, aunque normalmente el acceso a los puntos extremos es constante. Los arrays son contenedores implcitos con acceso directo. Esta ventaja de acceso en tiempo constante se ve mermada por poseer menor fiexibilidad. Por ejemplo, la operacin de insercin de un elemento en posiciones intermedias es de orden lineal. Sobre cualquiera de los contenedores secuenciales anteriormente citados puede construirse estructuras de datos muy conocidas y empleadas, las pilas (LIFO) o las colas (fiFO). Cualquiera de ellas implementada sobre una lista puede considerarse como una estructura de datos dinmica. Esta consideracin tambin puede realizarse sobre arrays dinmicos. Contenedores asociativos Los contenedores asociativos poseen una filosofa de manejo y una estructura interna totalmente diferente a las secuencias. La diferencia fundamental es que el acceso a la informacin se realiza siempre utilizando una clave y no una posicin, que puede identificar o no de forma unvoca al dato. Las operaciones fundamentales son de insercin, actualizacin, borrado y bsqueda por dicha clave. La organizacin interna de los datos depende del tipo de contenedor asocitivo, por rbol o por tabla hash. Los primeros mantienen un rbol binario de bsqueda o Inorden, manteniendo una relacin de orden entre nodos padre e hijos. Normalmente, todo nodo padre es mayor que su hijo izquierdo pero menor o igual que su hijo derecho. El tiempo de acceso en este tipo de estructuras permite eliminar en cada consulta la mitad del grueso de la informacin, siempre que todas las ramas del rbol permanezcan a la misma altura. Estas estructuras de datos garantizan bsquedas en O(logn). Las estructuras de datos consideradas de carcter general son ampliamente utilizadas en Geometra Computacional, pero existen otros aspectos como son la naturaleza espacial de los objetos geomtricos o sus propiedades estructurales que requieren del manejo de estructuras de datos ms especficas para construir algoritmos eficientes. La eleccin de un tipo de estructura de datos o de otro va a depender del tipo de objetivo que se persiga: captura de informacin estructural, acceso a los datos o actualizacin eficiente de stos, optimizacin del espacio requerido o del nmero de operaciones de E/S. En otras ocasiones, las estructuras de datos se eligen segn la asociacin de objetos geomtricos que representen. 1.4. Algunos mtodos de programacin utilizados en C.
La Geometra Computacional, en contraste con la disciplina clsica basada en proporcionar teoremas matemticos, enfatiza los aspectos computacionales de
148
149
1.5.1.1. Lnea de barrido Esta estrategia es una particularizacin del mtodo incremental, considerndose vlida para problemas en dos dimensiones cuando el conjunto de entrada se produce en un cierto orden. La solucin de la mayora de estos problemas puede ser incremental, de hecho, la implementacin de este paradigma sigue las mismas premisas que las dadas para el mtodo incremental citado anteriormente. El mtodo supone que una lnea horizontal (o vertical) recorre el plano de arriba hacia abajo (o en sentido contrario). Cada vez que dicha lnea encuentra un tem (un punto, una lnea, etc) lo procesa modificando el conjunto de estructuras que datos que participen en la construccin de dicho algoritmo. La validez de esta tcnica est basada en la observacin de que la parte que queda por encima o por debajo de la lnea de barrido se ha construido correctamente. Por ejemplo en el problema de interseccin de segmentos, cuando la lnea encuentra un nuevo segmento, se realizar una insercin en alguna estructura de datos capaz de mantenerlos ordenados de izquierda a derecha (en el caso de que la lnea de barrido sea horizontal). Normalmente se escogen estructuras de datos con tiempos de actualizacin y de acceso logartmico. Si el procesamiento de dichos objetos geomtricos es constante, como es el caso de la interseccin de dos segmentos, pueden trabarse con tiempos del orden de O(nlog n).
150
151
Esta tcnica clsica de programacin es vlida para resolver de forma eficiente problemas Geom. tricos. Normalmente se basa en la sucesiva divisin en partes iguales del problema original, hasta conseguir que ste posea un tamao lo suficientemente pequeo como para poder resolverse fcilmente. Llegado a un punto en que la divisin deja de tener sentido, los problemas se van resolviendo recursivamente y combinando sus soluciones para obtener la solucin final. El mtodo ms eficiente de ordenacin, el quicksort, est basado en este paradigma. El Algoritmo 2 resume los pasos empleados para resolver el problema Prob(S) partiendo del conjunto de datos S y realizando sucesivas divisiones por dos. Para que el algoritmo se considere eficiente se espera que el Paso 3.a) que divide el problema en subproblemas y el Paso 3.c) que combina las soluciones parciales, se realice en tiempo lineal. El segundo ejemplo de ecuacin de recurrencia de la Seccin 1.2 corresponde al mtodo Divide y Vencers. Algoritmo 2 Paradigma de divide y vencers
152
153
Es un ejemplote Voronoi. Esta tcnica es ampliamente utilizada y sirve de base para construir
154
2 La envolvente convexa y triangulacin de polgonos 2.1. La envolvente convexa 2.1.1. Introduccin El clculo de la envolvente convexa de un conjunto de puntos en espacios eucldeos ha sido sin duda uno de los problemas a la vez ms bsicos y ms ampliamente estudiados a lo largo de la historia de la Geometra Computacional. Adems, los campos en los que ha resultado un clculo til sorprenden por lo aparentemente poco relacionados con las matemticas en general y la geometra en particular.
Un conjunto convexo del plano se define como el conjunto que verifica que el segmento que une a dos cualesquiera de sus puntos est totalmente contenido en l. Evidentemente, esta definicin puede ser aplicada en cualquier espacio eucldeo n-dimensional. La idea de conjunto convexo nos lleva inmediatamente a la de envolvente convexa, considerando a sta como el menor conjunto convexo que contiene a dicho conjunto. Este concepto es fcil de entender en cierto modo si consideramos a la envolvente convexa de un conjunto de puntos en el plano, como la forma que adquirira una goma elstica envolviendo a todos los puntos del conjunto que estn fijos sobre el plano. De nuevo esta idea es extensible intuitivamente a otras dimensiones, y puede servir de partida para construir algoritmos simples para el clculo de la envolvente convexa. Pero exiten otras definiciones vlidas: la envolvente convexa de un conjunto de puntos en el plano es la unin de todos los tringulos determinados por dicho conjunto de puntos. El estudio de la envolvente convexa en dos dimensiones ha sido objeto de especial inters. Existen una serie de caractersticas asociadas a los puntos que
155
156
Todo punto que caiga dentro de la envolvente convexa de todas las muestras representadas por puntos en el plano, indica que puede ser producida. Si por contra, cayera fuera de dicha envolvente, la combinacin final no podra producirse. Este problema sera un problema 3D si cada mezcla tuviera tres componentes, la solucin sera la contruccin de la envolvente convexa tridimensional. 2.1.3 Algoritmo trivial 1. Determinacin de puntos extremos 1. Para cada i hacer 2. Para cada j i hacer 3. Para cada k i j hacer 4. Para cada h i k j hacer 5. Si Ph est a la izqda de (Pi,Pj) y 6. Ph est a la izqda de (Pj,Pk) y 7. Ph est a la izqda de (Pk,Pi) 8. entonces Ph no es extremo
Complejidad: O(n4 )
2.1.4 Algoritmo trivial 2. Determinacin de aristas extremas 1. Para cada i hacer 2. Para cada j i hacer 3. Para cada k i j hacer
157
Complejidad: O(n3 )
2.1.5 Gift Wrapping 1. Encontrar punto p ms pequeo en coord. y, sea i[0] su ndice 2. i := i[0] 3. Repetir 4. Para cada j i hacer 5. Calcular el ngulo en sentido antihorario entre Pj y la arista anterior de la EC 6. Sea k el ndice del punto con ngulo menor 7. Marcar (Pi,Pk) como una arista de la EC 8. i := k 9. Hasta que i = i0
2.1.6 Quick Hull QuickHull(a,b,S) 1. Si S={a,b} entonces devolver (a,b) 2. sino 3. c := ndice del punto con mxima distancia a (a,b) 4. A := puntos a la izquierda de (a,c) 5. B := puntos a la izquierda de (c,b) 6. devolver concatenar(QuickHull(a,c,A),QuickHull(c,b,B) ConvexHull(S) 1. a := punto ms a la derecha de S; 2. b := punto ms a la izquierda de S
158
La idea bsica del quickhull (envolvente rpida) es que para la mayora de las configuraciones de puntos se puede en cada paso descartar muchos puntos a la hora de construir la envolvente convexa. El primer paso del quickhull es encontrar los cuatro puntos extremos en las direcciones norte, sur, este y oeste y formar el cuadriltero que ellos definen (este cuadriltero puede ser degenerado), ahora todos los puntos en el interior de dicho cuadriltero no son extremos, con lo cual pueden ser descartados.
As nos quedan puntos repartidos en cuatro regiones no conectadas entre si, trataremos cada una de estas regiones independientemente. En cada una de ellas encontramos el punto ms alejado a la recta que define dicha regin obteniendo as cuatro nuevos puntos y un polgono de a lo ms ocho lados que divididir a los puntos que no hemos eliminado en ocho regiones que tratamos individualmente siguiendo la misma regla anterior.
159
En nuestro ejemplo en el paso siguiente se obtine ya la envolvente convexa. El QuickHull suele calcular la envolvente convexa en un tiempo mucho ms corto que si lo hacemos a travs del diagrma de Voronoi. Sin embargo, un anlisis del algoritmo nos lleva a que su complejidad en tiempo es cuadrtica. Por lo tanto, centrmosno ahora en encontrar un algoritmo ptimo. Ejemplo:
160
161
El Scan de Graham construye una lista que al final ser la de los puntos extremos ordenados. Supondremos que no existen tres puntos alineados (aunque esta condicin puede ser eliminada). Comenzamos encontrando el primer punto con el orden lexicogrfico, llamemosle p0. A continuacin ordenamos los puntos por el ngulo que forman con p0.
Suponemos que partimos de la lista ordenada as obtenida. En cada momento, tendremos tres puntos, llammosles Inicial, Medio y Final. Nos preguntamos si el ngulo IMF es positivo (en el sentido contraro de las agujas del reloj o negativo. Si es positivo, la lista la dejamos como estaba y el anterior Medio pas a ser Inicial y el final pas a ser Medio y escogemos el siguiente en la lista para ser el nuevo Final. Si es negativo, eliminamos Medio de la lista, el anterior Inicial pasa a ser Medio, el Final sigue como Final y escogemos el anterior de la lista para ser el nuevo Incial. La lista resultante despus de recorrer todos los puntos ser la de los extremos de la envolvente convexa. Teorema 5.1: El Scan de Graham calcula la envolvente convexa de n puntos en el plano en tiempo ptimo O(n log n).
162
2.1.4. La marcha de Jarvis La marcha de Jarvis est basada en el siguiente resultado, que sirve de definicin para la envolvente convexa: El segmento l, definido por dos puntos de la nube de puntos, es un eje de la envolvente convexa si todos los puntos de la envolvente convexa estn a un lado de sta. Siguiendo este criterio podramos descubrir para cada punto los n2 combinaciones posibles, lo que nos da un fcil pero costoso O(n3) algoritmo. Sin embargo, Jarvis pudo bajar la cota al comprobar que si pi pj es una arista perteneciente a la envolvente convexa, la siguiente arista la encontramos partiendo de p j en tiempo lineal. Veamos el siguiente ejemplo: Partiendo de s6, el punto de menor ordenada, alcanzamos a s5 tras realizar un barrido angular en sentido antihorario desde la horizontal. El siguiente punto de la envolvente se puede localizar partiendo de s5 y haciendo un nuevo barrido angular, localizando as a s1. Es fcil de intuir que este proceso tardar en ejecutarse un tiempo proporcional al nmero de puntos en la envolvente y al tamao de la nube. Cada barrido angular necesita un tiempo de proceso del orden de O(n) pasos. Si la envolvente final posee k puntos, el tiempo final de ejecucin es del orden de O(nk). En el mejor de los casos el comportamiento puede ser lineal, por ejemplo si la envolvente es un tringulo. El peor de los casos, sin embargo, se da cuando todos los puntos estn en la envolvente convexa, convirtindose en un mtodo cuadrtico.
163
2.1.5. Algoritmo Incremental La ventaja de unos mtodos con respecto a otros a veces viene dada por su velocidad computacional y otras veces por su fcil extensin a tres dimensiones, lo que habitualmente llamamos problemas 3D. El mtodo incremental para el clculo de la envolvente convexa es uno de estos casos. En todo mtodo incremental se supone que se ha resuelto el problema para un tamao n y que en cada paso se aade un nuevo punto dando solucin a un problema de tamao n+1. Para el clculo de la envolvente convexa ordenamos inicialmente los puntos del conjunto P de izquierda a derecha, por ejemplo, obteniendo el conjunto p0; p1; :::; pn1. Tomamos los tres primeros puntos tras esta ordenacin sabiendo que el polgono que forman p0; p1; p2, un tringulo, es convexo. El siguiente paso intenta aadir el siguiente punto, p3, de modo que se tras finalizar este paso tengamos la envolvente convexa de los primerso cuatro puntos p0; p1; p2; p3. Para aadir cada nuevo punto pi+1 basta con lanzar tangentes desde este punto hasta el polgono convexo obtenido en el paso anterior. Localizaremos dos tangentes, una superior y otra inferior, como vemos en la siguiente figura:
Siempre ocurre que el punto ms bajo de tangencia es tal que pi, es tal
que q est a laizquierda de pi1 pi pero a la derecha de pi pi+1.
164
Por tanto, y aunque el algoritmo es susceptible de aadir mejoras, necesita en el peor de los casos un tiempo O(n2). 2.1.6.Mtodo Divide y Vencers Los mtodos divide y vencers siempre trabajan de modo similar. En este caso, partimos de una nube de puntos ordenada de izquierda a derecha que se divide en dos mitades A y B de aproximadamente el mismo tamao. Para cada una de estas mitades, continuamos el proceso de divisin hasta que finalmente el tamao de la nube de puntos es tan pequeo que puede resolverse el problema fcilmente. Este caso concreto es cuando tenemos tres puntos. Cuando el problema no pueda dividirse ms, el siguiente paso es unir dos a dos los polgonos convexos resultantes de la etapa anterior, en un nuevo polgono convexo. El proceso finaliza obteniendo la envolvente convexa de todos los puntos. Sin embargo, la etapa de unin de dos polgonos convexos en un nico polgono convexo no es inmediata. Necesitamos calcular dos tangentes que unan dichas envolventes, una tangente superior y otra inferior. El mecanismo para conseguir, por ejemplo, la tangente inferior, podemos observarlo en la siguiente figura. Se comenzara suponiendo que el segmento que une el punto ms a la derecha de A y el punto ms a la izquierda de B es una tangente vlida. Como esta suposicin es falsa para este ejemplo, decidimos bajar vrtices sucesivamente hasta que por fin para el polgono A se localiza una envolvente. En el ejemplo, A2-B5 ya es una tangente para A, sin embargo no lo es para B. El siguiente paso es hacer exactamente lo mismo pero bajando sucesivos vrtices de B. El proceso termina cuando para los dos polgonos se encuentra una tangente.
165
Para saber si ab es tangente a un polgono observemos los siguientes grficos: queda como ejercicio la implementacin de las funciones TangenteMenor y TangenteMayor.
El tiempo de ejecucin de un algoritmo divide y vencers depende en gran medida del comportamiento de la funcin de mezcla de cada pareja de diagramas polares. Cuando sto se realiza en tiempo lineal, como es este caso, sabemos que contamos con un algoritmo en tiempo O(nlog n). 2.2. Triangulacin de polgonos
En el Tema 1 hicimos referencia por primera vez a la triangulacin de polgonos. En esa ocasin se hizo incapi de la necesidad de encontrar un algoritmo eficiente para realizar este clculo, puesto que el dado en dicho tema posee un tiempo de ejecucin poco eficiente. En esta seccin conseguiremos triangular cualquier tipo de polgono en tiempo ptimo O(nlogn), para ello sern necesarios dos pasos diferentes: la particin de cualquier polgono en particiones montonas y la triangulacin de cada una de estas porciones. 2.2.1. Polgonos montonos Un polgono montono con respecto a la vertical es aquel que si se recorre con una lnea horizontal bajando a lo largo del total del polgono, ocurre que slo encontramos como mximo dos intersecciones del polgono con dicha recta. Si
166
167
Veamos como funciona el algoritmo en sus primeros pasos para este ejemplo. Al ordenar los puntos de mayor a menor obtenemos la numeracin que vemos en la figura. Antes de entrar en el bucle, la lista l = s0; s1. Al entrar por primera vez en el bucle con j = 2, observamos que s2 es adyacente al final de la lista l (2a sentencia condicional) pero el algoritmo no construye an diagonales porque el Angulo(s[2],1,0)>por lo que la lista acaba siendo l =s0; s1; s2. Las siguientes iteraciones son iguales, hasta que para j = 4 se construyen las diagonales 14;24;34. La idea bsica del algortimo es construir diagonales con el comienzo de la lista l o con el final de sta , teniendo en cuenta que slo se unen puntos visibles entre s (ngulo <) y que no son adyacentes. El tiempo de ejecucin de este algoritmo es O(nlog n). El proceso de ordenacin de los vrtices ya posee este orden de ejecucin, por lo que dicho algoritmo no podra ejecutarse en menor tiempo. Adems habra que aadir un
168
Vrtice final: el vrtice vi es de final si vi1 y vi+1 poseen mayor ordenada y su ngulo interior es menor que .
Vrtice Particin: el vrtice vi es de particin si vi1 y vi+1 poseen menor ordenada ysu ngulo interior es mayor que .
169
Vrtice Mezcla: el vrtice vi es de mezcla si vi1 y vi+1 poseen mayor ordenada y sungulo interior es mayor que .
Utilizaremos la tcnica de .lnea de barrido. para encontrar las distintas particiones montonas. La idea ser localizar los vrtices que rompen la monotona, los de particin y los de mezcla. Desde ellos se lanzarn diagonales, el destino de stos ser tambin un objetivo primordial del algoritmo. Las estructuras de datos implicadas son las siguientes: P: ser un array conteniendo los vrtices del polgono, ordenados como es habitual en sentido antihorario. Q: La lnea imaginaria bajando por el plano se encontrara los puntos de P de
170
Algoritmo de triangulacin PROCEDIMIENTO HacerMonotono (VAR P : TipoPol igono ; VAR D: TipoLi s ta ) ENTRADA: El polgono P de tamao n SALIDA : El conjunto D de diagonales INICIO Ordenar_Y ( P, n ,Q) I n i c i l i z a r L i s t a ( T) I n i c i a l i z a r L i s t a (D) Para k<_ 0 hasta n_1 Repet i r i <_Q( k )
171
172
3 Intersecciones La deteccin de intersecciones constituye una de las primitivas geomtricas fundamentales con muy diversas aplicaciones. En realidad virtual o diseo de circuitos VLSI el manejo de intersecciones es fundamental. Pero existen otras reas de inters ms prximas a la Topografa como son los Sistemas de Informacin Geogrfica. En muchas ocasiones para hacer los mapas ms manejables y legibles, la informacin que contienen se divide en distintos tipos de mapas, cada uno especializado en carreteras, ciudades, ros y montaas, densidad de poblacin, etc. La informacin geomtrica subyacente en cada uno de estos mapas tambin puede considerarse diferente, as una carretera puede ser representada mediante una polilnea y un ncleo urbano puede serlo mediante conjunto de polgonos. Sin embargo, cuando dos de estos mapas necesitan ser manejados al mismo tiempo (por ejemplo para conocer las carreteras que llegan a una ciudad), es necesario el manejo de intersecciones entre iguales o diversos objetos geomtricos. Los problemas que necesitan del procesamiento de intersecciones pueden ser de distinta ndole. En algunas ocasiones no es necesario determinar con exactitud el punto de corte entre dos elementos geomtricos, nicamente conocer si existe dicha interseccin. Tambin podemos encontrar una diferencia sustancial entre manejar un par de lneas o segmentos o hacerlo con un conjunto de ellos. De hecho, la realidad a veces necesita simular la forma de cualquier lnea mediante una polilnea o conjunto de segmentos unidos a modo de cadena. La naturaleza de los objetos tambin puede ser conveniente conocerla a priori, puesto que la interseccin de polgonos convexos cuenta con un orden de ejecucin menor que si se trata de polgonos generales. 3.1. Interseccin de polgonos convexos El tiempo de ejecucin para conocer la interseccin de dos polgonos cualesquiera es O(nm), siendo n y m el nmero de ejes de los dos polgonos. El resultado de calcular la interseccin de dos polgonos cualesquiera podemos verlo en la siguiente figura:
173
Sin embargo, realizar esta operacin con polgonos convexos puede hacerse en tiempo O(n+m). Existe una propiedad importante para la interseccin de polgonos convexos: la interseccin es tambin un polgono convexo. Denominaremos a A y B a los ejes que en cada momento se estn ejecutando. En cada iteracin se avanza el eje A o el B (siempre en orden inverso a las agujas del reloj) dependiendo de ciertas reglas de avance. El objetivo es que dichos avances se vayan sincronizando en cuanto a su velocidad para encontrar todas las intersecciones. Denominamos a como el punto de la cabecera del vector A, y b el punto de la cabecera de B. Las reglas de avance harn por ejemplo, que si B apunta hacia la lnea que contiene a A, entonces avanzamos B para buscar la interseccin con A. Denominaremos a H(A) como el semiplano cerrado a la izquierda de A y a H(B) como el semiplano cerrado a la izquierda de H(B). Ocurre que AxB > 0 cuando el giro ms corto de girar A hacia B es en sentido inverso a las agujas del reloj. Como por regla general los dos vectores no coincidirn en su inicio, imaginaremos sin embargo que as ocurre para localizar el giro ms corto. En el siguiente ejemplo, AxB > 0 puesto que observamos que hacemos un giro en sentido de las agujas del reloj para ir de A hacia B.
Las reglas de avance quedan resumidas en la siguiente tabla: AXB Condiciones del semiplano Regla de avance
174
El mtodo anteriormente descrito aparece a continuacin. Tambin aparece el pseudocdigo de otros subalgoritmos llamados por el algoritmo principal. PROCEDIMIENTO IntersectaPol igonosConvexos (VAR P,Q: TipoPol igono ; n ,m: Entero ) ENTRADA: P,Q de tamao n y m SALIDA : VARIABLES: CONSTANTES: Origen : ( 0 , 0 ) INICIO a<0 b<0 Dentro < 1 REPETIR a1 < (a+n1) mod n b1 < (b+m1) mod m Subvector (P[ a ] , P[ a1 ] , A) Subvector (Q[ b ] , Q[ b1 ] , B) ProductoX < Area2 ( Origen , A, B) bHA < IzdaSobre (P[ a1 ] ,P[ a ] ,Q[ b ] ) aHB < IzdaSobre (Q[ b1 ] ,Q[ b ] ,P[ a ] ) SI ( I n t e r s e c t a P[ a1 ] ,P[ a ] ,Q[ b1 ] ,Q[ b ] ,P) ENTONCES SI Dentro = 1 ENTONCES AvanA < 0 AvanB < 0 fiNfiSI Dentro < TestDentro ( aHB) fiNfiSI SI ( ProductoX fi 0) ENTONCES SI ( bHA) ENTONCES a < Avanza ( a , AvanA , n , Dentro , P[ a ] ) SINO b < Avanza ( b , AvanB , m, NOT Dentro , Q[ b ] ) SINO SI ( aHB) ENTONCES b < Avanza ( b , AvanB , m, NOT Dentro , Q[ b ] ) SINO a < Avanza ( a , AvanA , n , Dentro , P[ a ] ) fiNfiSI HASTA ( AvanA fi n AND AvanB fi m) SI Dentro = 1 ENTONCES ESCRIBIR "No ha habido i n t e r s e c c i n " ; fiN
175
En la siguiente tabla observamos el resultado tras aplicar el algoritmo. En la ltima columna observamos el avance de los ejes. Podemos comprobar que el recorrido conjunto de ambos ejes permite localizar todas y cada una de las intersecciones existentes.
176
3.2. Interseccin de segmentos La interseccin de segmentos es un clculo muy importante por las repercusiones que tiene a nivel de intersecciones en el mundo real. Podemos simular una carretera como un conjunt de segmentos. Para saber donde se podra construir un puente podramos computar el conjunto de intersecciones entre el mapa de carreteras y el mapa de ros. Las operaciones realizadas a bajo nivel en la aplicacin informtica que lleve a cabo este clculo sern las de intersecciones de segmentos. Puede realizarse siempre un algoritmo de fuerza bruta para realizar este clculo utilizando para ello un tiempo O(n2) si supuestamente empleamos un nmero similar de ros y de carreteras. Como es de imaginar este algoritmo procesara todos los ros con todas las carreteras, y siendo por tanto poco eficiente. Probablemente el nmero de intersecciones sea mucho menor al de potenciales puntos de interseccin, por lo que podra buscarse un mtodo alternativo que tuviera por principio el procesar nicamente posibles intersecciones en segmentos que estn cerca, evitando as clculos innecesarios. La estrategia a seguir puede ser la de bajar una lnea horizontal L de arriba hacia abajo por el plano de modo que se vaya tropezando tanto con un tipo de segmentos como del otro. Cada vez que L se encuentra con un segmento lo almacena en una lista ordenada de izquierda a derecha, y as sucesivamente con todos y cada uno de los segmentos localizados. Para cada nueva interseccin y borrado en dicha lista se pregunta si la nueva situacin provoca una interseccin, siempre entre segmentos vecinos de la lista.
177
178
179
Sin embargo, la funcin de interseccin de segmentos desarrollada en el primer tema no es vlida para conocer el punto de interseccin entre dos segmentos, slo para saber si dicha interseccin se produce.
180
4 Localizacin de puntos y diagramas de Voronoi 4.1. Punto en polgono El problema denominado punto en polgono se presenta cada vez que se pincha el ratn en pantalla. Si el polgono P sobre el que trabajamos es convexo, el problema puede solucionarse en tiempo O(logn). Pero el mtodo ms interesante ocurre cuando P no es convexo. Para este caso utilizamos el siguiente mtodo: si queremos saber si el punto q est dentro o fuera del polgono P trazamos una lnea en cualquier direccin, por ejemplo utilizando la recta r igual a y = 0, x fi 0 y entonces contamos el nmero de intersecciones que se producen. El punto q est dentro de P si el nmero de intersecciones es impar. Para hacer ms fcil el clculo y utilizar una recta r vlida para cualquier caso, hacemos coincidir el punto q con el origen de coordenadas de forma que la r pueda ser simplemente y = 0; para x >= 0.
181
trasladamos la idea anterior al siguiente algoritmo en pseudocdigo que realiza el test de inclusin de punto en polgono. El primer conjunto de bucles hace el cambio de origen de coordenadas. En el siguiente se detectan las intersecciones con la recta y = 0, pero slo se tienen en cuenta los cortes que se producen para x > 0.
El tiempo de ejeccin de este test de inclusin es lineal, como claramente indica la bsqueda exhaustiva de intersecciones de una recta con todas las aristas de un polgono.
182
En este captulo estudiamos el diagrama Voronoi, una estructura geomtrica segunda en importancia slo detrs del buque convexo. En cierto sentido un diagrama de Voronoi registra todo lo que uno alguna vez querra saber acerca de proximidad para un grupo de puntos (u objetos ms generales). Y a menudo uno quiere saber detalles acerca de la proximidad: Quin est ms cercano a quin? Quin est ms lejos? Etctera. El concepto tiene ms de un siglo de antigedad, discutido en 1850 por Dirichlet y en 1908 por Voronoi. Comenzaremos con una serie de ejemplos para motivar el debate y entonces, la zambullida en los detalles de la estructura enriquecedora del diagrama Voronoi (en las Secciones 5.2 y 5.3). Hay que familiarizarse con estos detalles antes de que los algoritmos puedan ser apreciados (en la Seccin 5.4). Finalmente revelaremos la bella conexin entre diagramas Voronoi y buques convexos en la Seccin 5.7. Este captulo incluye slo dos pedazos pequeos de cdigo, para construir lo dual del diagrama Voronoi (la triangulacin Delaunay), en la Seccin 5.7.4.
APLICACIONES PRELIMINARES
1. Las torres de observacin de fuego Imagine un bosque vasto conteniendo un nmero de torres. Cada guardabosque es responsable de extinguir cualquier fuego ms cercano para su torre que para cualquier otra torre. El grupo de todos los rboles para los cuales un guardabosque particular es responsable constituye el Polgono de Voronoi asociado con su torre. El diagrama de Voronoi traza las lneas entre estas reas de responsabilidad: Los lugares en el bosque que son equidistantes de dos o ms torres. (Una vistazo a la Figura 5.5 puede ayudar a la intuicin).
183
184
4. La facilidad de Localizacin Suponga que a usted le gustara localizar una tienda de comestibles nueva en un rea con varias tiendas de comestibles existentes, irreconciliables. Asumiendo densidad de poblacin uniforme, dnde debera estar la tienda nueva localizada para optimizar sus ventas? Un mtodo natural que satisfaga esta restriccin vaga es localizar la tienda nueva tan lejos de las viejas como sea posible. Aun esto es un poco vago; Ms precisamente podramos escoger una localizacin cuya distancia para la tienda prxima es tan grande como sea posible. Esto es equivalente a localizar la tienda nueva en el centro del crculo vaco ms grande, el circulo ms grande cuyo interior no contiene otras tiendas. La distancia para la tienda mas prxima es entonces el radio de este crculo. Mostraremos en 5.5.3 Seccin que mientras central de crculo vaco ms grande debe mentir en el diagrama Voronoi. 5. Planeando el camino Imagine un ambiente desordenado a travs del cual un robot debe planear un camino. Para minimizar el riesgo de colisin, al robot le gustara quedarse tan lejos de todos los obstculos como sea posible. Si restringimos la pregunta a dos dimensiones, y si el robot es circular, entonces el robot debera quedarse todo el tiempo en el diagrama de Voronoi de los obstculos. Si los obstculos son puntos (digamos polos delgados), entonces ste es el diagrama convencional de Voronoi. Si los obstculos son polgonos u otras formas, entonces una versin generalizada del punto del diagrama Voronoi determina el camino apropiado. Revisaremos este ejemplo en el Captulo 8 (la Seccin 8.5.2). 6. La cristalografa
185
Asuma un nmero de granos de cristal crecen uniformes, a velocidad constante. Cul ser la apariencia del cristal cuando el crecimiento ya no es posible? Debera estar claro ahora que esto es anlogo al incendio de bosques, y que cada grano crecer para un polgono de Voronoi, con regiones adyacentes del grano encontrndose a lo largo del diagrama de Voronoi. Los diagramas de Voronoi por mucho tiempo se han usado para simular crecimiento del cristal. La lista de aplicaciones podra seguir sin parar, y veremos otros en la Seccin 5.5. Pero es hora de definir el diagrama formalmente. DEFINICIONES Y PROPIEDADES BASICAS Sea P = {p1, p2,, pn} un grupo de puntos en el plano Euclidiano de dos dimensiones. stos son llamados los sitios. Divida en partes el plano asignando cada punto en el plano a su sitio ms prximo. Todos esos puntos asignados a pi forman la regin de Voronoi V (pi). V (pi) consiste de todos los puntos al menos tan cercanos a pi en lo que se refiere a cualquier otro sitio: V (pi) = {x: | pi - x pj - x j }. Note que hemos definido este grupo para ser cerrado. Algunas puntos no tienen un nico sitio prximo, o vecino prximo. El grupo de todos los puntos que tienen ms de un vecino cercano forman el diagrama de Voronoi V (P) para el grupo de sitios. Ms tarde definiremos los diagramas de Voronoi para grupos de objetos ms generales que puntos. Primero miramos diagramas con justamente algunos sitios antes de detallar sus propiedades para n mayor. Dos sitios Considere solo dos sitios, p1 y p2. Sea B (p1, p2) = B12 la bisectriz perpendicular del segmento p1p2. Entonces cada punto x en B12 es equidistante de p1 y p2. Esto puede verse dibujando el tringulo (p1, p2, x) como se muestra en la Figura 5.2. Por el teorema del lado - ngulo - lado de Euclides, | p 1x | = | p2x |.
186
Tres sitios Para tres sitios, es claro que fuera del tringulo (p1, p2, p3), el diagrama contenga la bisectriz B12, B23, B31. Lo que no esta claro es que ocurre en los alrededores del tringulo. Otra vez de Euclides las bisectrices perpendiculares de los tres lados del tringulo todos atraviesan un punto, el circuncentro, el centro del nico crculo que pasa a travs de los vrtices del tringulo. As el diagrama Voronoi para tres puntos debe aparecer como en la Figura 5.3. (Sin embargo, el circuncentro de un tringulo no est siempre dentro del tringulo como se muestra).
Semiplanos La generalizacin ms all de tres puntos quiz todava no esta clara, pero es ciertamente claro que la bisectriz Bij desempear un papel. Sea H el semiplano cerrado con lmite Bij y conteniendo pi. Entonces H puede ser visto como todos los puntos que estn cercanos a p i que a pj. Ahora ordene el regreso de que V (pi) es el grupo de todos los puntos ms cercano a p i que a cualquier otro sitio: En otras palabras, los puntos ms cercanos a pi que a p1, y
187
i j
H (pi, pj)
(ecuacin 5.2)
Donde la notacin significa que la interseccin debe estar ocupada sobre todo i y j como i j. Note que esa conjuncin inglesa y ha sido trasladada a interseccin de conjunto.
Figura 5.4 (a) Diagrama de Voronoi para cuatro puntos cocirculares; (b) diagrama despus de mover los puntos hacia la izquierda. La ecuacin (5.2) inmediatamente nos da una propiedad importante de los diagramas de Voronoi: Las regiones de Voronoi son convexas, pues la interseccin de cualquier nmero de Semiplanos es un grupo convexo. Cuando las regiones estn rodeadas, son polgonos convexos. Los bordes de las regiones de Voronoi son llamados bordes de Voronoi, y los vrtices son llamados vrtices de Voronoi. Note que un punto en el interior de un borde de Voronoi tiene dos sitios prximos, y un vrtice de Voronoi tiene al menos tres sitios prximos. Cuatro sitios El diagrama de cuatro puntos formando las esquinas de un rectngulo es mostrado en la Figura 5.4 (a). Note que el vrtice de Voronoi es de grado cuatro. Ahora suponga que un sitio es movido ligeramente, como en la Figura 5.4 (b). Hay un sentido en el cual este diagrama es normal, y uno en la Figura 5.4 (a) que es anormal o degenerado. Es degenerado por que hay cuatro puntos cocirculares. A menudo lo encontraremos til para excluir este tipo de degeneracin.
188
189
190
La implicacin inversa es ms sutil. Suponga que hay un crculo vaco C (x) a travs de a y b, con centro en x. Tenemos la intencin de poner a prueba que
191
192
193
Omitiremos este algoritmo histricamente importante para enfocar la atencin en algunos desarrollos recientes emocionantes. El algoritmo de Fortune
Hasta la mediados de los 80, la mayora de implementaciones para computar el diagrama de Voronoi le usaron a la O (n 2) algoritmo incremental, aceptando su desempeo ms lento para evitar las complejidades de la codificacin divide y conquista. Pero en 1985, Fortune (1987) invent un algoritmo del barrido de plano listo que es tan simple como los algoritmos incrementales pero tiene complejidad del peor caso de O (n log n). Nosotros ahora esbozaremos la idea principal detrs de este algoritmo. Los algoritmos Plane-sweep(barrido de plano) (Seccin 2.2.4 ) pasan una lnea de barrido sobre el plano, dejando en cualquier hora el problema solucionado para la porcin del plano ya barrido y no resuelta para la porcin todava no alcanzada. Un algoritmo Plane-sweep para construir el diagrama de Voronoi construira el diagrama detrs de la lnea. A primera vista, esto parece realmente mentira, como los bordes Voronoi de una regin de Voronoi V (p) seran encontrados por la lnea de barrido antes de que la L encuentre la p del sitio responsable para la regin. Fortune super esta imposibilidad aparente por una idea extraordinariamente lista.
194
Imagine los sitios en el plano xy del sistema de coordenadas tridimensional. Erecto sobre cada sitio p un cono cuya cima est en p, y cuyos lados se inclinan a 45. Si la tercera dimensin es mirada como el tiempo, entonces el cono sobre p representa un crculo dilatndose sobre p a una velocidad nica: Despus de t unidades tiempo, su radio es t. Ahora considere dos conos cercanos, sobre los sitios p1 y p2. Se intersecan en una curva en el espacio. Recordando la vista de crculos en expansin del diagrama de Voronoi, debera ser esperado que esta curva yazca enteramente en un plano vertical, el plano ortogonal para la bisectriz de p 1p2. Vea la Figura 5.9. As que aunque la interseccin est curvada en tres dimensiones, se proyecta para una lnea recta en el plano xy. Es solamente un paso pequeo de aqu a que si los conos sobre todos los sitios son opacos, y son mirados de z = - , lo que se ve es precisamente el diagrama Voronoi! El corte del cono Estamos ahora preparados para describir la idea de Fortune. Su algoritmo barre los conos con un plano sesgado, sesgado a 45 para el plano xy. La L de la lnea de barrido es la interseccin con el plano xy. Demos por supuesto que la L es paralela al eje vertical y que su coordenada de la x es l(ele). Vea Figura 5.10. Imagnate que , al igual que los conos, es opaco, y otra vez considera la vista de z = - . Para la x > l, lado de L, solamente es visible desde abajo: Hace un viraje debajo del plano xy y as tambin obscurece los sitios y los conos. Esto representa la porcin del plano todava no ha sido barrido. Para la x < l , lado de L, el diagrama de Voronoi es visible hasta la interseccin de con la frontera derecha (x positiva) de los conos. La interseccin de con cualquier cono es una parbola (una propiedad bsica de secciones cnicas), y as la interseccin de con su frontera derecha proyecta al plano xy (y as aparece z = - ) como un frente parablico, una curva compuesta de piezas de parbolas. Vea Figura 5.11. Dos parbolas se unen en un lugar donde encuentra dos conos. De nuestro debate de la interseccin de dos conos arriba, esto debe estar en un borde de Voronoi. Frente parablico Ahora finalmente podemos ver cmo solucion Fortune el problema del problema de la lnea de barrido encontrando bordes de Voronoi antes de los sitios generadores: Porque su plano de barrido se inclina en los mismos bordes como los lados de los conos, L encuentra un sitio p exactamente cuando primero golpea el cono para p! Por lo tanto no es se el caso que el diagrama de Voronoi que est en todo tiempo construido para la izquierda de L, pero est en todo tiempo construido bajo , lo cual quiere decir que esta
195
1. D V (p) (p) Disear un algoritmo para la computar del diagrama de Voronoi, dado la triangulacin Delaunay. Trate de lograr complejidad de 0 (n) tiempo. 2. Diagramas de Voronoi unidimensionales. Un Diagrama unidimensional de Voronoi para un grupo de puntos P = { P1, , Pn } en una lnea (diga el eje de la x) es un grupo de puntos V (P) = { x1, , xn-1 } algo semejante que el x1 es el punto medio de pi de Pi + 1. Suponga que usted da un conjunto X = { x1, , xn-1 }. Disee criterios que te permitirn determinar si es o no X es un diagrama de unidimensional de Voronoi de un grupo de puntos, y si es as. Determine P. Con qu rapidez es el algoritmo implementado? 3. Los diagramas dinmicos Voronoi. La imagen un grupo de puntos moviendo en el plano, cada uno con una velocidad fija y direccin. Sea V (t) el diagrama de Voronoi de puntos en el tiempo t. Este un problema no resuelto, obtener saltos apretados en el nmero de diagramas distintos combinatoriamente que pueden resultar todo el tiempo. Aqu le pregunto a usted que establezca lo mejor conoce salto inferior: (n2). En otras palabras, encuentre un grupo de n moviendo puntos algo tal que V (t) cambie su estructura combinatoria cn2 para alguna constante C. Ningn a mismo capaz de encontrar un ejemplo en el cual haya ms cambios pero el mejor salto alto esta alrededor de O(n3). n2
4. La triangulacin arbitraria. Disee un algoritmo para encontrar que una triangulacin arbitraria de un grupo de punto P: Una coleccin de diagonales incidente para cada punto de P que divide H (P) en tringulos. La ausencia del
196
Ahora Discutiremos cinco aplicaciones del diagrama de Voronoi, en el detalle accidentado: Los vecinos prximos, las triangulaciones gordas, los crculos ms grandes vacos, los rboles de extensin mnimos, y viajando a travs de caminos del vendedor. 5.5.1 Los vecinos ms cercanos. Una aplicacin del diagrama Voronoi para agrupamiento de los vecinos ms cercanos mencionado en Seccin 5.1 Este problema puede verse como un problema de consulta: Cul es el vecino mas cercano a un punto buscado? Otra versin es la problema del vecino ms cercano: Encuentras el vecino mas cercano para cada punto en un grupo dado. Esto tiene un nmero de aplicacin en una variedad de campos, incluyendo biologa, la ecologa, la geografa, y Fsica. Defina la relacin entre el vecino mas cercano y un grupo P de puntos como sigue: La b es una vecina prxima de a si | a b | minc a| a c |, donde c P. Podemos escribir esta relacin a b: Un vecino cercano de a es b. Note que la definicin no es simtrica con respectos a las tareas que a a y b les toca, sugiriendo que la relacin no sea as misma simtrica. Y de hecho ste es ciertamente el caso: Si a b, no es necesaria que b a; Ver a Figure 5.12 Tambin nota que un punto puede tener varios vecinos igualmente cercanos (ejemplo, punto d en la figura). El vecino cercano pregunta Dado un grupo fijo de puntos P, construir el diagrama de Voronoi en el tiempo O (n log n). Ahora para un punto de consulta q, encontrando un vecino cercano de q para encontrar en cul regin de Voronoi cae, pues los sitios de esas regiones de Voronoi son precisamente sus vecinos cercanos. El problema de hallar un punto dentro de una particin es llamada localizacin del punto. El problema ha sido estudiado con exceso y ser discutido en el Captulo 7 (Seccin 7.11). Veremos que en este ejemplo, el tiempo O (log n) es suficiente para cada consulta. Todos los Vecino Cercanos
197
Defina al Nearest Neigbor Graph ((NNG) Graficos de vecinos mas cercanos) para asociar un nodo con cada punto de P y un arco entre ellos si un punto es un vecino cercano del otro. Hemos definido esto para ser un grfico orientado, aunque la relacin no es simtrica, adecuadamente podra ser directa. Pero no necesitaremos la versin directa aqu.
Una forma sucinta a captar la esencia del algoritmo del vecino cercano eficiente es a travs del siguiente lema. Lema 5.5.1 NNG D (P) Dejo la prueba para el ejercicio 5.5.6 [2] y [3 ] Un algoritmo de fuerza bruta para encontrar a los vecinos cercanos para cada punto en un grupo requerira O (n2), pero el lema de arriba nos deja registrar solo los bordes O (n) de la triangulacin de Delauny y por lo tanto logra O (n log n). Vecino natural: Otra forma de conseguir el valor que tendra un punto cualquier p sera el de conocer todos aquellos vecinos naturales de p. Averiguar esta informacin no es ms que resolver el problema de los vecinos ms cercanos a un punto utilizando el diagrama de Voronoi. Aplicaciones en este sentido son la identi_cacin de tomos vecinos en el espacio, molculas o partculas en estructuras cristalinas y amorfas, etc. Ahora el punto de estudio p puede estar in_uenciado por dicho conjunto de vecinos, los cuales tambin puede llevar asociados distintos pesos de in_uencia
198
1.5.2 La triangulacin Maximizando el ngulo Mnimo. Analizar las propiedades estructurales de forma complicada es a menudo realizado por una tcnica llamada anlisis finito del elemento. Esto es usado, por ejemplo, por fabricantes del automvil a modelar cuerpos del coche (Field 1986). El dominio a ser estudiado est subdividido en una malla de elementos finitos, y entonces las ecuaciones diferenciales relevantes modelando la dinmica estructural sea solucionado por discretizacin sobre la particin. La estabilidad de los procedimientos numricos usados depende de la calidad las buenas particiones y esto pasa por que la triangulacin de Delaunay son especialmente buenas particiones. Nosotros ahora discutiremos el sentido en el cual la triangulacin Delauny es buena. Una triangulacin de un grupo de puntos S es la generalizacin del objeto del cual la triangulacin de Delauny es un ejemplo particular. Un grupo de segmentos cuyos puntos finales estn en S, Que slo interseca a cada quien en puntos finales, y cul divide en partes el buque convexo de S en tringulos. Para los propsitos del anlisis finito del elemento, las triangulaciones con tringulos gordos son ms convenientes. Una forma para hacer esto precisa ms es evitar tringulos con ngulos pequeos. As es natural buscar una triangulacin que tiene el ngulo menor ms grande, esto es, para maximizar el ngulo de ms pequeo sobre todas las triangulaciones. Esto ocurre para hacer precisamente la triangulacin de Delauny! De hecho, una declaracin algo ms fuerte puede ser hecha, cul nosotros ahora describimos despus de introducir alguna notacin. Sea T una triangulacin de un grupo de puntos S, y sea su secuencia de angulos( 1, 2, , 3t), una lista de los ngulos de los tringulos, clasificados del ms pequeo al ms grande, con t el nmero de tringulos en T. El nmero t es uno constante para cada S (Ejercicio 5.5.6[4 ] ). Podemos definir una relacin entre dos triangulaciones del mismo grupo del punto, T y T ', eso trata de capturar la gordura de los tringulos. Diga que T T (T es ms gorda que T) si la secuencia de ngulo de T es lexicogrficamente mayor que la secuencia de ngulo de T ': Ya sea 1 > 1, o 1 = 1 y 2 > 2 o 1 = 1 y 2= 2 y 3 > 3,, etctera. Edelsbrunnerr (1987, p. 302) prob este teorema: Theorem5.5.2..La triangulacin de Delaunay T=D (P) es lo mximo con respecto a la relacin de la gordura - ngulo: T T para cualquier otra triangulacin T ' de P. En particular esto dice que la triangulacin Delaunay maximiza el ngulo menor. 1.5.3 El crculo Vaco ms grande
199
200
201
Supongo que f (p) es un mximo con p en H y el crculo incluye justamente s1 de sitios. Primero, que no puede ser esa p est en un vrtice de H, pues los vrtices de H es todos los sitios mismos, y esto implicara a esa f (P) = 0. As es que p est en el interior de un borde de H. Entonces moviendo p en uno u otro caso a lo largo de h debe aumentar su forma de distancia s1, cortado en rodajas por un plano vertical (la Figura 5.9). Si, sin embargo, el crculo centr en p contiene s1 de dos sitios y s2, entonces es posible que la direccin a lo largo de la bisectriz de los sitios que aumenta sus distancias sea la direccin que va fuera del buque. As adecuadamente podra ser que f (P) est en el mximo. Hemos mostrado este hecho: Lema5.5.4 si el centro p de un circulo vaci mas grande permanece en el buque de sitios H (S), Entonces p debe permanecer sobre un borde Voronoi.
202
El algoritmo Nosotros ahora hemos establecido nuestro meta: Ha encontrado un grupo finito de punto que son centros potenciales de crculos vacos ms grandes: Los vrtices de Voronoi y las intersecciones entre bordes de Voronoi y el buque de sitios. Esto sugiere el algoritmo 5.1, debido a Toussaint (1983a). Note que no cualquier vrtice de Voronoi est necesariamente dentro del buque (la Figura 5.14), que necesita comprobar que v H dentro del algoritmo. Una implementacin ingenua de este algoritmo requerira el tiempo cuadrtico en n, pero localizar un vrtice Voronoi en H e intersecar un borde de Voronoi con e puede estar consumado en el tiempo O (log n), y estas eficiencias conducen a un algoritmo O (n log n) en conjunto. Dejamos Detallamos para ejercitar a 5.5.6[6. El algoritmo: crculo Vaco MS GRANDE Computar el diagrama Voronoi V (s) de la S de sitios. Computar el buque convexo H=H (S). Para v del vrtice Voronoi haga Si la v est dentro de H: V H entonces El radio de cmputo si el grupo cerrado de gente gir alrededor de v y actualizacin llega al lmite. Para cada e del borde Voronoi haga El cmputo p =e H, la interseccin del con el lmite del buque. El radio de cmputo de crculo gir alrededor de actualizacin de la P llegue al lmite. El regreso llegue al lmite.
203
Lo mnimo que se extiende a lo largo un rbol. Lo mnimo que se extiende a lo largo un rbol. (MST)(A minimum spanning tree) de un grupo de puntos es la longitud del arbol que se extiende a lo largo de todos los puntos: es decir en rbol ms pequeo cuyos nodos son precisamente esos en el grupo. Cuando el largo de un borde es medido por la longitud usual del segmento Euclideano conectando sus puntos finales, el rbol es a menudo llamado el Euclideano mnimo extendindose a lo largo de rbol, abreviado a EMST. Aqu slo considerarn las longitudes Euclideano y as tambin dejarn caer al modificador redundante. Un ejemplo es mostrado en Figure 5.15. MST tienen muchas aplicaciones. Pues el ejemplo es la topologa de la red que minimiza la longitud total del alambre que usualmente minimiza ambos costo y el tiempo que se demora. Algoritmo de Kruskal Aqu consideraremos el problema de computar el MST de un grupo de puntos en el plano. Veamos primero el problema ms general de computar el MST para una grfica G. Aunque es de ninguna manera obvio, una estrategia vida sin discernimiento es encontrar al MST, basada en la intuicin simple que un rbol ms pequeo debera estar cercano de los bordes ms pequeos. Esto sugiere que puede estar tal rbol construido arriba del incrementalmente aadiendo borde ms pequeo, todava ningn explorado, lo cual tambin mantiene un arbolado (alifaticidad). Este algoritmo es conocido como el algoritmo de Kruskal y se publico en 1956. Sea T el rbol incrementalmente construido, y sea la notacin T + e quiere decir que el rbol T une el borde e. El algoritmo Kruskal se muestra en Algoritmo 5.2. No nos detendremos para probar este algoritmo, esta bien?. pero slo demanda que su complejidad se domina por el primer paso ordenando. Esto requiere (E log E) de tiempo, dnde la E es el nmero de bordes en la grfica.
El algoritmo: El ALGORITMO DE KRUSKAL Ponga en cortocircuito bordes de G por el largo por ah: E1, e2 Inicializar T para que este vaco Mientras la T no avanza a rastras haga Si T + e1 es acclica Entonces T + T + ei Juan Carlos Gutirrez Barquero____________________________________________ Ii + 1 El algoritmo 5.2 el algoritmo de Kruskal.
204
MST D (p) Para el MST de puntos en el plano, hay ( n ) bordes, as es que la complejidad 2 del paso de clasificacin es O (n2 log n) si es cargada fuera en la grfica completa. Para llamar a este registro de los bordes de la triangulacin de Delaunay de proximidad en algn sentido, es razonable esperar que slo los bordes de Delaunay alguna vez necesiten ser usados para construir un MST. Y afortunadamente esto es cierto, como se muestra en el siguiente teorema. Teorema 5.5.5 Lo mnimo que se extiende a lo largo un rbol es un subconjunto de triangulacin Delaunay: MST D (p). Prueba. Queremos mostrar que si ab MST, entonces ab D. Implica that ab MST y suponga lo contrario que ab MST. Entonces tratamos de derivar una contradiccin enseando lo que se supuso MST no es mnimo. Recuerde que si ab D, entonces hay un crculo vaco a travs de a y b (Propiedad V7 y Teorema 5.3.1) .en caso contrario ab D, ningn crculo a travs de a y b puede estar vacos. En particular, el crculo de dimetro ab debe de tener un sitio dentro de este. As se supone que C est en este crculo, como se muestra en figura 5.16. Entonces | ac | < | ab |, y |bc|< |ab|; Estas desigualdades tienen aplicacin aun si C est en el crculo, puesto que la C es distinta de a y b. La extraccin de ab desconectar el rbol en dos rboles internos, con a en primera parte, Ta, y b en el otro, Tb. Suponga sin la prdida de generalidad que e esta en Ta. Elimine ab y aada el borde bc para hacer un rbol nuevo, T = Ta bc +Tb. Este rbol es mas corto, as el nico nico usado ab, no podra serminimo. Hemos alcanzado una contradiccin negando que ab est en D, as es que debe ser ese ab D.
205
Esto entonces produce una mejora en el primer paso de algoritmo de Kruskal: Primero encuentre la triangulacin de Delaunay en el tiempo O (n Long n), y entonces clasifique slo esos bordes O (n), en el tiempo O (n logn). Resulta lo dems de algoritmo de Kruskal puede ser implementado para poner a funcionar en O (n log n), para que la complejidad total por encontrar el MST para el grupo de n untos en el plano es O (n log n). 5.5.5. El Problema del Vendedor de viajes. Uno de los problemas ms estudiados en la informtica es el problema del vendedor de viajes: Encuentre el ms pequeo camino cerrado que visita cada punto en un grupo dado. Tal camino se llamado El camino Vendedor de viajes(TSP); imagine los puntos como ciudades que el vendedor debe visitar en el orden arbitrario antes de devolver casa. Este problema tiene tremenda importancia prctica, no slo para esa aplicacin si no porque muchas otras problemticas pueden reducirse a l. Se ha probado que desafortunadamente, el problema es duro NP, un trmino tcnico que ningn algoritmo polinmico conoce para resolverlo (Garey y Johnson 1979); Ni parece probablemente al momento de escribir la presente que a ser encontrada. Las combinaciones de significado prctico y la inflexibilidad han conducido a una bsqueda para los algoritmos de heursticas efectivos y de aproximacin. Uno de los algoritmos de la aproximacin ms simples es basado en la triangulacin de Delaunay, Va lo mnimo que Se extiende a lo largo el rbol. La idea es ms bien algo simple, pero no obstante hace un trabajo razonable. Encuentra al MST para el grupo de puntos, y simplemente lo lleva cabo y lo all por la manera ilustrada en Figure 5.17. Debera estar claro que la excursin construida por aqu tiene exactamente dos veces el largo del MST, desde que cada borde del rbol se cruza una vez en cada direccin.
206
Ahora obtenemos un lmite dentrote que esta mal este doble-MST recorrido podra ser. Sea M la longitud de Lo mnimo que se extiende a lo largo un rbol y M2 la longitud de a doble-MST; claro M2 = 2M. Sea T la longitud de El camino de un Vendedor de viajes r y T1 la longitud de un TSP con un borde removido. Note que T1 se extiende a lo largo del rbol.
Las siguientes desigualidades son inmediatas: T1 < T, M T1, M < T, M2 < 2T. Esto entones logra un lmite superior constante en la calidad del recorrido: Lo doble-MST no est peor que dos veces la longitud de TSP.
207
Este resultado puede ser mejorado con heursticas diversas. Esbozar slo el ms simple tan heurstico, lo cual se basa en la determinacin comprensible para no volver a visitar un sitio dos veces. El recorrido del camino doble-MST de entrada, con la modificacin que si el prximo sitio ya se ha visitado hasta ahora por el camino, salte el sitio y considera conectarse al prximo uno a lo largo del doble-MST recorrido. Esto hace el efecto de tomar una ruta ms directa para recorrer MST . Si ponemos en un ndice los sitios por el orden en que ellos se visitan a lo largo del recorrido del MST, a algunos sitios que Si podra conectar para Sj por un segmento de la lnea recta o un atajo al recorrido, considerando que el recorrido doble-MST sigue un camino encorvado Si, Si+1 , , Sj-1,Sj.. Heurstico puede ser nico acorta el camino. Un ejemplo es mostrado 5.18. Note que el camino fue acortado. Desafortunadamente este heuristico no garantiza un desempeo mejorado, pero una variacin leve Conocido como las gamas Heursticas Christofides. Usa un grupo de segmentos llamados un El mnimo de Euclideano emparejando como un gua para atajos y puede garantizar un longitud del camino no ms de (3/2) T, eso es, no ms de 50 % ms largo que lo ptimo. Ms heursticos sofisticaron generalmente encuentran un camino dentro de un poco porcentaje ptimo (Bentley 1992), aunque este desempeo no est garantizado en su estado actual para el algoritmo citado anteriormente. Un resiente descanso terico es sin dudarlo el esquema de aproximacin de Polinomio-tiempo para el TSP, acerca de lo mejor, puede ser esperanza para un problema completo a NP. ste es un mtodo de llegar dentro (1 + ) de > 0, en un tiempo O (np), dnde la p son optativo para cualquier . Vea a Arora (1996) y Mitchell (1996). proporcionales para 1/ 5.5.6 Los ejercicios 1. El grado de NING. Cul es grado mnimo de salida de un nodo de un Grafico de vecino mas cercano(NING) (la Seccin 5.5.1) de n puntos en dos 2 dimensiones? Cul es el grado mximo de un nodo? Demuestran ejemplos que justifiquen su respuesta, e intento probar que son mximos. 2. NNG y D [Fcil] . Encuentran un ejemplos que muestre ese NNG pueden ser un subconjunto correcto de D (p). 3. NND D. Ponga a prueba a Lema5.5.1: Si la b es una vecina prxima de a. Entonces ab D (p). 4. Los Nmeros de tringulos en una estrangulacin. Comprobar que el nmero de tringulos t en cualquier triangulacin de algn grupo de puntos reparados S esat una constante toda triangulacin de S tiene la misma t. 5. El vrtice de Voronoi no un mximo local. Construya un grupo de puntos que tiene un vrtice de Voronoi estrictamente p dentro del buque, algo
208
209
11. Los puntos ms remotos de Voronoi. Defina el diagrama de puntos ms remotos de Voronoi F (P) asociado cada punto del plano para el sitio que es su vecino ms remoto, el sitio que est ms lejos (fuera). Los puntos con el vecino mas cercano de una region de voronoi mas remota; Los puntos con dos vecinos mas lejanos limitan con forma de bordes F (P). Vea Figura 5.19. a. Que es F (P) para dos sitios? b. Cul es F (P) para tres sitios? c. Derive algunas propiedades estructurales de diagrama ms remoto Voronoi, parecido al Delaunay y Voronoi en Seccin 5.3.1 y 5.3.2. Uso Figure 5.19 y 5 5.2.3. Uso 5.19 para ayudar a formar a hiptesis
210
Ejes Medios El diagrama de Voronoi puede ser generalizado en varias direcciones, y algunas de estas generalizaciones tienen importante significado prctico. En esta seccin tocamos una generalizacin, una de las ms simples: aceptando un grupo de sitios que son un grupo infinitos de puntos, en particular el lmite contino de un polgono.
En la seccin 5.20 definimos el diagrama de Voronoi como el grupo de puntos cuyo sitio ms cercano no es nico. Estos puntos son equidistantemente mejor cerrados en dos o ms sitios. Define los ejes medios de un polgono P, que estn dentro de un grupo de puntos internos P que un punto bien cerrado entre los puntos de P. Una definicin muy similar puede ser usada para una coleccin de puntos arbitrarios, pero aqu examinaremos solo el caso donde los puntos forman el lmite de un polgono. El eje medio de un rectngulo se muestra en la figura 5.20; cada punto sobre el segmento horizontal dentro del rectngulo est equidistante de los puntos verticales de arriba abajo y estn por encima y por debajo de los lados del rectngulo. Cada punto sobre un segmento diagonal esta equidistante de dos lados adyacentes del rectngulo y los dos puntos finales del segmento horizontal estn equidistante de tres lados del rectngulo.
211
212
El eje medio de un polgono de n vrtices puede ser construido en 0 (n log n) time; asintoticamente menor pero ms prcticos de logaritmos estn disponibles. Para polgonos convexos, 0 (n) veces es suficiente.
Ejercicios Eje medio de un polgono no convexo. Mostrar por ejemplo que el eje medio de un polgono no convexo puede contener segmentos curvados. Qu puedes decir acerca de la forma funcional de estas curvas?
213
Eje medio de un polgono. Describe lo que debe parecer el eje medio de un polgono. Estructura recta. Aichholzer, Alberts, Aurenhammer & Grtner, introdujo una estructura que es similar al eje medio, pero compuesta de segmentos rectos incluso para polgonos no convexos. Mover cada borde de un paralelo al mismo interior a una velocidad constante con bordes adyacentes encogiendo y creciendo as que los vrtices viajan a lo largo del ngulo bisector. Cuando un borde se encoge hasta la longitud cero, sus bordes vecinos se hacen adyacentes. Cuando un vrtice reflejo choca hacia adentro de un borde, el poligono se agrieta y el proceso de encogimiento de las piezas contina. Trabaja manualmente la estructura recta con unas formas letras conectadas del alfabeto: T, E, X. Forma algunas suposiciones acerca de las propiedades de la estructura recta.
Conexin con el Convexo Hulls El 1986 Ellels Brunner & Seidel decubri una bella conexin entre la triangulacin de Delaunay y el convex hulls en una de las ms altas dimensiones: primero explicar entre el convex hull bidimensional y la triangulacin unidimensional de Delaunay (que son admitimademente triviales) y entonces generaliza la triangulacin bidimensional de Delaunay y el tridimensional convex hull. Entonces esta conexin nos dar un mtodo fcil para calcular la triangulacin de Delaunay y del diagrama de Voronoi, va tridimensional hulls triangulacin unidimensional de Delaunay. Empezaremos en una dimensin donde la matemtica es transparente sea P= {x1,,xn} un conjunto de puntos sobre el eje x. Claramente la triangulacin unidimensional de Delaunay es simple el camino conecta x1 a x2 a xn , pero veremos que esto es una proyeccin sobre el eje x de un conjunto de puntos bidimensionales con coordenadas (xi, x2i). Estos puntos pueden ser vistos como una proyeccin de la ascendencia de x en la parbola z= x2. Es trivialmente verdadero que el connuex hull de estos puntos bidimensionales proyectado hacia abajo a la triangulacin unidimensional de Delaunay, tanto como el borde ms alto del hull es descartado, pero hay mucho ms aqu que esta observacin trivial que puede ser aclarada con la consideracin de las tangentes a la parbola.
214
La pendiente de la parbola z= x2 en el punto x= a es 2a (porque dz/dx= 2x). De esta manera la ecuacin de la tangente a la parbola en el punto (a, a2) es z-a2= 2a (x-a) z= 2a x-a2 En preparacin para estudiar el mismo proceso en tres dimensiones, ahora investigaremos la interseccin entre esta tangente y la parbola cuando la tangente es trasladada verticalmente una distancia r2. Cuando la tangente es aumentada por esta cantidad su ecuacin se convierte en z=2a x-a2 + r2 Entonces la tangente aumentada intersecta la parbola en + r lejos de a, el punto original de tangencia. Nota que x= a + r puede ser pensado como la ecuacin de un circulo unidimensional de radio r centrado en a. Esto es ilustrado en la figura 5.23 con a= 5 y r= 3 as que el disco es el segmento [2,8]. Triangulacin Bidimensional de Delaunay Repetimos el mismo anlisis en dos dimensiones. El paraboloide es z= x2 + y2, (Ver la figura 5.24) toma los sitios/puntos dados en el plano y los proyecta hacia arriba hasta que toca el paraboloide, eso es, trazar cada punto como sigue: (xi, yi) | (xi, yi, x2i + y2i)
215
Ahora cambiamos este plano superior por r2, exactamente como cambiamos la lnea tangente en la subseccin previa z= 2a x +2b y (a2 + b2)+ r2 (x-a)2 + (y-b2)= r2
216
El plano cambiado intercepta el paraboloide en una curva (una elipse) que proyecta a un crculo. Esto es ilustrado en la figura 5.27 y 5.28. Ahora revisemos desde un punto de vista para dirigirnos s la triangulacin Delaunay. Considere el plano a travs de tres puntos en el paraboloide = ( pi, pj, pk) que forma una cara del buque de convexo en tres dimensiones. Este plano parte de la paraboloide. Si traducimos verticalmente hacia abajo, entonces en algn punto cesar de intersecar el paraboloide. Digamos que el ltimo punto que toca es (a, b, a2 b2). Entonces podemos observar como un cambio ascendente de este plano contiguo; Llame a la cantidad de cambio r2. Ahora debera estar claro que el anlisis previo tiene aplicaciones. Desde esta en una cara inferior del buque, todo las otras puntos del paraboloide estn arriba. Desde que estn arriba , estn ms que el r2 arriba, cul es el r2 debajo. Por eso estos puntos se proyectan fuera del crculo de radio r en el plano x y. Por eso el crculo determinado adentro de los planos x y est vaco en todos los otros sitios. Por eso forma un tringulo Delaunay. Por eso cada cara triangular inferior del buque convexo es propia de un tringulo Delaunay. Por eso la proyeccin del fondo del buque convexo se proyecta para la triangulacin Delaunay! Otra vez evacue a Figure 5.26. Djeme explicar esta compenetracin importante otra vez de otra manera. Comience con el plano t contiguo para el paraboloide por encima de p = (a, b). Su punto de contacto se proyecta hacia abajo para p. Ahora muvase t arriba. La proyeccin de su interseccin con el paraboloide es un crculo en expansin puesto en el centro en p. Cuando los t golpes una punto q en el paraboloide que esta por encima de un sitio, las intercepciones del crculo en expansin en el sitio en el plano que es la proyeccin de q. As el crculo est vaco t hasta los lmites exteriores, cundo atraviese los tres sitios cuya proyeccin forma la cara del buque del tringulo soportada por . Un corolario til para el debate citado anteriormente es ste:
217
Corolario 5.7.1 Cuatro puntos (xi, yi), i = 1, 2, 3, 4, consisten en una mentira del crculo si (xi, yi, xi2 yi2) en un plano. La coplanaridad de estas puntos puede ser comprobada viendo si el volumen del tetraedro que determinan (la Ecuacin 1.15 y 4.6) es cero.
La implicacin Teorema 5.7.2 La triangulacin de Delaunay de un grupo de puntos en dos dimensiones es precisamente la proyeccin para el Plano x y del buque convexo inferior de lo transformado apunta en tres dimensiones, transformado por mapeo arriba para el paraboloide z = x2 y2. Desde que el buque convexo en tres dimensiones puede ser computado en el tiempo O (la Seccin 4.2.2) (n log n), esto significa que la triangulacin de Delaunay puede ser computada en el mismo tiempo lmite. Una vez que la triangulacin Delaunay est en tus manos, es relativamente fcil computar el diagrama Voronoi (el Ejercicio 5.7.5[2 ] ). Esto conduce a otro algoritmo O (n log n) para construir el diagrama de Voronoi. Como se podra esperar, esta relacin entre diagramas Voronoi y podra abombar buques que yo una dimensin ms alta mantengo en dimensiones arbitrarias. As ambos el diagrama Voronoi y la triangulacin Delaunay en tres dimensiones pueden forjarse de un buque convexo en cuatro dimensiones. De hecho, puede ser que el ms uso comn de cdigo del buque del 4D es para construir mallas slidas de Delaunay tetradrico. En general, el diagrama de Voronoi dual para un grupo de puntos de d-dimensional es la proyeccin del buque inferior de puntos en d + 1 dimensin. La implementacin de la Triangulacin de Delaunay: El cdigo O (n4) Teorema 5.7.2 el cdigo conciso permite increblemente computar la triangulacin de Delaunay, si uno es indiferente sobre la complejidad de tiempo En particular, si O (n4) es aceptable (y raramente lo es), entonces la triangulacin de Delaunay puede ser computada con menos esas treinta lneas de cdigo de la C! Esto es presentado en cdigo 5.1 en parte como la curiosidad, pero tambin a enfatiza cmo la comprensin profunda de geometra puede conducir al cdigo limpio.
218
/*Intrda de puntos y computar z=x^2+y^2*/ scanf("%d",&n); for(i=0; i<n; i++) { scanf("%d %d",&x[i],&y[i]); z[i]=x[i]*x[i]+y[i]*y[i]; } /*por cada tres (i,j,k)*/ for(i=0;i<=n-2;i++) for(j=0;j<=n-2;j++) for(k=0;k<=n-2;k++) if(j!=k) /*computar la triangulacion normal*/ xn=(y[j]-y[i]*z[k]-z[i])-(y[k]-y[i]*z[j]-a[i]); yn=(x[k]-x[i]*z[j]-z[u])-(x[j]-x[i]*z[k]-z[i]); zn=(x[j]-x[i]*y[k]-y[i])-(x[k]-x[i]*y[j]-y[i]); /*solo examina las caras del boton de la paraboloide zn <0*/ if(flag==(zn<0)) /*para otro punto m*/ for(m=0;m<n;m++) { /*revizar si m se acerca (i,j,k)*/ flag=flag&& ((x[m]-x[i]*xn+ (y[m]-y[i]*yn+ (z[m]-z[i]*zn<=0; if(flag) printf("%d\t%d\t%d\n",i,j,k);+ } } La estructura O (n4) del cdigo es evidente yo los cuatro de para lazos anidados. Para cada triple de puntos (i, j, k), el programa revisa y ve si todos los otros puntos m estn o por encima del plano conteniendo i, j, y k. Si es as, (i, j, k) es salida como tringulo Delaunay. (La smil arridad para el algoritmo del buque de dos dimensiones en Algoritmo 3.2 debera ser evidente).
219
La prueba de por encima de plano es realizada chocheando la orientacin exterior normal para el tringulo, (xn, yn, zn), con un vector de punto para apuntar m. Aunque es interesante para ver tal cdigo sucinto computar un propsito guste la triangulacin Delaunay, es imprctica para varias razones: 1. El cdigo devuelve todos los tringulos dentro de una cara de triangulacin Delaunay cuyo lmite consta de cuatro o ms puntos del cocircular. As una mueca cuadrada resulta en salida cuatro de tringulo, representando las dos triangulaciones del cuadrado. Obtener ms salida til requerira el postprocesamiento. 2. Hay ineficiencias obvias en el cdigo (por ejemplo, la m-loop podra quebrarse cuando un punto es descubierto debajo del plano del I, j, k). Estos podran repararse fcilmente al precio de alargarle un poco, pero
carreras con n = 100 y n = 200 puntos, el tiempo de computar fue 12 y 239 segundos respectivamente, exhibiendo un ms de 24 incremento de 16 pliegues para el doble nmero de puntos. Esto indica 1,000 tan n tomaba varios das.
Triangulacin de Delaunay 3D cscara: O (el n2) el Cdigo Es una tarea fcil convertir el cdigo cuadrtico desarrollado en Captulo 4 para construir el buque del 3D en el cdigo cuadrtico para construir la triangulacin Delaunay. Toda la complejidad est en el cdigo del buque (cdigo de casi 1,000 lneas de ) acerca del razonamiento que entr en Teorema 5.7.2. Las modificaciones adicionales son relativamente menores.
220
221
222
5.8 Conexin a arreglos Tenemos que mostrar que la triangulacin de Delaunay puede ser derivada de la transformacin paraboloide e indican que es fcil de obtener el diagrama de Voronoi si es posible obtener el diagrama de Voronoi directamente de la transformacin del paraboloide. Aunque todo esto se entiende que tienes que esperar al siguiente capitulo (Seccin 6.7) y mostraremos la conexin que se realiza utilizando las ecuaciones mas relevante. 5.8.1 Diagrama de Voronoi unidimensional Considerando dos tangentes examinadas en la seccin 5.7.1 (ecuacin 5.4) siendo x=a y otro siendo x=b: z=2ax-a2 z=2bx b2 Donde se intersecan resolviendo las ecuaciones simultneas la solucin sera 2ax-a2 = 2bx b2, x(2a 2b)=a2 b2, x=(a+b)(a-b) 2(a-b) x= a+b 2 De esta manera la proyeccin de las intersecciones estn adyacentes al diagrama de Voronoi y al grupo de puntos
223
Bibliografa [1] M. Berg, M. Kreveld, M. Overmars, O. Schwarzkopf. Computational Geometry, Algorithms and Applications. Springer, 1997. [2] M. Kreveld, J. Nievergelt, T. Roos, P. Widmayer. Algorithmic Foundations of Geographic Information Systems. Springer, 1997. [3] J. O'Rourke. Computational Geometry in C. Cambridge University Press, 1994. [4] F. P. Preparata y M. I. Shamos. Computational geometry: an introduction. Springer-Verlag, New York, 1985. 73
224