Graficos de C

225
Bismarck Salvador Traña López__________________________________________UNI Introducción a la Programación grafica en C. Para la mejor comprensión de este tutor hemos realizado un análisis de las Funciones que se suelen utilizar con mucha frecuencia al programar en el modo grafico de C, dando como resultado la librería conio.h, dos.h, stdlib.h, y evidentemente graphics.h. En este pequeño tutor solo haremos énfasis en estas librerías, puesto que al final del libro se encuentran las demás librerías que comúnmente encontramos con frecuencia en el programa. Muchos libros nos marean dándonos conceptos los cuales se aprenden conforme programando; esto no significa, que no sean importan tantees los ejercicios que aquí te enseñamos te ayudaran a darte todo el conocimiento así como también te los daremos conforme avancemos así que dejemos de hablar y aventurémonos en el mundo de la programación grafica. Lo primero que debemos saber al realizar una grafica son las dimensiones del ordenador (Monitor) en modo texto las dimensiones de este es 25X80 esto dependiendo de la versión de video instalada. En el modo grafico estas dimensiones cambian dependiendo del tipo de macro de inicialización se realice(ver Macro modos). Quedando la mas común de 640X480 modo VGA. A la hora de desarrollar un programa gráfico se debe tener en cuenta los siguientes cuatro puntos: 1. Especificar el fichero o librería graphics.h # include<graphics.h> 2. Inicializar el modo grafico correspondiente mediante la Función initgraph; Initgraph(&adaptador,&modo,”dirección de los archivos bgi”); 3. Crear y manipular las figuras graficas. /*Desarrollo del programa*/ 4. Restaurar el modo de video antes de salir del programa(restaurar el modo texto) closegraph() o restorecrtmode() Juan Carlos Gutiérrez Barquero____________________________________________ 1

description

Programacion grafica en C

Transcript of Graficos de C

Page 1: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

Introducción a la Programación grafica en C. Para la mejor comprensión de este tutor hemos realizado un análisis de las Funciones que se suelen utilizar con mucha frecuencia al programar en el modo grafico de C, dando como resultado la librería conio.h, dos.h, stdlib.h, y evidentemente graphics.h. En este pequeño tutor solo haremos énfasis en estas librerías, puesto que al final del libro se encuentran las demás librerías que comúnmente encontramos con frecuencia en el programa. Muchos libros nos marean dándonos conceptos los cuales se aprenden conforme programando; esto no significa, que no sean importan tantees los ejercicios que aquí te enseñamos te ayudaran a darte todo el conocimiento así como también te los daremos conforme avancemos así que dejemos de hablar y aventurémonos en el mundo de la programación grafica. Lo primero que debemos saber al realizar una grafica son las dimensiones del ordenador (Monitor) en modo texto las dimensiones de este es 25X80 esto dependiendo de la versión de video instalada. En el modo grafico estas dimensiones cambian dependiendo del tipo de macro de inicialización se realice(ver Macro modos). Quedando la mas común de 640X480 modo VGA.

A la hora de desarrollar un programa gráfico se debe tener en cuenta los siguientes cuatro puntos:

1. Especificar el fichero o librería graphics.h

# include<graphics.h>

2. Inicializar el modo grafico correspondiente mediante la Función initgraph;

Initgraph(&adaptador,&modo,”dirección de los archivos bgi”);

3. Crear y manipular las figuras graficas.

/*Desarrollo del programa*/

4. Restaurar el modo de video antes de salir del programa(restaurar el modo texto)

closegraph() o restorecrtmode()

Juan Carlos Gutiérrez Barquero____________________________________________ 1

Page 2: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

Otra de las cosas importantes que debemos saber es que Funciones contiene graphics.h

Funciones de Graphics.h Esta librería se encuentra los prototipos de las Funciones que manipulan la parte gráfica 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

linesettingstype palettetype

textsettingstype viewporttype

Entre los macros se encuentran: colores drivers enlazar

errores fuentes línea

modos put_op trama

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 más efectiva nuestros gráficos.

Juan Carlos Gutiérrez Barquero____________________________________________ 2

Page 3: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

Colores :

Colores de Fondo

Constante Valor Significado BLACK 0 Negro BLUE 1 Azul GREEN 2 Verde CYAN 3 Cían RED 4 Rojo MAGENTA 5 Magenta BROWN 6 Marrón LIGHTGRAY 7 Gris Claro DARKGRAY 8 Gris Oscuro LIGHTBLUE 9 Azul Claro LIGHTGREEN 10 Verde Claro LIGHTCYAN 11 Cían Claro LIGHTRED 12 Rojo Claro LIGHTMAGENTA 13 Magenta Claro YELLOW 14 Amarillo WHITE 15 Blanco

Modo de 16 Colores

Constante Valor Significado BLACK 0 Negro BLUE 1 Azul GREEN 2 Verde CYAN 3 Cían RED 4 Rojo MAGENTA 5 Magenta BROWN 6 Marrón LIGHTGRAY 7 Gris Claro DARKGRAY 8 Gris Oscuro LIGHTBLUE 9 Azul Claro LIGHTGREEN 10 Verde Claro LIGHTCYAN 11 Cían Claro LIGHTRED 12 Rojo Claro LIGHTMAGENTA 13 Magenta Claro YELLOW 14 Amarillo WHITE 15 Blanco

Juan Carlos Gutiérrez Barquero____________________________________________ 3

Page 4: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

Color del modo CGA

Número Paleta Color 1 Significado Color 2 Significado Color 3 Significado

0 CGA_LIGHTGREEN

Verde Claro CGA_LIGHTRED Rojo Claro CGA_YELLOW Amarillo

1 CGA_LIGHTCYAN

Cían Claro CGA_LIGHTMAGENTA Magenta Claro CGA_WHITE Blanco

2 CGA_GREEN

Verde CGA_RED Rojo CGA_BROWN Marrón

3 CGA_CYAN Cían CGA_MAGENTA Magenta CGA_LIGHTGRAY Gris Claro

Valor asignado: 1 2 3 Nota: Color 0 se reserva para el color de fondo y se asigna con lo función setbkcolor, pero los demás colores son fijos. Estas constantes se usan con setcolor.

Colores para las paletas.

Constante (CGA) Valor Constante (EGA/VGA) Valor BLACK 0 EGA_BLACK 0 BLUE 1 EGA_BLUE 1 GREEN 2 EGA_GREEEN 2 CYAN 3 EGA_CYAN 3 RED 4 EGA_RED 4 MAGENTA 5 EGA_MAGENTA 5 BROWN 6 EGA_LIGHTGRAY 7 LIGHTGRAY 7 EGA_BROWN 20 DARKGRAY 8 EGA_DARKGRAY 56 LIGHTBLUE 9 EGA_LIGHTBLUE 57 LIGHTGREEN 10 EGA_LIGHTGREEN 58 LIGHTCYAN 11 EGA_LIGHTCYAN 59 LIGHTRED 12 EGA_LIGHTRED 60 LIGHTMAGENTA 13 EGA_LIGHTMAGENTA 61 YELLOW 14 EGA_YELLOW 62 WHITE 15 EGA_WHITE 63 Nota: Estas constantes se usan con las Funciones setpalette y setallpalette.el cual veremos en capítulos posteriores

Juan Carlos Gutiérrez Barquero____________________________________________ 4

Page 5: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

Fuentes:

Fuentes para Texto

Constante Valor Valor DEFAULT_FONT 0 Fuente bitmap de 8x8 TRIPLEX_FONT 1 Fuente escalable de tipo triple SMALL_FONT 2 Fuente escalable pequeña SANS_SERIF_FONT 3 Fuente escalable de tipo sans serif GOTHIC_FONT 4 Fuente escalable de tipo gótico SCRIPT_FONT 5 Fuente escalable de tipo manuscrito SIMPLEX_FONT 6 Fuente escalable de tipo manuscrito simple TRIPLEX_SCR_FONT 7 Fuente escalable de tipo manuscrito triple COMPLEX_FONT 8 Fuente escalable de tipo complejo EUROPEAN_FONT 9 Fuente escalable de tipo europeo BOLD_FONT 10 Fuente escalable en negrita

Dirección del Texto

Constante Valor Significado

HORIZ_DIR 0 Texto horizontal

VERT_DIR 1 Texto vertical

Justificación de Texto en la Horizontal

Constante Valor Significado LEFT_TEXT 0 Justificar a la izquierda CENTER_TEXT 1 Centrar el texto RIGHT_TEXT 2 Justificar a la derecha

Justificación de Texto en la Vertical

Constante Valor Significado

BOTTOM_TEXT 0 Justificar debajo CENTER_TEXT 1 Centrar el texto

TOP_TEXT 2 Justificar arriba

Juan Carlos Gutiérrez Barquero____________________________________________ 5

Page 6: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

Tramas: Tramas predefinidas

Constante Valor Significado

EMPTY_FILL 0 Rellena con el color de fondo SOLID_FILL 1 Rellena enteramente LINE_FILL 2 Rellena con líneas horizontales: --- LTSLASH_FILL 3 Rellena con rayas finas: /// SLASH_FILL 4 Rellena con rayas gruesas: /// BKSLASH_FILL 5 Rellena con rayas inversas y finas: \\\ LTBKSLASH_FILL 6 Rellena con rayas inversas y gruesas: \\\ HATCH_FILL 7 Rellena con líneas cruzadas cuadriculadamente: +++ XHATCH_FILL 8 Rellena con líneas cruzadas diagonalmente: XXXX INTERLEAVE_FILL 9 Rellena con líneas entrelazadas WIDE_DOT_FILL 10 Rellena con lunares bastante distanciados CLOSE_DOT_FILL 11 Rellena con lunares poco distanciados USER_FILL 12 Rellena con la trama definida por el usuario 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 Gráficos

Dispositivo/Constante Valor DETECT 0 CGA 1 MCGA 2 EGA 3 EGA64 4 EGAMONO 5 IBM8514 6 HERCMONO 7 ATT400 8 VGA 9 PC3270 10

Líneas: Estilos de Líneas

Constante Valor Significado

SOLID_LINE 0 Línea continua _______ DOTTED_LINE 1 Línea hecha con puntos …….. CENTER_LINE 2 Línea centrada ––––––––––– DASHED_LINE 3 Línea discontinua _._._._. USERBIT_LINE 4 Línea definida por el usuario Nota: El grosor es definido escribiendo NORM_WIDTH para rallas normales y THICK_WIDTH para líneas mas gruesos

Juan Carlos Gutiérrez Barquero____________________________________________ 6

Page 7: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

Grosores para Líneas Modos de Escritura

Constante Grosor Valor Significado

NORM_THICK 1 Grosor es de 1 píxel

THICK_WIDTH 3 Grosor es de 3 píxeles

Constantes Valor Significado COPY_PUT 0 Píxeles de la línea sobrescriben

los píxeles existentes XOR_PUT 1 Píxel de la pantalla son el

Resulta do de la operación OR de los píxeles existentes y los de la línea

Modos:

Modos Gráficos Dispositivo Modo/Constante Código Resolución Paleta Pagina

CGA CGAC0 0 320X200 4 Clores 1 CGAC1 1 320X200 4 Clores 1 CGAC2 2 320X200 4 Clores 1 CGAC3 3 320X200 4 Clores 1 CGAHI 4 640X200 2 Clores 1 MCGA MCGAC0 0 320X200 4 Clores 1 MCGAC1 1 320X200 4 Clores 1 MCGAC2 2 320X200 4 Clores 1 MCGAC3 3 320X200 4 Clores 1 MCGAMED 4 640X200 2 Clores 1 MCGAHI 5 640X480 2 Clores 1 EGA EGALO 0 640X200 16 Colores 4 EGAHI 1 640x350 16 Colores 2 EGA64 A64LO 0 640X200 16 Colores 1 EGA64HI 1 640X350 4 Colores 1 EGAMONO AMONOHI 3 640x200 2 Colores 1* / 2** VGA VGALO 0 640X200 16 Colores 2 VGAMED 1 640x350 16 Colores 2 VGAHI 2 640X480 16 Colores 1 ATT400 ATT400C0 0 320x200 4 Colores 1 ATT400C1 1 320x200 4 Colores 1 ATT400C2 2 320x200 4 Colores 1 ATT400C3 3 320x200 4 Colores 1 ATT400MED 4 640x400 2 Colores 1 ATT400HI 5 640x400 2 Colores 1 HERC HERCMONOHI 0 720X348 2 Colores 2 PC3270HI 0 720X350 2 Colores 1 IBM8514LO 0 640X480 256 Colores IBM8514HI 1 1024X768 256 Colores Si la tarjeta es de 64 K o la tarjeta es de 256 K

Juan Carlos Gutiérrez Barquero____________________________________________ 7

Page 8: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

Errores:

Códigos de Errores

Constante Código Significado grOk 0 Ningún error grNoInitGraph -1 Gráficos no iniciados grNotDetected -2 Ningún adaptador gráfico detectado grFileNotFound -3 Fichero de dispositivo no encontrado grInvalidDriver -4 Fichero de dispositivo no válido grNoLoadMem -5 No hay memoria para cargar dispositivo grNoScanMem -6 No hay memoria para rellenar grNoFloodMem -7 No hay memoria para usar floodfill grFontNotFound -8 Fichero de fuente no encontrado grNoFontMem -9 No hay memoria para cargar la fuente grInvalidMode -10 Modo gráfico no válido grError -11 Error gráfico grIOerror -12 Error gráfico de Entrada/Salida grInvalidFont -13 Fichero de fuente no válido grInvalidFontNum -14 Número de fuente no válido grInvalidDeviceNum -15 Número de dispositivo no válido grInvalidVersion -18 Número de versión no válido Put_op:

Operaciones con putimage

Constante Valor Significado COPY_PUT 0 Sobrescribir los píxeles existentes XOR_PUT 1 Operación OR Exclusivo con los píxeles OR_PUT 2 Operación OR Inclusivo con los píxeles AND_PUT 3 Operación AND con los píxels NOT_PUT 4 Invertir la imagen Nota: Estas operaciones se usan exclusivamente con la función putimage. El cual veremos en capítulos posteriores.

Juan Carlos Gutiérrez Barquero____________________________________________ 8

Page 9: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

Métodos de Inicialización del modo grafico.

Antes de conocer los métodos de inicialización debemos conocer la función initgraph la cual nos permitirá realizar gráficos. Función initgraph void far initgraph(int far *driver, int far *modo, int far *path); Esta función es usada para cargar o validar un dispositivo gráfico y cambiar el sistema de vídeo a modo gráfico. La función initgraph debe ser llamada antes de cualesquier Funciónes que generan una salida gráfica sean usadas. Existen varios valores a ser usados para el argumento *driver. Si *driver es asignado a DETECT, ó 0, la función detectgraph es llamada, y un dispositivo y modo gráfico apropiados son seleccionados. Asignando a *driver cualquier otro valor predefinido inicia la carga del dispositivo gráfico correspondiente. Existen varios valores a ser usados para el argumento *modo. Estos valores deberían corresponder al dispositivo especificado en el argumento *driver. El argumento *path especificad el directorio donde los dispositivos gráficos están localizados. La función initgraph buscará el dispositivo primeramente en este directorio. Si no es encontrado, la función buscará en el directorio de inicio. Cuando el argumento *path es NULL, solamente el directorio de inicio es buscado. Otra forma para evitar cargando el dispositivo desde el disco cada vez que el programa es ejecutado es ligarlo o enlazarlo al dispositivo apropiado en un programa ejecutable. La función initgraph no retorna ningún valor. Sin embargo, cuando la función initgraph es llamada, el código de error interno es activado. Si la función initgraph termina con éxito, el código es asignado un 0. Si no, el código es asignado así: -2 grNotDetected La tarjeta gráfica no se encontró -3 grFileNotFound El fichero del dispositivo no se encontró -4 grInvalidDriver El fichero del dispositivo es inválido -5 grNoLoadMem No hay suficiente memoria para cargar el dispositivo 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(); getch(); Existen diferentes métodos de inicialización pero en este pequeño tutorial trataremos dos que suelen ser los más utilizados hoy en día.

Juan Carlos Gutiérrez Barquero____________________________________________ 9

Page 10: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

1. Método de inicialización del modo grafico a prueba de errores.

#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

2. Método de inicialización rápido del modo grafico. #include <graphics.h> void main() int driver = DETECT,modo; initgraph(&driver,modo,” c:\\tc20\\bin”); cuerpo del programa driver: Es la dirección de la variable que contiene el código del tipo de de driver o adaptador que tiene la computadora. modo: Es la dirección de la variable que contiene el código del modo en que se podrá adaptar. c:\\tc20\\bin: Es el directorio donde se encuentra el código del manejador, puede ser camino relativo o absoluto. graphresult():Regresa el código error de la ultima llamada a una función grafica de turbo c un valor de 0 significa que no hubo error. grOk : regresa el código de error de la función graphresult(). DETECT: Dispositivo grafico de auto detección del la tarjeta de video y del modo grafico.

Juan Carlos Gutiérrez Barquero____________________________________________ 10

Page 11: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

¿Qué son los primitivos gráficos…? Definición. Un primitivo gráfico es un elemento fundamental de dibujo en un paquete grafico tal como un punto, línea, o circulo; puede ser un carácter, o puede ser una operación tal como relleno, coloreado o trasferido de la imagen. C cuenta con 5 grupos de primitivos gráficos. Figuras geométricas: Dibujan las figuras de la geometría clásica: líneas,

círculos, rectángulos, arcos, polígonos etc. Relleno: tiene dos formas de realizarse. El primero es con polígonos, donde se

definen los vértices del polígono a ser rellenado segunda es una operación grafica que busca algorítmicamente las fronteras de la región del relleno.

Rasterop: Es una operación grafica que copia el área de una imagen para luego

dibujarla en cualquier región de la pantalla. Gráficas Matemáticas: Dibujan los primitivos barras y sectores para conseguir

dibujar las herramientas del sector. Texto Gráfico: Sirve para escribir texto en modo grafico, utilizando diferentes

fuentes. Figuras geométricas: LINEAS. void far line(int x1, int y1, int x2, int y2); Esta función es usada para conectar dos puntos con una línea recta. El primer punto es especificado por los argumentos x1 e y1. El segundo punto es especificado por los argumentos x2 e y2. La línea se dibuja usando el estilo de línea actual, el grosor, y el color actual. La posición del cursor gráfico no es afectada por la función line.

La función line() no retorna ningún valor.

Juan Carlos Gutiérrez Barquero____________________________________________ 11

Page 12: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

Ejemplo: #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 función se utiliza para dibujar un círculo. Los argumentos x e y definen el centro del círculo, mientras que el argumento radio define el radio del círculo. El círculo no es rellenado pero es dibujado usando el color actual.

El grosor de la circunferencia puede ser establecido por la función setlinestyle; sin embargo, el estilo de la línea es ignorado por la función circle. La función circle no retorna ningún 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();

Juan Carlos Gutiérrez Barquero____________________________________________ 12

Page 13: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

RECTANGULOS. void far rectangle(int izquierda,int superior, int derecha, int inferior); Esta función dibujará un rectángulo sin rellenar su interior usando el color actual. La esquina superior izquierda del rectángulo 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 rectángulo. El perímetro del rectángulo es dibujado usando el estilo y grosor de línea actuales.

La función rectangle() no retorna ningún 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 función 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 dirección contraria al de las agujas del reloj hasta llegar al ángulo especificado por el argumento final_angulo. La función arc usa el este (extendiéndose hacia la derecha del centro del arco en la dirección horizontal) como su punto de 0 grados. La función setlinestyle puede usarse para establecer el grosor del arco. La función arc, sin embargo, ignorará el argumento trama de la función setlinestyle.

Juan Carlos Gutiérrez Barquero____________________________________________ 13

Page 14: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

La función arc no retorna ningún 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 función es usada para colocar a un píxel en una posición en particular la cual es cuestionada por los argumentos x e y. El argumento color específico el valor del color del píxel. La función putpixel no retorna ningún 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();

Juan Carlos Gutiérrez Barquero____________________________________________ 14

Page 15: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

ELIPSES. void far ellipse(int x, int y, int comienzo_angulo, int final_angulo, int x_radio, int y_radio); Esta función es usada para dibujar un arco elíptico en el color actual. El arco elíptico está centrado en el punto especificado por los argumentos x e y. Ya que el arco es elíptico el argumento x_radio especifica el radio horizontal y el argumento y_radio especifica el radio vertical. El arco elíptico 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 función ellipse considera este - el eje horizontal a la derecha del centro del elipse - ser 0 grados. El arco elíptico es dibujado con el grosor de línea actual como es establecido por la función setlinestyle. Sin embargo, el estilo de línea es ignorado por la función ellipse. La función ellipse no retorna ningún 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(); Funciones básicas de graphics.h. Función setbkcolor void far setbkcolor(int color); Esta función es usada para asignar el color de fondo al valor del color de fondo especificado por el argumento color. Existen varios valores para ciertos colores de fondo. La función setbkcolor no retorna ningún valor.

Juan Carlos Gutiérrez Barquero____________________________________________ 15

Page 16: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

Ejemplo: #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(); Función getbkcolor. int far getbkcolor(void); Esta función 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 función setbkcolor. Existen varios valores para ciertos colores de fondo. La función 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 función coloca el atributo color es decir escoge un color entre 0 y 15 o su equivalente en inglés (ver pagina 3 Modo de 16 colores) todo lo que se dibuje después de esta instrucción tendrá el color establecido por la función setcolor el valor de esta es función es WHITE. Esta función no devuelve ningún valor.

Juan Carlos Gutiérrez Barquero____________________________________________ 16

Page 17: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

Ejemplo. # include <graphics.h> # include <dos.h> # include <stdlib.h> # include <conio.h> void main() int driver=DETECT,modo,i; initgraph(&driver,&modo,"c:\\tc20\\BIN"); i=0; do setcolor(i); circle(random(639),random(479),random(i+8));/*Random definida en stdlib*/ delay(30000); /*Detiene la ejecución del programa durante 30000 milisegundos*/ i=(i<16)?i:0; i++; while(!kbhit()); Función cleardevices void far cleardevice(void); Esta función es usada para despejar una pantalla gráfica. La función cleardevice usa el color de fondo actual, como es establecido por la función setbkcolor, para rellenar la pantalla. La posición del cursor gráfico es la esquina superior izquierda de la pantalla - posición (0,0) - después de que la pantalla haya sido borrado. La función cleardevice no retorna ningún valor. Ejemplo: #include <graphics.h> #include <conio.h> void main() int driver = EGA; int modo = EGAHI; int relleno, color; initgraph( &driver, &modo, "C:\\tc20\\BIN" ); relleno = 1; color = 1; setlinestyle( SOLID_LINE, relleno, THICK_WIDTH ); circle( 300, 200, 80 ); getch(); /* Pausa */ setbkcolor( color ); cleardevice(); setlinestyle( SOLID_LINE, relleno, THICK_WIDTH ); circle( 400, 200, 20 ); getch(); /* Pausa */

Juan Carlos Gutiérrez Barquero____________________________________________ 17

Page 18: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

closegraph(); getch(); Función getmaxx int far getmaxx(void); Esta función es usada para obtener la coordenada máxima de la pantalla en la dirección horizontal. Este valor suele ser la resolución horizontal máxima menos 1. La función getmaxx retorna la coordenada máxima de la pantalla en la dirección horizontal. Ejemplo: #include <graphics.h> #include <conio.h> #include <stdio.h> void main() int driver = EGA,modo = EGAHI,x_max; initgraph( &driver, &modo, "C:\\TC20\\BIN" ); x_max = getmaxx(); closegraph(); printf( "X máxima: %d\n", x_max ); getch(); Función getmaxy int far getmaxy(void); Esta función es usada para obtener la coordenada máxima de la pantalla en la dirección vertical. Este valor suele ser la resolución vertical máxima menos 1. La función getmaxy retorna la coordenada máxima de la pantalla en la dirección vertical. Ejemplo: #include <graphics.h> #include <conio.h> #include <stdio.h> void main() int driver = VGA; int modo = EGAHI; int x_max, y_max; initgraph( &driver, &modo, “C:\\TC20\\BIN” ); x_max = getmaxx(); y_max = getmaxy(); closegraph(); printf( "X máxima: %d\tY máxima: %d\n", x_max, y_max ); getch();

Juan Carlos Gutiérrez Barquero____________________________________________ 18

Page 19: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

Rellenos Es el proceso de rellenar una región de la pantalla con un patrón o color. Turbo C utiliza dos métodos para definir la región de rellenos. El primero relleno de polígonos, usa la lista de vértices del polígono para calcular la geometría del interior, El segundo relleno es por el método de inundación, 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 píxel que tiene. Antes de estudiar los dos métodos estudiaremos la función setfillstyle que será de gran importancia a la hora de realizar los dos tipos de rellenado y bar que es una función similar a rectangle. Función bar void far bar(int izquierda, int superior, int derecha, int inferior); Esta función 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 función setlinestyle. La función bar no retorna ningún 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 patrón de relleno se define con las Funciónes setfillstyle y setfillpattern

Juan Carlos Gutiérrez Barquero____________________________________________ 19

Page 20: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

Función setfillstyle void far setfillstyle(int trama, int color); Esta función 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 debería usarse para asignar una trama definida por el usuario. En su lugar, se debería usar la función setfillpattern. La función setfillstyle no retorna ningún 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 ). Función setfillpattern void far setfillpattern(char far *trama, int color); Esta función 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 píxel correspondiente será asignado el color de relleno actual. Un bit de 0 indica que el píxel correspondiente no será alterado. El argumento color especifica el color de relleno que será usado para la trama. La función setfillpattern no retorna ningún valor. Ejemplo: #include <graphics.h> #include <conio.h> void main() int driver = EGA,modo = EGAHI; char trama1[8] = 0x33, 0xEE, 0x33, 0xEE, 0x33, 0xEE, 0x33, 0xEE ;

Juan Carlos Gutiérrez Barquero____________________________________________ 20

Page 21: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

char trama2[8] = 0x0A, 0xF0, 0xF0, 0x0A, 0x0A, 0xF0, 0xF0, 0x0A ; initgraph( &driver, &modo, "C:\\tc20\\bin" ); bar( 50, 50, 150, 150 ); setfillpattern( trama1, 9 ); bar( 160, 50, 260, 150 ); setfillpattern( trama2, 4 ); bar( 105, 160, 205, 260 ); getch(); /* Pausa */ closegraph(); 1. Relleno por medio de un polígonos. void far fillpoly(int numpuntos, int far *puntos); Esta función es usada para crear un polígono rellenado. El argumento numpuntos es usado para definir el número de puntos en el polígono. Al contrario que la función drawpoly, la función automáticamente cierra el polígono. El argumento *puntos apunta a un array de números de longitud numpuntos multiplicado por 2. Los dos primeros miembros del array identifica las coordenadas x e y del primer punto, respectivamente, mientras que los dos siguientes especifican el siguiente punto, y así sucesivamente. La función fillpoly dibuja el perímetro del polígono con el estilo de línea y color actuales. Luego, el polígono es rellenado con la trama de relleno y color de relleno actuales. La función fillpoly no retorna ningún valor. Ejemplo: #include <graphics.h> #include <conio.h> #include <stdio.h> void main() int driver = EGA,modo = EGAHI,trama, color; int puntos[6] = 300, 50, 500, 300, 100, 300 ; initgraph( &driver, &modo, "C:\\tc20\\bin" ); trama = SLASH_FILL; for(color=0;color<=15;color++) setfillstyle( trama, color ); fillpoly( 3, puntos ); getch(); getch(); /* Pausa */ closegraph(); /*Este programa te muestra los diferentes colores con una misma trama trata de modificarlo para que obtengas todas las tramas con todos los colores*/

Juan Carlos Gutiérrez Barquero____________________________________________ 21

Page 22: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

2. Relleno por el método de inundación. void far floodfill(int x, int y, int borde); Esta función es usada para rellenar un área cerrado con el color de relleno y trama de relleno actuales. Los argumentos x e y especifican el punto de comienzo para el algoritmo de relleno. El argumento borde especifica el valor del color del borde del área. Para que la función fillpoly Funcione como es esperado, el área a ser rellenado debe estar rodeada por el color especificado por el argumento borde. Cuando el punto especificado por los argumentos x e y se encuentra dentro del área a ser rellenada, el interior será rellenado. Si se encuentra fuera del área, el exterior será rellenado. Nota: Esta función no Funciona con el driver IBM-8514.La función floodfill no retorna ningún valor. Ejemplo: #include <graphics.h> #include <conio.h> #include <stdio.h> void main() int driver = EGA,modo = EGAHI,trama, color; int puntos[8] = 300, 50, 500, 300, 100, 300, 300, 50 ; initgraph( &driver, &modo, "C:\\tc20\\bin" ); setcolor( 10 ); /*verde*/ drawpoly( 4, puntos ); trama = SLASH_FILL; for(color = 0;color<=15;color++) setfillstyle( trama, color ); floodfill( 400, 250, 10 ); getch(); getch(); /* Pausa */ closegraph();

Funciónes de coordenadas relativas

Entre ellas tenemos las Funciónes moveto, moverel, lineto, linerel, getx, gety. Estudiaremos cada una de ellas para afianzar mas conocimientos. Función moveto. void far moveto(int x, int y); Esta función es usada para colocar el cursor gráfico al punto especificado por los argumentos x e y. Ya que el cursor es movido desde su posición anterior al punto especificado por los argumentos x e y, no hay dibujo alguno.

Juan Carlos Gutiérrez Barquero____________________________________________ 22

Page 23: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

La función moveto no retorna ningún valor. Ejemplo: #include <graphics.h> #include <conio.h> void main() int driver = EGA,modo = EGAHI; initgraph( &driver, &modo, "C:\\tc20\\BIN" ); moveto( 20, 20 ); lineto( 40, 60 ); lineto( 80, 90 ); getch(); closegraph(); Función lineto. void far lineto(int x, int y); Esta función es usada para dibujar una línea recta desde la posición actual del cursor gráfico hasta el punto especificado por los argumentos x e y. La línea se dibuja usando el estilo de línea actual, el grosor, y el color actual. Después de que la línea recta haya sido dibujado, la posición del cursor gráfico es actualizado a la posición especificado por los argumentos x e y (el punto final de la línea). La función lineto no retorna ningún valor. Ejemplo: #include <graphics.h> #include <conio.h> void main() int driver = EGA, modo = EGAHI; initgraph( &driver, &modo, "C:\\tc20\\bin" ); moveto( 20, 20 ); lineto( 40, 60 ); lineto( 80, 90 ); getch(); closegraph(); Función moverel. void far moverel(int dx, int dy); Esta función es usada para mover la posición del cursor gráfico a una distancia relativa como los argumentos dx y dy. El argumento dx define la distancia relativa a moverse en la dirección horizontal. El argumento dy define la distancia relativa a moverse en la

Juan Carlos Gutiérrez Barquero____________________________________________ 23

Page 24: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

dirección vertical. Estos valores pueden ser positivos o negativos. No se dibuja ya que el cursor es mudado. La función moverel no retorna ningún 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(); Función linerel. void far linerel(int dx, int dy); Esta función es usada para dibujar una línea recta a una distancia y dirección predeterminadas desde la posición actual del cursor gráfico. El argumento dx especifica el número relativo de píxels para atravesar en la dirección horizontal. El argumento dy especifica el número relativo de píxels para atravesar en la dirección vertical. Estos argumentos pueden ser tanto valores positivos como negativos. La línea se dibuja usando el estilo de línea actual, el grosor, y el color actual desde la posición actual del cursor gráfico a través de la distancia relativa especificada. Cuando la línea esté terminada, la posición del cursor gráfico es actualizado al último punto de la línea. La función linerel no retorna ningún 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();

Juan Carlos Gutiérrez Barquero____________________________________________ 24

Page 25: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

Función getx. int far getx(void); Esta función es usada para obtener la posición, en la dirección horizontal, del cursor gráfico. El valor retornado especifica el lugar del píxel horizontal del cursor gráfico (la coordenada x), relativo a la pantalla del usuario actual. La función getx retorna la coordenada x del cursor gráfico. Ejemplo: #include <graphics.h> #include <stdio.h> void main() int driver = EGA,modo = EGAHI, x, y; initgraph( &driver, &modo, "C:\\tc20\\BIN" ); moveto( 300, 150 ); x = getx(); y = gety(); closegraph(); printf( "Cursor gráfico\n\nX: %d\tY: %d\n", x, y ); Función gety. int far gety(void); Esta función es usada para obtener la posición, en la dirección vertical, del cursor gráfico. El valor retornado especifica el lugar del píxel vertical del cursor gráfico (la coordenada y), relativo a la pantalla del usuario actual. La función gety retorna la coordenada y del cursor gráfico. Ejemplo: #include <graphics.h> #include <stdio.h> void main() int driver = EGA,modo = EGAHI, x, y; initgraph( &driver, &modo, “C:\\TC20\\BIN” ); moveto( 300, 150 ); x = getx(); y = gety(); closegraph(); printf( "Cursor gráfico\n\nX: %d\tY: %d\n", x, y );

Juan Carlos Gutiérrez Barquero____________________________________________ 25

Page 26: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

Otras funciones de la librería graphics.h.

En este capitulo describimos una a una las librerías de la librería graphics.h. Las funciones serán explicadas mediante un orden. Cuando sabemos como dibujar líneas, círculos, rectángulos, y otras figuras es hora de que empieces a conocer otro tipo de funciones en las cuales no hacen mucho énfasis los profesores como lo son las funciones bar3d, palette y otras que presentan una gran gama de tareas de gran calidad grafica. Dejemos de hablar y comencemos ya que los puedo aburrir. Función bar3d void far bar3d(int izquierda, int superior,int derecha, int inferior, int profundidad, int banderin_tapa); Esta función creará una barra rectangular y rellenada de tres dimensiones. La esquina superior izquierda de la barra rectangular más frontal está definida por los argumentos izquierdos y superiores. Estos argumentos corresponden a los valores x e y de la esquina superior izquierda del rectángulo más frontal. Similarmente, los argumentos derecha e inferior definen la esquina inferior derecha del rectángulo más frontal. La barra tiene borde, en todas las tres dimensiones, rellenada con el color y estilo de línea actuales. El rectángulo más frontal es rellenado usando la trama de relleno actual y el color de relleno como es establecido por la función 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 función bar3d no retorna ningún 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();

Juan Carlos Gutiérrez Barquero____________________________________________ 26

Page 27: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

Función clearviewport void far clearviewport(void); Esta función es usada para rellenar la pantalla actual del usuario con el color de fondo actual. El color de fondo puede ser establecido con la función setbkcolor. La posición del cursor gráfico es la esquina superior izquierda de la pantalla actual del usuario. Esta posición es (0,0) según la pantalla actual del usuario. La función clearviewport no retorna ningún 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(); Función closegraph void far closegraph(void); Esta función es usada para cerrar el sistema gráfico como es iniciada por la función initgraph. La función closegraph libera toda la memoria usada por el sistema gráfico y luego restaura el modo de vídeo al modo de texto que estaba en uso anteriormente a la llamada a la función initgraph. La función closegraph no retorna ningún 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();

Juan Carlos Gutiérrez Barquero____________________________________________ 27

Page 28: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

Función detectgraph void far detectgraph(int far *driver, int far *modo); Esta función es usada para detectar el adaptador gráfico y el modo óptimo para usar con el sistema en uso. Si la función detectgraph no puede detectar ningún dispositivo gráfico, el argumento *driver es asignado grNotDetected (-2). Una llamada a graphresult resultará en un valor de retorno de -2, o grNotDetected. Existen varios valores que indican los diferentes dispositivos gráficos que pueden ser usados por el argumento *driver. Un valor de 0, o DETECT, inicia la Funciónalidad de auto detección, el cual determina el driver óptimo a usar. Para cada dispositivo existen varios valores que indican los diferentes modos gráficos que pueden ser usados por el argumento *modo. Sin embargo, si el argumento *driver es asignado el valor de 0, o DETECT, el argumento *modo es automáticamente establecido al modo de resolución mas alto para el driver. La función detectgraph no retorna ningún valor. Ejemplo: #include <graphics.h> #include <conio.h> #include <stdio.h> void main() int driver, modo; detectgraph( &driver, &modo, ); initgraph( &driver, &modo, "C:\\tc20\\BIN" ); circle( 300, 200, 80 ); getch(); /* Pausa */ closegraph(); printf( "Driver: %d\tModo: %d\n\n", driver, modo ); getch(); Función drawpoly void far drawpoly(int numpuntos, int far *puntos); Esta función es usada para crear un polígono con un número especificado de puntos. El argumento numpuntos es usado para definir el número de puntos en el polígono. Para la función drawpoly, el número de puntos debe ser el número actual de puntos más 1 para poder crear un polígono cerrado. En otras palabras, el primer punto debe ser igual al último punto. El argumento *puntos apunta a un array de números de longitud numpuntos multiplicado por 2. Los dos primeros miembros del array identifica las coordenadas x e y del primer punto, respectivamente, mientras que los dos siguientes especifican el siguiente punto, y así sucesivamente. La función drawpoly dibuja el perímetro del polígono con el estilo de línea y color actuales, pero no rellena el polígono. La función drawpoly no retorna ningún valor.

Juan Carlos Gutiérrez Barquero____________________________________________ 28

Page 29: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

Ejemplo: #include <graphics.h> #include <conio.h> #include <stdio.h> void main() int driver = EGA; int modo = EGAHI; int puntos[8] = 300, 50, 500, 300, 100, 300, 300, 50 ; initgraph( &driver, &modo, "C:\\tc20\\BIN" ); drawpoly( 4, puntos ); getch(); /* Pausa */ closegraph(); getch(); Función fillellipse void far fillellipse(int x, int y,int x_radio, int y_radio); Esta función es usada para dibujar y rellenar una elipse. El centro de la elipse es especificado por los argumentos x e y. El argumento x_radio especifica el radio horizontal y el argumento y_radio especifica el radio vertical de la elipse. La elipse es dibujado con el perímetro en el color actual y rellenada con el color de relleno y la trama de relleno actuales. La función fillellipse no retorna ningún valor. Ejemplo: #include <graphics.h> #include <conio.h> void inicializar(void); void main() int trama, color; inicializar(); trama = SOLID_FILL; color = 4; setfillstyle( trama, color ); fillellipse( 300, 150, 100, 50 ); getch(); /* Pausa */ closegraph(); void inicializar(void) int driver = EGA,modo = EGAHI; initgraph( &driver, &modo, "C:\\tc20\\BIn" );

Juan Carlos Gutiérrez Barquero____________________________________________ 29

Page 30: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

Función getarccords void far getarccoords(struct arccoordstype far *coordenadas_arco); Esta función es usada para recoger las coordenadas del centro, y los puntos del comienzo y final de la última llamada con éxito a la función arc. El argumento *coordenadas_arco apunta a la estructura de tipo arccoordstype que guarda la información 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 función getarccoords no retorna ningún 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(); Función getaspectratio void far getaspectratio(int far *x_proporcion,int far *y_proporcion); Esta función es usada para obtener la proporción anchura-altura del modo gráfico actual. La proporción anchura-altura puede definirse como la proporción de la anchura del píxel del modo gráfico y la altura del píxel. Esta proporción, usando los modos gráficos existentes, es siempre menor o igual que 1. El valor para determinar la proporción 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

Juan Carlos Gutiérrez Barquero____________________________________________ 30

Page 31: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

*y_proporcion. El argumento *y_proporcion es asignado 10000, el cual es retornado cuando se llama a la función getaspectratio. El argumento *x_proporcion es casi siempre menor que el valor de *y_proporcion. Esto es debido al hecho de que la mayoría de los modos gráficos tiene píxeles más altos que anchos. La única excepción es en los modos de VGA que produce píxeles cuadrados; es decir, x_proporcion = y_proporcion. La función getaspectratio no retorna ningún valor, directamente. Ejemplo: #include <graphics.h> #include <conio.h> #include <stdio.h> void main() int driver = EGA, modo = EGAHI; int x_proporcion, y_proporcion; initgraph( &driver, &modo, "C:\\tc20\\BIN" ); getaspectratio( &x_proporcion, &y_proporcion ); circle( 300, 150, 50 ); getch(); /* Pausa */ closegraph(); printf( "Proporción anchura-altura.\nFactor x: %d\tFactor y: %d\n", x_proporcion, y_proporcion ); getch(); Función getcolor int far getcolor(void); Esta función obtiene el valor del color actual. El color actual es el color usado para dibujar líneas, arcos, etc.. Este color no es el mismo que el color de relleno. El valor del color obtenido es interpretado según el modo que esté en uso. Existen varios valores para ciertos colores de fondo. La función getcolor retorna el valor del color actual. Ejemplo: #include <graphics.h> #include <conio.h> #include <stdio.h> void main() int driver = EGA; int modo = EGAHI,color; initgraph( &driver, &modo, "C:\\Tc20\\BIN" ); setcolor( 4 ); circle( 300, 150, 50 ); color = getcolor(); getch(); /* Pausa */ closegraph();

Juan Carlos Gutiérrez Barquero____________________________________________ 31

Page 32: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

printf( "Color del perímetro: %d\n", color ); getch(); Función getdefaultpalette struct palettetype far *getdefaultpalette(void); Esta función es usada para obtener una estructura que define la paleta según el dispositivo en la inicialización - 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 tamaño de la paleta. El campo colors contiene los valores numéricos que representan los colores que ofrece el dispositivo en su paleta de colores. La función 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\nTamaño: %d\nColores: %d", palette->size, palette->colors[0] ); for( i=1; i<palette->size; i++ ) printf( ", %d", palette->colors[i] ); printf( "\n" ); getch();

Juan Carlos Gutiérrez Barquero____________________________________________ 32

Page 33: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

Función getdrivename char *far getdrivername(void); Esta función es usada para obtener una cadena de caracteres que contiene el nombre del dispositivo gráfico actual. Esta función debería ser llamada después de que un dispositivo haya sido definido e inicializado – esto es, después de llamar a initgraph. La función getdrivername retorna una cadena de caracteres conteniendo el nombre del dispositivo gráfico. 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 gráfico: %s\n", nombre ); getch(); Función getfillpattern void far getfillpattern(char far *trama); Esta función es usada para obtener una trama de relleno definido por el usuario, como es definida por la función 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 píxel correspondiente será asignado el color de relleno actual. Un bit de 0 indica que el píxel correspondiente no será alterado. La función getfillpattern no retorna ningún 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" );

Juan Carlos Gutiérrez Barquero____________________________________________ 33

Page 34: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

getfillpattern( trama2 ); bar( 50, 50, 150, 150 ); setfillpattern( trama1, 9 ); bar( 160, 50, 260, 150 ); setfillpattern( trama2, 4 ); bar( 105, 160, 205, 260 ); getch(); /* Pausa */ closegraph(); getch(); Función getfillsettings void far getfillsettings(struct fillsettingstype far *info); Esta función es usada para obtener la información de tramas de relleno. El argumento *info apunta a una estructura de tipo fillsettingstype, el cual es actualizado cuando se llama a la función getfillsettings. La estructura es: struct fillsettingstype int pattern; int color; ; 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. La función getfillsettings no retorna ningún valor, directamente. Ejemplo: #include <graphics.h> #include <conio.h> #include <stdio.h> void main() int driver = EGA; int modo = EGAHI; struct fillsettingstype info; initgraph( &driver, &modo, "C:\\tc20\\BIN" ); getfillsettings( &info ); bar( 50, 50, 350, 300 ); getch(); /* Pausa */ closegraph(); printf( "Trama de relleno: %d\tColor de relleno: %d\n", info.pattern, info.color ); getch();

Juan Carlos Gutiérrez Barquero____________________________________________ 34

Page 35: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

Función getgraphmode int far getgraphmode(void); Esta función es usada para obtener el valor del modo gráfico actual. El dispositivo actual debe ser considerado cuando se interprete el valor de retorno. Esta función sólo debería ser llamada después de que el sistema gráfico haya sido inicializado con la función initgraph. Existen varios valores para los modos de cada dispositivo. La función getgraphmode retorna el modo gráfico 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 gráfico: %d\n", modo ); getch(); Función getlinesettings void far getlinesettings(struct linesettingstype far *info); Esta función obtiene la información actual para las líneas. Esta información es guardada en una estructura de tipo linesettingstype que es apuntado por el argumento *info. El estilo de línea, 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 línea recta. El campo upattern es la trama de la línea 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 línea definido por el usuario de 16 bits. Un bit 1 en esta trama indica que el píxel correspondiente será asignado el color actual. Un bit 0 indica que el píxel correspondiente no será alterado. El campo thickness es el grosor de la línea. Existen varios valores para los diferentes estilos y grosores de líneas rectas.

Juan Carlos Gutiérrez Barquero____________________________________________ 35

Page 36: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

La función getlinesettings no retorna ningún valor, directamente. Ejemplo: #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( "Líneas rectas.\nEstilo: %d\tTrama: %X\tGrosor: %d\n", info.linestyle, info.upattern, info.thickness ); getch(); Función getmaxcolor int far getmaxcolor(void); Esta función es usada para obtener el valor más 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 función getmaxcolor retorna el valor máximo 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();

Juan Carlos Gutiérrez Barquero____________________________________________ 36

Page 37: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

Función getmodename char *far getmodename(int num_modo); Esta función es usada para obtener el nombre del modo gráfico especificado por el argumento num_modo. La función getmodename retorna el nombre del modo gráfico que está contenido en todos los dispositivos gráficos. 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(); Función getmoderange void far getmoderange(int driver, int far *modo_bajo, int far *modo_alto); Esta función es usada para obtener los valores altos y bajos del modo gráfico del dispositivo especificado por el argumento driver. El valor más bajo del modo es retornado en *modo_bajo, y el valor más alto del modo es retornado en *modo_alto. Si el dispositivo especificado es inválido, 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 función getmoderange no retorna ningún 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;

Juan Carlos Gutiérrez Barquero____________________________________________ 37

Page 38: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

initgraph( &driver, &modo, “C:\\TC20\\BIN” ); getmoderange( driver, &modo_bajo, &modo_alto ); closegraph(); printf( "Alcance de modos, de %d á %d\n", modo_bajo, modo_alto ); getch(); Función getpalette void far getpalette(struct palettetype far *paleta); Esta función es usada para obtener la información de la paleta actual. El argumento *paleta apunta a una estructura del tipo palettetype donde la información de la paleta es guardada. 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 número de colores en la paleta. El campo colors contiene los valores numéricos que representan los colores que ofrece el dispositivo en su paleta de colores. La función getpalette no retorna ningún valor, directamente. Ejemplo: #include <graphics.h> #include <conio.h> #include <stdio.h> void main() int driver = EGA; int modo = EGAHI,i; struct palettetype palette; initgraph( &driver, &modo, "C:\\TC20\\BIN" ); getpalette( &palette ); closegraph(); printf( "\t\t\t\t\tPaleta\n\nTama¤o: %d\n",palette.size); printf("Colores: %d,",palette.colors[0] ); for( i=1; i<palette.size; i++ ) printf( "%d, ", palette.colors[i] ); printf( "\n" ); getch();

Juan Carlos Gutiérrez Barquero____________________________________________ 38

Page 39: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

Función getpalettesize int far getpalettesize(void); Esta función es usada para obtener el número de entradas de paleta válidas para la paleta actual, considerando el modo gráfico en uso. La función getpalettesize retorna el número de colores en la paleta actual. Para modos de 16 colores, la función 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\nNúmero de colores: %d\n", num_colores ); getch(); Función getpixel unsigned far getpixel(int x, int y); Esta función es usada para obtener el valor del color del píxel especificado por los argumentos x e y. Estos argumentos especifican las coordenadas de la pantalla del píxel a ser evaluado. Cuando se evalúa el valor del color retornado, el modo gráfico en uso debe ser considerado. Existen varios valores para describir colores. La función getpixel retorna el número del color del píxel 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();

Juan Carlos Gutiérrez Barquero____________________________________________ 39

Page 40: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

closegraph(); printf( "Colores\n\nEl color del píxel (%d,%d): %d\n", x, y, color ); getch(); Función gettextsettings void far gettextsettings(struct textsettingstype far *info); Esta función es usada para obtener información acerca de la fuente gráfica actual. Esta información es guardada en una estructura de tipo textsettingstype, la cual es apuntada por el argumento *info. Esta estructura contiene información de la fuente actual en uso, la orientación del texto, el tamaño del carácter, y la justificación horizontal y vertical. La síntaxis de la estructura textsettingstype es la siguiente: struct textsettingstype int font; int direction; int charsize; int horiz; int vert; ; Existen varios valores para describir el tipo, la orientación, y justificación de fuentes. La función gettextsettings no retorna ningún valor. Ejemplo: #include <graphics.h> # include<conio.h> #include <stdio.h> void main() int driver = EGA; int modo = EGAHI; struct textsettingstype info; initgraph( &driver, &modo, "C:\\TC20\\BIN" ); gettextsettings( &info ); closegraph(); printf( "Texto\n\nFuente: %d\tSentido: %d\tTamaño: %d\n""Justificación:\nHorizontal: %d, Vertical: %d\n", info.font, info.direction, info.charsize, info.horiz, info.vert); getch(); Función getviewsettings void far getviewsettings(struct viewporttype far *info); Esta función es usada para obtener información acerca del área gráfica actual. Esta información es guardada en una estructura de tipo viewporttype, la cual es apuntada por

Juan Carlos Gutiérrez Barquero____________________________________________ 40

Page 41: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

el argumento *info. Esta estructura contiene información acerca de las esquinas superior izquierda e inferior derecha, también como el banderín de recorte del área gráfica. La síntaxis de la estructura viewporttype es la siguiente: struct viewporttype int left, top; int right, bottom; int clip; ; La función getviewsettings no retorna ningún 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\tBander¢n: %d\n", info.left, info.top, info.right, info.bottom, info.clip ); getch(); Función graphdefaults void far graphdefaults(void); Esta función es usada para reiniciar todos los datos gráficos a sus valores originales, o por defecto. La función graphdefaults reinicia la pantalla del usuario para que cubra la pantalla entera, mueve el cursor a la posición (0,0), y reinicia la paleta actual a sus colores por defecto. También 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 justificación de texto. La función graphdefaults no retorna ningún valor. Ejemplo: #include <graphics.h> #include <conio.h> void main() int driver = VGA; int modo = VGAHI; initgraph( &driver, &modo, "C:\\TC20\\BIN" ); setcolor( 4 );

Juan Carlos Gutiérrez Barquero____________________________________________ 41

Page 42: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

setviewport( 250, 150, 350, 250, 1 ); graphdefaults(); circle( 300, 200, 50 ); getch(); closegraph(); getch(); Función grapherrormsg char *far grapherrormsg(int codigo_error); Esta función es usada para obtener una cadena de caracteres conteniendo el mensaje de error para un código de error especificado. El argumento codigo_error específica el valor del código de error. La función graphresult debe ser usada para obtener el código de error usado para el argumento codigo_error. La función grapherrormsg retorna una cadena de caracteres. Ejemplo: #include <graphics.h> #include <conio.h> #include <stdio.h> void main() int driver = EGA; int modo = EGAHI; int codigo_error; char *mensaje_error; initgraph( &driver, &modo, “C:\\TC20\\BIN” ); setgraphmode( 40 ); /* Creamos un ERROR */ codigo_error = graphresult(); strcpy( mensaje_error, grapherrormsg( codigo_error ) ); closegraph(); printf( "ERROR: \"%s\" (%d)\n", mensaje_error, codigo_error ); getch(); Función graphfreemem void far _graphfreemem(void far *ptr, unsigned tamanyo); Esta función es usada por la librería gráfica para desadjudicar memoria previamente reservada mediante una llamada a la función _graphgetmem. Esta función es llamada por la librería gráfica cuando se quiere liberar memoria. Por defecto, la función simplemente llama a free, pero se puede controlar la administración de memoria de la librería gráfica. La forma de hacer esto es simplemente creando la definición de la función, con el mismo prototipo mostrado aquí. La función _graphfreemem no retorna ningún valor.

Juan Carlos Gutiérrez Barquero____________________________________________ 42

Page 43: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

Ejemplo: #include <graphics.h> #include <conio.h> #include <stdio.h> #include <stdlib.h> void far _graphfreemem( void far *ptr, unsigned tamanyo ) printf( "__graphfreemem ha sido llamado para " "desadjudicar %d bytes en memoria\n" ); printf( "para el montón (heap) interno\n", tamanyo ); printf( "Pulse cualquier tecla...\n\n" ); getch(); free( ptr ); void far * far _graphgetmem( unsigned tamanyo ) printf( "__graphgetmem ha sido llamado para " "adjudicar %d bytes en memoria\n" ); printf( "para el montón (heap) interno\n", tamanyo ); printf( "Pulse cualquier tecla...\n\n" ); getch(); return malloc( tamanyo ); void main() int driver = EGA,modo = EGAHI; initgraph( &driver, &modo, “C:\\TC20\\BIN” ); circle( 200, 100, 50 ); getch(); closegraph(); getch(); Función graphgetmem void far * far _graphgetmem(unsigned tamanyo); Esta función es usada por la librería gráfica para adjudicar memoria gráfica para búferes internos, dispositivos gráficos, y fuentes. Esta función tiene como intención ser llamada por la librería gráfica cuando se quiere adjudicar memoria. Por defecto, la función simplemente llama a malloc, pero se puede controlar la administración de memoria de la librería gráfica. La forma de hacer esto es simplemente creando la definición de la función, con el mismo prototipo mostrado aquí. La función _graphgetmem no retorna ningún valor. Ejemplo: #include <graphics.h> #include <conio.h> #include <stdio.h> #include <stdlib.h> void far _graphfreemem( void far *ptr, unsigned tamanyo )

Juan Carlos Gutiérrez Barquero____________________________________________ 43

Page 44: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

printf( "__graphfreemem ha sido llamado para " "desadjudicar %d bytes en memoria\n" ); printf( "para el montón (heap) interno\n", tamanyo ); printf( "Pulse cualquier tecla...\n\n" ); getch(); free( ptr ); void far * far _graphgetmem( unsigned tamanyo ) printf( "__graphgetmem ha sido llamado para " "adjudicar %d bytes en memoria\n" ); printf( "para el montón (heap) interno\n", tamanyo ); printf( "Pulse cualquier tecla...\n\n" ); getch(); return malloc( tamanyo ); void main() int driver = EGA, modo = EGAHI; initgraph( &driver, &modo, “C:\\TC20\\BIN” ); circle( 200, 100, 50 ); getch(); closegraph(); getch(); Función graphresult int far graphresult(void); Esta función obtiene y retorna el código de error para la última llamada sin éxito. Además, reinicia el nivel de error a 0, o grOk. Existen varios valores de códigos de error. La función graphresult retorna el código de error de la última llamada gráfica sin éxito. Ejemplo: #include <graphics.h> #include <conio.h> #include <stdio.h> void main() int driver = EGA; int modo = EGAHI; int codigo_error; char *mensaje_error; initgraph( &driver, &modo, "C:\\TC20\\BIN" ); setgraphmode( 40 ); /* Creamos un ERROR debe de ser 0 o 1*/ codigo_error = graphresult(); strcpy( mensaje_error, grapherrormsg( codigo_error ) ); closegraph(); printf( "ERROR: \"%s\" (%d)\n", mensaje_error, codigo_error ); getch();

Juan Carlos Gutiérrez Barquero____________________________________________ 44

Page 45: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

Función installuserdriver int far installuserdriver(char far *nombre, int huge (*detectar)(void)); Esta función permite al usuario añadir dispositivos adicionales de otras compañías o grupos a la tabla interna BGI de los dispositivos. El argumento *nombre define el nombre del fichero nuevo del dispositivo .BGI. El parámetro *detectar es un puntero a una función opcional para autodetectar que puede ser o no ser provisto con el dispositivo nuevo. La función de autodetectación espera no recibir ningún parámetro y retorna un valor entero. La función installuserdriver retorna el parámetro del número del dispositivo que hubiese sido pasado a la función initgraph para seleccionar un dispositivo nuevo. Ejemplo: /* Este programa no Funcionará, ya que se necesitaría otra tarjeta gráfica desconocida por las librerías gráficas de BGI. Esto sólo es para poner un ejemplo.*/ #include <graphics.h> #include <conio.h> int huge detectarSMGGA( void ) int driver, modo, modo_sugerirdo=0; detectgraph( &driver, &modo ); if( SMGGA == driver ) return modo_sugerido; return grError; void main() int driver, modo; /* Intentamos instalar nuestra tarjeta gráfica: ** Súper Mega Guay Graphics Array (SMGGA) ** Ya sé que suena muy cursi, pero esto sólo es un ejemplo :) */ driver = installuserdriver( "SMGGA", detectarSMGGA ); /* Forzamos a que use nuestra función para autodetectar */ driver = DETECT; initgraph( &driver, &modo, “C:\\TC20\\BIN” ); closegraph(); getch(); Función installuserfont int far installuserfont(char far *nombre); Esta función carga un fichero de fuente escalable que no está provisto con el sistema BGI. El parámetro *nombre especifica el nombre del fichero fuente a cargar, en el directorio de inicio. El sistema gráfico puede tener hasta veinte fuentes instaladas a la vez.

Juan Carlos Gutiérrez Barquero____________________________________________ 45

Page 46: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

La función installuserfont retorna el número de identificación de la fuente que es usada para seccionar la fuente nueva a través de la función settextstyle. Si la tabla interna de fuentes está llena, un valor de -11 (grError) es retornado, indicando un error. Ejemplo /* Este programa no Funcionará, ya que se * necesitaría tener una fuente nueva * y desconocida por las librerías gráficas de BGI. * Esto sólo es para poner un ejemplo. */ #include <graphics.h> #include<stdio.h> # include<conio.h> void main() int driver = EGA; int modo = EGAHI; int fuente_SMCF; initgraph( &driver, &modo,"C:\\TC20\\BIN" ); /* Intentamos instalar nuestra fuente nueva: ** Súper Mega Chula Fuente (SMCF) ** Ya sé que suena muy cursi, pero esto sólo es un ejemplo :) */ if( (fuente_SMGF = installuserfont( "SMGF.CHR" )) != grError ) settextstyle( fuente_SMGF, HORIZ_DIR, 4 ); printf("Instalación completada");getch(); else settextstyle( DEFAULT_FONT, HORIZ_DIR, 4 ); printf("Error de al instalar la aplicación");getch(); closegraph(); getch(); Función kbhit int kbhit(void); Revisa si se ha presionado una tecla. Cualesquier pulsadas disponibles pueden ser recogidas con las Funciones getch o getche. La función kbhit retorna 0 si no se ha registrado una pulsada de tecla; si lo fue, entonces el valor retornado es distinto a cero. Veremos el uso de esta función en el modo grafico; para utilizar esta función se tiene que declarar la cabecera conio.h

Juan Carlos Gutiérrez Barquero____________________________________________ 46

Page 47: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

Ejemplo: #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()); Función outtext void far outtext(char far *cadena_texto); Esta función 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 gráfico actualmente usando el color actual y fuente, dirección, valores, y justificaciones de texto. La posición del cursor permanece sin ser cambiado al menos que la justificación horizontal actual es LEFT_TEXT y la orientación del texto es HORIZ_DIR. Cuando esto sea el caso, la posición del cursor es colocada horizontalmente a la anchura del píxel de la cadena de texto. Además, cuando se use la fuente por defecto, cualquier texto que se extiende a fuera del área gráfica actual es truncado. Aunque la función outtext está diseñada para texto sin formato, texto con formato puede ser mostrada a través del uso de un búfer de caracteres y la función sprintf. La función outtext no retorna ningún 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” );

Juan Carlos Gutiérrez Barquero____________________________________________ 47

Page 48: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

outtext( mensaje ); outtextxy( 300, 150, mensaje ); getch(); closegraph(); getch(); Función outtextxy void far outtextxy(int x, int y, char far *cadena_texto); Esta función es usada para mostrar una cadena de caracteres. El argumento *cadena_texto define la cadena de texto a ser mostrado. La cadena es mostrada en la posición descrita por los argumentos x e y usando el color actual y fuente, dirección, valores, y justificaciones de texto. Cuando se use la fuente por defecto, cualquier texto que se extiende fuera del área gráfica actual es truncado. Aunque la función outtextxy está diseñada para texto sin formato, texto con formato puede ser mostrada a través del uso de un búfer de caracteres y la función sprintf. La función outtextxy no retorna ningún 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 ); outtextxy( 300, 150, mensaje ); getch(); closegraph(); getch(); Función pieslice void far pieslice(int x, int y,int comienzo_angulo, int final_angulo, int radio); Esta función es usada para dibujar y rellenar un una cuña circular. La cuña circular está centrada en el punto especificado por los argumentos x e y. La porción circular de la cuña 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 función pieslice considera este – el eje horizontal a la derecha del centro

Juan Carlos Gutiérrez Barquero____________________________________________ 48

Page 49: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

– como su punto de referencia de 0 grados. El perímetro de la cuña es dibujado con el color actual y es rellenado con la trama y color de relleno actual. La función pieslice no retorna ningún valor. Ejemplo: #include <graphics.h> #include <conio.h> void main() int driver = EGA; int modo = EGAHI; initgraph( &driver, &modo, “C:\\TC20\\BIN” ); pieslice( 300, 150, 45, 225, 50 ); getch(); /* Pausa */ closegraph(); getch(); Función registerbgidriver int registerbgidriver(void (*driver)(void)); Esta función es usada para cargar y registrar un dispositivo gráfico. El argumento *driver apunta a un dispositivo. Un fichero de dispositivo registrado puede ser tanto cargado desde el disco o convertido en un formato .OBJ y ligado (o enlazado) dentro del programa. Registrando el dispositivo de esta manera, el fichero .EXE no depende de un fichero externo de dispositivo para poder ejecutarse. La función registerbgidriver retorna número del dispositivo cuando tiene éxito. Un código de error, un número negativo, es retornado si el dispositivo especificado es inválido. Ejemplo: #include <graphics.h> #include <conio.h> void main() int driver = EGA; int modo = EGAHI; registerbgidriver(IBM8514LO); initgraph( &driver, &modo, "C:\\TC20\\BIN" ); rectangle( 20, 20, 400, 300 ); getch(); /* Pausa */ closegraph(); getch();

Juan Carlos Gutiérrez Barquero____________________________________________ 49

Page 50: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

Función registerbgifont int registerbgifont(void (*fuente)(void)); Esta función es usada para informar al sistema que la fuente apuntada por el argumento *fuente fue incluida durante el enlazo. Un fichero de fuente registrado ha de ser convertido en un fichero objeto .OBJ y ligado (o enlazado) dentro del programa. Registrando la fuente de esta manera, el fichero .EXE no depende de un fichero externo de fuentes para poder ejecutarse. Nota: La fuente de defecto es la única que está disponible en el programa, ya que forma parte del sistema gráfico; no es necesario ligarlo al programa. La función registerbgifont retorna número del dispositivo cuando tiene éxito. Un código de error, un número negativo, es retornado si el dispositivo especificado es inválido. Ejemplo: #include <graphics.h> #include <conio.h> void main() int driver = EGA; int modo = EGAHI; registerbgifont(1); initgraph( &driver, &modo,"C:\\TC20\\BIN" ); outtext( "Esto es una prueba con la fuente \"Sans Serif\"" ); getch(); /* Pausa */ closegraph(); getch(); Función restorecrtmode void far restorecrtmode(void); Esta función es usada para reiniciar el modo gráfico del vídeo al modo en uso anterior a la inicialización del sistema gráfico. Esta función suele ser usada en conjunción con la función setgraphmode para cambiar entre ambos modos de texto y de gráficos. La función restorecrtmode no retorna ningún valor. Ejemplo: #include <graphics.h> #include <conio.h> #include <stdio.h> void main() int driver = EGA; int modo = EGAHI; initgraph( &driver, &modo, “C:\\TC20\\BIN” ); outtext( "Esto es una prueba para cambiar entre modo gráfico..." );

Juan Carlos Gutiérrez Barquero____________________________________________ 50

Page 51: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

getch(); restorecrtmode(); printf( "...y en modo texto.\nPulsa una tecla para volver\n" ); getch(); setgraphmode( modo ); rectangle( 200, 100, 400, 250 ); getch(); /* Pausa */ closegraph(); getch(); Función sector void far sector(int x, int y, int comienzo_angulo, int final_angulo, int x_radio, int y_radio); Esta función es usada para dibujar y rellenar la parte de una elipse. El centro de la cuña elíptica es especificado por los argumentos x e y. El argumento x_radio especifica el radio horizontal y el argumento y_radio especifica el radio vertical de la cuña elíptica. La cuña elíptica comienza al ángulo especificado por el argumento comienzo_angulo y es dibujado en la dirección contraria al de las agujas del reloj hasta llegar al ángulo especificado por el argumento final_angulo. La cuña elíptica es dibujado con el perímetro en el color actual y rellenada con el color de relleno y la trama de relleno actuales. La función sector no retorna ningún valor. Ejemplo: #include <graphics.h> #include <conio.h> void main() int driver = EGA; int modo = EGAHI; initgraph( &driver, &modo, “C:\\TC20\\BIN” ); setfillstyle( SOLID_FILL, 6 ); sector( 300, 150, 45, -45, 150, 50 ); getch(); /* Pausa */ closegraph(); getch(); Función setactivepage void far setactivepage(int pagina); Esta función es usada para especificar un número de página que representa una sección de memoria del vídeo donde todos los datos gráficos para mostrar son enviados. Está sección de memoria se denomina una página activa. El argumento pagina específica el número de la página activa. Para usar esta función con eficacia, el adaptador de vídeo usado debe ser EGA o VGA y tener suficiente memoria para soportar múltiples páginas para gráficos. Esta función es usada con la función setvisualpage para dibujar páginas no visuales y para crear animación.

Juan Carlos Gutiérrez Barquero____________________________________________ 51

Page 52: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

La función setactivepage no retorna ningún valor. Ejemplo: #include <graphics.h> #include <conio.h> #include <stdio.h> void main() int driver = EGA; int modo = EGAHI; int visual=1; printf( "Instrucciones:\nPulsa el espacio para cambiar de " "página, cualquier otra tecla para salir\n" ); printf( "(Pulsa cualquier tecla para entrar en modo gráfico)\n" ); getch(); initgraph( &driver, &modo, "C:\\TC20\\BIN" ); setactivepage( 0 ); setfillstyle( SOLID_FILL, 6 ); sector( 300, 150, 45, 315, 150, 50 ); setactivepage( 1 ); setfillstyle( SOLID_FILL, 6 ); sector( 300, 150, 90, 270, 150, 50 ); while( getch() == ' ' ) setvisualpage( visual ); visual = 0==visual ? 1 : 0; closegraph(); getch(); Función setallpalette void far setallpalette(struct palettetype far *paleta); Esta función es usada para asignar la paleta actual a la paleta definida en la estructura del tipo palettetype que es apuntado por el argumento *paleta. Todos los colores de la paleta actual son asignados a aquéllos definidos en la estructura palettetype. La síntaxis de la estructura palettetype es: #define MAXCOLORS 15 struct palettetype unsigned char size; signed char colors[MAXCOLORS+1]; El campo size indica el número de colores de la paleta actual. El campo colors es un array que contiene los valores numéricos que representan los colores que ofrece el dispositivo en su paleta de colores. Si la entrada de cualquier elemento del array es -1, el valor del color de ese elemento no cambiará.

Juan Carlos Gutiérrez Barquero____________________________________________ 52

Page 53: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

Nota: Recuerda que todos los cambios hechos a la paleta tiene un efecto visual inmediato y que la función setallpalette no debería usarse con el dispositivo IBM-8514. La función setallpalette no retorna ningún valor; sin embargo, si los valores pasados son inválidos, entonces la función graphresult retorna grError (-11) y la paleta no es alterada. Ejemplo: #include <graphics.h> #include <conio.h> void main() int driver = EGA; int modo = EGAHI; struct palettetype palette; int size, temp, i, y=0; initgraph( &driver, &modo, “C:\\TC20\\BIN” ); getpalette( &palette ); size = palette.size; for( i=0; i<size; i++ ) y += 30; setcolor( palette.colors[i] ); line( 20, y, 520, y ); getch(); /* Pausa */ for( i=0; i<size/2; i++ ) temp = palette.colors[i]; palette.colors[i] = palette.colors[size-1-i]; palette.colors[size-1-i] = temp; setallpalette( &palette ); getch(); /* Pausa */ closegraph(); getch(); Función setaspectratio void far setaspectratio(int x_proporcion, int y_proporcion); Esta función es usada para modificar la proporción anchura-altura del modo gráfico actual. La proporción anchura-altura puede definirse como la proporción de la anchura del píxel del modo gráfico y la altura del píxel. Esta proporción es usada por el sistema gráfico para calcular círculos y arcos. Por ello, alterando la proporción anchura-altura afectará la visualización de estas Funciones. La función getaspectratio puede ser usada para obtener las opciones por defecto del modo actual anteriormente a ser modificados. La función setaspectratio no retorna ningún valor. Ejemplo: #include <graphics.h>

Juan Carlos Gutiérrez Barquero____________________________________________ 53

Page 54: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

#include <conio.h> void main() int driver = EGA, modo = EGAHI,x_proporcion, y_proporcion; initgraph( &driver, &modo, “C:\\TC20\\BIN” ); getaspectratio( &x_proporcion, &y_proporcion ); circle( 300, 150, 50 ); getch(); /* Pausa */ setaspectratio( 2*x_proporcion, y_proporcion ); circle( 300, 150, 50 ); getch(); /* Pausa */ closegraph(); getch(); Función setgraphbufsize unsigned far setgraphbufsize(unsigned bufer_tam); Esta función es usada para cambiar el tamaño del búfer gráfico interno como es asignado por la función initgraph cuando el sistema gráfico es inicializado. El búfer gráfico es usado por varias Funciones gráficos; por ello, se debería tener un mayor cuidado cuando se altera este búfer del tamaño por defecto de 4096. La función setgraphbufsize se debería llamar antes de llamar a la función initgraph. La función setgraphbufsize retorna el tamaño anterior del búfer gráfico interno. Ejemplo: #include <graphics.h> #include <conio.h> #include <stdio.h> void main() int driver = EGA; int modo = EGAHI; int buf_inicial, buf_nuevo=10000; initgraph( &driver, &modo, “C:\\TC20\\BIN” ); buf_inicial = setgraphbufsize( buf_nuevo ); closegraph(); printf( "Búfer inicial: %d\tBúfer nuevo: %d\n", buf_inicial, buf_nuevo ); getch(); Función setgraphmode void far setgraphmode(int modo); Esta función es usada para seleccionar el modo gráfico actual pero solamente cuando el sistema gráfico haya sido inicializado con la función initgraph. El argumento modo define el modo a usar según el dispositivo actual. Además de seleccionar un nuevo modo, la función setgraphmode despeja la pantalla y reinicia todas las opciones gráficas a sus valores por defecto. Esta función suele usarse conjuntamente con restorecrtmode para cambiar entre modos gráficos y de texto.

Juan Carlos Gutiérrez Barquero____________________________________________ 54

Page 55: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

La función setgraphmode no retorna ningún valor. Ejemplo: #include <graphics.h> #include <conio.h> #include <stdio.h> void main() int driver = EGA, modo = EGAHI; initgraph( &driver, &modo, “C:\\TC20\\BIN” ); outtext( "Esto es una prueba para cambiar entre modo gráfico..." ); getch(); restorecrtmode(); printf( "...y en modo texto.\nPulsa una tecla para volver\n" ); getch(); setgraphmode( modo ); rectangle( 200, 100, 400, 250 ); getch(); /* Pausa */ closegraph(); getch(); Función setlinestyle void far setlinestyle(int estilo,unsigned trama, int grosor); Esta función es usada para definir las características de líneas para líneas rectas. El argumento estilo específica la trama de línea predefinida para su uso. El argumento trama es una trama de 16 bits que describe el estilo de línea cuando el argumento estilo es USERBIT_LINE, ó 4. Un bit 1 en esta trama indica que el píxel correspondiente será asignado el color actual. Un bit 0 indica que el píxel correspondiente no será alterado. El argumento grosor define el grosor de la línea. Existen varios valores para los diferentes estilos y grosores de líneas rectas. La función setlinestyle no retorna ningún valor; sin embargo, si un argumento es inválido, entonces la función graphresult retorna grError (11). Ejemplo: #include <graphics.h> #include <conio.h> void main() int driver = EGA,modo = EGAHI; initgraph( &driver, &modo, “C:\\TC20\\BIN” ); setlinestyle( DOTTED_LINE, 0, THICK_WIDTH ); line( 200, 300, 400, 50 ); getch(); /* Pausa */ closegraph(); getch();

Juan Carlos Gutiérrez Barquero____________________________________________ 55

Page 56: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

Función setpalette void far setpalette(int num_paleta, int color); Esta función es usada para modificar una sola entrada en la paleta actual. El argumento num_paleta especifica el miembro de la paleta a cambiar. El argumento color especifica el nuevo valor de color para el miembro de la paleta. Existen varios valores para los colores dependiendo del dispositivo. Nota: Recuerda que todos los cambios hechos a la paleta tiene un efecto visual inmediato y que la función setpalette no debería usarse con el dispositivo IBM-8514. La función setpalette no retorna ningún valor; sin embargo, si los valores pasados son inválidos, entonces la función graphresult retorna grError (-11) y la paleta no es alterada. Ejemplo: #include <graphics.h> #include <conio.h> void main() int driver = EGA; int modo = EGAHI; struct palettetype palette; int size, temp, i, y=0; initgraph( &driver, &modo, “C:\\TC20\\BIN” ); getpalette( &palette ); size = palette.size; for( i=0; i<size; i++ ) y += 30; setcolor( palette.colors[i] ); line( 20, y, 520, y ); getch(); /* Pausa */ for( i=0; i<size/2; i++ ) temp = palette.colors[i]; setpalette( i, palette.colors[size-1-i] ); setpalette( size-1-i, temp ); getch(); /* Pausa */ closegraph(); getch(); Función setrgbpalette void far setrgbpalette(int num_paleta,int rojo, int verde, int azul); Esta función es para usarse con los dispositivos de IBM 8514 y VGA. El argumento num_paleta especifica el miembro de la paleta a ser modificado. Para la IBM 8514 (y para el modo de 256K de la VGA), el intervalo de la paleta es de 0 á 255. Para los modos de VGA, el intervalo es de 0 á 15. Los argumentos rojo, verde, y azul especifican la intensidad del color para el miembro de la paleta. De cada byte (de cada argumento) sólo

Juan Carlos Gutiérrez Barquero____________________________________________ 56

Page 57: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

los seis bits más significativos son cargados en la paleta. Por razones de compatibilidad con otros adaptadores gráficos de IBM, el dispositivo BGI define las primeras dieciséis entradas a la paleta de la IBM 8514 a los colores por defecto de la EGA/VGA. Nota: Recuerda que todos los cambios hechos a la paleta tiene un efecto visual inmediato y que la función setrgbpalette no debería usarse con el dispositivo IBM-8514. La función setrgbpalette no retorna ningún valor. Ejemplo: #include <graphics.h> #include <conio.h> void main() int driver = EGA; int modo = EGAHI; struct palettetype palette; int size, i, y=0; initgraph( &driver, &modo, “C:\\TC20\\BIN” ); getpalette( &palette ); size = palette.size; for( i=0; i<size; i++ ) y += 30; setcolor( palette.colors[i] ); line( 20, y, 520, y ); getch(); /* Pausa */ for( i=0; i<size; i++ ) setrgbpalette( i, 2*i+33, 42, 63-4*i ); /* Tonos de naranja y azul */ getch(); /* Pausa */ closegraph(); getch(); Función settextjustify void far settextjustify(int horizontal, int vertical); Esta función es usada para especificar el método en el cual el texto es colocado en la pantalla con relación a la posición del cursor. El argumento horizontal define la justificación horizontal, mientras que el argumento vertical indica la justificación vertical. Existen varios valores y constantes para las justificaciones. La función settextjustify no retorna ningún valor; sin embargo, si los valores pasados son inválidos, entonces la función graphresult retorna grError (-11) y la paleta no es alterada. Ejemplo: #include <graphics.h> #include <conio.h> void main()

Juan Carlos Gutiérrez Barquero____________________________________________ 57

Page 58: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

int driver = EGA; int modo = EGAHI; initgraph( &driver, &modo, “C:\\TC20\\BIN” ); settextjustify( RIGHT_TEXT, BOTTOM_TEXT ); moveto(300, 200); outtext( "(RIGHT_TEXT, BOTTOM_TEXT)" ); settextjustify( RIGHT_TEXT, TOP_TEXT ); moveto(300, 200); outtext( "(RIGHT_TEXT, TOP_TEXT)" ); settextjustify( LEFT_TEXT, BOTTOM_TEXT ); moveto(300, 200); outtext( "(LEFT_TEXT, BOTTOM_TEXT)" ); settextjustify( LEFT_TEXT, TOP_TEXT ); moveto(300, 200); outtext( "(LEFT_TEXT, TOP_TEXT)" ); setcolor( 1 ); line( 300, 200, 300, 100 ); setcolor( 2 ); line( 300, 200, 300, 300 ); setcolor( 3 ); line( 300, 200, 100, 200 ); setcolor( 4 ); line( 300, 200, 500, 200 ); getch(); closegraph(); getch(); Función settextstyle void far settextstyle(int fuente,int orientacion, int tam_caracter); Esta función es usada para especificar las características para la salida de texto con fuente. El argumento fuente especifica la fuente registrada a usar. La fuente ha de estar registrada para resultados predecibles; es decir, usa registerbgifont antes de usar esta función. El argumento orientacion especifica la orientación en que el texto ha de ser mostrado. La orientación por defecto es HORIZ_DIR. El argumento tam_caracter define l factor por el cual la fuente actual será multiplicada. Un valor distinto a 0 para el argumento tam_caracter puede ser usado con fuentes escalables o de bitmap. Sin embargo, un valor distinto a 0 para el argumento tam_caracter, el cual selecciona el tamaño del carácter definido por el usuario usando la función setusercharsize, solamente Funciona con fuentes escalables. El argumento tam_caracter puede agrandar el tamaño de la fuente hasta 10 veces su tamaño normal. Existen varios valores y constantes para las justificaciones. La función settextstyle no retorna ningún valor.

Juan Carlos Gutiérrez Barquero____________________________________________ 58

Page 59: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

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 ); /* Esta fuente ha de ser enlazada antes de poder registrarla registerbgifont( sansserif_font ); */ initgraph( &driver, &modo, “C:\\TC20\\BIN” ); settextstyle( DEFAULT_FONT, 0, 2 ); outtextxy( 100, 50, mensaje ); settextstyle( DEFAULT_FONT, 1, 2 ); outtextxy( 200, 125, mensaje ); settextstyle( SANS_SERIF_FONT, 1, 3 ); outtextxy( 400, 150, mensaje ); getch(); closegraph(); getch(); Función setusercharsize void far setusercharsize(int x_dividendo, int x_divisor,int y_dividendo, int y_divisor); Esta función extablece las características de fuentes escalables. Para que esta función afecte el tamaño del carácter, el argumento tam_caracter de la función settextstyle debe ser 0. La anchura del carácter se establece con los argumentos x_dividendo y x_divisor que representan la proporción. Similarmente, los argumentos y_dividendo e y_divisor especifican la altura del carácter. La función setusercharsize no retorna ningún 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 );

Juan Carlos Gutiérrez Barquero____________________________________________ 59

Page 60: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

initgraph( &driver, &modo, “C:\\TC20\\BIN” ); settextstyle( SANS_SERIF_FONT, 0, 0 ); setusercharsize( 1, 4, 1, 2 ); /* 25% de ancho; 50% de alto */ outtextxy( 100, 50, mensaje ); settextstyle( SANS_SERIF_FONT, 0, 1 ); outtextxy( 100, 125, mensaje ); settextstyle( SANS_SERIF_FONT, 1, 0 ); setusercharsize( 1, 2, 3, 4 ); /* 50% de ancho; 75% de alto */ outtextxy( 400, 150, mensaje ); getch(); closegraph(); getch(); Función setviewport void far setviewport(int izquierda, int superior,int derecha, int inferior, int recorte_banderin); Esta función es usada para definir el área gráfico. La esquina superior izquierda del área gráfica está definida por los argumentos izquierda y superior. 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 área gráfica. El argumento recorte_banderin define si los datos para la salida gráfica serán recortados por el borde del área gráfico. Un valor de 0 para recorte_banderin indica que los datos de salida no serán recortados, mientras que un valor distinto a 0 indica que los datos serán recortados. Cuando el área gráfica es inicializada, la posición del cursor será mudado a la posición (0,0) (la esquina superior izquierda). Todos los datos de salida después de que el área gráfica haya sido inicializada serán con relación a este punto. El área gráfica por defecto cubre la pantalla entera. La función setviewport no retorna ningún valor; sin embargo, si los valores pasados son inválidos, entonces la función graphresult retorna grError (-11) y el área gráfica no será alterada. Ejemplo: #include <graphics.h> #include <conio.h> void main() int driver = EGA, modo = EGAHI; initgraph( &driver, &modo, "C:\\TC20\\BIN" ); lineto( 100, 100 ); outtextxy( 15, 5, "Inicial" ); getch(); setviewport( 250, 200, 450, 300, 0 ); setcolor( 9 ); lineto( 100, 100 ); outtextxy( 15, 5, "Nueva" ); moveto( 0, 0 ); lineto( -50, -20 ); /* Fuera del área */ getch(); setviewport( 250, 200, 450, 300, 1 );

Juan Carlos Gutiérrez Barquero____________________________________________ 60

Page 61: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

setcolor( 4 ); moveto( 120, 40 ); lineto( 150, -20 ); /* Fuera del área */ outtextxy( 25, 15, "Con recorte" ); getch(); /* Pausa */ closegraph(); getch(); Función setvisualpage void far setvisualpage(int pagina); Esta función es usada para establecer la página visual como es especificado por el argumento pagina. Una página es una sección de memoria donde se guarda la información del vídeo. Cuando se usa con un sistema (EGA o VGA) con suficiente memoria de vídeo para soportar múltiples páginas de gráficos, la función setvisualpage (junto con la función setactivepage) permite al programador crear gráficos en páginas escondidas y pasar de página entre las que se han definido con información gráfica. Esto es la base para crear animación. La función setvisualpage no retorna ningún valor. Ejemplo: #include <graphics.h> #include <conio.h> #include <stdio.h> void main() int driver = EGA; int modo = EGAHI; int visual=1; printf( "Instrucciones:\nPulsa el espacio para cambiar de página, cualquier otra tecla para salir\n" ); printf( "(Pulsa cualquier tecla para entrar en modo gráfico)\n" ); getch(); initgraph( &driver, &modo, "C:\\TC20\\BIN" ); setactivepage( 0 ); setfillstyle( SOLID_FILL, 6 ); sector( 300, 150, 45, 315, 150, 50 ); setactivepage( 1 ); setfillstyle( SOLID_FILL, 6 ); sector( 300, 150, 90, 270, 150, 50 ); while( getch() == ' ' ) setvisualpage( visual ); visual = 0==visual ? 1 : 0; closegraph(); getch();

Juan Carlos Gutiérrez Barquero____________________________________________ 61

Page 62: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

Función setwritemode void far setwritemode(int modo); Esta función es usada para establecer el modo lógico de escritura para líneas rectas. El argumento modo especifica el modo de escritura, el cual determina la interacción entre valores de píxeles existentes y los valores de píxeles en la línea. Existen dos valores para los modos de escritura. La función setwritemode no retorna ningún valor. Ejemplo: #include <graphics.h> #include <conio.h> void main() int driver = EGA; int modo = EGAHI; initgraph( &driver, &modo, "C:\\TC20\\BIN" ); setfillstyle( SOLID_FILL, 1 ); bar( 50, 50, 500, 300 ); setwritemode( COPY_PUT ); setcolor( 10 ); line( 20, 60, 220, 100 ); setwritemode( XOR_PUT ); line( 20, 80, 220, 120 ); getch(); closegraph(); getch(); Función textheight int far textheight(char far *texto); Esta función es usada para determinar la altura, en píxeles, de la cadena de texto especificada por el argumento *texto. La altura del texto se determina usando la fuente actual y el tamaño del carácter. La función textheight retorna la altura, en píxeles, 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";

Juan Carlos Gutiérrez Barquero____________________________________________ 62

Page 63: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

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(); Función textwidth int far textwidth(char far *texto); Esta función es usada para determinar la anchura, en píxeles, de la cadena de texto especificada por el argumento *texto. La anchura del texto se determina usando la fuente actual y el tamaño del carácter. La función textwidth retorna la anchura, en píxeles, 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();

Juan Carlos Gutiérrez Barquero____________________________________________ 63

Page 64: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

Estructuras del modo gráfico. Estructura arccoordstype 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. Esta estructura se usa como parámetro en la función 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 función 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 información 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.

Juan Carlos Gutiérrez Barquero____________________________________________ 64

Page 65: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

Ejemplo: #include <graphics.h> #include <conio.h> #include <stdio.h> void main() int gdriver = EGA,gmodo = EGAHI; struct fillsettingstype info; initgraph( &gdriver, &gmodo, "C:\\tc20\\BIN" ); getfillsettings( &info ); bar( 50, 50, 350, 300 ); getch(); /* Pausa */ closegraph(); printf( "Trama de relleno: %d\tColor de relleno: %d\n", info.pattern, info.color ); getch(); Estructura linesettingstype.

struct linesettingstype int linestyle; unsigned upattern; int thickness;

Esta estructura se usa para obtener la información actual para las líneas mediante la función getlinesettings. El campo linestyle es el estilo de la línea recta. El campo upattern es la trama de la línea 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 línea definido por el usuario de 16 bits. Un bit 1 en esta trama indica que el píxel correspondiente será asignado el color actual. Un bit 0 indica que el píxel correspondiente no será alterado. El campo thickness es el grosor de la línea. Existen varios valores para los diferentes estilos y grosores de líneas 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 */

Juan Carlos Gutiérrez Barquero____________________________________________ 65

Page 66: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

closegraph(); printf( "Líneas rectas.\nEstilo: %d\tTrama: %X\tGrosor: %d\n",info.linestyle, info.upattern, info.thickness ); getch(); 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 según cada dispositivo. El campo size indica el tamaño de la paleta. El campo colors contiene los valores numéricos 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\nTamaño: %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; ;

Juan Carlos Gutiérrez Barquero____________________________________________ 66

Page 67: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

Esta estructura se usa para obtener información acerca de la fuente gráfica actual mediante la función getextsettings. Esta estructura contiene información de la fuente actual en uso, la orientación del texto, el tamaño del carácter, y la justificación horizontal y vertical. Existen varios valores para describir el tipo, la orientación, y justificación de fuentes. 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\tTamaño: %d\n" "Justificación:\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 información acerca del área gráfica actual mediante la función getviewsettings. Esta estructura contiene información acerca de las esquinas superior izquierda e inferior derecha, también como el banderín de recorte del área gráfica. 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\tBanderín: %d\n", info.left, info.top, info.right, info.bottom, info.clip); getch();

Juan Carlos Gutiérrez Barquero____________________________________________ 67

Page 68: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

Estructura time

struct viewporttype int left, top; int right, bottom; int clip; ;

Esta estructura se usa para obtener información acerca del área gráfica actual mediante la función getviewsettings. Esta estructura contiene información acerca de las esquinas superior izquierda e inferior derecha, también como el banderín de recorte del área gráfica. 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\tBanderín: %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. imagesize 2. malloc 3. getimage 4. putimage

Las cuatro complementan la operación de mover una imagen almacenándola en una variable temporal de tipo buffer. Procederemos a explicar cada una de ellas para realizar buestros ejercicios de movimiento.

Juan Carlos Gutiérrez Barquero____________________________________________ 68

Page 69: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

Función imagesize unsigned far imagesize(int izquierda,int superior, int derecha, int inferior); Esta función es usada para determinar el tamaño del búfer necesitado para almacenar una imagen con la función getimage. Los argumentos izquierda y superior definen las coordenadas x e y de la esquina superior izquierda de la imagen rectangular. Similarmente, los argumentos derecha y inferior definen las coordenadas x e y de la esquina inferior derecha de la imagen rectangular. La función imagesize retorna el número actual de bytes necesarios, si el tamaño requerido es menor que 64 Kb menos 1 byte. Si esto no es el caso, el valor retornado es 0xFFFF, ó -1. Ejemplo: #include <graphics.h> #include <conio.h> #include <stdlib.h> void main() int driver = EGA; int modo = EGAHI; void *imagen; int imagentam; initgraph( &driver, &modo, “C:\\tc20\\BIN” ); setfillstyle( SLASH_FILL, 5 ); bar( 50, 50, 350, 300 ); imagentam = imagesize( 50, 50, 100, 100 ); closegraph(); getch(); /*En este ejercicio solo calculamos el tamaño de la imagen*/ Función malloc void *malloc(size_t size) Función definida en conio.h. El tamaño está en bytes. Regresa un puntero(indicador)al bloque recientemente asignado, o Nulo (NULL) si no existe suficiente espacio en nuevo bloque. Si el tamaño==0, este regresa un Nulo(NULL) . Talvez no comprenda lo que quiera dar a entender pero ala hora del ejercicio lo entenderán. Ejemplo: #include <graphics.h> #include <conio.h> #include <stdlib.h> void main()

Juan Carlos Gutiérrez Barquero____________________________________________ 69

Page 70: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

int driver = EGA; int modo = EGAHI; void *imagen; int imagentam; initgraph( &driver, &modo, “C:\\tc20\\BIN” ); setfillstyle( SLASH_FILL, 5 ); bar( 50, 50, 350, 300 ); imagentam = imagesize( 50, 50, 100, 100 ); imagen = malloc(imagesize( 50, 50, 100, 100 )); free( imagen ); closegraph(); getch(); En este ejemplo calculamos en tamaño de la imagen y el número de bytes necesarios para contenerla Función getimage void far getimage(int izquierda, int superior,int derecha, int inferior, void far *imagen); Esta función es usada para guardar una porción rectangular de la pantalla para un uso posterior. La esquina superior izquierda del área rectangular que ha de ser guardada está definida por los argumentos izquierda y superior. Estos argumentos representan las coordenades x e y de la esquina superior izquierda, respectivamente. Los argumentos derecha e inferior definen la esquina inferior derecha de la imagen rectangular. Estos argumentos definen las coordenades x e y de la esquina inferior derecha, respectivamente. El argumento *image apunta al búfer de memoria donde la imagen está guardada. La función getimage no retorna ningún valor, directamente. Ejemplo: #include <graphics.h> #include <conio.h> #include <stdlib.h> void main() int driver = EGA; int modo = EGAHI; void *imagen; int imagentam; 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 ); free( imagen ); getch();

Juan Carlos Gutiérrez Barquero____________________________________________ 70

Page 71: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

/*En este ejemplo solo conseguimos el tamaño de la imagen y guardamos la imagen en un buffer*/ Función putimage void far putimage(int izquierda , int superior, void far *image, int acción); Esta función coloca una imagen que fue previamente guardada con la función 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 búfer de memoria donde la imagen está guardada. La imagen se coloca en la pantalla con la acción definida en el argumento acción. Los valores y consonantes usados por el argumento accion se describen a continuación ya que pudieron haberlos olvidado:

Constante Valor Significado COPY_PUT 0 Sobrescribir los píxeles existentes XOR_PUT 1 Operación OR Exclusivo con los píxeles OR_PUT 2 Operación OR Inclusivo con los píxeles AND_PUT 3 Operación AND con los píxels NOT_PUT 4 Invertir la imagen La función putimage no retorna ningún 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 pequeño ejemplo del rasterop

Juan Carlos Gutiérrez Barquero____________________________________________ 71

Page 72: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

Otros ejemplo de Rasterop. 1. Un círculo 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();

Juan Carlos Gutiérrez Barquero____________________________________________ 72

Page 73: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

getch(); Realice un programa que muestre el movimiento de la tierra alrededor de la tierra y que mustre los meses del año 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

Juan Carlos Gutiérrez Barquero____________________________________________ 73

Page 74: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

if((x2>=-100)&&(x2<0)) setcolor(YELLOW); rectangle(480,440,600,460); setfillstyle(1,BLUE); floodfill(485,450,YELLOW); outtextxy(500,450,"Marzo"); else if((x2>=0)&&(x2<100)) setcolor(GREEN); rectangle(480,440,600,460); setfillstyle(1,BLUE); floodfill(485,450,GREEN); outtextxy(500,450,"Abril"); else if((x2>=100)&&(x2<200)) setcolor(CYAN); rectangle(480,440,600,460); setfillstyle(1,BLUE); floodfill(485,450,CYAN); outtextxy(500,450,"Mayo"); else if((x2>=200)&&(x2<299)) setcolor(MAGENTA); rectangle(480,440,600,460); setfillstyle(1,BLUE); floodfill(485,450,MAGENTA); outtextxy(500,450,"Junio"); setcolor(WHITE); y2=sqrt((1-((x2*x2)/90000.00))*23850.00); circle(310+x2,240-y2,10); getimage(310+x2-10,240-y2-10,310+x2+10,240-y2+10,buffer); delay(20000); putimage(310+x2-10,240-y2-10,buffer,XOR_PUT); circle(310,240,30); setfillstyle(1,YELLOW);

Juan Carlos Gutiérrez Barquero____________________________________________ 74

Page 75: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

floodfill(310,240,WHITE); setcolor(WHITE); x2+=2; free(buffer); delay(30000); x=300; while(x>=-300 && !kbhit()) putpixel(random(639),random(480),WHITE); putpixel(random(639),random(480),YELLOW); if((x<=300)&&(x>200)) setcolor(RED); rectangle(480,440,600,460); setfillstyle(1,BLUE); floodfill(485,450,RED); outtextxy(500,450,"Julio"); else if((x2<=200)&&(x>100)) setcolor(LIGHTGRAY); rectangle(480,440,600,460); setfillstyle(1,BLUE); floodfill(485,450,LIGHTGRAY); outtextxy(501,450,"Agosto"); else if((x<=100)&&(x>0)) setcolor(YELLOW); rectangle(480,440,600,460); setfillstyle(1,BLUE); floodfill(485,450,YELLOW); outtextxy(500,450,"Septiembre"); else if((x<=0)&&(x>-100)) setcolor(GREEN); rectangle(480,440,600,460); setfillstyle(1,BLUE); floodfill(485,450,GREEN); outtextxy(500,450,"Octubre"); else

Juan Carlos Gutiérrez Barquero____________________________________________ 75

Page 76: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

if((x<=-100)&&(x>-200)) setcolor(CYAN); rectangle(480,440,600,460); setfillstyle(1,BLUE); floodfill(485,450,CYAN); outtextxy(500,450,"Noviembre"); else if((x<=-200)&&(x>-300)) setcolor(MAGENTA); rectangle(480,440,600,460); setfillstyle(1,BLUE); floodfill(485,450,MAGENTA); outtextxy(500,450,"Diciembre"); setcolor(WHITE); y1=(sqrt((1-((x*x)/90000.00))*23850.00))*-1; circle(310+x,240-y1,10); getimage(310+x-10,240-y1-10,310+x+10,240-y1+10,buffer); delay(20000); putimage(310+x-10,240-y1-10,buffer,XOR_PUT); circle(310,240,30); setfillstyle(1,YELLOW); floodfill(310,240,WHITE); setcolor(WHITE); x-=2; free(buffer); delay(2000); while(!kbhit()); /***********************INICIALIZAR***************************/ void inicializar(void) int drive=DETECT,modo; initgraph(&drive,&modo,"c:\\tc20\\bin");

Juan Carlos Gutiérrez Barquero____________________________________________ 76

Page 77: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

Existen otras maneras mas sencillas de hacerlo, que te parece si te doy una idea??? Declara un arreglo unidimensional donde escribiras los meses y hay un for que inicie en 1 y termine en 12 dentro de ese for llama a una funcion que es bottom_fond donde dibujaras un rectangulo que se pintará siempre de azul pero su color frontera seran las i recomendación (pasarle parámetros a la funcion para ahorrar códigodentro de ese misno for llama al arreglo bidimensional imprimiendo en las coordenadas del rectangulo y los demas cálculos son los mismos.

Funciones mas utilizadas en <graphics.h> de <stdlib.h> La función atoi int atoi(const char *s); El macro atoi() convierte una cadena a su valor entero. Retorna el valor convertido de la cadena leída. Si el valor no puede ser convertido el valor de retorno es 0. Observación: es usada para convertir cadenas que contengas valores numéricas a fin de que estos valores puedan ser computados. Ejemplo #include <stdio.h> #include <conio.h> #include <stdlib.h> void main(void) char *string="545"; long int valor_entero; clrscr(); valor_entero=atoi(string); printf("La cadena es %s, el valor entero correspondiente es %d\n",string,valor_entero); getch(); La función itoa int itoa(int value, char *string, int radix); La función itoa convierte un entero a cadena, recibe los siguientes parámetros: 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 función es comúnmente usada con outtextxy(), en el siguiente ejemplo deseo mostrar en pantalla gráfica el valor de una variable entera para lo cual tengo que convertirla a cadena.

Juan Carlos Gutiérrez Barquero____________________________________________ 77

Page 78: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

Ejemplo #include <conio.h> #include <stdlib.h> #include <graphics.h> void main(void) char *stringx,*stringy; int x=150,y=150; int adaptador=DETECT,modo; initgraph(&adaptador,&modo,"c:\\tc20\\bin"); cleardevice(); itoa(x,stringx,10); itoa(y,stringy,10); outtextxy(150,130,"LOS VALORES DE X e Y SON:"); outtextxy(150,150,"x="); outtextxy(170,150,stringx); outtextxy(150,160,"y="); outtextxy(170,160,stringy); getch(); Funciones rand y random int rand(void); int random(int valor_final); Las funciones rand() y random() son similares, ambas devuelve un valor seudo-aleatorio, la primera no recibe parámetros 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 librería mouse.h; esta función 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 también como las funciones contenidas dentro de ella.

Juan Carlos Gutiérrez Barquero____________________________________________ 78

Page 79: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

Funciones de la librería Mouse.h Todos las librerias aqui explicadas aparecen en la carpeta include de tc20.paracomenzar tenemos: La función mver Void mver (void) La función mver muestra el puntero del ratón no es necesario en viar ningún parámetro. La función mver no retorna ningún 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(); La función mocultar void mocultar (void) Esta función oculta el puntero del ratón no recibe ni retorna ningún 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(); mocultar() while(!kbhit()); closegraph(); getch(); Al utilizar estas dos funciones obtenemos un efecto del ratón muy vistoso.

Juan Carlos Gutiérrez Barquero____________________________________________ 79

Page 80: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

La función mtest. int mtest (void) Esta función sirve para testear el ratón en esta no es necesario enviar ningún parametro retorna: 0 si no esta instalado el ratón, y n si el número de botones del ratón. La funcion mtest retorna un entero Ejemplo: #include<graphics.h> #include<conio.h> #include<mouse.h> void main() int adaptador=DETECT,modo; initgraph(&adaptador,&modo,"c:\\tc20\\BIN"); do mver(); mtest(); while(!kbhit()); closegraph(); getch(); La función mxpos int mxpos (int modo) Dice la posición de la coordenada x en la cual se encuentra el ratón. Es necesario enviarunvalor para especificar el modo en cual sera usado. 1 es para modo gráfico. 8 es para modo texto La función mxpos regresa la posición horizontal de un entero que seria la posición del ratón 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);

Juan Carlos Gutiérrez Barquero____________________________________________ 80

Page 81: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

while(!kbhit()) setfillstyle(SOLID_FILL,BLUE); mver(); x=mxpos(1); y=mypos(1); itoa(x,strx,10); itoa(y,stry,10); outtextxy(100,100,strx); outtextxy(100,120,stry); if(x!=mxpos(1)||y!=mypos(1)) setcolor(BLUE); outtextxy(100,100,strx); outtextxy(100,120,stry); setcolor(WHITE); La función mypos int mypos (int modo) Dice la posición de la coordenada y en la cual se encuentra el ratón. Es necesario enviarunvalor para especificar el modo en cual sera usado. 1 es para modo gráfico. 8 es para modo texto La función mypos regresa la posición horizontal de un entero que seria la posición del ratón 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);

Juan Carlos Gutiérrez Barquero____________________________________________ 81

Page 82: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

itoa(x,strx,10); itoa(y,stry,10); outtextxy(100,100,strx); outtextxy(100,120,stry); if(x!=mxpos(1)||y!=mypos(1)) setcolor(BLUE); outtextxy(100,100,strx); outtextxy(100,120,stry); setcolor(WHITE); La función msituar void msituar(int modo, int x, int y) Esta función permite situar al curcor en una posición específica para su utilización es necesario enviar tres parámetros modo, x,y. Modo: 1 para modo gráfico. 8 para modo texto. X: posición horizontal. Y: posición vertical. La función no retorna ningún 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();

Juan Carlos Gutiérrez Barquero____________________________________________ 82

Page 83: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

La función mclick int mclick(void) Nos dice si se ha pulsado un boton del Mouse, no es necesario enviar un parámetro. Retorna 0 si no es presionado ningún botón. 1 si se presionó el botón izquierdo del Mouse. 2. si se presionó el botón derecho del Mouse. Ejemplo #include<graphics.h> #include<stdlib.h> #include<conio.h> #include<mouse.h> void main() int adaptador=DETECT,modo,x,y; initgraph(&adaptador,&modo,"c:\\tc20\\BIN"); do mver(); x=mxpos(1); y=mypos(1); if(mclick()==1) setcolor(GREEN); outtextxy(x+30,y,"Diste un click izquierdo"); if(mclick()==2) setcolor(RED); outtextxy(x+30,y,"Diste un click derecho"); delay(10000); setcolor(BLACK); outtextxy(x+30,y,"Diste un click izquierdo"); outtextxy(x+30,y,"Diste un click derecho"); while(!kbhit()); closegraph(); getch(); La función mlimit void mlimit(int modo, int x1, int y1, int x2, int y2) Esta función limita el espacio de movilización del cursor (ratón), en esta función es necesario enviar cinco parámetros modo,x1,y1,x2,y2.

Juan Carlos Gutiérrez Barquero____________________________________________ 83

Page 84: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

Modo: 1 para modo gráfico. 8 para modo texto. X1: límite de arriba. Y1: límite ablajo. X2: limite de abajo Y2: límite de la derecha Estas coordenadas formarán un rectángulo el cual sera el limite hasta donde podra llegar el ratón. Ejemplo #include<graphics.h> #include<conio.h> #include<mouse.h> void main() int adaptador=DETECT,modo; initgraph(&adaptador,&modo,"c:\\tc20\\BIN"); do outtextxy(100,50,"Dibuj‚ el rect ngulo para que observaran el limite"); rectangle(100,100,500,400); mlimit(1,100,100,500,400); mver(); while(!kbhit()); closegraph(); getch(); La función minlimit int minlimit(int modo,int x1,int y1,int x2,int y2) Esta función verifica si el ratón se encuentra en un área determinada para la implementación de ésta función es necesario enviar cinco parámetros. Modo: 1 para modo gráfico. 8 para modo texto. X1: límite de arriba. Y1: límite ablajo. X2: limite de abajo Y2: límite de la derecha Retorna 1 si esta en esa area en caso contrario regresará 0 (cero).

Juan Carlos Gutiérrez Barquero____________________________________________ 84

Page 85: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

Ejemplo #include<graphics.h> #include<conio.h> #include<mouse.h> void main() int adaptador=DETECT,modo; initgraph(&adaptador,&modo,"c:\\tc20\\BIN"); setbkcolor(BLUE); do setcolor(WHITE); outtextxy(210,105,"pasa el mouse por encima del bot¢n y veras el efecto"); mver(); rectangle(100,100,200,120); if(minlimit(1,100,100,200,120)==1) outtextxy(310,240,"Haz pulsado el rat¢n por encima del bot¢n"); delay(30000); setcolor(BLACK); outtextxy(310,240,"Haz pulsado el rat¢n por encima del bot¢n"); while(!kbhit()); closegraph(); getch();

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;

Juan Carlos Gutiérrez Barquero____________________________________________ 85

Page 86: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

printf("desea seguir viendo los graficos"); initgraph(&adaptor,&modo,"c:\\tc20\\bin"); if((codigo=graphresult())!=0) printf("%s",grapherrormsg(codigo)); exit(1); void cuadro(void) int paginas=1; int i=155,j=120; /*i=izquierda arriba eje x jes igual eje y*/ int q=465,w=120; /* t= derecha arriba eje x k es igual eje y*/ int t=155,k=360; /*q= izquierda abajo eje x w es igual eje y */ int a=465,s=360; /*a= derecha abajo eje x s igual eje y*/ int pentagono[]=55,340, 105,410, 205,410, 255,340, 155,270, 55,340; int hexagono[]=365,360, 415,410, 515,410, 565,360, 515,310, 415,310, 365,360; while(paginas<=4) system("cls"); setbkcolor(WHITE); setlinestyle(SOLID_LINE,15,THICK_WIDTH); setcolor(8); rectangle(1,1,getmaxx()-1,getmaxy()-1); line(310,0,310,480); line(0,240,640,240); setcolor(9); setlinestyle(SOLID_LINE,15,NORM_WIDTH); if(paginas>=1&&paginas<=2) settextstyle(SMALL_FONT,HORIZ_DIR,4); outtextxy(400,460,"Presione enter para ver las sig. graficas"); else settextstyle(SMALL_FONT,HORIZ_DIR,4); outtextxy(370,460,"Fin de presentacion Presione enter para Salir"); if(paginas==1) /***************triangulo1**************************/ outtextxy(i-60,j-90,"Triangulo Rectangulo"); outtextxy(i-67,j-20,"h"); outtextxy(i,j+40,"b"); outtextxy(i-5,j+70,"S=(b x h)/2"); outtextxy(i-60,j-90,"Tri ngulo rectangulo"); line(i-60,j-60,i-60,j+40); line(i-60,j+40,i+100,j+40); line(i+100,j+40,i-60,j-60);

Juan Carlos Gutiérrez Barquero____________________________________________ 86

Page 87: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

/******************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)

Juan Carlos Gutiérrez Barquero____________________________________________ 87

Page 88: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

/********************Rectangulo******************/ line(i-45,j-25,i+65,j-25); line(i-60,j+25,i+50,j+25); line(i-45,j-25,i-60,j+25); line(i+65,j-25,i+50,j+25); setlinestyle(DOTTED_LINE,8,NORM_WIDTH); line(i-45,j-25,i-45,j+25); /*altura*/ outtextxy(i-25,j-90,"Rectangulo"); outtextxy(i-52,j,"h"); outtextxy(i,j+30,"b"); outtextxy(i-35,j+60,"S=b x h"); setlinestyle(SOLID_LINE,8,NORM_WIDTH); /*****************************Rombo***********************/ line(t-90,k,t+90,k); line(t,k-60,t,k+60); line(t-90,k,t,k-60); line(t,k-60,t+90,k); line(t,k+60,t+90,k); line(t-90,k,t,k+60); setlinestyle(DOTTED_LINE,24,NORM_WIDTH); rectangle(t-90,k,t+90,k+70); line(t,k-60,t+120,k-60); line(t+120,k-60,t+120,k+60); line(t+120,k+60,t,k+60); line(q-60,w-45,q-60,w+45); outtextxy(t-25,k-90,"Rombo"); outtextxy(t-45,k,"D"); outtextxy(i+3,k+30,"d"); outtextxy(t-35,k+75,"S=(D * d)/2"); setlinestyle(SOLID_LINE,8,NORM_WIDTH); /*****************************Trapecio******************************/ line(q-60,w-45,q+60,w-45); line(q-85,w+45,q+90,w+45); line(q-85,w+45,q-60,w-45); line(q+90,w+45,q+60,w-45); outtextxy(q-25,w-90,"Trapecio"); outtextxy(q-52,w,"h"); outtextxy(q,w+50,"B"); outtextxy(q,w-60,"b"); outtextxy(q-35,w+60,"S=((B + b)* h)/2"); /*************************Pol¡gono*****************************/ line(a-60,s,a+100,s); line(a+100,s,a+70,s+45); line(a+70,s+45,a-60,s); line(a+100,s,a+40,s-60); line(a+40,s-60,a-60,s); line(a+40,s-60,a-40,s-40);

Juan Carlos Gutiérrez Barquero____________________________________________ 88

Page 89: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

line(a-60,s,a-40,s-40); outtextxy(a-25,s-90,"Poligono"); outtextxy(a-30,s-40,"S1"); outtextxy(a+25,s-30,"S2"); outtextxy(a+30,s+10,"S3"); outtextxy(a-35,s+60,"S= S1 + S2 + S3"); getch(); if(paginas==3) /*********************tri ngulo equilatero*********************/ line(i-60,j+55,i+20,j-85); /*cat*/ line(i+100,j+55,i+20,j-85); /*cat*/ line(i-60,j+55,i+100,j+55); /*base*/ outtextxy(i-25,j-100,"Triangulo equilatero"); setlinestyle(DOTTED_LINE,24,NORM_WIDTH); line(i+20,j-85,i+20,j+55); setlinestyle(SOLID_LINE,8,NORM_WIDTH); outtextxy(i+25,i-30,"h"); outtextxy(i+30,i+20,"b"); outtextxy(i-35,i+55,"S= (b * h)/2"); /*******************************cuadrado***********************/ rectangle(q-50,w-50,q+50,w+50); outtextxy(q-25,w-100,"Cuadrado"); outtextxy(q,w+50,"b"); outtextxy(q-35,w+65,"S= b * b"); /****************************pent gono***********************/ fillpoly(5,pentagono); outtextxy(t-25,k-110,"Pent gono"); line(t,k-20,t,k+50); outtextxy(t+10,k+10,"a"); outtextxy(t-35,k+65,"S=(P * a)/2"); /*************Exagono o poligono regular*******************/ fillpoly(6,hexagono); outtextxy(a-65,s-100,"Hex gono o poligono regular"); /*setfillstyle(LINE_FILL,GREEN); floodfill(370,460,BLUE);*/ line(a,s,a,s+50); outtextxy(a+10,s+10,"a"); outtextxy(a-35,s+65,"S=(P * a)/2"); getch(); if(paginas>4) exit(1); paginas=paginas+1; clrscr(); Este programa te simula un paisaje nocturno con algunas efectos de estrellas.

Juan Carlos Gutiérrez Barquero____________________________________________ 89

Page 90: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

# 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)

Juan Carlos Gutiérrez Barquero____________________________________________ 90

Page 91: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

setcolor(BROWN); moveto(105,370); lineto(125,350); lineto(155,365); lineto(155,360); lineto(125,345); lineto(55,345); lineto(22,370); lineto(105,370); setfillstyle(6,BROWN); floodfill(50,350,BROWN); setcolor(BROWN); rectangle(30,365,110,400); setfillstyle(SOLID_FILL,BROWN); floodfill(50,385,BROWN); line(150,362,150,382.5); /*linea lateral | */ line(110,400,150,382.5); /*union de la linea lateral con la casa*/ setfillstyle(SOLID_FILL,BROWN); floodfill(112,385,BROWN); setcolor(RED); line(130,367,140,364); /*ventana arriba --*/ line(130,377,140,374); /*ventana abajo __*/ line(130,367,130,377); /*lado derecha | */ line(140,364,140,374); /*lado izquierdo | */ setfillstyle(SOLID_FILL,MAGENTA); floodfill(135,368,RED); line(112,398,112,378); /*puerta arriba*/ line(112,378,120,374); /*puerta lado izquierdo*/ line(120,374,120.5,395); /*puerta lado derecho*/ line(112,397,120.5,394); /*puerta abajo*/ setfillstyle(SOLID_FILL,MAGENTA); floodfill(114,380,RED); line(110,365,110,400); setcolor(YELLOW); arc(310,300,90,270,30); ellipse(310,300,90,270,05,30); setfillstyle(SOLID_FILL,YELLOW); floodfill(300,300,YELLOW); void marco(int *x1,int *y1,int *x2,int *y2,int *color) setbkcolor(BLUE);

Juan Carlos Gutiérrez Barquero____________________________________________ 91

Page 92: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

setcolor(*color); rectangle(*x1,*y1,*x2,*y2); void estrellas(int *x,int *y) int i,px=*x,py=*y,color,t; setcolor(YELLOW); arc(310,180,90,270,30); ellipse(310,180,90,270,05,30); setfillstyle(SOLID_FILL,YELLOW); floodfill(300,180,YELLOW); color=getcolor(); t=1; for(i=0;i<=400;i++) montana(); setcolor(GREEN); putpixel(px,py,color); putpixel(px+10,py+50,WHITE); px=(rand()%640); py=(rand()%200); if(i>=230) continue; else putpixel(310,(480-t)-12,RED); putpixel(310,(480-t)-9,YELLOW); putpixel(310,(480-t),BLUE); putpixel(t+1,100,RED); putpixel(t-5,100,YELLOW); putpixel(t-11,100,BLUE); putpixel(t+1,50,RED); putpixel(t-5,50,YELLOW); putpixel(t-11,50,BLUE); t+=3; delay(4000); void montana() setcolor(LIGHTGRAY); line(0,250,494,250); /*linea del lago superior */ line(480,250,560,200); /*monta¤a / */ line(560,200,639,250); /* monta¤a \ */ line(480,250,639,250); /* monta¤a ___ */

Juan Carlos Gutiérrez Barquero____________________________________________ 92

Page 93: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

setfillstyle(SOLID_FILL,LIGHTGREEN); floodfill(590,230,LIGHTGRAY); void cometas(void) int i,t; do t=1; for(i=0;i<=450;i++) if(i>=230) continue; else putpixel(t+3,65,RED); putpixel(t-3,65,YELLOW); putpixel(t-9,65,BLUE); putpixel(t+13,80,RED); putpixel(t+7,80,YELLOW); putpixel(t+1,80,BLUE); putpixel(t+13,100,RED); putpixel(t+7,100,YELLOW); putpixel(t+1,100,BLUE); if((t+1)>=292 && (t+1)<=317) putpixel(t+1,180,RED); putpixel(t-5,180,YELLOW); putpixel(t-11,180,YELLOW); else putpixel(t+1,180,RED); putpixel(t-5,180,YELLOW); putpixel(t-11,180,BLUE); t+=3; delay(2000); t=0; while(!kbhit()); Este programa dibuja con el Mouse. #include <mouse.h>

Juan Carlos Gutiérrez Barquero____________________________________________ 93

Page 94: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

#include <stdlib.h> #include <stdio.h> #include <graphics.h> #include <conio.h> #define ESC 27 void main() int a=DETECT,b; int posx,posy,h,z=0; initgraph(&a,&b,"c:\\tc20\\bin"); setcolor(YELLOW); outtextxy(10,10,"a) click izq sostenido para dibujar "); outtextxy(10,20,"b) click izq dibuja una linea desde la pos. anterior hasta la nueva pos."); outtextxy(10,30,"c) presionar una vez click der indica que se escogera un nuevo punto donde"); outtextxy(10,40," empezara a dibujar el click debe ser fuera del dibujo en caso contrario "); outtextxy(10,50," se borrara"); outtextxy(10,60,"d) click der sostenido para borrar"); outtextxy(10,70,"e) presiona una tecla para salir o click si no has empezado ha dibujar"); outtextxy(10,420,"Hecho por:"); settextstyle(4,0,1); outtextxy(10,430," Bismarck Salvador Tra¤a L¢pez"); outtextxy(10+textwidth("Hecho por: "),450,"Juan Carlos Guti‚rrez Barquero"); while(mclick()!=1) setcolor(WHITE); rectangle(100,100,getmaxx()-100,getmaxy()-100); mver(); posx=mxpos(1); posy=mypos(1); while(!kbhit()) setcolor(WHITE); mlimit(1,100,100,getmaxx()-100,getmaxy()-100); rectangle(100,100,getmaxx()-100,getmaxy()-100); mver(); mocultar(); if(mclick()==1) if(z==1) z=0; posx=mxpos(1); posy=mypos(1); line(posx,posy,mxpos(1),mypos(1)); posx=mxpos(1); posy=mypos(1);

Juan Carlos Gutiérrez Barquero____________________________________________ 94

Page 95: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

else if(mclick()==2) z=1; setcolor(BLACK); for(h=0;h<=20;h++) circle(mxpos(1),mypos(1),h); floodfill(mxpos(1),mypos(1),BLACK); mlimit(1,100,100,getmaxx()-100,getmaxy()-100); clrscr(); 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)

Juan Carlos Gutiérrez Barquero____________________________________________ 95

Page 96: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

int i; setbkcolor(BLUE); setcolor(YELLOW); outtextxy(5,5,"Cargando programa de movimiento grafico"); rectangle(21,20,450,30); sleep(1); for(i=11;i<=430;i++) bar(10+i,20,20+i,30); delay(5000); if(i==430) moveto(480,400); outtext("programa Cargado"); sleep(1); void mover(void) void far *buffer; int i; setcolor(WHITE); buffer=malloc(imagesize(127,98,172,143)); /*rectangle(127,98,172,143);*/ i=100; while(!kbhit()) ala: circle(127+i,180,20); getimage(107+i,160,147+i,200,buffer); sleep(1); putimage(107+i,160,buffer,XOR_PUT); i+=10; if(i==300) i=100; goto ala; free( buffer); void fondo_de_la_pantalla(void) setbkcolor(BLUE); setcolor(LIGHTBLUE);

Juan Carlos Gutiérrez Barquero____________________________________________ 96

Page 97: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

rectangle(1,1,getmaxx()-1,getmaxy()-1); setcolor(LIGHTGRAY); rectangle(6,5,634,20); setfillstyle(SOLID_FILL,LIGHTGRAY); floodfill(10,7,LIGHTGRAY); setcolor(BLUE); rectangle(5,5,100,20); setcolor(RED); outtextxy(8,11,"N"); setcolor(BLACK); outtextxy(17,11,"uevo Juego"); setcolor(BLUE); rectangle(110,5,160,20); setcolor(RED); outtextxy(116,11,"S"); setcolor(BLACK); outtextxy(124,11,"alir"); Modo 13h 320x200().

Introducción. Cuando aparecieron los primeros computadores existía una memoria de solo 640 Kb (memoria convencional) y el procesador que dominaba en aquella época era el 8086 y 8088 el cual podía direccionar hasta 1 Mb de memoria, ya que el microprocesador era de 16 bits. Añadieron a este diferentes áreas de memoria, para la BIOS, el video, cartuchos ROM, etc. Hoy en día la configuración de todo PC está organizada en bloques de 64 kb. Organización de la memoria de un PC A000: corresponde a la memoria de la pantalla en los modos gráficos de las tarjetas EGA y VGA. B000: Es para las tarjetas de video monocromo MDA y Hercules. También sirve para la tarjeta CGA. Se utiliza como alojamiento de los modos alfanuméricos. C000: Se depositan algunas rutinas BIOS, que no forman parte del núcleo 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.

Juan Carlos Gutiérrez Barquero____________________________________________ 97

Page 98: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

El Procesador . Para hacer la programación del sistema, hay que conocer algunos conceptos que juegan un papel importante, términos 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 definición un poco más acertada, sería decir que los registros son como variables internas con las que el computador realiza operaciones, y lleva el control de los programas. El tamaño 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 más 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 aritméticas, 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 propósito general para el programador. Registros de dirección (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 Instrucción: 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 después 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 según su valor. Las interrupciones . Las interrupciones, tal y como indica su nombre, tienen como función interrumpir en medio de un procedimiento, ejecutar un trozo de código y continuar con lo que se estaba haciendo. De esta manera la CPU se ahorra de ir preguntado todo el rato a los diferentes periféricos 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

Juan Carlos Gutiérrez Barquero____________________________________________ 98

Page 99: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

una tabla que nos servirá de “índice” para así obtener la dirección de la rutina. Esta tabla se aloja en la parte más baja de la memoria, es decir, en 0000:0000, y tiene una longitud de 256 entrada de 4bytes cada una; 2 bytes de dirección (segmento) y 2 bytes de desplazamiento (offset), o sea, 1 kb en total. El Bios dispone de las funciones principales que necesita un programa para la comunicación con el hardware del PC y los dispositivos conectados a él. Hay rutinas de todas clases. Su función más importante, es que permite usar a los programas diferentes periféricos independientemente de las características del hardware. Esto nos ahorra mucho tiempo a la hora de programar para diferentes periféricos. O sea, que el Bios es un sistema de comunicación estándar. A continuación describiré todas las interrupciones de la BIOS y su finalidad de la 00H a la 1BH, pero aunque hay más, no serán comentadas ya que es de uso de la BIOS. INTERRUPCION 00H: División entre cero. INTERRUPCION 01H: Un solo paso. INTERRUPCION 02H: Interrupción no enmascarable. INTERRUPCION 03H: Punto de ruptura. INTERRUPCION 04H: Desbordamiento. INTERRUPCION 05H: Imprime pantalla. INTERRUPCION 08H: Sistema del cronómetro. INTERRUPCION 09H: Interrupción del teclado. INTERRUPCION 0BH y INTERRUPCION 0CH: Estas dos son para el Control de Dispositivo Serial. INTERRUPCION 0DH y INTERRUPCION 0FH: Estas son para el Control del Dispositivo Paralelo. INTERRUPCION 0EH: Control disco flexible. INTERRUPCION 10H: Servicios de video. INTERRUPCION 11H: Obtener equipo instalado. Determinación equipo. INTERRUPCION 13H: Obtención tamaño memoria. INTERRUPCION 14H: Comunicaciones i/o. INTERRUPCION 15H: Servicios sistema. INTERRUPCION 16H: Entrada teclado.

Juan Carlos Gutiérrez Barquero____________________________________________ 99

Page 100: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

INTERRUPCION 17H: Salida impresora. INTERRUPCION 18H: Entrada basic de rom. INTERRUPCION 19H: Cargador de arranque. INTERRUPCION 1AH: Lee y pone hora. INTERRUPCION 1BH: Tomar control en interrupción del teclado. Estas son las interrupciones del BIOS, pero hay más, las del sistema operativo, MS-DOS en nuestro caso. Cada interrupción se divide en funciones, que son los diferentes servicios a los que tenemos acceso. Para llamar a una interrupción utilizamos los registros, donde en AX indicaremos por norma general el número de interrupción, y en los demás registros los parámetros. La Programación del Sistema A la hora de programar una aplicación, la forma de tratar la información, ordenarla, y representarla es siempre igual para todos los computadores, los algoritmos utilizados no varían, los podemos describir de forma muy general. Pero lo que sí varía y que depende del sistema, es la forma en la que se debe tratar la información que entra en un programa y la forma en la que sale, esto sí es realmente la programación de sistemas, en la que se deben conocer como acceder al teclado, pantalla, impresora, archivos, etc. Una de las cosas mas importantes en este tipo de programación es el acceso al hardware. Debemos saber por donde nos movemos si queremos que nuestra aplicación funcione correctamente. Aunque la programación de sistemas esté tan fuertemente ligada al hardware, no significa que tengamos que rompernos la cabeza para poner un "¡Hola!" en pantalla, tenemos unas ayudas que nos simplifican mucho la vida. Esto es las funciones de el BIOS y del Sistemas Operativo. Estas rutinas (interrupciones) nos ahorrará mucho trabajo, ya que cada uno de estos servicios, conlleva más tiempo mediante la programación directa al hardware. Resumiendo, tenemos que las diferentes capas a la que una aplicación puede acceder son tres: Para decidirnos por uno de los tres, se tendrá que pensar en el objetivo de la aplicación que se está desarrollando: si es un juego se tendrá que ir directo al hardware del computador, por que si se hace mediante rutinas BIOS, el juego quedará demasiado lento. Esto no quiere decir que las rutinas de la BIOS sean lentas de por si, lo que pasa es que son “universales” y llevan muchos tipos de comprobaciones. Por otro lado, si lo que se quiere es hacer una aplicación en modo texto, simplemente usaremos las funciones que nos pone a disposición nuestro lenguaje de programación favorito.

Capitulo I. Inicialización del modo gráfico.

Introducción.

Juan Carlos Gutiérrez Barquero____________________________________________ 100

Page 101: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

La pantalla de nuestro computador puede funcionar en dos modos, modo texto (o alfanumérico) en el que se representan caracteres, y en modo gráfico, en el cual además de caracteres se pueden representar imágenes. Cuando hablamos de modos gráficos, la unidad representable es el pixel. Un pixel (un punto) es la unidad mínima de información que podemos representar en pantalla. El elemento que determina tanto la resolución como la cantidad de colores que podemos representar, es el adaptador. Cada adaptador tiene unas características determinadas, que hace que la forma de programar sea distinta para cada uno. La diferencia fundamental es la manera de gestionar la memoria. La información de un pixel, se almacena en código binario. Esta información hace referencia al color y atributos especiales. Los registros de las tarjetas constituyen el dispositivo de Entrada/Salida (E/S) de más bajo nivel de los adaptadores gráficos. Es en ellos donde se almacena la información relativa a como debe el computador representar los datos en la pantalla. Están conectados a puertos de E/S que los hacen accesibles, permitiendo su modificación y lectura. Una tarjeta de video esta formada por varios controladores hardware integrados en una misma placa. Cada uno de estos controladores tiene a su vez una serie de registros asociados. A la hora de programar las tarjetas gráficas, tendremos que acceder a estos registros, para lo cual se emplea un índice de puerto o index port. Un mismo controlador puede controlar más de un registro, por lo que la finalidad de este índice es señalar cuál de todos los registros es el que se modificará. El modo de acceder a cada controlador es distinto, la forma de leer o escribir en los registros será diferente en cada caso. La aparición de la tarjeta de video VGA (Video Graphic Array) como en el año 1987, hizo que se convirtiera en un estándar de los computadores IBM y compatibles. La VGA tiene una resolución máxima de 640x480 pixeles y puede mostrar simultáneamente un máximo de 256 colores. Esta resolución es muy alta comparada con las antiguas tarjetas CGA y EGA. Lamentablemente para usar los 256 colores solo se puede usar una resolución de 320x200 pixeles. Este modo de vídeo es el conocido Modo 13h, en el cual se han programado la mayoría de los juegos, demos, aplicaciones gráficas, etc. Este modo es uno de los más usados en la programación gráfica, debido a su facilidad de uso y rapidez. Las tarjetas VGA tienen normalmente un mínimo de 256 Kb, estando la memoria dividida en 4 segmentos o planos. Existe un bit, que puede estar a 1 o 0. En el primer caso (bit a 1) hablamos de modos lineales, limitados a un plano. Cuando el bit está a 0, fuerza a usar los cuatro planos, por lo que estamos en el caso de los modos denominados planares. Este bit se denomina CHAIN-4, porque encadena los cuatro planos. La denominación chained (modos lineales) y unchained (modos planares), hacen referencia al estado de este bit, indicando que esta a 1 o 0, respectivamente. Los registros de estas tarjetas pueden ser, de lectura, de escritura, o de lectura/escritura. Las tarjetas SVGA tienen cada una de ellas su conjunto de registros. El inconveniente que presentan estas tarjetas, es que aparecen problemas de compatibilidad. No estaremos seguros de que todos nuestros programas que desarrollemos funcionen correctamente

Juan Carlos Gutiérrez Barquero____________________________________________ 101

Page 102: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

con todas las tarjetas. Este problema se puede evitar si nos limitamos a utilizar el conjunto de registros de la VGA, con los que la SVGA son perfectamente compatibles. Entrando al modo 13h . El nombre 13h viene del parámetro que hay que pasarle a la interrupción 10h para iniciar este modo. Esta ultima es un interrupción software que facilita al programador tomar el control del hardware de un PC. La interrupción 10h esta encargado de dar los servicios de video. Ahora para iniciar el modo de video 13h debemos usar la función 00h de la interrupción 10h, y para esto se les pasa unos parámetros. Qué significa todo esto, lo que sucede es que cada interrupción posee varias funciones y a su vez cada función también puede tener sub-funciones. En este caso nosotros queremos iniciar un nuevo modo de video, para esto utilizamos la función 00h de la interrupción 10h, la cual esta encargada de activar modos de video específicos. En este caso en el registro de 8 bits AL se le pasa el valor 00h y en el otro registro (también de 8 bits) se coloca el modo de video a inicializar. A continuación podrás ver los distintos modos de video, que soporta la tarjeta VGA. Como podemos ver en la tabla el Modo 13h es uno de los que tiene menor resolución de los modos gráficos, pero es el que tiene mayor número de colores. Nosotros utilizaremos dos modos, el 13h y el 03h, este último los usaremos por la sencilla razón, de que cuando se termina un programa gráfico, se debe regresar nuevamente al modo texto, en este caso al modo 03h que es el que tienen por defecto todos los PC al ser encendidos. Este modo texto es de 80x25 y con 16 colores. Existen modos superiores al 13h, pero estos pertenecen a tarjetas Super VGA o superiores. El modo de video que utilizaremos se compone de 320 pixeles horizontales por 200 pixeles verticales, teniendo un total de 64000 pixeles. (320x200=64000) Después de haber visto todo la teoria necesaria, podremos crear nuestra primera rutina en lenguaje C para inicializar el modo 13h. Al iniciarse el modo 13h, los registros de la VGA se programan automáticamente con las características propias de este modo. Cuando se inicia este modo la memoria de video, en este caso los 64 Kb se limpian, es decir todos tienen el color 0 (negro). Acuérdense de incluir la cabecera <dos.h> para utilizar la función int86 y la union REGS. La turina para incluir este modo sería: void Modo13h(void) union REGS r; r.h.ah=0; r.h.al=0x13; int86(0x10, &r, &r);

Juan Carlos Gutiérrez Barquero____________________________________________ 102

Page 103: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

Lo que hemos hecho con esta función es simplemente llamar a la interrupción 10h con los parámetros necesarios para iniciar el modo 13h. Otra rutina que nos será de mucha utilidad será la que regresa al modo texto, esta función es similar al anterior, la única diferencia es que al registro AL se le debe pasar el valor 03h. Podríamos crear una función general para que realice los cambios de modos de video, esto quedaría 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 interrupción 10h, sólo 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, llamaríamos a la función 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()

Juan Carlos Gutiérrez Barquero____________________________________________ 103

Page 104: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

void Modo13h(void) union REGS r; r.h.ah=0; r.h.al=0x13; int86(0x10, &r, &r); void ModoTexto(void) union REGS r; r.h.ah=0; r.h.al=0x03; int86(0x10, &r, &r); void main(void) Modo13h(); printf("Inicializacion correcta\npresione una tecla para volver\n al modo grafico"); getch(); ModoTexto(); printf("Regreso a modo VGA"); getch(); De la segunda manera seria: #include <dos.h> para la funcion int86() # include <stdio.h> para la funcion printf() #include <conio.h> para la funcion getch() unsigned char *DIR_VGA=(unsigned char *) MK_FP(0xA000, 0); void Modo13h(void) _AX=0x0013 ; geninterrupt(0x10) ; void ModoTexto(void) _AX=0x0003 ; geninterrupt(0x10) ; void main(void) Modo13h(); printf("Inicializacion correcta\npresione una tecla para volver\n al modo grafico");

Juan Carlos Gutiérrez Barquero____________________________________________ 104

Page 105: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

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++)

Juan Carlos Gutiérrez Barquero____________________________________________ 105

Page 106: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

Setrgbpalette(x,x*2-1,0,0); Setrgbpalette(x+32,63,x*2-1,0); Setrgbpalette(x+64,63,63,x*2-1); Setrgbpalette(x+96,63,63,63); do x=0; do y=60; do c=(Video[(y<<8)+(y<<6)+x]+Video[(y<<8)+(y<<6)+x+2]+ Video[(y<<8)+(y<<6)+x-2]+Video[(y+2)*320+x+2])/4; if(c!=0) c--; poke(0xA000,(y-2)*320+x,(c<<8)+c); poke(0xA000,(y-1)*320+x,(c<<8)+c); y+=2; while(y<202); y-=2; Video[(y<<8)+(y<<6)+x]=random(2)*160; x+=2; while(x<=320); while(!kbhit()); ModoTexto(); Ya vimos un ejemplo en el modo13h y que les parecio el efecto del fuego bonito no pero que dirian si les digo que hay otro metodo de inicializacion que puede darle mas realce a sus programas,!No es broma ¡, si quieren saber un poco aquí les va: Se lla modo XGA Para poder ver estos ejemplos debes de tener intalada las librería que esta incluida en el tc20 que te obsequiamos Modo grafico con resolucion de 1024x768x256 (1024 pixeles horizontales, 768 verticales, 256 colores) Antes que nada debes copiar el archivo Svga256.bgi ,que es un controlador para graficos, a la carpeta bin de TC20. Luego tienes que poner dentro del main la siguiente instrucción: installuserdriver(“Svga256”,DetectVGA256); “Svga256” es nombre del dispositivo debes omitir la extensión .bgi DetectVGA256 es una función que debes declarar anteriormente como: int huge DetectVGA256() return 4; y luego puedes llamar a la funcion initgraph() para empezar a trabajar en modo grafico, para esta resolucion no estan disponibles las funciones setbkcolor(), ni cleardevice(). Aquí tienes el ejemplo completo:

Juan Carlos Gutiérrez Barquero____________________________________________ 106

Page 107: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

#include<conio.h> #include <graphics.h> int huge DetectVGA256() /* 0 = 320x200x256 modo CGA 320(horizontal) con 200(vertical) pixeles(puntos) en 256colores 1 = 640x400x256 modo ATT400 2 = 640x480x256 modo VGA 3 = 800x600x256 modo SVGA 4 = 1024x768x256; modo XGA Todos son los modos graficos estandar */ return 4; void main() int modo = DETECT, tarj,TIPOLETRA; int color=0,x=180,y=50; /*/Instalamos el driver SVGA.bgi para acceder a 256 colores*/ installuserdriver("Svga256",DetectVGA256); /*Instalamos en nuestro proyecto el tipo de letra*/ TIPOLETRA = installuserfont("LITT.CHR"); /*Iniciamos el modo grafico*/ initgraph(&modo,&tarj,""); setfillstyle(SOLID_FILL,WHITE); /*elegimos el color de relleno para dibujar una barra */ bar(0 , 0, 1028, 768); /*y asi simulamos que hemos elegido un color de fondo*/ /*No se pueden utilizar los comandos cleardevice ni setbkcolor.*/ setcolor(7); while(color<256) rectangle(x ,y ,x + 40, y + 40); setfillstyle(SOLID_FILL,color); bar(x + 1, y + 1, x + 39, y + 39); x = x + 40; color++; if((color%16==0)&&(color!=0)) x = 180; y = y + 40; settextstyle(TIPOLETRA,0,9); /*usamos el tipo de letra*/ setcolor(41); /*usamos el color numero 18, un gris oscuro*/ outtextxy(40,10,"Prueba de Inicializacion del modo XGA 1024x768 pixeles"); settextstyle(TIPOLETRA,0,6); setcolor(BLACK);

Juan Carlos Gutiérrez Barquero____________________________________________ 107

Page 108: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

outtextxy(12,690,"Como ves ahora si puedes usar el color negro en tus aplicaciones y usar una mayor resolucion: 1024x768"); settextstyle(TIPOLETRA,0,7); setcolor(55); outtextxy(425,740,"Huacho - Peru"); getch(); closegraph(); Ahora si quieren ver un programa funcionando a qui lo tienen Programa que carga imágenes .bmp en modo 1024x768: #include <stdio.h> #include <stdlib.h> #include <conio.h> #include <graphics.h> #include <dos.h> #include <mouse.h> #define VAR 0 #define INVALIDO -1 #define FALLA 0 #define EXITO 1 #define KB_ESC 27 /* MACROS PARA LAS FUNCIONES GRAFICAS */ #define SEG_VIDEO 0xA000 #define M320x200 0x13 #define MTexto 0x3 struct cabecera char ident[2]; unsigned long int tam; char reservado[4]; unsigned long int offset; ; struct info_general unsigned long int tam_cabecera; unsigned long int anchura; /* en pixels */ unsigned long int altura; /* en pixels */ int planos; int tam_pixel; /* tama¤o en bits de cada pixel */ unsigned long int compresion; unsigned long int tam_imagen; /* en bytes */ unsigned long int h_resolution; unsigned long int v_resolution; unsigned long int num_color; /* numero de colores utilizados */ unsigned long int color_imp; /* numeros de colores importantes */ ;

Juan Carlos Gutiérrez Barquero____________________________________________ 108

Page 109: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

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 */

Juan Carlos Gutiérrez Barquero____________________________________________ 109

Page 110: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

bmp_info.num_color = 1 << bmp_info.tam_pixel; /* calculamos dependiendo del numero de bits que ocupa cada pixel */ /* reservamos memoria dinamica para la tabla de colores RGB */ rgb = (struct valor_rgb *) malloc (bmp_info.num_color * sizeof(struct valor_rgb)); fread(rgb, bmp_info.num_color * sizeof(struct valor_rgb), 1, f); void presentacion(void) char control; clrscr(); printf("%55s","---VISUALIZADOR DE IMAGENES BMP---"); printf("\n\n\n Introduzca el nombre y ruta de ser necesario"); printf("\n ARCHIVO: "); gets(fname); if (!fname[0]) exit(0); control = verifica(fname); if (control == FALLA) printf("\n ERROR FATAL: el archivo no existe o esta protegido..."); exit(1); if (control == INVALIDO) printf("\n ERROR FATAL: el archivo no es un BMP valido... "); exit(1); /* llamamos al menu principal */ menu(); char verifica(char *fname) f = fopen(fname,"rb"); if (!f) return (FALLA); carga(); /* leemos y almacenamos del archivo */ /* comprobamos que sea un archivo valido BMP */ if (bmp_cab.ident[0] == 'B' && bmp_cab.ident[1] == 'M') return (EXITO);

Juan Carlos Gutiérrez Barquero____________________________________________ 110

Page 111: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

else return (INVALIDO); void menu(void) char opcion; for (;;) clrscr(); printf("\n\n (1) INFORMACION GENERAL DEL ARCHIVO"); printf("\n\n (2) PALETA DE COLORES USADAS"); printf("\n\n (3) MOSTRAR PALETA"); printf("\n\n (4) VISUALIZAR IMAGEN"); printf("\n\n (5) SALIR"); printf("\n\n OPCION: "); opcion = getche(); switch (opcion) case '1': info_general(); break; case '2': paleta(); break; case '3': mostrar_pal(); break; case '4': mostrar_imagen(); break; case '5': despedida(); /* termina bucle for(;;) */ void info_general(void) clrscr(); printf("%35s%s>\n","<",fname); printf("\n Tama¤o del archivo: %ld bytes",bmp_cab.tam); printf("\n Offset del archivo: %ld",bmp_cab.offset); printf("\n Tama¤o de la cabecera: %d bytes",bmp_info.tam_cabecera); printf("\n Anchura: %d pixels",bmp_info.anchura); printf("\n Altura: %d pixels",bmp_info.altura); printf("\n Numero de planos: %d",bmp_info.planos); printf("\n Numero de bits por pixel: %d bits",bmp_info.tam_pixel); printf("\n Compresion: %d ",bmp_info.compresion); printf("\n Tama¤o de la imagen: %ld bytes",bmp_info.tam_imagen); printf("\n Resolucion horizontal: %d pixels/metros",bmp_info.h_resolution); printf("\n Resolucion vertical: %d pixels/metros",bmp_info.v_resolution); printf("\n Numero de colores utilizados: %d colores",bmp_info.num_color); printf("\n Numero de colores importantes: %d colores",bmp_info.color_imp); printf("\n\n\n PRESIONE CUALQUIER TECLA PARA CONTINUAR...");

Juan Carlos Gutiérrez Barquero____________________________________________ 111

Page 112: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

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 */

Juan Carlos Gutiérrez Barquero____________________________________________ 112

Page 113: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

modo_video(M320x200); mver(); cambiar_pal(rgb); /* reservamos memoria suficiente para albergar una linea de pixeles */ linea = (char *) malloc (bmp_info.anchura); /* calculamos la cantidad de bytes necesario que sumado con la anchura sea un multiplo de cuatro */ resto = (4 * ((bmp_info.anchura + 3) >> 2)) - bmp_info.anchura; for (y = bmp_info.altura - 1; y >= 0; y--) fread(linea, bmp_info.anchura, 1, f); for (x = 0; x < bmp_info.anchura; x++) putpixel(x,y,linea[x]); fseek(f, resto, SEEK_CUR); getch(); fseek(f, posicion, SEEK_SET); /* restauramos la posicion inicial del puntero */ modo_video(MTexto); void mostrar_pal(void) register int i,j; modo_video(M320x200); cambiar_pal(rgb); for (i = 0; i < 256; i++) for (j = 0; j <= 50; j++) putpixel(i,j,i); getch(); modo_video(MTexto); void despedida(void) clrscr(); gotoxy(20,13); printf("ESPERO QUE HAYA DISFRUTADO DEL PROGRAMA..."); getch(); exit(0);

Juan Carlos Gutiérrez Barquero____________________________________________ 113

Page 114: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

/* ----FUNCIONES GRAFICAS ESCRITAS EN ENSAMBLADOR PARA SU MAYOR RAPIDEZ---- */ int huge DetectVGA256() return 4; void modo_video() int a=DETECT,b; installuserdriver("Svga256",DetectVGA256); initgraph(&a,&b,"c:\\tc20\\bin"); /* union REGS r; r.h.ah=0; r.h.al=0x13; int86(0x10,&r,&r);*/ /*void putpixel(unsigned int x, unsigned int y, unsigned char color) unsigned char *vga=(unsigned char *) MK_FP(0xA000, 0); asm push ax push bx push di push es mov ax,SEG_VIDEO mov es,ax mov bx,[y] mov di,bx shl bx,8 shl di,6 add di,bx add di,[x] mov bl,[color] mov es:[di],bl pop es pop di pop bx pop ax memset(vga+x+(y*320),color,1); */ void setpal(char col,char r,char g,char b)

Juan Carlos Gutiérrez Barquero____________________________________________ 114

Page 115: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

/*asm mov dx,03c8h; mov al,col; out dx,al; mov dx,03c9h; mov al,r; out dx,al; mov al,g; out dx,al; mov al,b; out dx,al; */ outportb(0x3c8,col); outportb(0x3c9,r); outportb(0x3c9,g); outportb(0x3c9,b); Ahora un Ejemplo de la utilización de las estructuras este programa se llama reloj analogo muestra la hora del sistema. #include <graphics.h> #include <stdio.h> #include <dos.h> #include <math.h> #include <conio.h> #include <stdio.h> void main(void) struct time tiempo; int a=DETECT,b; int radio=180; int seg,min,w,h; float angulmin, anguloseg, angulhora,hora; char mensaje[20]; int xseg, yseg, xmin, ymin, xhora, yhora; initgraph(&a,&b,"c:\\tc20\\bin"); circle(310,240,238); h=0; for(w=0;w<=60;w++) if(h%5==0) setcolor(RED); else setcolor(WHITE); outtextxy(310+sin(6*h*(3.141592/180))*225,240-cos(h*(3.141592/180)*6)*225,"*"); h+=1;

Juan Carlos Gutiérrez Barquero____________________________________________ 115

Page 116: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

settextstyle(1,0,2); outtextxy(300,20,"12"); outtextxy(520,230,"3"); outtextxy(310,433,"6"); outtextxy(100,230,"9"); do gettime(&tiempo); seg=tiempo.ti_sec; min=tiempo.ti_min; hora=tiempo.ti_hour; if(hora>12) hora-=12; hora+=(min/60); anguloseg=((seg-15)/(3*3.14159)); angulmin=((min-15)/(3*3.14159)); angulhora=((hora*5-15)/(3*3.14159)); setcolor(WHITE); circle(310,240,8); rectangle(240,390,360,420); sprintf(mensaje,"%2.0f: %2.0d: %2.0d",hora,tiempo.ti_min,tiempo.ti_sec); outtextxy(250,390,mensaje); xseg = 310 + radio * cos(anguloseg); yseg = 240 + radio * sin(anguloseg); xmin = 310 + 120 * cos(angulmin); ymin = 240 + 120 * sin(angulmin); xhora= 310 + 90 * cos(angulhora); yhora= 240 + 90 * sin(angulhora); setcolor(WHITE); line(310,240,xseg,yseg); setcolor(GREEN); line(310,240,xmin,ymin); setcolor(RED); line(310,240,xhora,yhora); sleep(1); setcolor(BLACK); line(310,240,xseg,yseg); line(310,240,xmin,ymin); line(310,240,xhora,yhora); outtextxy(250,390,mensaje); while(!kbhit());

Juan Carlos Gutiérrez Barquero____________________________________________ 116

Page 117: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

Ahora aremos un efecto que talvez les guste y lo estudien con detenimiento ya que merece mucha atención. Primero guarda estas lineas de codigo en un programa de C con el nombre TECLA.C #define ARRIBA 72 #define ABAJO 80 #define DERECHA 77 #define IZQUIERDA 75 #define ESC 27 #define ENTER 13 Ahora en otro programa copia este codigo y te sorprenderas de ver lo que hace #include <graphics.h> #include <stdio.h> #include <stdlib.h> #include <math.h> #include <dos.h> #include <conio.h> #include "tecla.c" //es para el manejo del teclado float A,B,TAM=15,fi= -M_PI/7,teta= -M_PI/7,pro_X,pro_Y; /* ÉÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ» º Definicion de funciones º º º ÈÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍͼ */ void IniciarGraficos(); void xyz(); void ProyectaPunto(float ,float ,float); void Objeto(); void instrucciones(); /*****************************************************************/ /* ÉÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ ProyectaPunto ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ» º Funcion: Localiza un punto en la pantalla 3D º º º ÈÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍͼ */ void ProyectaPunto(float x, float y, float z) pro_X = y*cos(teta) + x*sin(teta); pro_Y = z*cos(fi) + x*cos(teta)*sin(fi) - y*sin(fi)*sin(teta); /* ÉÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ IniciarGraficos ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ» º Funcion: Inicializa el modo grafico º º º

Juan Carlos Gutiérrez Barquero____________________________________________ 117

Page 118: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

ÈÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍͼ */ void IniciarGraficos() int Tarjeta=VGA,Modo=VGAHI; initgraph(&Tarjeta,&Modo,""); if(graphresult()!=grOk) printf("\nSi perdiste el archivo EGAVGA.BGI no podes correr el programa :( asi que buscalo el C:\\tc\\bgi"); getch(); exit(0); /* ÉÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ Main ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ» º Funcion: Main. º º º ÈÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍͼ */ void main() IniciarGraficos(); A=getmaxx()/2,B=getmaxy()/2; xyz(); Objeto(); closegraph(); /* ÉÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ xyz ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ» º Funcion: Dibuja Lineas de Guia en las coordenadas X,Y,Z º º º ÈÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍͼ */ void xyz() float X0,Y0,X,Y,z,tam=3; int x,y; setcolor(8); ProyectaPunto(0,0,0);X0 = pro_X,Y0 = pro_Y; ProyectaPunto(tam,0,0);X = pro_X,Y = pro_Y; line(A + X0*TAM,B - Y0*TAM,A + X*TAM,B - Y*TAM); x=A + X*TAM,y=B - Y*TAM; setcolor(8); outtextxy(x,y,"x"); setcolor(8); ProyectaPunto(0,tam,0);X = pro_X,Y = pro_Y; line(A + X0*TAM,B - Y0*TAM,A + X*TAM,B - Y*TAM);

Juan Carlos Gutiérrez Barquero____________________________________________ 118

Page 119: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

x= A + X*TAM,y=B - Y*TAM; setcolor(8); outtextxy(x,y,"y"); setcolor(8); ProyectaPunto(0,0,tam);X = pro_X,Y = pro_Y; line(A + X0*TAM,B - Y0*TAM,A + X*TAM,B - Y*TAM); setcolor(8); x=A + X*TAM,y=B - Y*TAM; outtextxy(x,y,"z"); ProyectaPunto(0,10,0);X=pro_X,Y = pro_Y; x=A + X*TAM,y=B - Y*TAM; setcolor(RED); outtextxy(x,y,"JDZx"); setcolor(8); /* ÉÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ Objeto ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ» º Funcion: Dibuja un objeto 3D º º º ÈÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍͼ */ void Objeto() float angulo=-M_PI/100.0; float AA[8],BB[8],CC[12],estrellas[2],EE[8],FF[8], xa1=3,ya1=-3,za1=-3,xa2=-3,ya2=-3,za2=-3, xa3=-3,ya3=-3,za3=3,xa4=3,ya4=-3,za4=3, xb1=3,yb1=3,zb1=-3,xb2=-3,yb2=3,zb2=-3, xb3=-3,yb3=3,zb3=3,xb4=3,yb4=3,zb4=3; float x,y; unsigned char tecla; int fo; do ProyectaPunto(xa1,ya1,za1);AA[0]=pro_X,AA[1]=pro_Y; ProyectaPunto(xa2,ya2,za2);AA[2] = pro_X,AA[3] = pro_Y; ProyectaPunto(xa3,ya3,za3);AA[4] = pro_X,AA[5] = pro_Y; ProyectaPunto(xa4,ya4,za4);AA[6] = pro_X,AA[7] = pro_Y; /*-------------------------------------------*/ ProyectaPunto(xb1,yb1,zb1);BB[0]=pro_X,BB[1]=pro_Y; ProyectaPunto(xb2,yb2,zb2);BB[2] = pro_X,BB[3] = pro_Y; ProyectaPunto(xb3,yb3,zb3);BB[4] = pro_X,BB[5] = pro_Y; ProyectaPunto(xb4,yb4,zb4);BB[6] = pro_X,BB[7] = pro_Y; ProyectaPunto(5,8,0);CC[0]=pro_X,CC[1]=pro_Y; ProyectaPunto(-4,-8,0);CC[4]=pro_X,CC[5]=pro_Y; ProyectaPunto(5,-5,3);CC[6]=pro_X,CC[7]=pro_Y; ProyectaPunto(10,5,-1);CC[8]=pro_X,CC[9]=pro_Y; ProyectaPunto(0,0,0);CC[10]=pro_X,CC[11]=pro_Y; setcolor(1);

Juan Carlos Gutiérrez Barquero____________________________________________ 119

Page 120: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

circle(A + CC[0]*TAM,B - CC[1]*TAM,TAM*0.52); setcolor(2); circle(A + CC[4]*TAM,B - CC[5]*TAM,TAM*0.25); setcolor(3); circle(A + CC[6]*TAM,B - CC[7]*TAM,TAM*0.8); setcolor(4); circle(A + CC[8]*TAM,B - CC[9]*TAM,TAM*2.5); setcolor(YELLOW); circle(A + CC[10]*TAM,B - CC[11]*TAM,TAM*2.2); /*-----------------------*/ ProyectaPunto(5,0,2);estrellas[0] = pro_X,estrellas[1] = pro_Y; putpixel(A + estrellas[0]*TAM,B - estrellas[1]*TAM,7); ProyectaPunto(-15-0.2,5,-2);estrellas[0] = pro_X,estrellas[1] = pro_Y; setcolor(8); circle(A + estrellas[0]*TAM,B - estrellas[1]*TAM,TAM*0.2); ProyectaPunto(-10,-3,-2);estrellas[0] = pro_X,estrellas[1] = pro_Y; putpixel(A + estrellas[0]*TAM,B - estrellas[1]*TAM,7); ProyectaPunto(-10,-3,-2);estrellas[0] = pro_X,estrellas[1] = pro_Y; putpixel(B + estrellas[1]*TAM,A - estrellas[1]*TAM,7); ProyectaPunto(-5,3,-2);estrellas[0] = pro_X,estrellas[1] = pro_Y; putpixel(A + estrellas[0]*TAM,B - estrellas[1]*TAM,7); ProyectaPunto(10,-3,-2);estrellas[0] = pro_X,estrellas[1] = pro_Y; putpixel(A + estrellas[0]*TAM,B - estrellas[1]*TAM,7); xyz(); line(A + AA[0]*TAM,B - AA[1]*TAM,A + AA[2]*TAM,B - AA[3]*TAM); line(A + AA[4]*TAM,B - AA[5]*TAM,A + AA[6]*TAM,B - AA[7]*TAM); line(A + AA[0]*TAM,B - AA[1]*TAM,A + AA[6]*TAM,B - AA[7]*TAM); line(A + AA[2]*TAM,B - AA[3]*TAM,A + AA[4]*TAM,B - AA[5]*TAM); line(A + AA[0]*TAM,B - AA[1]*TAM,A + BB[0]*TAM,B - BB[1]*TAM); line(A + AA[2]*TAM,B - AA[3]*TAM,A + BB[2]*TAM,B - BB[3]*TAM); line(A + AA[4]*TAM,B - AA[5]*TAM,A + BB[4]*TAM,B - BB[5]*TAM); line(A + AA[6]*TAM,B - AA[7]*TAM,A + BB[6]*TAM,B - BB[7]*TAM); line(A + BB[0]*TAM,B - BB[1]*TAM,A + BB[2]*TAM,B - BB[3]*TAM); line(A + BB[2]*TAM,B - BB[3]*TAM,A + BB[4]*TAM,B - BB[5]*TAM); line(A + BB[4]*TAM,B - BB[5]*TAM,A + BB[6]*TAM,B - BB[7]*TAM); line(A + BB[6]*TAM,B - BB[7]*TAM,A + BB[0]*TAM,B - BB[1]*TAM); tecla=IZQUIERDA; if(kbhit()) tecla=getch(); setfillstyle(1,0);

Juan Carlos Gutiérrez Barquero____________________________________________ 120

Page 121: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

switch(tecla) case DERECHA:teta-=angulo;break; case IZQUIERDA:teta+=angulo;break; case ABAJO:fi+=angulo;break; case ARRIBA:fi-=angulo;break; case 122:if(TAM>0)TAM-=0.2;break; case 120:if(TAM<30)TAM+=0.2;break; /*endcase*/ if(!kbhit())delay(50); bar(0,0,getmaxx(),getmaxy()); while(tecla!=ESC); /*Ahora un juego de la serpientes este es un programa que encontre en Internet, no se quien es el autor, le hice algunos cambios */ #include<stdlib.h> # include <dos.h> #include<stdio.h> #include<conio.h> #include<graphics.h> #define clear; clrscr(); #define colorfondo 0 #define colorcabeza 4 #define c 1 #define bordear 40 #define bordeab 460 /*acotamos la parte valida de pantalla*/ #define bordeiz 20 #define bordede 620 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);

Juan Carlos Gutiérrez Barquero____________________________________________ 121

Page 122: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

struct bola int x; int y; /*La serp no es mas que una lista doble de puntos con su x y su y*/ struct bola *sig,*ant; ; int m,v,vel,tarj,modo,puntos,max,punt[9]=90,80,70,60,50,40,30,20,10; int longitud=0,radio=5,xa,ya,superado=0; /*No hay mas remedio que usar todas estas globales*/ struct bola *cabeza,*indice,*ultimo; /*Para la lista*/ void main(void) detectgraph(&tarj,&modo);/*comprueba el hw y detecta la tarjeta a usar*/ Inicio(); Juego(); void Inicio(void) int i; clear; textcolor(14); for (i=1; i<81; i++) gotoxy(i,9); cprintf ("Ä"); textcolor(1); gotoxy(34,1); cprintf (" Û Û"); gotoxy(34,2); cprintf (" Û ÛÛ ÛÛ Û"); gotoxy(34,3); cprintf (" ÛÛÛÛÛ ÛÛÛÛÛ"); gotoxy(34,4); cprintf ("ÛÛ ÛÛÛ ÛÛÛ ÛÛ"); gotoxy(34,5); cprintf ("ÛÛ ÛÛÛÛÛÛÛ ÛÛ"); gotoxy(33,6); cprintf ("ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ"); gotoxy(33,7); cprintf ("ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ"); gotoxy(34,8); cprintf ("ÛÛÛÛÛÛÛÛÛÛÛÛÛ"); gotoxy(38,9); cprintf ("Û");gotoxy(42,9); cprintf("Û"); textcolor(4); gotoxy(40,1); cprintf("Û");gotoxy(40,2); cprintf("Û"); gotoxy(40,3); cprintf("Û");gotoxy(40,4); cprintf("Û"); gotoxy(36,4); cprintf("Û");gotoxy(44,4); cprintf("Û"); gotoxy(36,5); cprintf("Û");gotoxy(44,5); cprintf("Û"); gotoxy(39,7); cprintf("O");gotoxy(41,7); cprintf("O");

Juan Carlos Gutiérrez Barquero____________________________________________ 122

Page 123: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

textcolor(9); gotoxy(31,10); cprintf ("ÛÛÛ Û Û ÛÛÛ ÛÛÛ ÛÛÛ"); gotoxy(31,11); cprintf ("Û Û Û Û Û Û Û Û"); gotoxy(31,12); cprintf ("Û ÛÛÛ ÛÛÛ Û Û ÛÛÛ"); gotoxy(31,13); cprintf ("Û Û Û Û Û Û Û Û"); gotoxy(31,14); cprintf ("ÛÛÛ Û Û Û Û ÛÛÛ ÛÛÛ"); textcolor(15); gotoxy(29,16); cprintf ("Dise¤ado por Abdul Ruiz"); gotoxy(31,17); cprintf ("CopyRight (c) 2002"); getch(); gotoxy(29,19); cprintf("Espera, por favor..."); delay(5500); clear; cprintf("TECLAS:\n\n\r"); cprintf(" -(Ar) 5(Ar)\n\r"); cprintf("MOVIMIENTOS o en el t.num.\n\r"); cprintf(" <Ä(Izq) (Ab) Ä>(Der) 1(Izq) 2(Ab) 3(Der)\n\r"); cprintf("Pausa: P\n\r"); cprintf("Salir: S\n\n\r"); cprintf("Si utilizas el teclado numerico, asegurate de que este activado\n\n\n\r"); cprintf("Pulsa una tecla para empezar"); getch(); sleep(5); clear; cprintf ("Dime el nivel de dificultad 1(Minima)...9(Maxima): "); do scanf("%d",&m); while(m<1 || m>9); switch(m) case 1:v=9;break;case 2:v=8;break;case 3:v=7;break;case 4:v=6;break;case 5:v=5;break; case 6:v=4;break;case 7:v=3;break;case 8:v=2;break;case 9:v=1;break; void Juego(void) int obj=0;/*Para saber si hay algo de comida en la pantalla*/ int mov=radio*2; char t,a;/*La tecla pulsada y la anterior*/ char pito=7; int x2,y2; initgraph(&tarj,&modo,"c:\\tc20\\bin");/*iniciamos modo grafico*/ setbkcolor(colorfondo);/*configuramos los colores del juego*/ setcolor(colorfondo); setfillstyle(1,c);

Juan Carlos Gutiérrez Barquero____________________________________________ 123

Page 124: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

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();

Juan Carlos Gutiérrez Barquero____________________________________________ 124

Page 125: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

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*/

Juan Carlos Gutiérrez Barquero____________________________________________ 125

Page 126: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

cleardevice(); Pinta_serpiente(); gotoxy(37,15); printf("Pausa"); t=getch(); cleardevice(); Pinta_serpiente(); break; /*si la tecla pulsada no hace nada, volvemos a poner la enterior*/ default: t=a; /*si se pasa por encima del objeto, se borra y se crece*/ if(cabeza->x==x2 && cabeza->y==y2) puntos+=punt[v-1]; obj=0; printf("%c",pito); switch(m) case 1: Crece(); break; case 2: case 3: Crece();Crece();break; case 4: case 5: Crece();Crece();Crece();break; case 6: case 7: case 8: Crece();Crece();Crece();Crece();Crece();break; case 9: Crece();Crece();Crece();Crece();Crece();Crece();break; /*cuantas mas bolas tenga que dibujar el ordenador, mas se*/ /*ralentiza el juego, esto lo contrarestamos disminuyendo el delay*/ /*cada 30 bolitas(lo he calculado a ojo) if((longitud)/(i*30)<0) vel-=15; i++; */ delay(vel); if(puntos>max)

Juan Carlos Gutiérrez Barquero____________________________________________ 126

Page 127: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

max=puntos; superado=1; while(1); void Salir(void) char opc; /*no hace falta comentar nada*/ if(superado!=0) Escribe_record(); gotoxy(11,10); printf(" Puntuacion maxima conseguida, eres el mejor, felicidades"); gotoxy(11,15); printf("Estas muerto, lo siento (R)Reintentar,(I)Reiniciar,(S)Salir"); do opc=toupper(getch()); while(opc!='R' && opc!='I' && opc!='S'); puntos=0; switch (opc) case 'R': Libera(); Juego(); break; case 'I': closegraph(); Libera(); Inicio(); Juego(); break; case 'S': closegraph(); Libera(); exit(1); break; void Avanza(void) indice=ultimo;

Juan Carlos Gutiérrez Barquero____________________________________________ 127

Page 128: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

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?, co¤o 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);

Juan Carlos Gutiérrez Barquero____________________________________________ 128

Page 129: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

int Choque(void) indice=cabeza->sig; /*si la cabeza esta en la pos de alguna bola o sale de los limites, devolvemos un 1*/ while(indice!=NULL) if(cabeza->x==indice->x && cabeza->y==indice->y) return 1; if((cabeza->y<bordear+radio)||(cabeza->x<bordeiz+radio)||(cabeza->x>bordede-radio)||(cabeza->y>bordeab-radio)) return 1; indice=indice->sig; return 0; void Crece(void) struct bola *este; este=malloc(sizeof(struct bola)); /*pues eso, se a¤ade una struct bola al final de la lista*/ if(cabeza==NULL) ultimo=cabeza=este; cabeza->ant=NULL; ultimo->sig=NULL; cabeza->x=bordeiz+radio; cabeza->y=bordeab-radio; else ultimo->sig=este; este->ant=ultimo; ultimo=este; ultimo->sig=NULL; este->x=-100; este->y=-100; indice=ultimo; longitud++;

Juan Carlos Gutiérrez Barquero____________________________________________ 129

Page 130: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

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;

Juan Carlos Gutiérrez Barquero____________________________________________ 130

Page 131: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

while(indice!=NULL) if(x==indice->x && y==indice->y) return 1; indice=indice->sig; return 0; void Lee_record(void) FILE *arch; if((arch=fopen("chaos.ars","rb"))!=NULL) fread(&max,1,sizeof(int),arch); if(puntos>max) max=puntos; fclose(arch); else max=puntos; void Escribe_record(void) FILE *arch; arch=fopen("chaos.ars","wb"); fwrite(&max,1,sizeof(int),arch); fclose(arch);

Juan Carlos Gutiérrez Barquero____________________________________________ 131

Page 132: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

1 Introducción a la Geometría Computacional 1.1. Historia de la Geometría Computacional La Geometría fue estudiada desde la antigua Grecia y Egipto. Constituían una herramienta muy importante para resolver problemas prácticos. El primer algoritmo que pueda considerarse completo es la construcción Euclídea, porque fue el primero que satisfizo todos los requerimientos: es correcto, no ambiguo y tiene un final. Este algoritmo además da una colección 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 Euclídeas. Se hablaba por entonces ya del término complejidad, no computacional pero sí de dificultad para medir la complicación de su realización. Se puede decir que fue una aproximación a lo que entendemos hoy por .complejidad temporal.. No se hablaba del problema en función del conjunto de entrada, pero sí intentaban reducirse el número de pasos a realizar para resolver un problema. Poco a poco se fueron dando cuenta de que todo problema posee un esfuerzo mínimo de realización, lo que nosotros llamamos .complejidad del algoritmo.. Ya en 1672 se demostró que cualquier construcción que pudiera realizarse sólo con regla y compás podría hacerse usando sólo compás. El concepto de línea se amplió pasando a ser el lugar geométrico compuesto por la unión de los puntos de corte de dos arcos realizados con un compás. La Geometría ha tenido momentos de especial realce, por ejemplo el crecimiento del análisis real, la Geometría métrica y la teoría de la convexidad, han supuesto las herramientas matem áticas para el diseño de algoritmos rápidos. Por un lado la distancia es un tema esencial en conceptos geométricos y la teoría de la convexidad es analizada para obtener propiedades globales. La Geometría Algorítmica está basada en caracterizaciones de objetos geométricos en términos de propiedades de subconjuntos finitos. Un tratamiento algorítmico implica eliminar el término infinito. Hoy día la Geometría Computacional se utiliza como herramienta básica, no sólo en disciplinas inmediatamente relacionadas con la Geometría. A partir de finales de los años 60 y 70, el incremento del uso de la computadoras en investigación y desarrollo, propicia usar estas máquinas para resolver problemas clásicos que siempre fueron resueltos a base de reglas y compás. Pero la memoria de las máquinas y el tiempo de ejecución de éstas, la mayoría de las veces compartido, exigió de pronto el conseguir métodos que no sólo funcionaran, sino que intentaran optimizar al máximo dos recuerdos muy importantes, sobre todo por aquel entonces: la memoria y el tiempo de CPU. Hoy por hoy a pesar de utilizar máquinas más potentes, también se plantea en

Juan Carlos Gutiérrez Barquero____________________________________________ 132

Page 133: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

muchas ocasiones incrementar el número de datos a procesar, por lo que hoy sigue siendo un problema a resolver. Algunas aplicaciones donde la Geometría Computacional es necesaria es la Informática Gráfica, Robótica, Sistemas de Información Geográficos, etc. El término nace en 1975 por Shamos y desde entonces los trabajos y los estudios en esta disciplina han ido creciendo de forma espectacular. 1.2. Eficiencia de los algoritmos Existen distintas formas de medir algoritmos o de clasificarlos. Un algoritmo fácil de entender, codificar y depurar es preferible a otro que realice lo mismo pero que no cumpla estas carácter í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 ejecución 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 diseñarse. Por el contrario es beneficioso en muchas ocasiones realizar un buen diseño a pesar de utilizar gran cantidad de esfuerzo y emplear estructuras de datos complejas, si se consigue finalmente un método de resolución que realice buenos tiempos de ejecución para entradas grandes de datos. Por otra parte, cuando nuestro algoritmo pretende resolver un problema clásico, como puede ser en Geometría Computacional, se da por supuesto que tiene que ser eficiente con grantes cantidades de datos y además hay que suponer que dicho algoritmo va a ser ampliamente utilizado. Por tanto, nuestro propósito es no sólo entender y utilizar algoritmos que funcionen en Geometría Computacional sino que también sean eficientes. Para medir dicha eficiencia, hay que tener en cuenta ciertos parámetros:

Dependencia de los datos de entrada del programa. Calidad del código que genera el compilador en el programa objeto. Las instrucciones y arquitectura de las computadoras. Tiempo de ejecución de dicho programa.

Como entrar en detalles de compiladores diferentes y de distintas arquitecturas es muy amplio y además es absolutamente cambiante, basta decir que cuanto más rápido mejor. Lo que haremos será estudiar los algoritmos en función de la entrada, básicamente de su tamaño, y además en la complejidad o tiempo que emplea el algoritmo para su ejecución. Obviamente un algoritmo, o programa puesto que se está ejecutando, va a ser más rápido si tiene que procesar diez datos que si tiene que realizar lo mismo con una entrada de tamaño cien.

Juan Carlos Gutiérrez Barquero____________________________________________ 133

Page 134: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

Vamos a denominar T(n) al tiempo de ejecución de un programa con tamaño n. Para no especi ficar el tiempo en segundos, puesto que depende excesivamente de la máquina empleada, se usará una función expresada en términos de n. Por ejemplo, T(n) = cn2, siendo c una constante. En muchas ocasiones es necesario referirse al tiempo de ejecución esperado del algoritmo en el peor de los casos para una entrada de tamaño 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 también puede ser interesante en casos donde se conozca que el peor caso se produce con una probabilidad muy pequeña. Cuando decimos que el tiempo de ejecución 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 genérico decimos que T(n) es O( f (n)). También existen cotas inferiores para hablar del tiempo de ejecución. Es una cota inferior o lo que es lo mismo: el algoritmo se ejecutará al menos en el tiempo que la función 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 representación gráfica de la función f (n), más rápido se ejecutará el algoritmo para un conjunto de entrada de tamaño dado. Pero esto no siempre es verdadero para todo n, es decir, en ocasiones el tiempo de ejecución se refiere a grandes cantidades de información 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 más lento para n menor que 20 que otro que se ejecute en tiempo O(5n2). En algoritmos típicos de Geometría 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 tamaño 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 pequeño. En algunas ocasiones un algoritmo puede permitirse el lujo de ser algo más lento si a cambio es más didáctico. 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 numéricos es tan importante la precisión de los cálculos como la eficiencia de éstos. Para calcular la eficiencia de un algoritmo hay que tener en cuenta ciertos casos:

Juan Carlos Gutiérrez Barquero____________________________________________ 134

Page 135: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

Si T1(n) y T2(n) son tiempos de ejecución de dos fragmentos de programa, el tiempo totalserá de T1(n)+T2(n). Sin embargo, se considera únicamente el más lento de los dos y eltiempo de ejecución 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). También existen simplificaciones, por ejemplo,O(c f (n)) se considera siempre O( f (n)).

Una asignación u operación aritmética suele considerarse con tiempo

O(1). En las proposiciones condicionales, la parte de la condición suele

considerarse tiempoconstante si no necesita realizar llamadas a otras funciones. El tiempo global de esta instrucción se toma de nuevo como el mayor de las dos partes que la forman, parte then o parte else.

En un ciclo se suele determinar por el número de iteraciones

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 cuadrático (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 según las pautas anteriores, pero en procesos recursivos se trabaja de forma distinta. Supongamos la siguiente función:

Para n > 2, tenemos que T(n) = c +T(n –1). El término T(n –1) se sustituye por n –1: T(n–1) = c+T(n–2), sustituyendo tenemos que T(n) = c+c+T(n–2). Siguiendo este proceso hasta el término i entonces T(n) = ic+T(n–i). Cuando i = n–1, 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 tamaño. Cuando éste proceso de división termina necesita un tiempo lineal para unir los resultados de las dos mitades. Este método es muy habitual en los problemas resueltos con el método Divide y Vencerás.

Juan Carlos Gutiérrez Barquero____________________________________________ 135

Page 136: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

1.3. Operaciones básicas en Geometría Computacional En este apartado entraremos en contacto con métodos para la resolución de algunos de los problemas más elementales en Geometría. Nos servirá igualmente para recordar conceptos a nivel computacional. Los algoritmos aparecerán mayormente escritos en lenguaje Pascal, a no ser que alguno de ellos aparezca, no por razones prácticas sino didácticas. 1.3.1. Introducción A nivel de tratamiento de la información, en Geometría Computacional es clara la preferencia por los tipos de datos enteros, lo que se denomina aritmética entera. La razón 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 transformación í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 precisión al ser guardados. Cuando una variable de tipo real nace en la ejecución 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 razón, y siempre que sea posible, es preferible hacer uso de la aritmética entera. Por ejemplo, para saber si dos segmentos intersecan basta utilizar aritmética entera, sin embargo si queremos saber exactamente el lugar de intersección, sí era necesario realizar algún cálculo en coma flotante. 1.3.2. Algunos tipos de datos simples Los datos geométricos, a la hora de ser procesados por un ordenador, son reemplazados por lo que denominamos tipos de datos. Muchos conceptos típicamente matemáticos se denominan de forma análoga 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 programación soporta cubren el espectro más habitual, sin embargo, los de tipo geométrico deben ser definidos explícitamente 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 prácticas se definirán muchos de ellos, ahora identificaremos los anteriores en Pascal para poder trabajar con ellos a lo largo de este tema:

Juan Carlos Gutiérrez Barquero____________________________________________ 136

Page 137: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

/************REPRESENTACION DE UN PUNTO*********************/ # define x 0; # define y 0; typedef enum FALSE, TRUEbool; # define DIM 2 /*Dimensión del punto*/ typedef int tpointi(DIM); /*Declaración de un arreglo de puntos*/ /*********REPRESENTACION DE UN PUNTO***********************/ # define PMAX 100 Typedef tpointi tpolygoni[PMAX] Por simplicidad computacional, se emplea un array con dos posiciones para un punto, identifi cando la posición 0 para guardar el valor de la x y la posición 1 para el de la y. Cuando se dice que un polígono es un array de puntos, realmente tenemos una matriz bidimensional con un total de dos columnas, igualmente fácil de manejar computacionalmente. Las técnicas de tricoloreado dos tecnicas utilizadas para la representación de los guardas y otras entidades diferentes de las triangulaciones y vasadas en las diagonales si desean información de estas acudan al libro geometry computacional in C. 1.3.3. Cálculo del área Una de las operaciones más elementales en Geometría es el cálculo del área de un triángulo, sea del tipo que sea. El método para realizar este cálculo no es otro que la resolución de un determinante 3x3, aunque no es objetivo de esta asignatura el cálculo matemático correspondiente. El algoritmo escrito en pseudocódigo aparece a continuación. Por razones argumentadas anteriormente, se opta por trabajar siempre con aritmética entera. La función AreaTriangulo2 evitará la división por dos y calculará el doble del área del triángulo, por lo hay que tener en cuenta que para obtener el valor real del área será necesario hacer la división correspondiente. Ahora vemos el código: Int Area2(tPointi a, tPointi c, tPointi c) return : = ( ( a [ 0 ] *b[1])–(a [ 1 ] * b [ 0 ]) + ( b [ 0 ] * c [1])–(b [ 1 ] * c [ 0 ]) + ( c [ 0 ] * a[1])–(c [ 1 ] * b [ 0 ]) ) ; El resultado de este cálculo será positivo siempre que los vértices abc sean recorridos en orden inverso a las agujas del reloj. En caso contrario el valor será igualmente válido y medirá el área, pero tendrá el signo negativo.

Juan Carlos Gutiérrez Barquero____________________________________________ 137

Page 138: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

El cálculo del área de un polígono convexo es bien sencillo, basta con calcular el área de todos los triángulos que se pueden formar lanzando diagonales desde cualquier vértice, hasta el resto de los vértices del polígono convexo.

Si el polígono no es convexo, el área puede calcularse sumando las áreas de los triángulos resultantes o incluso restando los de aquellos que no tengan superficie, como en el siguiente ejemplo:

El área del polígono puede calcularse de dos modos: Area (abd) + area (bcd) Area(abc) – area(adc)

Este mismo principio puede extenderse a cualquier polígono, indistintamente del tipo y número de vértices que tuviera. Veamos el siguiente ejemplo: se ha elegido un punto cualquiera p, interior o exterior al polígono y se han trazado diagonales a todos sus vértices. Los vértices de éste han sido enumerados del o al n–1 en orden inverso a las agujas del reloj. Este dato es muy importante, porque va a ser siempre el mecanismo utilizado para numerar los vértices cuando trabajemos con polígonos. El número de triángulos obtenidos será de n–1, siempre partiendo del punto p y siguiendo con dos vértices sucesivos del modo siguiente:

Juan Carlos Gutiérrez Barquero____________________________________________ 138

Page 139: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

El triángulo p01 se traza en sentido inverso a las agujas del reloj, lo que implicará siempre que el área de dicho triángulo es positiva. Se ha señalado utilizando un símbolo + cuando el cálculo se realiza en el sentido antihorario y con – cuando el área es negativa. Cuando el recorrido de los vértices del triángulo siempre en la forma pvivi+1, sea en sentido horario, por ejemplo el triángulo p67, el área correspondiente se resta. El resultado final, como podemos observar en la figura, es que todas las áreas de los triángulos no contenidas en el interior del polígonos 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 función AreaTriangulo2 tantas veces como triángulos se vayan formando con el proceso anterior, sumando unas veces las áreas y otras restándose automáticamente según sea la salida de dicha función. Como de cada triángulo 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 polígono, podemos optar por tomar al punto del polígono s[0], o lo que es lo mismo computacionalmente, a s[0]. El resultado lo podemos escribir a continuación: Veamos el código: 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. Intersección de segmentos Una de las operaciones elementales en Geometría Computacional es la intersección de segmentos, cálculo válido para otros muchos problemas. Sin

Juan Carlos Gutiérrez Barquero____________________________________________ 139

Page 140: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

embargo, y siguiendo con la dinámica de trabajar siempre que sea posible con aritmética de enteros, el algoritmo de intersección de segmentos va utilizar otra serie de subrutinas necesarias. Si recordamos una de las propiedades de la función del cálculo del área del triángulo, el resultado es positivo si la lectura ordenada de los vértices nos da un recorrido antihorario. Esta propiedad puede ser útil para determinar si un punto c está a la izquierda del segmento ab. Observemos la siguiente figura:

El triángulo imaginario abc se dibuja en orden inverso a la agujas del reloj, lo que automáticamente 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 triángulo bac es negativa porque el punto c está a la derecha del segmento ba. El subprograma correspondiente únicamente necesita realizar una llamada a la función AreaTriangulo2 anteriormente vista. Aprovechamos un cálculo en principio de distinta índole, para determinar la posición 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 difícil entender que este mismo principio sirve para determinar si el punto c está justamente a la derecha (la función anterior nos devuelve un valor f alse). o si el área del triángulo abc es igual a cero, lo que indica que los tres puntos son colineales:

Juan Carlos Gutiérrez Barquero____________________________________________ 140

Page 141: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

Veamos el codigo en C: bool Collineal(tpointi a, tpoint b, tpoint c) return Area2(a,b,c)==0; Debemos insistir en que el código anterior da por supuesto que todos los cálculos se realizan únicamente utilizando aritmética de enteros. No quiere decir ésto que no pueda migrarse dicho código a operaciones en coma fiotante, pero en ese caso jamás debería realizarse una operación 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 más 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 próximo a cero. Para saber si dos segmentos ab y cd intersectan, deberíamos saber si: 1. no son colineales 2. si d está a la izquierda de ab y c está a la derecha (o al revés) y además 3. si a está a la derecha de cd y b lo está a la izquierda (o al revés) Nos podemos dar cuenta en la figura de que si no se cumple algunas de estas premisas no tenemos garantía de que ambos segmentos intersecten.

El código debe tener en cuenta todos los casos citados anteriormente. La operación válida para implementar el .al revés., es la operación XOR(a;b) cuya tabla de verdad da el valor verdadero cuando a y b son distintos.

Juan Carlos Gutiérrez Barquero____________________________________________ 141

Page 142: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

bool Intersect(tpointi a, tpoint b, tpointi c, tpointi d) If (IntersectProp(a,b,c,d)) Return TRUE; /*Hay intersección 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 método es la redundancia. Ahora realizaremos una nueva versión 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 versión del algoritmo además cuenta con al ventaja de poder trabajar con las intersecciones de forma propia o impropia. Una intersección impropia ocurre cuando un extremo de uno de los segmentos está justo en en alguna posición del otro. La siguiente función en Pascal detecta primero si existe la posibilidad de colinealidad con la función Entre. Posteriormente hace el mismo proceso que IntersectaSegmento. Veamos el código: 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) )

Juan Carlos Gutiérrez Barquero____________________________________________ 142

Page 143: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

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. Cálculo de diagonales El cálculo de una diagonal tiene como objetivo la triangulación de polígonos. Una diagonal es aquel segmento que une dos vértices del polígono de forma que no intersecte con ningún otro eje de dicho polígono y además sea interno al polígono. Para saber si existe o no intersección puede utilizarse el proceso anterior, pero para saber si es o no interno necesitamos realizar un procesamiento adicional. Este cálculo puede realizarse en tiempo constante porque si una diagonal es interior a un polígono P en su vecindario (vértices próximos), también lo es para todo el polígono, no siendo necesario un procesamiento completo del polígono P. Diremos que un segmento s es interno a P si y sólo si es interno al cono cuyo vértice es vi y cuyos lados pasan a través de vi–1 y vi+1. Existen dos casos, el caso convexo en el que el resto del polígono está en la parte de menor ángulo y el caso cóncavo en cuyo caso el ángulo es mayor que . La siguiente función determina si el vector que une los vértices i y j del polígono P es interior o no al polígono. Veamos el codigo: Esta función 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]));

Juan Carlos Gutiérrez Barquero____________________________________________ 143

Page 144: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

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 vértice vi+1 está a la izquierda del eje trazado por vi–1vi. En este caso, lo vemos en la figura de la izquierda, para que se trate de un eje interno debe ocurrir que vi–1 esté a la izquierda de viv j y que vi+1 lo esté a la izquierda. El caso cóncavo aparece a la derecha.

Por tanto, una diagonal es aquel segmento interior que está dentro del polígono. Pero el segmento i j es una diagonal si no intersecta con ninguna otro de las aristas del polígono. Este cálculo necesita forzosamente un tiempo de ejecución lineal. La función DiagonalfiIE se encargará de realizar este chequeo, y que será invocado por la función Diagonal cuyo código resulta bastante evidente: el segmento i j es una diagonal del polígono P de tamaño n si es interior y además no intersecta con ninguna arista. Veamos el código: 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 ) ) )

Juan Carlos Gutiérrez Barquero____________________________________________ 144

Page 145: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

if ( Intersect (p[i], p[j], p[k], p[k1])) return FALSE;

return TRUE;

/*Esta function remueve el triangulo formado por la diagonal y la arista asociada ala diagonal, para lo cual reasigna las etiquetas del polígono.*/ 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 vértices 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 lºn",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: triangulación de un polígono La triangulación de polígonos es un cálculo muy importante en muchas aplicaciones de Geometr ía Computacional. Permite, aparte de otras muchas aplicaciones, dividir un polígono con posible cierta complejidad, en un conjunto de triángulos fáciles de procesar. Veremos que el siguiente método puede ser perfectamente válido para lograr la triangulación de cualquier polígono P de tamaño n. Sin embargo, y a pesar

Juan Carlos Gutiérrez Barquero____________________________________________ 145

Page 146: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

de su simpleza, su utilización no es aconsejable y por ello no se ha implementado en un leguaje de programación. Vemos que es un método recursivo porque se llama a sí mismo. La llamada recursiva se realiza cuando se localiza una diagonal, y como en ese momento el número de vértices a procesar es uno menos, puesto que el vértice i1 queda aislado al encontrarse la diagonal ii2. La función EliminaVertice se encargaría de este operación, dejando cada vez que se llama un polígono más pequeño. Esta función triangula el poligono P de n vertices. void Trinagulate1 (int n, tpoligoni) tpoligoni.pt; int labels[PMax]; clrscr(); for(i=0;i<n;i++) PointAssign(pt[i]<P[i]); labels[i]; printf("Diagonales de la triangulacion;\n"); TriRecurse(n,pt,Labels); /*Esta función asigna al punto "a" el valor del punto "b".*/ void PointAssign(tpoint a, tpoint b) int i; for(i=0;i<DIM;i++) a[i]=b[i]; La razón por la que este algoritmo no es desde luego nada interesente es por su tiempo de ejecución. El algoritmo trabaja en O(n3) porque realiza un total n–3 llamadas recursivas y cada una de ellas, en el peor de los casos, necesita un tiempo cuadrático (la función diagonal es lineal, así como la ejecución completa del bucle). Como veremos a lo largo de este curso, para valores de n elevados, este algoritmo resulta Evidentemente lento, y en Geometría Computacional todos los problemas cuyas soluciones inmediatas sean susceptibles de mejora, son estudiados. Como veremos en sucesivos capítulos, cualquier polígono puede ser triangulado en tiempo O(nlog n). Los algoritmos geométricos, al igual que los desarrollados para otras disciplinas, deberán combinar adecuadamente junto con su conjunto de

Juan Carlos Gutiérrez Barquero____________________________________________ 146

Page 147: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

sentencias, a las estructuras de datos correctas para conseguir el objetivo final, obtener programas eficientes. 1.4.1. Introducción a las estructuras de datos El estudio de las estructuras de datos y los métodos para la organización de dichos datos es uno de los aspectos clásicos más importantes para construir algoritmos eficientes. Los programas trabajan con información que permanece en memoria principal o en algún dispositivo de memoria secundaria. La organización que se le da a dichos datos es lo que denominamos estructuras de datos. La mayoría de las estructuras de datos pueden verse como contenedores que mantienen información de un determinado tipo con un cierto orden. El acceso y manejo de los datos en un contenedor se realiza a través de un localizador. Dependiendo de la estructura del contenedor, el localizador proporcionará un modo de acceso a los datos, por ejemplo, un índice de un array o un puntero. Una estructura de datos además de proporcionar un modo de acceso, también deber llevar asociado un conjunto de operadores, como insertar un nuevo dato, actualizar uno ya existente o eliminar algún otro. Las características de una estructura de datos va en relación al orden de ejecución de sus operaciones y a los requerimientos de espacio. En cualquier caso, la estructura de datos más idónea dependerá siempre del problema que se pretenda resolver. Un tipo de dato es una colección de objetos a la que se le da una representación matemática. Un tipo de dato abstracto o TDA es un tipo de dato, más un conjunto de operaciones que lo manejan. Las estructuras de datos pueden considerarse como implementaciones concretas de tipos de datos abstractos. Los TDAs (notación anglosajona) han evolucionado hasta convertirse en clases de objetos. Lo que inicialmente se concibió como un concepto matemático que se adaptó a la sintaxis de los lenguajes de programación tradicionales, se ha ido convirtiendo en una nueva filosofía de programación con los nuevos lenguajes orientados a objetos. Existen multitudes de estructuras de datos ampliamente documentadas en la bibliografía. En este apartado repasaremos algunas de las estructuras de datos usadas en el curso. Dependiendo de la organización interna y del modo de acceso a los datos, existen dos tipos fundamentales de contenedores, los contenedores secuenciales o secuencias y los asociativos. Una secuencia es un contenedor que almacena los elementos con un orden lineal determinado, realizando el acceso a la información indicando la posición donde se localiza el dato. Por el contrario un contenedor asociativo, independientemente de su organización interna, permite el acceso por clave. Contenedores secuenciales

Juan Carlos Gutiérrez Barquero____________________________________________ 147

Page 148: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

Las secuencias más usuales son las listas enlazadas y los arrays. Las primeras forman una sucesión 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 implícitos con acceso directo. Esta ventaja de acceso en tiempo constante se ve mermada por poseer menor fiexibilidad. Por ejemplo, la operación de inserción 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 dinámica. Esta consideración también puede realizarse sobre arrays dinámicos. Contenedores asociativos Los contenedores asociativos poseen una filosofía de manejo y una estructura interna totalmente diferente a las secuencias. La diferencia fundamental es que el acceso a la información se realiza siempre utilizando una clave y no una posición, que puede identificar o no de forma unívoca al dato. Las operaciones fundamentales son de inserción, actualización, borrado y búsqueda por dicha clave. La organización interna de los datos depende del tipo de contenedor asocitivo, por árbol o por tabla hash. Los primeros mantienen un árbol binario de búsqueda o Inorden, manteniendo una relación 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 información, siempre que todas las ramas del árbol permanezcan a la misma altura. Estas estructuras de datos garantizan búsquedas en O(logn). Las estructuras de datos consideradas de carácter general son ampliamente utilizadas en Geometría Computacional, pero existen otros aspectos como son la naturaleza espacial de los objetos geométricos o sus propiedades estructurales que requieren del manejo de estructuras de datos más específicas para construir algoritmos eficientes. La elección de un tipo de estructura de datos o de otro va a depender del tipo de objetivo que se persiga: captura de información estructural, acceso a los datos o actualización eficiente de éstos, optimización del espacio requerido o del número de operaciones de E/S. En otras ocasiones, las estructuras de datos se eligen según la asociación de objetos geométricos que representen. 1.4. Algunos métodos de programación utilizados en C. La Geometría Computacional, en contraste con la disciplina clásica basada en proporcionar teoremas matemáticos, enfatiza los aspectos computacionales de

Juan Carlos Gutiérrez Barquero____________________________________________ 148

Page 149: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

los problemas y atiende a las propiedades geométricas para encontrar algoritmos eficientes. Que un problema geométrico tenga solución dentro de la Geometría Computacional no basta en muchas ocasiones, se desea además que la solución se encuentre en un tiempo óptimo. Existen una serie de técnicas y paradigmas de programación que vienen siendo muy habituales no sólo en el campo de la Geometría Computacional. Algunos de estos métodos como el divide y vencerás ya habían proporcionado la solución óptima a problemas como la ordenación, en otras ocasiones los métodos de resolución están íntimamente relacionados con las capacidades de la propia Geometría. A continuación daremos un repaso a los paradigmas de programación más empleados dentro de la Geometría Computacional. 1.5.1. Método incremental Éste puede ser considerado como uno de los métodos más simples e intuitivos, también conocido como el método iterativo. La idea sobre la que trabaja este método consiste en construir la solución de modo iterativo, considerando que la entrada se produce de modo incremental. Para cada una de las nuevas entradas, el problema se resuelve convenientemente. Supongamos que se pretende procesar una nube de n puntos en el plano S, para resolver cualquier problema Prob(S) bajo esta técnica. En muchas ocasiones S deberá estar ordenada bajo algún criterio con coste O(nlogn). El algoritmo trabaja siempre de forma similar. Inicialmente Prob se resuelve de forma trivial para fs0; s1; :::; sk–1g, los primeros k puntos de S. Posteriormente y uno a uno, se resolverá Prob(Si) para el resto de si 2 S; i = fk; :::;n–1g tal y como indica el Algoritmo 1, obtiendo finalmente Prob(S). Si en un problema de tamaño n, el coste de insertar un nuevo dato es O(n), entonces el tiempo global del algoritmo será de O(n2). Pero si añadir un nuevo elemento a la solución parcial del problema tiene coste constante o logarítmico, el algoritmo final se procesará en O(nlogn), la misma cota impuesta por el algoritmo de ordenación. Algoritmo 1 Incremental-generalizado. Incremental(RC,p) 1. Si p está dentro de RC 2. entonces devolver RC 3. sino 4. (Pt1,Pt2) := puntosTangentes(RC,p) 5. Eliminar aristas en RC de Pt1 a Pt2 6. Conectar Pt1 con p y p con Pt2

Juan Carlos Gutiérrez Barquero____________________________________________ 149

Page 150: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

Ahora veremos los puntos tangentes:

1.5.1.1. Línea de barrido Esta estrategia es una particularización del método incremental, considerándose válida para problemas en dos dimensiones cuando el conjunto de entrada se produce en un cierto orden. La solución de la mayoría de estos problemas puede ser incremental, de hecho, la implementación de este paradigma sigue las mismas premisas que las dadas para el método incremental citado anteriormente. El método supone que una línea horizontal (o vertical) recorre el plano de arriba hacia abajo (o en sentido contrario). Cada vez que dicha línea encuentra un ítem (un punto, una línea, etc) lo procesa modificando el conjunto de estructuras que datos que participen en la construcción de dicho algoritmo. La validez de esta técnica está basada en la observación de que la parte que queda por encima o por debajo de la línea de barrido se ha construido correctamente. Por ejemplo en el problema de intersección de segmentos, cuando la línea encuentra un nuevo segmento, se realizará una inserción en alguna estructura de datos capaz de mantenerlos ordenados de izquierda a derecha (en el caso de que la línea de barrido sea horizontal). Normalmente se escogen estructuras de datos con tiempos de actualización y de acceso logarítmico. Si el procesamiento de dichos objetos geométricos es constante, como es el caso de la intersección de dos segmentos, pueden trabarse con tiempos del orden de O(nlog n).

Juan Carlos Gutiérrez Barquero____________________________________________ 150

Page 151: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

Esta técnica es empleada para diferentes problemas como la intersección de segmentos, partición de polígonos en subdivisiones monótonas, intersección de semiplanos, el diagrama de Voronoi y triangulación de Delaunay, los métodos de Jarvis y Graham para el cálculo de la envolvente convexa, la técnica de localización de los puntos más lejanos, y otros más. Existen técnicas análogas para dimensiones mayores. Algoritmo 1 El algoritmo de la línea de barrido rotatoria (Rotational Sweep Line): Entrada: Un conjunto de obstáculos poligonales S y un conjunto de puntos Q. Salida: Un grafo de visibilidad G = (V, E). Sea W la unión de los vértices de S y los puntos de Q, sea E el conjunto de aristas, y sea T un árbol de búsqueda equilibrado. 1.- Para cada vértice w de V: 2.- Ordenar todos los vértices de W en sentido horario según la semi-línea P, y, en caso de empate, ordenar según distancia al punto p. 3.- Ordenar las aristas que intersectan con P e insertarlas en el árbol equilibrado T. 4.- Para cada vértice w de la lista ordenada W: 5.- Si w es visible desde p, entonces añadir la arista e=(p, w) al grafo G. 6.- Insertar en el árbol los obstáculos que incidan en w y que estén en el lado horario de P. 7.- Eliminar del árbol los obstáculos que incidan en w y que estén en el lado antihorario de P.

1.5.2. Divide y Vencerás

Juan Carlos Gutiérrez Barquero____________________________________________ 151

Page 152: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

Esta técnica clásica de programación es válida para resolver de forma eficiente problemas Geom. étricos. Normalmente se basa en la sucesiva división en partes iguales del problema original, hasta conseguir que éste posea un tamaño lo suficientemente pequeño como para poder resolverse fácilmente. Llegado a un punto en que la división deja de tener sentido, los problemas se van resolviendo recursivamente y combinando sus soluciones para obtener la solución final. El método más eficiente de ordenación, 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 ecuación de recurrencia de la Sección 1.2 corresponde al método Divide y Vencerás. Algoritmo 2 Paradigma de divide y vencerás

Juan Carlos Gutiérrez Barquero____________________________________________ 152

Page 153: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

Juan Carlos Gutiérrez Barquero____________________________________________ 153

Page 154: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

Es un ejemplote Voronoi. Esta técnica es ampliamente utilizada y sirve de base para construir algoritmos aleatorios. Puede emplearse para construir la envolvente convexa, el diagrama de Voronoi, etc.

Juan Carlos Gutiérrez Barquero____________________________________________ 154

Page 155: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

2 La envolvente convexa y triangulación de polígonos 2.1. La envolvente convexa 2.1.1. Introducción El cálculo de la envolvente convexa de un conjunto de puntos en espacios euclídeos ha sido sin duda uno de los problemas a la vez más básicos y más ampliamente estudiados a lo largo de la historia de la Geometría Computacional. Además, los campos en los que ha resultado un cálculo útil sorprenden por lo aparentemente poco relacionados con las matemáticas en general y la geometría 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 definición puede ser aplicada en cualquier espacio euclídeo 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 fácil de entender en cierto modo si consideramos a la envolvente convexa de un conjunto de puntos en el plano, como la forma que adquiriría una goma elástica envolviendo a todos los puntos del conjunto que están 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 cálculo de la envolvente convexa. Pero exiten otras definiciones válidas: la envolvente convexa de un conjunto de puntos en el plano es la unión de todos los triángulos determinados por dicho conjunto de puntos. El estudio de la envolvente convexa en dos dimensiones ha sido objeto de especial interés. Existen una serie de características asociadas a los puntos que forman parte de la envolvente convexa en el plano y que han servido igualmente para definirla y construirla. Un punto q 2 S pertenece a la envolvente convexa de S, q 2CH(S), si es posible trazar una recta pasando por

Juan Carlos Gutiérrez Barquero____________________________________________ 155

Page 156: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

dicho punto de forma que todo el conjunto S0, S0 = S–fqg quede a un lado de dicha recta. Como se ha indicado con anterioridad, el cálculo de la envolvente convexa ha sido aplicado ampliamente a disciplinas en ocasiones ajenas a la Geometría Computacional y en espacios distintos de dos dimensiones. Tal es el caso del reconocimiento de patrones, procesamiento de imágenes, etc. Los algoritmos propuestos para este problema son realmente numerosos. Sin duda es uno de los planteamientos de la Geometría Computacional que más soluciones ha conseguido. Desde incluso antes del nacimiento oficial de esta disciplina se conoce el trabajo de Graham en el año 1972. Se han propuesto estrategias siguiendo los paradigmas más empleados como el método incremental y el divide y vencerás. Todos estos algoritmos construyen la envolvente convexa en tiempo (nlog n). El método propuesto por Preparata y Shamos en 1985 fue denominado Quickhull por su similitud con el método de ordenación Quicksort. Otra propuesta diferente se dió a conocer en 1973 como .La marcha de Jarvis.. Este método, que estudiaremos en este curso, posee un tiempo de ejecución cuadrático, sin embargo supone un interesante ejemplo basado en manejo de ángulos del cual partiremos para el tratamiento del diagrama polar. Todos estos trabajos constituyen el conjunto clásico de algoritmos para la resolución de la envolvente convexa, al que habría que añadir otras técnicas posteriores. La envolvente convexa posee una cota de (nlog n), es decir, no se puede encontrar una algoritmo que trabaje en menor tiempo para todos los casos. 2.1.2. Un ejemplo de resolución El problema de encontrar la envolvente convexa de un conjunto de puntos puede ser interesante porque es equivalente a encontrar todo el conjunto de puntos extremos de dicha nube. Por tanto, puede definirse como punto extremo a cualquier punto de la envolvente convexa, y todo punto extremo tiene la propiedad de que es posible trazar una línea recta a través de él de modo que el resto de puntos queden a un lado. También podemos decir que un punto es extremo si y sólo si está dentro de algún posible triángulo cuyos vértices son cualesquiera de los puntos de la nube original. Pero bajo esta definición, necesitaríamos procesar O(n3) triángulos para cada uno de los n puntos, lo que nos proporciona un método en triempo O(n4), lo cual no es eficiente teniendo en cuenta que se trata de un problema (nlog n). Pero la envolvente convexa posee aplicaciones fuera del ámbito de la Geometría. Supongamos que una explotación petrolífera extrae diferentes tipos de componentes mezclados en distinta propoción. Si el objetivo es conseguir los componentes A y B pero en una nueva proporción, podemos hacer uso de

Juan Carlos Gutiérrez Barquero____________________________________________ 156

Page 157: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

la envolvente convexa del modo siguiente. Supongamos que partimos de las mezclas: e1 = A10%B35%, e2 = A16%B20% y e3 = A7%B15% y queremos obtener e f = A13%B22%. Para saber si es posible obtener este producto final e f basta con considerar las anteriores mezclas como puntos del plano, obteniendo el siguiente esquema:

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 combinación final no podría producirse. Este problema sería un problema 3D si cada mezcla tuviera tres componentes, la solución sería la contrucción de la envolvente convexa tridimensional. 2.1.3 Algoritmo trivial 1. Determinación 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. Determinación de aristas extremas

1. Para cada i hacer 2. Para cada j ≠ i hacer 3. Para cada k ≠ i ≠ j hacer 4. Si Pk no está a la izqda de (Pi,Pj) 5. entonces (Pi,Pj) no es extremo

Juan Carlos Gutiérrez Barquero____________________________________________ 157

Page 158: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

Complejidad: O(n3 ) 2.1.5 Gift Wrapping 1. Encontrar punto p más pequeño 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 máxima 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 más a la derecha de S; 2. b := punto más a la izquierda de S 3. devolver concatenar(QuickHull(a,b,izquierda(a,b,S)), QuickHull(b,a,izquierda(b,a,S)))

Juan Carlos Gutiérrez Barquero____________________________________________ 158

Page 159: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

La idea básica del quickhull (envolvente rápida) es que para la mayoría 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 cuadrilátero que ellos definen (este cuadrilátero puede ser degenerado), ahora todos los puntos en el interior de dicho cuadrilátero 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 más alejado a la recta que define dicha región obteniendo así cuatro nuevos puntos y un polígono de a lo más ocho lados que divididirá a los puntos que no hemos eliminado en ocho regiones que tratamos individualmente siguiendo la misma regla anterior.

Juan Carlos Gutiérrez Barquero____________________________________________ 159

Page 160: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

En nuestro ejemplo en el paso siguiente se obtine ya la envolvente convexa.

El QuickHull suele calcular la envolvente convexa en un tiempo mucho más corto que si lo hacemos a través del diagrma de Voronoi. Sin embargo, un análisis del algoritmo nos lleva a que su complejidad en tiempo es cuadrática. Por lo tanto, centrémosno ahora en encontrar un algoritmo óptimo.

Ejemplo:

Juan Carlos Gutiérrez Barquero____________________________________________ 160

Page 161: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

2.1.4. Graham's scan Este es sin duda uno de los algoritmos más importantes para el cálculo de la envolvente convexa, no únicamente por su simpleza sino también por su rapidez. El proceso realiza primero una ordenación angular de los puntos. El punto tomado de referencia para tal fin debe ser un punto de la envolvente convexa, por ejemplo el de menor ordenada y al que llamaremos p0. El resto de puntos quedan ordenados de izquierda a derecha obteniendo la secuencia p1, p2,…, pn–1. El proceso seguido por Graham toma sucesivamente triángulos elegidos según el orden conseguido tras la ordenación. Siempre que el triángulo formado abc, posea una superficie positiva, el vértice central, es decir, el vértice b será tenido en cuenta como probable punto de la envolvente. Pero cuando dicho área es negativa, b es descartado definitivamente. Para comprender dicho algoritmo, será necesario repasar el concepto de pila. Una pila es un tipo de dato abstacto (tipo de dato más operaciones para su manejo) muy restrictivo a la hora de manejar los datos que almacena. Se construye utilizando una estructura de datos lineal, array o lista enlazada, sobre la que sólo se pueden introducir (push) o sacar elementos (pop) por uno de sus extremos, lo que se denomina cima o tope de la pila. Algoritmo Scan de Graham 1. Encontrar el punto inferior más a la derecha (P0) 2. Ordenar todos los puntos angularmente alrededor de P0; aquellos puntos que estén en el mismo ángulo colocar primero el más cercano a P0: etiquetarlos P1,...,Pn-1 3. Pila S := (Pn-1,P0) 4. t := tope de S (P0) 5. i := 1 6. Mientras que i<n hacer 7. Si Pi está estrictamente a la izqda de (Pt-1,Pt) 8. entonces Push(S,i); i := i+1 9. sino Pop(S) Ejemplo: El orden de ejecución de este algoritmo viene dado por la necesidad de ordenar los puntos angularmente. Cualquier ordenación necesita al menos un tiemo O(nlogn). A este tiempo se le debe añadir el del proceso ideado por Graham. Para averiguar este tiempo basta con percatarse que en cada paso un punto es tenido en cuenta o es descartado. En el peor de los casos, cuando la envolvente convexa es un triángulo, necesitamos del orden de 2n–3 operaciones.

Juan Carlos Gutiérrez Barquero____________________________________________ 161

Page 162: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

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 condición puede ser eliminada). Comenzamos encontrando el primer punto con el orden lexicográfico, llamemosle p0. A continuación 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, llamémosles 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 después 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).

Juan Carlos Gutiérrez Barquero____________________________________________ 162

Page 163: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

2.1.4. La marcha de Jarvis La marcha de Jarvis está basada en el siguiente resultado, que sirve de definición 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 están a un lado de ésta. Siguiendo este criterio podríamos descubrir para cada punto los n2 combinaciones posibles, lo que nos da un fácil 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 fácil de intuir que este proceso tardará en ejecutarse un tiempo proporcional al número de puntos en la envolvente y al tamaño 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 ejecución es del orden de O(nk). En el mejor de los casos el comportamiento puede ser lineal, por ejemplo si la envolvente es un triángulo. El peor de los casos, sin embargo, se da cuando todos los puntos están en la envolvente convexa, convirtiéndose en un método cuadrático.

Juan Carlos Gutiérrez Barquero____________________________________________ 163

Page 164: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

2.1.5. Algoritmo Incremental La ventaja de unos métodos con respecto a otros a veces viene dada por su velocidad computacional y otras veces por su fácil extensión a tres dimensiones, lo que habitualmente llamamos problemas 3D. El método incremental para el cálculo de la envolvente convexa es uno de estos casos. En todo método incremental se supone que se ha resuelto el problema para un tamaño n y que en cada paso se añade un nuevo punto dando solución a un problema de tamaño n+1. Para el cálculo de la envolvente convexa ordenamos inicialmente los puntos del conjunto P de izquierda a derecha, por ejemplo, obteniendo el conjunto p0; p1; :::; pn–1. Tomamos los tres primeros puntos tras esta ordenación sabiendo que el polígono que forman p0; p1; p2, un triángulo, es convexo. El siguiente paso intenta añadir 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 añadir cada nuevo punto pi+1 basta con lanzar tangentes desde este punto hasta el polígono 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 más bajo de tangencia es tal que pi, es tal

que q está a laizquierda de pi–1 pi pero a la derecha de pi pi+1. El punto pj será el punto de mayor tangencia si q está a la derecha de p

j–1 pj pero a laizquierda de pj pj+1. El procedimiento PuntosTangentes calcula los puntos resultantes de lanzar tangentes desde el punto q al polígono P de tamaño n obteniendo como

Juan Carlos Gutiérrez Barquero____________________________________________ 164

Page 165: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

resultado los vértices pt1 y pt2. El algoritmo determina que el vértice p[i] es un punto tangente si recorriendo cada arista del polígono P dicho vértice implica un cambio de resultado tras ejecutar la función IzquierdaOSobre. Pero obtener los dos puntos tangentes no implica de ningún modo que el proceso ha finalizado. El punto q será parte ahora del nuevo polígono convexo, así como lo serán los puntos pt1 y pt2. Sin embargo, es posible que algunos otros vértices del polígono convexo desaparezcan. En el ejemplo de la figura, la secuencia de vértices i+1; :::; j–1 claramente desaparece al añadir el nuevo punto. El resultado final sería el polígono P = p0; p1; :::; pi_1; pi;q; pj ; pj+1; :::; pn_1. El orden de ejecución del algoritmo es la suma de los siguientes términos:

1. la operación de ordenación con coste O(nlogn)

2. Operación que en el peor de los casos es lineal. Por tanto, y aunque el algoritmo es susceptible de añadir mejoras, necesita en el peor de los casos un tiempo O(n2).

2.1.6. Método Divide y Vencerás Los métodos divide y vencerás 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 tamaño. Para cada una de estas mitades, continuamos el proceso de división hasta que finalmente el tamaño de la nube de puntos es tan pequeño que puede resolverse el problema fácilmente. Este caso concreto es cuando tenemos tres puntos. Cuando el problema no pueda dividirse más, el siguiente paso es unir dos a dos los polígonos convexos resultantes de la etapa anterior, en un nuevo polígono convexo. El proceso finaliza obteniendo la envolvente convexa de todos los puntos. Sin embargo, la etapa de unión de dos polígonos convexos en un único polígono 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 comenzaría suponiendo que el segmento que une el punto más a la derecha de A y el punto más a la izquierda de B es una tangente válida. Como esta suposición es falsa para este ejemplo, decidimos bajar vértices sucesivamente hasta que por fin para el polígono 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 vértices de B. El proceso termina cuando para los dos polígonos se encuentra una tangente.

Juan Carlos Gutiérrez Barquero____________________________________________ 165

Page 166: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

Para saber si ab es tangente a un polígono observemos los siguientes gráficos: queda como ejercicio la implementación de las funciones TangenteMenor y TangenteMayor.

El tiempo de ejecución de un algoritmo divide y vencerás depende en gran medida del comportamiento de la función 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. Triangulación de polígonos En el Tema 1 hicimos referencia por primera vez a la triangulación de polígonos. En esa ocasión se hizo incapié de la necesidad de encontrar un algoritmo eficiente para realizar este cálculo, puesto que el dado en dicho tema posee un tiempo de ejecución poco eficiente. En esta sección conseguiremos triangular cualquier tipo de polígono en tiempo óptimo O(nlogn), para ello serán necesarios dos pasos diferentes: la partición de cualquier polígono en particiones monótonas y la triangulación de cada una de estas porciones. 2.2.1. Polígonos monótonos Un polígono monótono con respecto a la vertical es aquel que si se recorre con una línea horizontal bajando a lo largo del total del polígono, ocurre que sólo encontramos como máximo dos intersecciones del polígono con dicha recta. Si

Juan Carlos Gutiérrez Barquero____________________________________________ 166

Page 167: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

además no consideramos la existencia de aristas horizontales, entonces hablamos de polígono extrictamente monótono. Intuitivamente hablando, un polígono monótono será aquel que no posee cúspides interiores, considerándo al vértice vi como cúspide si vi–1 y vi+1 están ambos arriba o abajo. La ventaja de triangular un polígono monótono es más o menos intuitiva: al bajar una línea horizontal imaginaria a lo largo de todo el triángulo y encontrarse con el vértice vi, se sabe que su diagonal irá a un punto visible desde dicho punto. La idea es ir bajando paulatinamente vértice a vértice, bien por la izquierda, bien por la derecha, dibujando diagonales según el siguiente algoritmo. ALGORITMO TriangulacionMonotona ENTRADA: El Ìpolgono S de Òtamao n SALIDA : El conjunto de Diagonales que t r i a n g u l a n e l Ìpolgono INICIO Ordenar (S, n , p ) ListaCrea ( l ) l i s t aCr e a ( Diagonales ) ListaMeteFinal ( l , p [ 0 ] ) ListaMeteFinal ( l , p [ 1 ] ) PARA j <_ 2 HASTA n_1 REPETIR SI Adyacente ( L i s t a I n i c i o ( l , p [ j ] ) AND NOT Adyacente ( L i s t a F i n a l ( l ) , p [ j ] ) ENTONCES v<_ L i s t aSa c a I ni c io ( l ) MIENTRAS (NOT ListaVacia ( l ) ) REPETIR v <_ L i s t aSa c a I ni c i o ( l ) ListaMeteFinal ( Diagonales , v , p [ j ] ) FIN_MIENTRAS ListaMeteFinal ( l , v ) ListaMeteFinal ( l , p [ j ] ) SINO SI Adyacente ( L i s t a F i n a l ( l ) , p [ j ] ) AND NOT Adyacente ( L i s t a I n i c i o ( l ) , p [ j ] ) ENTONCES v<_ListaSacaFinal ( l ) x<_F i n a l L i s t a ( l ) MIENTRAS ( Angulo ( p [ j ] , v , x ) < Pi ) REPETIR ListaMeteFinal ( Diagonales , x , p [ j ] ) v <_ ListaFinalSaca ( l ) SI NOT ListaVacia ( l ) ENTONCES x<_L i s t a F i n a l ( l ) FIN_MIENTRAS ListaMeteFinal ( l , v ) ListaMeteFinal ( l , p [ j ] )

Juan Carlos Gutiérrez Barquero____________________________________________ 167

Page 168: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

SINO v<_L i s t aSa c a I n i c io ( l ) v<_L i s t aSa c a I n i c io ( l ) MIENTRAS NOT ( ListaVacia ( l ) ) v<_L i s t aSa c a I ni c i o ( l ) ListaMeteFinal ( Diagonales , p [ j ] , v ) FIN_MIENTRAS FIN_SI FIN_SI FIN_PARA En la siguiente figura podemos observar el conjunto de diagonales obtenidas tras la ejecución de este algoritmo para el polígono monótono de ejemplo.

Veamos como funciona el algoritmo en sus primeros pasos para este ejemplo. Al ordenar los puntos de mayor a menor obtenemos la numeración 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 aún 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 1–4;2–4;3–4. La idea básica del algortimo es construir diagonales con el comienzo de la lista l o con el final de ésta , teniendo en cuenta que sólo se unen puntos visibles entre sí (ángulo <) y que no son adyacentes. El tiempo de ejecución de este algoritmo es O(nlog n). El proceso de ordenación de los vértices ya posee este orden de ejecución, por lo que dicho algoritmo no podría ejecutarse en menor tiempo. Además habría que añadir un

Juan Carlos Gutiérrez Barquero____________________________________________ 168

Page 169: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

tiempo lineal, puesto que todas las operaciones del algoritmo, operaciones con el final y principio de la lista, el cálculo del ángulo, etc., se ejecutan en tiempo constante. Tan sólo nos puede plantear un problema los bucles MIENTRAS, pero sin embargo aseguramos el tiempo lineal del proceso, puesto que todo vértice es procesado como mucho dos veces, uno cuando entra en la lista y otra vez cuando sale de ésta. 2.2.2. Partición de un polígono en componentes monótonas La triangulación de polígonos monótonos desde luego deja de tener sentido si no es posible particionar cualquier tipo de polígono en particiones monótonas. En este apartado completamos el proceso de triangulación eficiente de polígonos dando un algoritmo capaz de encontrar diagonales tales que dividan dicho polígono en particiones monótonas. Consideramos a un polígono y-monótono si para cada horizontal h, la intersección del polígono con h es conexa, esto es, es un punto o el vacío. La definición para x-monótono es análoga. Antes de ver el funcionamiento del polígono determinaremos los cinco tipos de vértices que podemos encontrar: Vértice comienzo: el vértice vi es de comienzo si vi–1 y vi+1 poseen menor ordenada y su ángulo interior es menor que π.

Vértice final: el vértice vi es de final si vi–1 y vi+1 poseen mayor ordenada y su ángulo interior es menor que π.

Vértice Partición: el vértice vi es de partición si vi–1 y vi+1 poseen menor ordenada ysu ángulo interior es mayor que π.

Juan Carlos Gutiérrez Barquero____________________________________________ 169

Page 170: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

Vértice Mezcla: el vértice vi es de mezcla si vi–1 y vi+1 poseen mayor ordenada y suángulo interior es mayor que π.

Vértice Regular: cualquier otro vértice no considerado anteriormente.

Utilizaremos la técnica de .línea de barrido. para encontrar las distintas particiones monótonas. La idea será localizar los vértices que rompen la monotonía, los de partición y los de mezcla. Desde ellos se lanzarán diagonales, el destino de éstos será también un objetivo primordial del algoritmo. Las estructuras de datos implicadas son las siguientes: P: será un array conteniendo los vértices del polígono, ordenados como es

habitual en sentido antihorario. Q: La línea imaginaria bajando por el plano se encontraría los puntos de P de

Juan Carlos Gutiérrez Barquero____________________________________________ 170

Page 171: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

mayor a menor ordenada. Para no duplicar los puntos, y sobre todo por ventajas computacionales, Q será un vector de tamaño n con los índices de P identificando los puntos ordenados de mayor a menor ordenada.

T: Se trata de alguna estructura de datos con tiempo de acceso logarítmico. Almacenará los vértices ei, siendo ei = vi –vi+1, con excepción de en–1 = vn–1v0. El conjunto de ejes se almacenan por la coordenada x, tanto de izquierda a derecha.

Ayu: Es un array que almacena en todo momento el vértice candidato para unir a los vértices de partición y mezcla. Los valores podrán ir cambiando hasta que se localice el valor correcto.

D: Mantiene el resultado, es decir, el conjunto de diagonales conseguidas por el algoritmo.

Puede ser un array o una lista.

Algoritmo de triangulación 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 )

Juan Carlos Gutiérrez Barquero____________________________________________ 171

Page 172: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

34 2 La envolvente convexa y triangulaciÛn de polÌgonos EN CASO DE QUE TipoVer t i ce (P, i ) SEA 0 : ( _ Comienzo _) ListaInser tarOrdenado (T, i ,P) Ayu ( i ) <_ i 1 : ( _ Final _) Si TipoVer t i ce (P , Ayu ( i _1))=2 Entonces I n s e r t a r L i s t a (D, i_Ayu ( i _1)) L i s t aEl imi n a r ( T , i _1) 2 : ( _ Mezcla_) Si TipoVer t i ce ( P, Ayu ( i _1))=2 Entonces L i s t a I n s e r t a r (D, i_Ayu ( i _1)) L i s t aEl imi n a r ( T , i _1) j <_ ListaBuscar Izdo ( T , i ) Si TipoVer t i ce ( P, Ayu ( j ) )=2 Entonces L i s t a I n s e r t a r (D, i_Ayu ( j ) ) Ayu ( j ) <_ i 3 : ( _ ÛPa r t i c i n ) j <_ ListaBuscar Izdo ( T , i ) L i s t a I n s e r t a r (D, i_Ayu ( j ) ) Ayu ( j )<_ i ListaInser tarOrdenado ( T , i ,P) Ayu ( i )<_i 4 : ( _ Regular_) Si Inter iorDecha ( P, i ) Entonces Si TipoVer t ice (P , Ayu ( i _1))=2 Entonces L i s t a I n s e r t a r (D, i_Ayu ( i _1)) L i s t aBo r r a r (T, i _1) ListaInser tarOrdenado (T, i ,P) Ayu ( i )<_i Sino j <_ListaBuscar Izdo (T, i ) Si TipoVer t ice (P, Ayu ( j ) ) = 2 Entonces L i s t a I n s e r t a r (D, i_Ayu ( j ) Ayu ( j )<_ i FIN_SI FIN_SI FIN_CASE FIN El tiempo de ejecución del algoritmo es óptimo. La ordenación de los vértices puede realizarse en tiempo O(nlog n). Cada una de las n iteraciones de bucle se ejecuta en tiempo logarítmico, el correspondiente a las operaciones de manejo de la estructura de datos T.

Juan Carlos Gutiérrez Barquero____________________________________________ 172

Page 173: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

3 Intersecciones La detección de intersecciones constituye una de las primitivas geométricas fundamentales con muy diversas aplicaciones. En realidad virtual o diseño de circuitos VLSI el manejo de intersecciones es fundamental. Pero existen otras áreas de interés más próximas a la Topografía como son los Sistemas de Información Geográfica. En muchas ocasiones para hacer los mapas más manejables y legibles, la información que contienen se divide en distintos tipos de mapas, cada uno especializado en carreteras, ciudades, ríos y montañas, densidad de población, etc. La información geométrica subyacente en cada uno de estos mapas también puede considerarse diferente, así una carretera puede ser representada mediante una polilínea y un núcleo urbano puede serlo mediante conjunto de polígonos. 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 geométricos. 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 geométricos, únicamente conocer si existe dicha intersección. También podemos encontrar una diferencia sustancial entre manejar un par de líneas o segmentos o hacerlo con un conjunto de ellos. De hecho, la realidad a veces necesita simular la forma de cualquier línea mediante una polilínea o conjunto de segmentos unidos a modo de cadena. La naturaleza de los objetos también puede ser conveniente conocerla a priori, puesto que la intersección de polígonos convexos cuenta con un orden de ejecución menor que si se trata de polígonos generales. 3.1. Intersección de polígonos convexos El tiempo de ejecución para conocer la intersección de dos polígonos cualesquiera es O(nm), siendo n y m el número de ejes de los dos polígonos. El resultado de calcular la intersección de dos polígonos cualesquiera podemos verlo en la siguiente figura:

Juan Carlos Gutiérrez Barquero____________________________________________ 173

Page 174: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

Sin embargo, realizar esta operación con polígonos convexos puede hacerse en tiempo O(n+m). Existe una propiedad importante para la intersección de polígonos convexos: la intersección es también un polígono convexo. Denominaremos a A y B a los ejes que en cada momento se están ejecutando. En cada iteración 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 harán por ejemplo, que si B apunta hacia la línea que contiene a A, entonces avanzamos B para buscar la intersección 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 más corto de girar A hacia B es en sentido inverso a las agujas del reloj. Como por regla general los dos vectores no coincidirán en su inicio, imaginaremos sin embargo que así ocurre para localizar el giro más 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

Juan Carlos Gutiérrez Barquero____________________________________________ 174

Page 175: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

El método anteriormente descrito aparece a continuación. También aparece el pseudocódigo 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+n–1) mod n b1 <– (b+m–1) 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

Juan Carlos Gutiérrez Barquero____________________________________________ 175

Page 176: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

FUNCION TestDentro (H: Entero ) : óLgico INICIO SI H < > 0 ENTONCES TestDentro <– 1 SINO TestDentro <– 0 fiN FUCION Avanza (VAR ab , Avd : Entero ; n : Entero ; Dentro : óLgico ; v : TipoPunto ) INICIO SI Dentro ENTONCES Pi n t a r ( v ) fiNfiSI Adv <– Adv + 1 ab <– (ab +1) mod n fiN PROCEDIMIENTO Subvector (VAR a , b , c : TipoPunto ) INICIO PARA i <– 0 HASTA 1 INCR + 1 REPETIR c [ i ] <– a [ i ] – b [ i ] fiNfiPARA fiN En el siguiente ejemplo observamos un ejemplo de polígonos convexos.

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.

Juan Carlos Gutiérrez Barquero____________________________________________ 176

Page 177: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

3.2. Intersección de segmentos La intersección de segmentos es un cálculo 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 podría construir un puente podríamos computar el conjunto de intersecciones entre el mapa de carreteras y el mapa de ríos. Las operaciones realizadas a bajo nivel en la aplicación informática que lleve a cabo este cálculo serán las de intersecciones de segmentos. Puede realizarse siempre un algoritmo de fuerza bruta para realizar este cálculo utilizando para ello un tiempo O(n2) si supuestamente empleamos un número similar de ríos y de carreteras. Como es de imaginar este algoritmo procesaría todos los ríos con todas las carreteras, y siendo por tanto poco eficiente. Probablemente el número de intersecciones sea mucho menor al de potenciales puntos de intersección, por lo que podría buscarse un método alternativo que tuviera por principio el procesar únicamente posibles intersecciones en segmentos que estén cerca, evitando así cálculos innecesarios. La estrategia a seguir puede ser la de bajar una línea 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 intersección y borrado en dicha lista se pregunta si la nueva situación provoca una intersección, siempre entre segmentos vecinos de la lista.

Juan Carlos Gutiérrez Barquero____________________________________________ 177

Page 178: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

Emplear las estructuras de datos correctas en este método es fundamental para la eficiencia de éste. P: Es un array que contiene el conjunto de segmentos iniciales dispuesto en

principio en cualquier tipo de orden. El array tiene un tamaño de nx4 puntos, siendo cada fila los cuatro puntos que forman un segmento en el orden x0; y0; x1; y1, siendo siempre el punto (x0; y0) el extremo de mayor ordenada.

Q: Es la denominada cola de eventos que almacena el conjunto de vértices y de puntos intersección. Mantendrá los puntos extremos ordenados de mayor a menor ordenada. Cuando en dicha lista se inserten dos puntos con la misma ordenada, se considerará primero el de menor abscisa. Será preferentemente una lista a un array porque deberá permitir inserciones.

T: Estructura de datos que simula el comportamiento de la línea imaginaria L. Mantendrá ordenados de izquierda a derecha los segmentos que en todo momento vaya atravesando, eliminado los ya procesados e insertándolos cuando se comienzan a atravesar. Esta estructura de datos deberá permitir inserciones y borrados en tiempo logarítmico 1.

I: Cualquier tipo de estructura de datos que almacene las intersecciones localizadas.

La función ManejarEvento es la encargada de procesar cada uno de los nuevos extremos de la cola de eventos Q. Esta función sería llamada por el algoritmo EncontrarIntersecccion tal y como vemos a continuación. ALGORITMO Encontrar Intersección

Juan Carlos Gutiérrez Barquero____________________________________________ 178

Page 179: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

Juan Carlos Gutiérrez Barquero____________________________________________ 179

Page 180: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

Sin embargo, la función de intersección de segmentos desarrollada en el primer tema no es válida para conocer el punto de intersección entre dos segmentos, sólo para saber si dicha intersección se produce.

Juan Carlos Gutiérrez Barquero____________________________________________ 180

Page 181: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

En el siguiente ejemplo vemos un conjunto de segmentos en los cuales podemos encontrar un conjunto de intersecciones. Hay que tener en cuenta que el algoritmo también detecta las intersecciones de los segmentos por sus extremos, ya que hay que tener en cuenta que los segmentos pueden llegar desordenados y sin relación unos con otros.

4 Localización de puntos y diagramas de Voronoi 4.1. Punto en polígono El problema denominado punto en polígono se presenta cada vez que se pincha el ratón en pantalla. Si el polígono P sobre el que trabajamos es convexo, el problema puede solucionarse en tiempo O(logn). Pero el método más interesante ocurre cuando P no es convexo. Para este caso utilizamos el siguiente método: si queremos saber si el punto q está dentro o fuera del polígono P trazamos una línea en cualquier dirección, por ejemplo utilizando la recta r igual a y = 0, x fi 0 y entonces contamos el número de intersecciones que se producen. El punto q está dentro de P si el número de intersecciones es impar. Para hacer más fácil el cálculo y utilizar una recta r válida 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.

Juan Carlos Gutiérrez Barquero____________________________________________ 181

Page 182: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

Para conocer el lugar justo de intersección utilizaremos la siguiente fórmula:

trasladamos la idea anterior al siguiente algoritmo en pseudocódigo que realiza el test de inclusión de punto en polígono. 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 sólo se tienen en cuenta los cortes que se producen para x > 0.

El tiempo de ejección de este test de inclusión es lineal, como claramente indica la búsqueda exhaustiva de intersecciones de una recta con todas las aristas de un polígono.

Juan Carlos Gutiérrez Barquero____________________________________________ 182

Page 183: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

DIAGRAMA DE VORONOI

En este capítulo estudiamos el diagrama Voronoi, una estructura geométrica segunda en importancia sólo detrás del buque convexo. En cierto sentido un diagrama de Voronoi registra todo lo que uno alguna vez querría saber acerca de proximidad para un grupo de puntos (u objetos más generales). Y a menudo uno quiere saber detalles acerca de la proximidad: ¿Quién está más cercano a quién? ¿Quién está más lejos? Etcétera. El concepto tiene más de un siglo de antigüedad, 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 Sección 5.4). Finalmente revelaremos la bella conexión entre diagramas Voronoi y buques convexos en la Sección 5.7. Este capítulo incluye sólo dos pedazos pequeños de código, para construir lo dual del diagrama Voronoi (la triangulación Delaunay), en la Sección 5.7.4.

APLICACIONES PRELIMINARES

1. Las torres de observación de fuego

Imagine un bosque vasto conteniendo un número de torres. Cada guardabosque es responsable de extinguir cualquier fuego más 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 “Polígono de Voronoi” asociado con su torre. El diagrama de Voronoi traza las líneas entre estas áreas de responsabilidad: Los lugares en el bosque que son equidistantes de dos o más torres. (Una vistazo a la Figura 5.5 puede ayudar a la intuición).

Juan Carlos Gutiérrez Barquero____________________________________________ 183

Page 184: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

2. Las torres en llamas

Imagine ahora la situación perversa donde todos los guardabosques encienden sus torres simultáneamente, y el bosque se quema a una velocidad uniforme. El fuego se dispersará en círculos centrado en cada torre. Los puntos en los cuales el fuego se apaga es porque ha alcanzado previamente árboles consumidos son esas puntos equidistantes de dos o más torres, los cuáles son exactamente los puntos en el diagrama Voronoi.

3. La agrupación de vecinos mas cercanos

Una técnica frecuentemente utilizada en el campo de reconocimiento de patrones es trazar un mapa de un grupo de objetos blancos en un rasgo del espacio reduciendo los objetos a puntos cuyas coordenadas son las medidas de rasgo. El ejemplo de cinco medidas de la sastrería de la Sección 4.6.1 puede ser visto como una definición o una característica del espacio. La identidad de un objeto de afiliación desconocida entonces le puede ser asignada al objeto próximo de blanco en el rasgo del espacio.

Un ejemplo hará esto más claro. Suponga que un depósito de partes incluye dos tipos de nueces A y B, una con diámetros interior y exterior de 2 y 3 centímetros respectivamente, y B con el espacio de diámetros 3 y 4 cm., el rasgo es el cuadrante positivo del plano Euclidiano de dos dimensiones, positivo porque ningún radio puede ser negativo A traza al grano (2,3), y B al punto (3,4).

Suponga, que un sistema de visión enfoca la atención en una nuez x en el depósito y se mide su radio interior y exterior para tener 2.8 y 3.7 cm. Conociendo que hay inexactitudes de medida, y que sólo las nueces de tipo A y B están en el depósito, ¿que tipo de nuez es x? Es más probable que sea una nuez de tipo B, porque su distancia para B en el rasgo del espacio 0.36, considerando su distancia para A es 1.06. Vea la Figura 5.1. En otras palabras, la vecina más próxima de x es B, porque la x está en el polígono de Voronoi de B.

Si hay muchos tipos de nueces, la tarea de identificación es localizar la nuez desconocida x en el diagrama de Voronoi de las nueces blancos. Cómo puede estar esto hecho eficazmente se discutirá en la Sección 5.5.1.

Juan Carlos Gutiérrez Barquero____________________________________________ 184

Page 185: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

4. La facilidad de Localización

Suponga que a usted le gustaría localizar una tienda de comestibles nueva en un área con varias tiendas de comestibles existentes, irreconciliables. ¿Asumiendo densidad de población uniforme, dónde debería estar la tienda nueva localizada para optimizar sus ventas? Un método natural que satisfaga esta restricción vaga es localizar la tienda nueva tan lejos de las viejas como sea posible. Aun esto es un poco vago; Más precisamente podríamos escoger una localización cuya distancia para la tienda próxima es tan grande como sea posible. Esto es equivalente a localizar la tienda nueva en el centro del círculo vacío más grande, el circulo más grande cuyo interior no contiene otras tiendas. La distancia para la tienda mas próxima es entonces el radio de este círculo.

Mostraremos en 5.5.3 Sección que mientras central de círculo vacío más grande debe mentir en el diagrama Voronoi.

5. Planeando el camino

Imagine un ambiente desordenado a través del cual un robot debe planear un camino. Para minimizar el riesgo de colisión, al robot le gustaría quedarse tan lejos de todos los obstáculos como sea posible. Si restringimos la pregunta a dos dimensiones, y si el robot es circular, entonces el robot debería quedarse todo el tiempo en el diagrama de Voronoi de los obstáculos. Si los obstáculos son puntos (digamos polos delgados), entonces éste es el diagrama convencional de Voronoi. Si los obstáculos son polígonos u otras formas, entonces una versión generalizada del punto del diagrama Voronoi determina el camino apropiado.

Revisaremos este ejemplo en el Capítulo 8 (la Sección 8.5.2).

6. La cristalografía

Juan Carlos Gutiérrez Barquero____________________________________________ 185

Page 186: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

Asuma un número de granos de cristal crecen uniformes, a velocidad constante. ¿Cuál será la apariencia del cristal cuando el crecimiento ya no es posible? Debería estar claro ahora que esto es análogo al incendio de bosques, y que cada grano crecerá para un polígono de Voronoi, con regiones adyacentes del grano encontrándose 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 podría seguir sin parar, y veremos otros en la Sección 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 más próximo. Todos esos puntos asignados a pi forman la región 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 próximo, o vecino próximo. El grupo de todos los puntos que tienen más de un vecino cercano forman el diagrama de Voronoi V (P) para el grupo de sitios.

Más tarde definiremos los diagramas de Voronoi para grupos de objetos más 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 triángulo (p1, p2, x) como se muestra en la Figura 5.2. Por el teorema del lado - ángulo - lado de Euclides, | p1x | = | p2x |.

Juan Carlos Gutiérrez Barquero____________________________________________ 186

Page 187: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

Tres sitios Para tres sitios, es claro que fuera del triángulo (p1, p2, p3), el diagrama contenga la bisectriz B12, B23, B31. Lo que no esta claro es que ocurre en los alrededores del triángulo. Otra vez de Euclides las bisectrices perpendiculares de los tres lados del triángulo todos atraviesan un punto, el circuncentro, el centro del único círculo que pasa a través de los vértices del triángulo. Así el diagrama Voronoi para tres puntos debe aparecer como en la Figura 5.3. (Sin embargo, el circuncentro de un triángulo no está siempre dentro del triángulo como se muestra).

Semiplanos La generalización más allá de tres puntos quizá todavía no esta clara, pero es ciertamente claro que la bisectriz Bij desempeñará un papel. Sea H el semiplano cerrado con límite Bij y conteniendo pi. Entonces H puede ser visto como todos los puntos que están cercanos a pi que a pj. Ahora ordene el regreso de que V (pi) es el grupo de todos los puntos más cercano a pi que a cualquier otro sitio: En otras palabras, los puntos más cercanos a pi que a p1,

Juan Carlos Gutiérrez Barquero____________________________________________ 187

Page 188: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

y más cercano a pi que a p2, y más cercano a pi que a p3, etcétera. Esto muestra que podemos escribir esta ecuación o V(pi):

V (pi) = ji≠

H (pi, pj) (ecuación 5.2)

Donde la notación significa que la intersección debe estar ocupada sobre todo i y j como i≠ j. Note que esa conjunción inglesa “y” ha sido trasladada a intersección de conjunto.

Figura 5.4 (a) Diagrama de Voronoi para cuatro puntos cocirculares; (b)

diagrama después de mover los puntos hacia la izquierda.

La ecuación (5.2) inmediatamente nos da una propiedad importante de los diagramas de Voronoi: Las regiones de Voronoi son convexas, pues la intersección de cualquier número de Semiplanos es un grupo convexo. Cuando las regiones están rodeadas, son polígonos convexos. Los bordes de las regiones de Voronoi son llamados bordes de Voronoi, y los vértices son llamados vértices de Voronoi. Note que un punto en el interior de un borde de Voronoi tiene dos sitios próximos, y un vértice de Voronoi tiene al menos tres sitios próximos.

Cuatro sitios El diagrama de cuatro puntos formando las esquinas de un rectángulo es mostrado en la Figura 5.4 (a). Note que el vértice 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 degeneración.

Juan Carlos Gutiérrez Barquero____________________________________________ 188

Page 189: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

Muchos sitios Un diagrama típico con muchos sitios es mostrado en la figura 5.5. Un vértice de Voronoi no es mostrado en esta figura: Los dos rayos casi horizontales dejando el diagrama para la izquierda no son muy paralelos y se intersecan en un vértice de Voronoi cerca de 70 centímetros a la izquierda de la figura.

Tamaño del diagrama

Aunque hay exactamente n regiones de Voronoi para n sitios, el tamaño combinatorio total del diagrama concebible podría ser cuadrático en n, pues cualquier región particular de Voronoi puede tener Ω (n) bordes de Voronoi (Ejercicio 5.3.3 [4]). Sin embargo, nosotros ahora mostramos que de hecho este no es el caso, que el tamaño total del diagrama es Ο (n).

Asumamos pues por simplicidad que ninguna de los cuatro puntos son cocirculares, y por consiguiente cada vértice de Voronoi es de grado tres. Construya la gráfica dual G (Sección 4.4) para un diagrama Voronoi V (P) como sigue: Los nodos de G son sitios de V (P), y dos nodos están conectados por un arco si sus polígonos correspondientes de Voronoi comparten un borde de Voronoi (comparten un borde de longitud positiva).

Ahora observe que éste es un grafo planar: Podemos incrustar cada nodo en su sitio, y todo el incidente de arcos para el nodo puede ser angularmente clasificado lo mismo los bordes del polígono. Además todas las caras de G son triángulos, siendo propio del vértice de Voronoi de grado tres. Este reclamo será hecho más claro en un momento (la Figura 5.6).

Pero previamente mostramos que la fórmula de Euler significa que un grafo planar triangulado con n vértices tiene 3n-6 de bordes y 2n-4 caras; Vea la Sección 4.1.1 Teorema 4.4.5. Porque las caras de G son propias de los vértices de Voronoi, y porque los bordes de G son propios de los bordes de Voronoi (desde que cada arco de G le cruza un borde de Voronoi), hemos mostrado que el número de vértices de Voronoi, bordes, y las caras es Ο (n).

Si ahora removemos, entonces la suposición que ninguno de los cuatro puntos son cocirculares, la gráfica es todavía planar, pero no necesariamente triangulado. Por ejemplo, lo dual del diagrama mostrado en Figura 5.4 (a) es un cuadrilátero. Pero tales gráficas poco trianguladas tienen menos conexiones entre dos vértices de un gráfico y caras, así es que los Ο (n) saltos continúan teniendo aplicación.

Una consecuencia del salto del borde 3n-6 es que el número común de bordes de un polígono de Voronoi no puede ser más de seis (el Ejercicio 5.3.3 [5]).

Triangulación de Delaunay En 1934 Delaunay probó que cuándo la gráfica dual se traza con líneas rectas, produce una triangulación planar de los sitios de Voronoi P (si ninguno de los cuatro sitios son cocirculares), ahora llamado la triangulación de Delaunay D

Juan Carlos Gutiérrez Barquero____________________________________________ 189

Page 190: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

(P). Figura 5.6 muestra la triangulación de Delaunay para el diagrama de Voronoi en Figura 5.5, y la figura 5.7 muestra que la triangulación de Delaunay superpuesta en el diagrama correspondiente de Voronoi. Note que no es inmediatamente que usando líneas rectas en el duales evitaria cruzarse adentro del dual; El segmento dual entre dos sitios necesariamente no cruza el borde Voronoi compartido entre ahora, pero más bien esperaremos hasta que hayamos recogido más propiedades de la triangulación Voronoi de diagramas y Delaunay, cuándo la prueba será fácil.

Las propiedades de triangulación de Delaunay

Debido que la triangulación de Delaunay y el diagrama de Voronoi son estructuras duales, cada uno contiene la misma “información” en algún sentido, solamente representó en una forma más bien diferente. Para ganar un agarre en estas estructuras complicadas, es importante para tener una comprensión cabal de las relaciones entre una triangulación de Delaunay y su diagrama correspondiente de Voronoi. Listamos sin prueba varias propiedades de Delaunay y seguiremos con una lista más substantiva de propiedades de Voronoi. Sólo la propiedad D6 y D7 no han sido mencionados anteriormente. Fija un grupo de sitios P.

D1. D (P) es la línea recta dual de V (P). Esto es por definición.

D2. D (P) es una triangulación si ninguno de los cuatro puntos de P son cocirculares: Cada cara es un triángulo. Éste es el teorema de Delaunay. Las caras de D (P) son llamados triángulos de Delaunay.

D3. Cada cara (triángulo) de D (P) es propia de un vértice de V (P). D4. Cada borde de D (P) es propio de un borde de V (P). D5. Cada nodo de D (P) es propio de una región de V (P). D6. El límite de D (P) es el buque convexo de los sitios. D7. El interior de cada (triángulo) cara de D (P) no contiene sitios. Las propiedades D6 y D7 aquí son lo más interesante; Pueden ser verificados

en Figura 5.6 y 5.7. Elementos del diagrama de Voronoi Podemos considerar los siguientes elementos en el diagrama de Voronoi: pi punto generador. eje es el conjunto de segmentos, semirectas o lÌneas in_nitas que son frontera de una región de Voronoi a otra. vértice un punto que comparte m·s de dos polÌgonoos de Voronoi. adyacentes dos regiones se dice que son adyacentes si comparten algÿn eje.

Juan Carlos Gutiérrez Barquero____________________________________________ 190

Page 191: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

Los conceptos anteriores son extensibles a tres dimensiones, teniendo en cuenta que ahora las regiones de Voronoi serÌan poliedros y los ejes serÌan polÌgonos. Las propiedades de los Diagramas de Voronoi V1. Cada región de Voronoi V (pi) es convexa. V2. V (pi) es ilimitada si pi está en el buque convexo del grupo del punto. V3. Si la v es un vértice de Voronoi en la unión de V (p1), V (p2), y V (p3), entonces la v es el centro del círculo C (v) determinado por p1, p2, y p3. (Este reclamo generaliza a los vértices de Voronoi de cualquier grado).

V4. C (v) es el circuncirculo para el triángulo de Delaunay correspondiente a v. V5. El interior de C (v) no contiene sitios. V6. Si pj es el vecino próximo a pi, entonces (pi, pj) es un borde de D (P). V7. Si hay algún círculo a través pi y pj que no contiene otros sitios, entonces (pi, pj) es un borde de D (P). El inverso también tiene aplicación: Pues cada borde de Delaunay, hay algún círculo vacío.

La propiedad V7, la menos intuitiva, es una caracterización importante de los bordes de Delaunay y será usada en varias pruebas más tarde. Ésta es la única propiedad que probaremos formalmente.

La prueba. En una dirección es fácil: Si ab es un borde de Delaunay, entonces V (a) y V (b) comparten un borde de longitud positiva e ∈ V (P). Ponga a un círculo C (x) con centro en x, con radio igual a la distancia de a o b. Este círculo está obviamente vacío de otros sitios, pero si no fuera así, el sitio c estaría sobre o dentro del círculo, x estaría en V (c) igualmente, pero conocemos que x esta solamente V (a) y V (b).

La implicación inversa es más sutil. Suponga que hay un círculo vacío C (x) a través de a y b, con centro en x. Tenemos la intención de poner a prueba que

Juan Carlos Gutiérrez Barquero____________________________________________ 191

Page 192: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

ab ∈ D (P). Porque la x es equidistante de a y b, x está en las regiones de Voronoi de ambos a y b mientras ningún otro punto interfiera con “El sentido de la hermandad próximo”. Pero ninguno es, porque el círculo está vacío. Por consiguiente, x ∈V(a) ∩ V (b) (la retentiva que definimos como regiones de Voronoi son grupos cerrados). Porque ninguno de los puntos estan sobre el límite de C (x) de otra manera que a y b (por la hipótesis), allí deban ser libertad para contonearse la x un poco y mantener vacío C (x). En particular, podemos mover x a lo largo de Bab, la bisectriz entre a y b, y podemos mantener vacío al conservar el círculo a través de a y b. Ver la Figura 5.8. Por eso la x está en una longitud positiva del borde de Voronoi (un subconjunto de Bab ) compartido entre V (a) y V (b). Y por consiguiente ab EMBED Equation.3∈D (P). Dejamos la prueba de las otras propiedades para la intuición, los ejercicios, y para la Sección. 5.7.2

Ejercicios 1. El polígono regular [fácil]. Describa la triangulación del diagrama de Voronoi y la triangulación de Delaunay para los vértices de un polígono regular. 2. Las regiones ilimitadas. Ponga a prueba la propiedad V2: V (pi) es ilimitada

del si pi está en el buque convexo del grupo del punto. No se haga cargo de la propiedad correspondiente de Delaunay D6, pero de otra manera cualquier propiedad Delaunay o Voronoi puede ser empleada en la prueba.

3. El vecino más cercano. Ponga a prueba propiedad V6: Si el pj es un vecino próximo a pi, entonces (pi, pj) es un borde de D (P). Cualquier propiedad Delaunay o Voronoi puede ser empleada en la prueba.

4. El vértice de Delaunay de alto-grado. Diseñe un grupo de puntos, con n arbitrario, y sin cuatro puntos cocirculares, algo semejante aquél que el vértice de la triangulación Delaunay tiene grado n-1.

5. Numero promedio de bordes del polígono de Voronoi, pruebe que el promedio de todas las regiones Voronoi para cualquier grupo de n puntos, no excede 6.

6. Las triangulaciones de Pitteway. Una triangulación de un grupo de P de puntos es llamada una triangulación Pitteway si, para cada triángulo T = (a, b, c), cada punto en T tiene uno de a, b, o c como su vecino mas cercano entre los puntos de P.

a. Muestre por ejemplo que no toda triangulación de Delaunay es una triangulación de Pitteway. b. Caracterizar aquellas triangulaciones de Delaunay que son triangulaciones de Pitteway.

Los ALGORITMOS Las muchas aplicaciones del diagrama de Voronoi y su belleza inherente les han instado a los investigadores a que inventen una colección variada de algoritmos para computarlo. En esta Sección 5.7.2 examinaremos cuatro algoritmos, cada uno superficialmente, para ver que la Sección 5.7.2 que el

Juan Carlos Gutiérrez Barquero____________________________________________ 192

Page 193: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

diagrama Voronoi puede ser computado usando nuestro código del buque convexo.

La intersección de los Semiplanos Podríamos construir cada región de Voronoi separadamente, por la intersección de n-1 semiplanos según la ecuación (5.2). Construyendo la intersección de n semiplanos es dual para la tarea de construir el buque convexo de n puntos en dos dimensiones y puede ser llevado a cabo con algoritmos similares en el tiempo O(n log n) tiempo (Ejercicio 6.5.3 [5]). Hacer esto para cada sitio costaría a O (n2 log n).

Construcción incremental Suponga que el diagrama de Voronoi V para k puntos están ya construidos, y ahora nos gustaría construir el diagrama V’ después de añadir uno o mas puntos p. Suponga que p cae dentro de los círculos asociados con varios vértices de Voronoi, dice C (v1),…, C (vm). Entonces estos vértices de V no pueden ser vértices de V’, pues violan la condición de que los círculos del vértice de Voronoi deben estar vacíos de sitios (V5, Sección 5.3.2). Resulta que éstos son los únicos vértices de V que no están arrastrados sobre V’ También resulta que estos vértices están todos localizados en un área del diagrama. Estas observaciones vagas pueden ser hechas precisas, y forjan uno de los algoritmos más limpios para construir el diagrama de Voronoi. El algoritmo gasta O (n) tiempo por inserción de punto, para una complejidad total de O (n2). A pesar de esta complejidad cuadrática, éste ha sido el método más popular de construir el diagrama; Ver Field (1986) para los detalles de implementación.

El algoritmo incremental ha sido revitalizado recientemente con aleatorización, el cual tocaremos en la Sección 5.7.4.

Divide y vencerás El diagrama de Voronoi puede estar construido con un complejo algoritmo divide y conquista en el tiempo O (n log n), primera parte detallada por Sahmos y Hoey (1975). Fue este papel que introdujo el diagrama de Voronoi para la comunidad de ciencia de la computación. Esta vez la complejidad es asintóticamente óptima, pero el algoritmo es bastante difícil para implementar. De cualquier forma puede estar hecho con atención meticulosa para las estructuras de datos.

Juan Carlos Gutiérrez Barquero____________________________________________ 193

Page 194: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

Omitiremos este algoritmo históricamente importante para enfocar la atención en algunos desarrollos recientes emocionantes.

El algoritmo de Fortune

Hasta la mediados de los 80, la mayoría de implementaciones para computar el diagrama de Voronoi le usaron a la O (n2) algoritmo incremental, aceptando su desempeño más lento para evitar las complejidades de la codificación 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 detrás de este algoritmo.

Los algoritmos Plane-sweep(barrido de plano) (Sección 2.2.4 ) pasan una línea de barrido sobre el plano, dejando en cualquier hora el problema solucionado

Juan Carlos Gutiérrez Barquero____________________________________________ 194

Page 195: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

para la porción del plano ya barrido y no resuelta para la porción todavía no alcanzada. Un algoritmo Plane-sweep para construir el diagrama de Voronoi construiría el diagrama detrás de la línea. A primera vista, esto parece realmente mentira, como los bordes Voronoi de una región de Voronoi V (p) serían encontrados por la línea de barrido antes de que la L encuentre la p del sitio responsable para la región. Fortune superó esta imposibilidad aparente por una idea extraordinariamente lista.

Los conos

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 dimensión es mirada como el tiempo, entonces el cono sobre p representa un círculo dilatándose sobre p a una velocidad única: Después 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 círculos en expansión del diagrama de Voronoi, debería ser esperado que esta curva yazca enteramente en un plano vertical, el plano ortogonal para la bisectriz de p1p2. Vea la Figura 5.9. Así que aunque la intersección está curvada en tres dimensiones, se proyecta para una línea recta en el plano xy.

Es solamente un paso pequeño 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 línea de barrido es la intersección 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. Imagínate 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í también obscurece los sitios y los conos. Esto representa la porción del plano todavía no ha sido barrido. Para la x < l , lado de L, el diagrama de Voronoi es visible hasta la intersección de π con la “frontera” derecha (x positiva) de los conos. La intersección de π con cualquier cono es una parábola (una propiedad básica de secciones cónicas), y así la intersección de π con su frontera derecha proyecta al plano xy (y así aparece z = -∞ ) como un “frente parabólico”, una curva compuesta de piezas de parábolas. Vea Figura 5.11. Dos parábolas se unen en un lugar donde π encuentra dos conos. De nuestro debate de la intersección de dos conos arriba, esto debe estar en un borde de Voronoi.

Juan Carlos Gutiérrez Barquero____________________________________________ 195

Page 196: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

Frente parabólico Ahora finalmente podemos ver cómo solucionó Fortune el problema del problema de la línea 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 construido a la izquierda de L arriba para la parte delantera parabólica, lo cual queda atrás de L un poco.

El Lo que es mantenido en todo tiempo por el algoritmo es la parte delantera parabólica, cuyas uniones trazan el diagrama de Voronoi sobre el tiempo, Desde que todas estas enroscaduchas permanecen en los bordes de Voronoi. Aunque nos acabamos de ninguna manera con la descripción del algoritmo, no haremos el intento de detallarlo mas alla de esto. Finalmente, debería estar claro que el algoritmo sólo necesite almacenar la parte delantera parabólica, que es de tamaño O (n) y es a menudo O( n ) .Esto es una ventaja significante del algoritmo de Fortune cuando la n es grande: El almacenamiento necesitado es a menudo mucho más pequeño que el tamaño de diagrama. Y n es a menudo grande, quizá 106 (Sugihara e Iri 1992), para diagramas basados en datos recogidos por ejemplo en los sistemas de información geográficos.

5.4.5 Ejercicios

1. D V (p) (p) Diseñar un algoritmo para la computar del diagrama de Voronoi, dado la triangulación 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 línea (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 . Diseñe criterios que te permitirán 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 dinámicos Voronoi. La imagen un grupo de puntos moviendo en el plano, cada uno con una velocidad fija y dirección. Sea V (t) el diagrama de Voronoi de puntos en el tiempo t. Este un problema no resuelto, obtener saltos apretados en el número de diagramas distintos combinatoriamente que pueden resultar todo el tiempo. Aquí le pregunto a

Juan Carlos Gutiérrez Barquero____________________________________________ 196

Page 197: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

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.

Ningún a mismo capaz de encontrar un ejemplo en el cual haya más n2 cambios pero el mejor salto alto esta alrededor de O(n3).

4. La triangulación arbitraria. Diseñe un algoritmo para encontrar que una triangulación arbitraria de un grupo de punto P: Una colección de diagonales incidente para cada punto de P que divide H (P) en triángulos. La ausencia del requisito que la triangulación sea Delauny permite libertad considerable en el diseño. 5. Algoritmo Lanzando. Investigue el siguiente algoritmo pensado para construir a D (P): Comience con una triangulación arbitraria de P. Entonces repito el siguiente procedimiento hasta que D (P) es logrado. Identifique dos triángulos adyacentes abc y cbd compartiendo la diagonal bc, tal que el cuadrilátero abcd sea convexo. Si d está dentro del circuncirculo de abc, entonces suprima cb y agregue ad. ¿Trabajará esto? 5.5 Aplicaciones en Detalle. Ahora Discutiremos cinco aplicaciones del diagrama de Voronoi, en el detalle accidentado: Los vecinos próximos, las triangulaciones “gordas”, los círculos más grandes vacíos, los árboles de extensión mínimos, y viajando a través de caminos del vendedor.

5.5.1 Los vecinos más cercanos.

Una aplicación del diagrama Voronoi para agrupamiento de los vecinos más cercanos mencionado en Sección 5.1 Este problema puede verse como un problema de consulta: ¿Cuál es el vecino mas cercano a un punto buscado? Otra versión es la problema del vecino más cercano: Encuentras el vecino mas cercano para cada punto en un grupo dado. Esto tiene un número de aplicación en una variedad de campos, incluyendo biología, la ecología, la geografía, y Física. Defina la relación entre el vecino mas cercano y un grupo P de puntos como sigue: La b es una vecina próxima de a si | a – b |≤ minc≠ a| a – c |, donde c ∈ P. Podemos escribir esta relación a b: Un vecino cercano de a es b. Note que la definición no es simétrica con respectos a las tareas que a a y b les toca, sugiriendo que la relación no sea así misma simétrica. Y de hecho éste es ciertamente el caso: Si a b, no es necesaria que b a; Ver a Figure 5.12 También nota que un punto puede tener varios vecinos igualmente cercanos (ejemplo, punto d en la figura). El vecino cercano pregunta

Juan Carlos Gutiérrez Barquero____________________________________________ 197

Page 198: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

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 cuál región 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 partición es llamada localización del punto. El problema ha sido estudiado con exceso y será discutido en el Capítulo 7 (Sección 7.11). Veremos que en este ejemplo, el tiempo O (log n) es suficiente para cada consulta. Todos los Vecino Cercanos 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 gráfico orientado, aunque la relación no es simétrica, adecuadamente podría ser directa. Pero no necesitaremos la versión directa aquí.

Una forma sucinta a captar la esencia del algoritmo del vecino cercano eficiente es a través 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 requeriría O (n2), pero el lema de arriba nos deja registrar solo los bordes O (n) de la triangulación de Delauny y por lo tanto logra O (n log n). Vecino natural: Otra forma de conseguir el valor que tendrÌa un punto cualquier p serÌa el de conocer todos aquellos vecinos naturales de p. Averiguar esta informaciÛn no es m·s

Juan Carlos Gutiérrez Barquero____________________________________________ 198

Page 199: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

que resolver el problema de los vecinos m·s cercanos a un punto utilizando el diagrama de Voronoi. Aplicaciones en este sentido son la identi_caciÛn de ·tomos vecinos en el espacio, molÈculas o partÌculas en estructuras cristalinas y amorfas, etc. Ahora el punto de estudio p puede estar in_uenciado por dicho conjunto de vecinos, los cuales tambiÈn puede llevar asociados distintos pesos de in_uencia

1.5.2 La triangulación Maximizando el Ángulo Mínimo.

Analizar las propiedades estructurales de forma complicada es a menudo realizado por una técnica llamada “análisis finito del elemento.” Esto es usado, por ejemplo, por fabricantes del automóvil 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 dinámica estructural sea solucionado por discretización sobre la partición. La estabilidad de los procedimientos numéricos usados depende de la calidad las buenas particiones y esto pasa por que la triangulación de Delaunay son especialmente buenas particiones. Nosotros ahora discutiremos el sentido en el cual la triangulación Delauny es buena. Una triangulación de un grupo de puntos S es la generalización del objeto del cual la triangulación de Delauny es un ejemplo particular. Un grupo de segmentos cuyos puntos finales están en S, Que sólo interseca a cada quien en puntos finales, y cuál divide en partes el buque convexo de S en triángulos. Para los propósitos del análisis finito del elemento, las triangulaciones con triángulos “ gordos ” son más convenientes. Una forma para hacer esto precisa más es evitar triángulos con ángulos pequeños. Así es natural buscar una triangulación que tiene el ángulo menor más grande, esto es, para maximizar el ángulo de más pequeño sobre todas las triangulaciones. ¡Esto ocurre para hacer precisamente la triangulación de Delauny! De hecho, una declaración algo más fuerte puede ser hecha, cuál nosotros ahora describimos después de introducir alguna notación. Sea T una triangulación de un grupo de puntos S, y sea su secuencia de angulos(α 1, α 2, …, α 3t), una lista de los ángulos de los triángulos, clasificados del más pequeño al más grande, con t el número de triángulos en T. El número t es uno constante para cada S (Ejercicio 5.5.6[4 ] ). Podemos definir una relación entre dos triangulaciones del mismo grupo del punto, T y T ', eso trata de capturar “ la gordura ” de los triángulos. Diga que T ≥T’ (T es más gorda que T’) si la secuencia de ángulo de T es lexicográficamente 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,, etcétera. Edelsbrunnerr (1987, p. 302)

probó este teorema:

Juan Carlos Gutiérrez Barquero____________________________________________ 199

Page 200: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

Theorem5.5.2..La triangulación de Delaunay T=D (P) es lo máximo con respecto a la relación de la gordura - ángulo: T ≥T’ para cualquier otra triangulación T ' de P. En particular esto dice que la triangulación Delaunay maximiza el ángulo menor.

1.5.3 El círculo Vacío más grande

Mencionamos en sección 5.1 el problema de encontrar el círculo vacío más grande entre un conjunto S de sitios: El centro de tal círculo es una buena localización para una tienda nueva. Otra aplicación es mencionada por Toussaint (1983a): Localice un reactor nuclear tan lejos de una colección de ciudades-sitios como sea posible. Ahora examinamos problema del círculo vacío más grande en detalle. El problema hace sentir un poco menos alguna restricción sobre la localización del centro del círculo, para hay siempre círculos arbitrariamente vacíos grandes fuera de cualquier grupo de puntos finito. Así nosotros redactamos el problema de esta forma: El círculo Vacío más grande. Encuentre que un círculo vacío más grande cuyo centro está en el buque convexo (cerrado) de un grupo de n sitios S, vacíos en que no contiene sitios en su interior, y más grande que no hay otro semejante con estrictamente radio mayor. Sea a f (p) el radio del círculo más grande y vacío puesto en el centro en P del punto. Entonces andamos buscando un máximo de esta función sobre toda p en el buque de S, H=H(S). Pero hay un número aparentemente infinito de candidatos apuntando a este máximo. Un tema común en la geometría computacional es reducir un grupo infinito del candidato para una lista finita pequeña, y entonces encontrar estos eficazmente. Seguimos esto en este escenario en esta sección, comenzar por discutir informalmente que solamente ciertos puntos p son candidatos verdaderos para un máximo de f. Concéntrese Dentro del cierre. Imagine inflar un círculo desde un punto p en H. El radio en el cual este circulo golpea y por consiguiente incluye algún sitio de S = S1, … Sn es el valor de f (P). asumamos temporalmente a esta subdivisión que la p es estrictamente interior para H. Si el radio f (P), el círculo incluye justamente un sitio S1, entonces debería ser claro que f (p) no puede ser un máximo de la función del radio. Pues si p es movido para P ' a lo largo del rayo s1p (el rayo de s1 a través de p) lejos de s1, entonces f (P ') es mayor, como se muestra en Figure 5.13 (los segundos pisos). Por eso la p no pudo haber sido un máximo local de f, pues hay un punto P ' en cualquier barrio de p donde f es mayor. Nota que

Juan Carlos Gutiérrez Barquero____________________________________________ 200

Page 201: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

esa suposición de que p es estrictamente interior para el buque garantiza que hay una p ' como esa también en H. Asumamos que en el radio f (P), El circulo incluye exactamente dos sitios S1 y S2. Otra vez f (P) no puede estar en un máximo: Si la p es movida para P ' a lo largo de la bisectriz de s1s2 (fuera de s1 s2), entonces f (P ') es otra vez mayor, como se muestra en Figure 5.13 (baje círculos). Otra forma de ver esto por la intersección de dos tales conos de sitios en el centro (Figure5 5.9) discutido en la sección 4.4.4. la curva de intersección de dos conos represe la distancia de los sitios para puntos en la bisectriz. Desde que la curva es una hipérbola ascendente, ningún punto interior de la bisectriz es un máximo local: La distancia aumenta de una dirección o otra. Es única cuando el círculo incluye tres sitios que f (P) pudo estar en el máximo. Si lo tres sitios “entrecruzados” el centro p, en el sentido que hizo girar más que lo que un semicírculo (como en Figure 5.3), entonces el movimiento de p en cualquier dirección resulta en moverse p más cercano para algún sitio, y así disminuir a f (P). Nosotros ahora hemos establecido este hecho: Lema 5.5.3 Si el centro p de un círculo vacío más grande es estrictamente interior para el buque de la sitio H (S), entonces la p debe ser coincidente con un vértice de Voronoi. Note que no es necesariamente cierto que cada vértice de Voronoi represente un máximo local de f (p) (el Ejercicio 5.5.6[5 ] ). Centro dentro del convexo Ahora consideremos que el circulo de centro p está en el buque H =H(S). La razón que nuestras anteriores discusiones no ejercen es esa moviéndose p para p ' el movimiento fuera del buque, y nuestra especificación problemática restringieron centros para el buque. Nosotros ahora discutimos aún más informalmente que por encima de que un círculo máximo debe incluir dos sitios.

Juan Carlos Gutiérrez Barquero____________________________________________ 201

Page 202: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

Supongo que f (p) es un máximo con p en H y el círculo incluye justamente s1 de sitios. Primero, que no puede ser esa p está en un vértice de H, pues los vértices de H es todos los sitios mismos, y esto implicaría 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 círculo centró en p contiene s1 de dos sitios y s2, entonces es posible que la dirección a lo largo de la bisectriz de los sitios que aumenta sus distancias sea la dirección que va fuera del buque. Así adecuadamente podría ser que f (P) está en el máximo. 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.

Juan Carlos Gutiérrez Barquero____________________________________________ 202

Page 203: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

El algoritmo Nosotros ahora hemos establecido nuestro meta: Ha encontrado un grupo finito de punto que son centros potenciales de círculos vacíos más grandes: Los vértices 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 vértice de Voronoi está necesariamente dentro del buque (la Figura 5.14), que necesita comprobar que v ∈ H dentro del algoritmo. Una implementación ingenua de este algoritmo requeriría el tiempo cuadrático en n, pero localizar un vértice 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.

Juan Carlos Gutiérrez Barquero____________________________________________ 203

Page 204: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

El algoritmo: círculo Vacío MÁS GRANDE Computar el diagrama Voronoi V (s) de la S de sitios. Computar el buque convexo H=H (S). Para v del vértice Voronoi haga Si la v está dentro de H: V ∈H entonces El radio de cómputo si el grupo cerrado de gente giró alrededor de v y actualización llega al límite. Para cada e del borde Voronoi haga El cómputo p =e ∂∩ H, la intersección del con el límite del buque. El radio de cómputo de círculo giró alrededor de actualización de la P llegue al límite. El regreso llegue al límite.

Lo mínimo que se extiende a lo largo un árbol. Lo mínimo 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 más pequeño 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 mínimo extendiéndose a lo largo de árbol, abreviado a EMST. Aquí sólo considerarán las longitudes Euclideano y así también dejarán caer al modificador redundante. Un ejemplo es mostrado en Figure 5.15. MST tienen muchas aplicaciones. Pues el ejemplo es la topología 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 más general de computar el MST para una gráfica G. Aunque es de ninguna manera obvio, una estrategia ávida sin discernimiento es encontrar al MST, basada en la intuición simple que un árbol más pequeño debería estar cercano de los bordes más pequeños. Esto sugiere que puede estar tal árbol construido arriba del incrementalmente

Juan Carlos Gutiérrez Barquero____________________________________________ 204

Page 205: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

añadiendo borde más pequeño, todavía ningún explorado, lo cual también 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 notación 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 sólo demanda que su complejidad se domina por el primer paso ordenando. Esto requiere (E log E) de tiempo, dónde la E es el número de bordes en la gráfica.

MST ⊆D (p)

Para el MST de puntos en el plano, hay (

2n ) bordes, así es que la complejidad

del paso de clasificación es O (n2 log n) si es cargada fuera en la gráfica completa. Para llamar a este registro de los bordes de la triangulación de Delaunay de proximidad en algún sentido, es razonable esperar que sólo 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 mínimo que se extiende a lo largo un árbol es un subconjunto de triangulación 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 contradicción enseñando lo que se supuso MST no es mínimo. Recuerde que si ab ∈ D, entonces hay un círculo vacío a través de a y b (Propiedad V7 y Teorema 5.3.1) .en caso contrario ab ∉ D, ningún círculo a través de a y b puede estar vacíos. En particular, el círculo de diámetro ab debe de tener un sitio dentro de este. Así se supone que C está en este círculo, como se muestra en figura 5.16. Entonces

El algoritmo: El ALGORITMO DE KRUSKAL Ponga en cortocircuito bordes de G por el largo por

ahí: E1, e2 Inicializar T para que este vacío

Mientras la T no avanza a rastras haga Si T + e1 es acíclica Entonces T + T + ei

Ii + 1 El algoritmo 5.2 el algoritmo de Kruskal.

Juan Carlos Gutiérrez Barquero____________________________________________ 205

Page 206: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

| ac | < | ab |, y |bc|< |ab|; Estas desigualdades tienen aplicación aun si C está en el círculo, puesto que la C es distinta de a y b. La extracción de ab desconectará el árbol en dos árboles internos, con a en primera parte, Ta, y b en el otro, Tb. Suponga sin la pérdida de generalidad que e esta en Ta. Elimine ab y añada el borde bc para hacer un árbol nuevo, T’ = Ta bc +Tb. Este árbol es mas corto, así el único único usado ab, no podría serminimo. Hemos alcanzado una contradicción negando que ab está en D, así es que debe ser ese ab D.

Esto entonces produce una mejora en el primer paso de algoritmo de Kruskal: Primero encuentre la triangulación de Delaunay en el tiempo O (n Long n), y entonces clasifique sólo esos bordes O (n), en el tiempo O (n logn). Resulta lo demás 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 más estudiados en la informática es el problema del vendedor de viajes: Encuentre el más pequeño 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 práctica, no sólo para esa aplicación si no porque muchas otras problemáticas pueden reducirse a él. Se ha probado que desafortunadamente, el problema es duro NP, un término técnico que ningún algoritmo polinómico conoce para resolverlo (Garey y Johnson 1979); Ni parece probablemente al momento de escribir la presente que a ser encontrada. Las combinaciones de significado práctico y la inflexibilidad han conducido a una búsqueda para los algoritmos de heurísticas efectivos y de aproximación. Uno de los algoritmos de la aproximación más simples es basado en la triangulación de Delaunay, Vía lo mínimo que Se extiende a lo largo el árbol.

Juan Carlos Gutiérrez Barquero____________________________________________ 206

Page 207: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

La idea es más 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. Debería estar claro que la excursión construida por aquí tiene exactamente dos veces el largo del MST, desde que cada borde del árbol se cruza una vez en cada dirección.

Ahora obtenemos un límite dentrote que esta mal este doble-MST recorrido podría ser. Sea M la longitud de Lo mínimo 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,

Juan Carlos Gutiérrez Barquero____________________________________________ 207

Page 208: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

M ≤ T1, M < T, M2 < 2T. Esto entones logra un límite superior constante en la calidad del recorrido: Lo doble-MST no está peor que dos veces la longitud de TSP. Este resultado puede ser mejorado con heurísticas diversas. Esbozaré sólo el más simple tan heurístico, lo cual se basa en la determinación comprensible para no volver a visitar un sitio dos veces. El recorrido del camino doble-MST de entrada, con la modificación que si el próximo sitio ya se ha visitado hasta ahora por el camino, salte el sitio y considera conectarse al próximo uno a lo largo del doble-MST recorrido. Esto hace el efecto de tomar una ruta más 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 podría conectar para Sj por un segmento de la línea recta o un atajo al recorrido, considerando que el recorrido doble-MST sigue un camino encorvado Si, Si+1 , …, Sj-1,Sj.. Heurístico puede ser único acorta el camino. Un ejemplo es mostrado 5.18. Note que el camino fue acortado. Desafortunadamente este heuristico no garantiza un desempeño mejorado, pero una variación leve Conocido como las gamas “Heurísticas Christofides”. Usa un grupo de segmentos llamados un “El mínimo de Euclideano emparejando” como un guía para atajos y puede garantizar un longitud del camino no más de (3/2) T, eso es, no más de 50 % más largo que lo óptimo. Más heurísticos sofisticaron generalmente encuentran un camino dentro de un poco porcentaje óptimo (Bentley 1992), aunque este desempeño no está garantizado en su estado actual para el algoritmo citado anteriormente. Un resiente descanso teórico es sin dudarlo el esquema de aproximación de Polinomio-tiempo para el TSP, acerca de lo mejor, puede ser esperanza para un problema completo a NP. Éste es un método de llegar dentro (1 + ∈) de optativo para cualquier ∈> 0, en un tiempo O (np), dónde la p son proporcionales para 1/∈. Vea a Arora (1996) y Mitchell (1996). 5.5.6 Los ejercicios 1. El grado de NING. ¿Cuál es grado mínimo de salida de un nodo de un Grafico de vecino mas cercano(NING) (la Sección 5.5.1) de n puntos en dos 2 dimensiones? ¿Cuál es el grado máximo de un nodo? Demuestran ejemplos que justifiquen su respuesta, e intento probar que son máximos. 2. NNG y D [Fácil] . 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 próxima de a. Entonces ab D (p).

Juan Carlos Gutiérrez Barquero____________________________________________ 208

Page 209: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

4. Los Números de triángulos en una estrangulación. Comprobar que el número de triángulos t en cualquier triangulación de algún grupo de puntos reparados S esat una constante toda triangulación de S tiene la misma t. 5. El vértice de Voronoi no un máximo local. Construya un grupo de puntos que tiene un vértice de Voronoi estrictamente p dentro del buque, algo semejante que f (p) no es un máximo local, donde la f es función del radio definido en la sección 5.5.3 6. El algoritmo del círculo vacío. El detalle (en el código pseudo) cómo llevar a cabo el algoritmo del círculo vacío (Algoritmo 5.1) con el fin de que su complejidad de tiempo es O (n log n). 7. El Gráfico del Barrio relativo (RNG) de juego de puntos P1,…, Pn es un gráfico cuyos nodos corresponden a los puntos, y con Pi de dos nodos y Pj conectado por un arco ellos son para que no acerca de cualquier otro punto, eso es, si

|Pi + Pj|≤jim .

max≠

| Pi + Pm |,| Pi + Pm | .

(Vea Jaromezyk + y Toussaint (1992).) Esta ecuación determina una región “ prohibida ” dentro de la cual ningún punto Pm puede mentir si Pi y Pj son adyacentes en el RNG, no a diferencia del Teorema 5.3.1 Esta región, llamada Lune ( Pi, Pj), son la intersección de dos discos abiertos centradas en Pi y Pj, ambos de radio | Pi – Pj |.

a. Diseñe un algoritmo “de fuerza bruta” para construir al RNG. No se preocupe por eficiencia. ¿Qué es su complejidad de tiempo? b. Ponga a prueba a ese RNG: Cada borde del RNG es también borde de la triangulación de Delauny. (Compárese con Teorema 5.5.5). c. Use (b) diseñar un algoritmo más rápido.

8. El tamaño de triangulación de Delaunay en tres dimensiones. Tenemos que mostrar cual es el tamaño de la triangulación de Delaunay adentro de dos dimensiones es lineal, O (n). Mostrar que esto no se mantiene en tres dimensiones: El tamaño de D (p) puede ser cuadrático. Defina a D (p) en tres dimensiones exactamente, análogamente y para la versión de Dos dimensiones (bidimensional): Es el dual de V (p), el cual es el lugar de puntos geométricos que no tienen un único vecino cercano. Sea P un punto determinada consistente en dos partes:

a El n/2 puntos uniformemente distribuidos alrededor de un círculo en el plano x y centrados en el origen, y

Juan Carlos Gutiérrez Barquero____________________________________________ 209

Page 210: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

b El n/2 puntos uniformemente distribuidos en el origen del eje z simétrico al origen.. Sostenga la opinión que el tamaño de D (p) es Ω (n2).

9. El tamaño del gráfico del barrio relativo (RNG) en dimensiones del árbol. Ejercicio[7] anteriormente establecido ese RNG D (P) en dos dimensiones, y esta relación contiene dimensiones arbitrarias. Se ha demostrado el tamaño que tiene el RNG en dimensiones del árbol es O (n3/2) (Jaromezyk y Toussaint 1992), así es que es más pequeña que la triangulación de Delaunay. Pero parece que este salto superior es débil: Jaromezyk y Kowaluk (1991) suponen que el tamaño es O (n). Confirmar esta conjetura es un problema. 10. MST ⊆RNG Pruebe que cada borde de un MST es un borde del RNG. (Compárese con Teorema 5.5.5)

11. Los puntos más remotos de Voronoi. Defina el diagrama de puntos más remotos de Voronoi F (P) asociado cada punto del plano para el sitio que es su “vecino más remoto”, el sitio que está más 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?

Juan Carlos Gutiérrez Barquero____________________________________________ 210

Page 211: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

b. ¿Cuál es F (P) para tres sitios?

c. Derive algunas propiedades estructurales de diagrama más remoto Voronoi, parecido al Delaunay y Voronoi en Sección 5.3.1 y 5.3.2. Uso Figure 5.19 y 5 5.2.3. Uso 5.19 para ayudar a formar a hipótesis 12. L Mínimo que se expande a lo largo de un Círculo. Muestre cómo el círculo más remoto del radio – el diagrama del punto de Voronoi puede usarse para computar lo más pequeño – que rodea un grupo dado del punto. Asuma que F (P) está disponible.

Ejes Medios El diagrama de Voronoi puede ser generalizado en varias direcciones, y algunas de estas generalizaciones tienen importante significado práctico. En esta sección tocamos una generalización, una de las más simples: aceptando un grupo de sitios que son un grupo infinitos de puntos, en particular el límite continúo de un polígono.

En la sección 5.20 definimos el diagrama de Voronoi como el grupo de puntos cuyo sitio más cercano no es único. Estos puntos son equidistantemente mejor cerrados en dos o más sitios. Define los ejes medios de un polígono P, que están dentro de un grupo de puntos internos P que un punto bien cerrado entre los puntos de ∂ P. Una definición muy similar puede ser usada para una colección de puntos arbitrarios, pero aquí examinaremos solo el caso donde los puntos forman el límite de un polígono. El eje medio de un rectángulo se muestra en la figura 5.20; cada punto sobre el segmento horizontal dentro del rectángulo está equidistante de los

Juan Carlos Gutiérrez Barquero____________________________________________ 211

Page 212: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

puntos verticales de arriba abajo y están por encima y por debajo de los lados del rectángulo. Cada punto sobre un segmento diagonal esta equidistante de dos lados adyacentes del rectángulo y los dos puntos finales del segmento horizontal están equidistante de tres lados del rectángulo. Un ejemplo mas completo se muestra en la figura 5.21, ocho vértices en un polígono convexo. Uno puede suponer a partir de este ejemplo que el eje medio del polígono convexo P está un árbol cuyos permisos son los ejes de P. Esto es un porcentaje verdadero y está realmente lleno de polígonos no convexos. Todo punto de los ejes medios está en el centro de un circulo que toca el límite de los puntos más lejanos y así es como los vértices de Voronoi están en los centros de los círculos tocando tres sitios, los vértices de los ejes medios están en el centro de los círculos tocando tres puntos distintos del limite como se muestra en la figura 5.22. A veces los ejes medios de P están definidos como el sitio central de los círculos máximos: los círculos dentro de P estos no son los mismos encerrados en algunos otros sitos dentro de P. El proceso de transformación dentro de los ejes medios son en ocasiones llamados “Transformación de Bosques Quemados” por si una imagen del polígono P tal como un césped seco que alumbra con un fuego a los bordes de P, todo esto causará que queme todo dentro de el a una velocidad uniforme y los ejes medios sean el grupo de puntos extintos donde el fuego conozca al fuego de otra dirección. La conexión entre esta analogía y la quema del bosque discutido en la sección 5.1 debería ser evidente. Los ejes medios fueron introducidos por Blum en 1967 para el estudio en forma biológica, el observo de manera semejante a un esqueleto (eje) las amenazas bajo el medio (mediana) de alguna forma. Esta es menos aparente para un polígono convexo que para un no convexo y formas planas que era el principal interés de Blum, uno puede caracterizar la forma de cierta sección de la estructura de estos ejes medios y esto va incluido un interés considerable entre los investigadores en el reconocimiento de patrones y visiones de computadoras, por ejemplo bookstein lo usa para caracterizar las diferencias entre los huesos de la mandíbula normales y los deformados. Puede ser usada para calcular una compensación interior de un polígono, todos de cuyas fronteras son compensaciones interiores por una distancia fija. Expandidas o externas compensaciones cuentan en la versión exterior del eje medio. Calcular compensaciones es un importante problema en la manufacturación, donde la tolerancia de ingeniería es llevada naturalmente a formas de compensación.

Juan Carlos Gutiérrez Barquero____________________________________________ 212

Page 213: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

El eje medio de un polígono de n vértices puede ser construido en 0 (n log n) time; asintoticamente menor pero más prácticos de logaritmos están disponibles. Para polígonos convexos, 0 (n) veces es suficiente.

Ejercicios

• Eje medio de un polígono no convexo. Mostrar por ejemplo que el eje medio de un polígono no convexo puede contener segmentos curvados. ¿Qué puedes decir acerca de la forma funcional de estas curvas?

Juan Carlos Gutiérrez Barquero____________________________________________ 213

Page 214: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

• Eje medio y el diagrama de Voronoi o hay alguna relación entre el eje medio de un polígono convexo P y el diagrama de Voronoi de los vectores de P? Supone algunos aspectos de esta relación y pruébalos y construye contra ejemplos.

Eje medio de un polígono. Describe lo que debe parecer el eje medio de un polígono. Estructura recta. Aichholzer, Alberts, Aurenhammer & Gärtner, introdujo una estructura que es similar al eje medio, pero compuesta de segmentos rectos incluso para polígonos no convexos. Mover cada borde de un paralelo al mismo interior a una velocidad constante con bordes adyacentes encogiendo y creciendo así que los vértices viajan a lo largo del ángulo bisector. Cuando un borde se encoge hasta la longitud cero, sus bordes vecinos se hacen adyacentes. Cuando un vértice reflejo choca hacia adentro de un borde, el poligono se agrieta y el proceso de encogimiento de las piezas continúa. 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.

Conexión con el Convexo Hulls

El 1986 Ellels Brunner & Seidel decubrió una bella conexión entre la triangulación de Delaunay y el convex hulls en una de las más altas dimensiones: primero explicaré entre el convex hull bidimensional y la triangulación unidimensional de Delaunay (que son admitimademente triviales) y entonces generaliza la triangulación bidimensional de Delaunay y el tridimensional convex hull. Entonces esta conexión nos dará un método fácil para calcular la triangulación de Delaunay y del diagrama de Voronoi, vía tridimensional hulls triangulación unidimensional de Delaunay. Empezaremos en una dimensión donde la matemática es transparente sea P= x1,…,xn un conjunto de puntos sobre el eje x. Claramente la triangulación unidimensional de Delaunay es simple el camino conecta x1 a x2 a… xn , pero veremos que esto es una proyección sobre el eje x de un conjunto de puntos bidimensionales con coordenadas (xi, x2i). Estos puntos pueden ser vistos como una proyección de la ascendencia de x en la parábola z= x2. Es trivialmente verdadero que el connuex hull de estos puntos bidimensionales proyectado hacia abajo a la triangulación unidimensional de Delaunay, tanto como el borde más alto del hull es descartado, pero hay mucho más aquí que esta observación trivial que puede ser aclarada con la consideración de las tangentes a la parábola.

Juan Carlos Gutiérrez Barquero____________________________________________ 214

Page 215: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

La pendiente de la parábola z= x2 en el punto x= a es 2a (porque dz/dx= 2x). De esta manera la ecuación de la tangente a la parábola en el punto (a, a2) es z-a2= 2a (x-a) z= 2a x-a2 En preparación para estudiar el mismo proceso en tres dimensiones, ahora investigaremos la intersección entre esta tangente y la parábola cuando la tangente es trasladada verticalmente una distancia r2. Cuando la tangente es aumentada por esta cantidad su ecuación se convierte en z=2a x-a2 + r2

Entonces la tangente aumentada intersecta la parábola en + r lejos de a, el punto original de tangencia. Nota que x= a + r puede ser pensado como la ecuación 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]. Triangulación Bidimensional de Delaunay Repetimos el mismo análisis 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)

Juan Carlos Gutiérrez Barquero____________________________________________ 215

Page 216: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

Toma el convex hull de este conjunto de puntos tridimensionales, ver la figura 5.25. Ahora descarta las caras más altas de este hull. Todas esas caras que son exteriores punteando los puntos superiores normales, en el sentido de times un producto positivo el resultado es una “condra” más baja. Proyectar esto al plano xy. El reclamo es que esta es una triangulacion de Delaunay. Ver la figura 5.26. Ahora establecemos esta fenomenal conexión formalmente. La ecuación del plano tangente encima del punto (a, b) es z=2a x + 2b y – (a2 + b2) (Esta es una analogía directa a la ecuación z= 2a x – a2: dz/dx= 2x and dz/dy= 2y)

Ahora cambiamos este plano superior por r2, exactamente como cambiamos la línea tangente en la subsección previa z= 2a x +2b y – (a2 + b2)+ r2 (x-a)2 + (y-b2)= r2

Juan Carlos Gutiérrez Barquero____________________________________________ 216

Page 217: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

El plano cambiado intercepta el paraboloide en una curva (una elipse) que proyecta a un círculo. Esto es ilustrado en la figura 5.27 y 5.28. Ahora revisemos desde un punto de vista para dirigirnos s la triangulación Delaunay. Considere el plano π a través 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 algún 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 debería estar claro que el análisis previo tiene aplicaciones. Desde ∆ esta en una cara inferior del buque, todo las otras puntos del paraboloide están arriba. Desde que están arriba π , están más que el r2 arriba, cuál es el r2 debajo. Por eso estos puntos se proyectan fuera del círculo de radio r en el plano x y. Por eso el círculo determinado adentro de los planos x y está vacío en todos los otros sitios. Por eso forma un triángulo Delaunay. Por eso cada cara triangular inferior del buque convexo es propia de un triángulo Delaunay. ¡Por eso la proyección del “fondo” del buque convexo se proyecta para la triangulación Delaunay! Otra vez evacue a Figure 5.26. Déjeme explicar esta compenetración 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 muévase t arriba. La proyección de su intersección con el paraboloide es un círculo en expansión 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 círculo en expansión en el sitio en el plano que es la proyección de q. Así el círculo está vacío t hasta π los límites exteriores, cuándo atraviese los tres sitios cuya proyección forma la cara∆ del buque del triángulo soportada por π .

Juan Carlos Gutiérrez Barquero____________________________________________ 217

Page 218: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

Un corolario útil para el debate citado anteriormente es éste: Corolario 5.7.1 Cuatro puntos (xi, yi), i = 1, 2, 3, 4, consisten en una mentira del círculo 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 Ecuación 1.15 y 4.6) es cero.

La implicación

Teorema 5.7.2 La triangulación de Delaunay de un grupo de puntos en dos dimensiones es precisamente la proyección 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 Sección 4.2.2) (n log n), esto significa que la triangulación de Delaunay puede ser computada en el mismo tiempo límite. Una vez que la triangulación Delaunay está en tus manos, es relativamente fácil 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 podría esperar, esta relación entre diagramas Voronoi y podría abombar buques que yo una dimensión más alta mantengo en dimensiones arbitrarias. Así ambos el diagrama Voronoi y la triangulación Delaunay en tres dimensiones pueden forjarse de un buque convexo en cuatro dimensiones. De hecho, puede ser que el más uso común de código del buque del 4D es para construir mallas sólidas de Delaunay tetraédrico. En general, el diagrama de Voronoi dual para un grupo de puntos de d-dimensional es la proyección del buque “ inferior ” de puntos en d + 1 dimensión. La implementación de la Triangulación de Delaunay: El código O (n4)

Teorema 5.7.2 el código conciso permite increíblemente computar la triangulación de Delaunay, si uno es indiferente sobre la complejidad de tiempo ¡En particular, si O (n4) es aceptable (y raramente lo es), entonces la triangulación de Delaunay puede ser computada con menos esas treinta líneas de código de la C! Esto es presentado en código 5.1 en parte como la curiosidad, pero también a enfatiza cómo la comprensión profunda de geometría puede conducir al código limpio. main()

Juan Carlos Gutiérrez Barquero____________________________________________ 218

Page 219: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

int x[MAX],y[MAX],z[MAX]; /*Intreda de puntos x,y,z*/ int n; /*Numero dep puntos introducidos*/ int i,j,k,m; /*induce de cuatro puntos*/ int flag; /*localizacion normal de (i,j,k)*/ /*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 código 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 están o por encima del plano conteniendo i, j, y k. Si es así, (i, j, k) es salida como triángulo Delaunay. (La símil arridad para el algoritmo del buque de dos dimensiones en Algoritmo 3.2 debería ser evidente).

Juan Carlos Gutiérrez Barquero____________________________________________ 219

Page 220: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

Triang. de Delaunay dual.

La prueba de por encima de plano es realizada chocheando la orientación exterior normal para el triángulo, (xn, yn, zn), con un vector de punto para apuntar m. Aunque es interesante para ver tal código sucinto computar un propósito guste la triangulación Delaunay, es impráctica para varias razones:

1. El código devuelve todos los triángulos dentro de una cara de triangulación Delaunay cuyo límite consta de cuatro o más puntos del cocircular. Así una mueca cuadrada resulta en salida cuatro de triángulo, representando las dos triangulaciones del cuadrado. Obtener más salida útil requeriría el postprocesamiento. 2. Hay ineficiencias obvias en el código (por ejemplo, la m-loop podría quebrarse cuando un punto es descubierto debajo del plano del I, j, k). Estos podrían repararse fácilmente al precio de alargarle un poco, pero… 3. La dependencia de tiempo del n4 es inaceptable. Pues dos prueban

carreras con n = 100 y n = 200 puntos, el tiempo de computar fue 12 y 239 segundos respectivamente, exhibiendo un más de 24 incremento de 16 pliegues para el doble número de puntos. Esto indica 1,000 tan n tomaba varios días.

Triangulación de Delaunay 3D cáscara: O (el n2) el Código

Es una tarea fácil convertir el código cuadrático desarrollado en Capítulo 4 para construir el buque del 3D en el código cuadrático para construir la triangulación Delaunay. Toda la complejidad está en el código del buque (código de casi 1,000 líneas de ) acerca del razonamiento que entró en

Juan Carlos Gutiérrez Barquero____________________________________________ 220

Page 221: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

Teorema 5.7.2. Las modificaciones adicionales son relativamente menores. Primer, que la rutina ReadVertices (código 4.10) debería leer en x, y y computar z= x2 +y2. En segundo lugar, después del buque entero se forja, un procedimiento LowerFaces se siente llamado al lazo sobre todas las fases e identifique cuáles es en la carena (código 5.2). Como en código secreto 5.1, este está consumado computando las coordenadas de la z de un vector normal para cada f de la cara. Esta computar, encarnado en Normz, es justamente un cambio leve para Collinear (Código 4.12). Si Normz (f) < z, entonces la cara está en la carena, y su proyección encima del Plano x y es un triángulo de Delaunay. Ilustramos con un ejemplo de n = 10 puntos cuyas coordenadas son ostentadas en la tabla 5.1. Note que las coordenadas de la z son infundidas arriba en la magnitud cuadrando. Esta parte pequeña que el ejemplo detiene adecuadamente dentro del rango seguro de la computar de volumen discutió comparación para el código del buque del 3D. La salida Postscript del código es mostrada en Figure 5.29. Como esperada, esta implementación O (n2) es mucho más rápida que el código O (n4): En la misma n = 100 y n = 200 ejemplos que mientras código más lento usó 12 y 239 segundos, el código más rápido usaron 0.2 y 1.3 segundos respectivamente. Además, la aceleración del randomizadas discutió en Sección 4.5 vueltas así de en una O (n log n) esperado algoritmo de tiempo.

5.7.5 Ejercicio 1. El rango de dt2.c [programación] . Encuentro un grupo del punto cuyas coordenadas son tan pequeñas como sea posible, y para las cuales el código del dt2.c (código 5.2) devuelve un resultado incorrecto debido al derramamiento del cálculo de volumen. void LowerFaces(void) tFace f=faces; int Flower=0; /*numero total*/ do if(Normz(f)<0) Flower++; f->vertex[0]->Vnum, f->vertex[1]->Vnum, f->vertex[2]->Vnum); f=f->next; while(f!=faces); printf("%d lower faces identificada\n",Flower);

Juan Carlos Gutiérrez Barquero____________________________________________ 221

Page 222: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

int Normz (tFaces f) tvertex a, b, c; a=f->vertex[0]; b=f->vertex[1]; c=f->vertex[2]; return (b->v[x]-a->v[x])*(c->v[x]-a->v[y])- (b->v[y]-a->v[y])-(c->v[x]-a->v[x]); 2. D à V (P) (P) [programación] . Modifique el código del dt2.c para computar el diagrama de Voronoi de la triangulación de Delaunay. (Vea ejercicio 5.5.6 [1]). Hay que repetidamente construir círculos a través de tres puntos dadas a, b, c. Las coordenadas de la p central = (p0, p1) pueden ser computadas como sigue:

A = b0 – a0,

B= b1 – a1,

C = c0 – a0,

D = c1 – a1,

E = A(a0 + b0 ) + B(a1 + b1 ),

F = C(a0 + b0 ) + D(a1 + b1 ),

G = 2(A(c1 – b1 ) – B(c0 – b0 )),

p0 = (DE – BF)/G,

p1 = (AF – CE)/G.

Tabla 5.1 Coordenadas de sitios de Delaunay, Incluyendo z= x2 +y2

I X Y X2+y2 0 31 -76 6737 1 -13 21 610 2 -63 -83 10858 3 -5 -66 4381 4 87 -94 16405 5 40 71 6641 6 23 -46 2645 7 64 -80 10496

Juan Carlos Gutiérrez Barquero____________________________________________ 222

Page 223: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

8 0 -57 3249 9 -14 2 200

5.8 Conexión a arreglos Tenemos que mostrar que la triangulación de Delaunay puede ser derivada de la transformación paraboloide e indican que es fácil de obtener el diagrama de Voronoi si es posible obtener el diagrama de Voronoi directamente de la transformación del paraboloide. Aunque todo esto se entiende que tienes que esperar al siguiente capitulo (Sección 6.7) y mostraremos la conexión que se realiza utilizando las ecuaciones mas relevante. 5.8.1 Diagrama de Voronoi unidimensional Considerando dos tangentes examinadas en la sección 5.7.1 (ecuación 5.4) siendo x=a y otro siendo x=b:

z=2ax-a2

z=2bx – b2

Donde se intersecan resolviendo las ecuaciones simultáneas la solución sería

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 proyección de las intersecciones están adyacentes al diagrama de Voronoi y al grupo de puntos

Juan Carlos Gutiérrez Barquero____________________________________________ 223

Page 224: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

5.8.2 Diagrama de Voronoi bidimensinal Considere dos tangentes planas del paraboloide analizado en la Seccion (5.7.2) (ecuación 5.8), donde estan a y b y otra donde esta c y b.

z = 2ax + 2by – a2 + b 2,

z = 2cx + 2dy – c2 + d2

¿donde están los intersectos? Resolviendo la ecuación simultanea 2ax + 2by – a2 + b 2 = 2cx + 2dy – c2 + d2

x(2a – 2c) + y(2b – 2d) = ( a2 - c 2) + (a2 + b 2 ) Esta ecuación es precisamente la bisectriz perpendicular del segmento de (a,b) y (c,d) ver figura 5.31. Si observamos las tangentes opacas planas de z=+infinito (con el paraboloide transparente) debería ser visible en la primera intersección su primera intersección es la bisectriz entre los lugares que generan las tangentes planas la proyección de estas primeras tangentes es precisamente el diagrama de voronoi! También tenemos que recordar la situación al visualizar la proyección de puntos dentro del paraboloide de z=-infinito vea la triangulación de Delaunay la observación de las tangentes planas del paraboloide y estos puntos de z=+infinito vea el diagrama de Voronoi.

Juan Carlos Gutiérrez Barquero____________________________________________ 224

Page 225: Graficos de C

Bismarck Salvador Traña López__________________________________________UNI

Bibliografía [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

Juan Carlos Gutiérrez Barquero____________________________________________ 225