First commit 01/01/1993
This commit is contained in:
361
S.C
Normal file
361
S.C
Normal file
@ -0,0 +1,361 @@
|
||||
/*
|
||||
Este programa forma parte del Curso de C
|
||||
Copyright (C) 1991 Grupo Editorial Jackson
|
||||
Todos los derechos reservados
|
||||
*/
|
||||
|
||||
|
||||
/* ESPIRAL: dibuja espirales poligonales aleatorias */
|
||||
|
||||
|
||||
/* NOTA: tambi<62>n este fichero, como REBOTE.C, contiene dos programas
|
||||
distintos, el primero escrito con las funciones gr<67>ficas de Turbo C
|
||||
2.0 y el segundo con las de Quick C 2.0. La opci<63>n es autom<6F>tica
|
||||
con una instrucci<63>n #ifdef.
|
||||
|
||||
Este sistema comienza a resultar demasiado inc<6E>modo: en la lecci<63>n
|
||||
E5 se explica c<>mo crear una 'librer<65>a' de funciones gr<67>ficas
|
||||
port<72>til, parecida a la librer<65>a Jconio, empleada para las funciones
|
||||
de consola.
|
||||
*/
|
||||
|
||||
|
||||
/*========================= Versi<73>n para Turbo C 2.0 ======================*/
|
||||
|
||||
#ifdef __TURBOC__
|
||||
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include <math.h>
|
||||
#include <conio.h>
|
||||
#include <graphics.h>
|
||||
|
||||
|
||||
/* constantes y variables globales */
|
||||
|
||||
#define PAUSA 3 /*3 segundos de pausa entre espirales*/
|
||||
|
||||
int maxcol; /*l<>mite de colores*/
|
||||
int centroX; /*coordenadas del centro de la pantalla*/
|
||||
int centroY;
|
||||
double cuadra; /*factor de cuadratura*/
|
||||
double pi; /*n<>mero pi*/
|
||||
double grad; /*constante de conversi<73>n grados/radianes*/
|
||||
|
||||
|
||||
/* prototipos de funciones: */
|
||||
|
||||
void Espiral(void);
|
||||
|
||||
|
||||
/********************************************************************
|
||||
* main
|
||||
********************************************************************/
|
||||
|
||||
main()
|
||||
{
|
||||
int driver = DETECT; /*elige autom<6F>ticamente*/
|
||||
int modo;
|
||||
int dimx,dimy; /*dimensiones pantalla (n<>mero pixels)*/
|
||||
time_t t;
|
||||
|
||||
initgraph(&driver,&modo,NULL); /*inicia gr<67>ficos <1>*/
|
||||
if (driver < 0) { /*comprueba si ok*/
|
||||
cputs("\r\n- No se pueden utilizar los"
|
||||
" gr<67>ficos de este ordenador."); /*sale si no puede*/
|
||||
exit(1);
|
||||
}
|
||||
|
||||
maxcol = getmaxcolor(); /*color m<>s alto*/
|
||||
dimx = getmaxx()+1; /*y l<>mites pantalla*/
|
||||
dimy = getmaxy()+1;
|
||||
centroX = dimx/2; /*calcula centro <2>*/
|
||||
centroY = dimy/2;
|
||||
cuadra = (dimx/(double)dimy)/(4.0/3.0); /*cuadratura <3>*/
|
||||
pi = 4.0*atan(1.0); /*n<>mero pi <4>*/
|
||||
grad = pi/180.0; /*constante convers. <5>*/
|
||||
|
||||
srand((unsigned int)time(NULL)); /*inicia random*/
|
||||
while (kbhit()) getch(); /*vac<61>a buffer*/
|
||||
|
||||
while (! kbhit()) { /*sale con una tecla*/
|
||||
Espiral(); /*dibuja una espiral*/
|
||||
t = time(NULL)+PAUSA; /*espera o tecla <6>*/
|
||||
while (! kbhit() && time(NULL) < t)
|
||||
;
|
||||
}
|
||||
if (kbhit()) getch(); /*vac<61>a posibles teclas*/
|
||||
|
||||
closegraph(); /*vuelve al modo texto*/
|
||||
}
|
||||
|
||||
/* Notas sobre main:
|
||||
<1> El paso al modo gr<67>fico es id<69>ntico al de REBOTE.
|
||||
<2> Dado que el n<>mero de pixels es par, no existe un centro exacto.
|
||||
<3> El factor de cuadratura se utilizar<61> para corregir la dimensi<73>n
|
||||
horizontal de forma que la figura aparezca con las mismas proporciones
|
||||
tanto en vertical como en horizontal, independientemente de la forma
|
||||
de los pixels en un determinado ordenador. Las operaciones con
|
||||
(double) son necesarias para evitar que dimx/dimy sea una divisi<73>n
|
||||
entera con p<>rdida del resto.
|
||||
<4> Aprovechando el hecho de que 45<34> es <20>/4 y que la tangente de 45<34> es
|
||||
1.0, se puede obtener el valor de pi sin tener que escribirlo.
|
||||
<5> Es m<>s c<>modo disponer de una constante para convertir entre grados
|
||||
sexagesimales (una vuelta = 360<36>) y radianes (una vuelta = 2<>).
|
||||
<6> El tiempo de espera establecido (PAUSA segundos) se interrumpe si el
|
||||
usuario pulsa una tecla para terminar el programa. Si se desea una
|
||||
mayor precisi<73>n, se deber<65>a utilizar clock en lugar de time.
|
||||
*/
|
||||
|
||||
|
||||
/********************************************************************
|
||||
* Espiral: dibuja una espiral poligonal aleatoria.
|
||||
********************************************************************/
|
||||
|
||||
void Espiral(void) /*<1>*/
|
||||
{
|
||||
double r; /*radio*/
|
||||
double ia; /*incremento <20>ngulo*/
|
||||
double ir; /*incremento radio*/
|
||||
double rlim; /*l<>mite radio*/
|
||||
double s,c; /*seno y coseno actuales <2>*/
|
||||
double ca; /*coseno anterior*/
|
||||
double isin,icos; /*incremento seno y coseno*/
|
||||
int x,y;
|
||||
|
||||
rlim = centroY*2.5; /*fija l<>mite*/
|
||||
ia = (double)((rand()%3600)/10.0); /*extrae incrementos <3>*/
|
||||
ir = 1.0+(double)((rand()%200)/100.0);
|
||||
isin = sin(ia*grad);
|
||||
icos = cos(ia*grad);
|
||||
r = 0.0; /*parte del centro*/
|
||||
s = sin(0.0); /*con <20>ngulo 0 grados*/
|
||||
c = cos(0.0);
|
||||
|
||||
setcolor(1+rand()%maxcol); /*y color, no negro <4>*/
|
||||
cleardevice(); /*borra pantalla*/
|
||||
moveto(centroX,centroY); /*va al centro*/
|
||||
while (r < rlim) {
|
||||
ca = c; /*copia coseno*/
|
||||
c = c*icos-s*isin; /*nuevo coseno <5>*/
|
||||
s = s*icos+ca*isin; /*nuevo seno*/
|
||||
x = centroX+(int)(floor(r*c*cuadra+0.5)); /*nuevas coordenadas <6>*/
|
||||
y = centroY+(int)(floor(r*s+0.5));
|
||||
lineto(x,y); /*traza l<>nea*/
|
||||
r += ir; /*incrementa radio*/
|
||||
}
|
||||
}
|
||||
|
||||
/* Notas sobre Espiral:
|
||||
<1> Una espiral poligonal se obtiene girando a velocidad constante
|
||||
alrededor del centro y aumentando progresivamente el radio. A
|
||||
intervalos regulares (en t<>rminos de <20>ngulo) se fija un punto y
|
||||
se une con un segmento rectil<69>neo al punto anterior.
|
||||
<2> La funci<63>n Espiral usa un truco para no tener que llamar a dos
|
||||
funciones trigonom<6F>tricas relativamente lentas (seno y coseno) en
|
||||
cada vuelta. Es posible calcular una sola vez, al principio, las dos
|
||||
variables isin y icos, y utilizarlas con simples multiplicaciones
|
||||
para calcular la posici<63>n sucesiva a lo largo de una circunferencia.
|
||||
<3> La rotaci<63>n se obtiene aumentando en cada vuelta el <20>ngulo actual un
|
||||
determinado valor (en realidad utilizamos el truco descrito en la nota
|
||||
2). Ejecutando rand()%3600 se obtiene un valor entre 0 y 3599, y
|
||||
dividi<64>ndolo por 10.0 se subdivide el <20>ngulo de giro en d<>cimas de
|
||||
grado: el valor de ia resulta entonces comprendido entre 0.0 y 359.9
|
||||
grados. El valor de ir (incremento radio) estar<61> comprendido, sin
|
||||
embargo, entre 1.0 y 2.99.
|
||||
<4> Extrae un color entre los disponibles, excluido el cero. En el caso
|
||||
de un monitor monocromo, extrae siempre el blanco.
|
||||
<5> Este es el atajo utilizado para evitar el c<>lculo en cada vuelta del
|
||||
seno y el coseno del <20>ngulo actual. No profundizamos en la t<>cnica
|
||||
trigonom<6F>trica empleada.
|
||||
<6> La coordenada horizontal se multiplica por cuadra (el factor de
|
||||
cuadratura) para asegurar unas proporciones 'cuadradas'. Utilizamos
|
||||
el sistema habitual para aproximar un double al entero m<>s cercano:
|
||||
a<>adir 0.5 y aproximar con floor al entero inferior. La utilizaci<63>n
|
||||
de (int) no es estrictamente necesaria, pero muestra sin ninguna
|
||||
duda que se ejecuta un truncamiento de la parte decimal pasando de
|
||||
un double a un int (la parte decimal ya era cero, de todas formas,
|
||||
por el efecto de floor).
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/*========================= Versi<73>n para Quick C 2.0 ======================*/
|
||||
|
||||
#else
|
||||
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h> /*para definir NULL*/
|
||||
#include <time.h>
|
||||
#include <math.h>
|
||||
#include <conio.h>
|
||||
#include <graph.h>
|
||||
|
||||
|
||||
/* constantes y variables globales */
|
||||
|
||||
#define PAUSA 3 /*3 segundos de pausa entre espirales*/
|
||||
|
||||
int maxcol; /*l<>mite de colores*/
|
||||
int centroX; /*coordenadas del centro de la pantalla*/
|
||||
int centroY;
|
||||
double cuadra; /*factor de cuadratura*/
|
||||
double pi; /*n<>mero pi*/
|
||||
double grad; /*constante de conversi<73>n grados/radianes*/
|
||||
|
||||
|
||||
/* prototipos de funciones: */
|
||||
|
||||
void Espiral(void);
|
||||
|
||||
|
||||
/********************************************************************
|
||||
* main
|
||||
********************************************************************/
|
||||
|
||||
main()
|
||||
{
|
||||
int modos[] = { /*lista de los modos en orden de preferencia*/
|
||||
_VRES16COLOR, /*VGA 640 x 480*/
|
||||
_ERESCOLOR, /*EGA color 640 x 350*/
|
||||
_ERESNOCOLOR, /*EGA monocroma 640 x 350*/
|
||||
_ORESCOLOR, /*Olivetti 640 x 400*/
|
||||
_HERCMONO, /*Hercules 720 x 348*/
|
||||
_HRESBW, /*CGA 640 x 400*/
|
||||
_DEFAULTMODE /*indica fin de lista*/
|
||||
};
|
||||
struct videoconfig v; /*datos del modo de v<>deo actual*/
|
||||
int dimx,dimy; /*dimensiones de la pantalla (n<>mero pixels)*/
|
||||
time_t t;
|
||||
int i;
|
||||
|
||||
i = 0; /*inicia gr<67>ficos <1>*/
|
||||
while (modos[i] != _DEFAULTMODE
|
||||
&& _setvideomode(modos[i]) == 0) {
|
||||
i++;
|
||||
}
|
||||
|
||||
if (modos[i] == _DEFAULTMODE) { /*comprueba si ok*/
|
||||
cputs("\r\n- No se pueden utilizar los"
|
||||
" gr<67>ficos de este ordenador."); /*sale si no puede*/
|
||||
exit(1);
|
||||
}
|
||||
|
||||
_getvideoconfig(&v); /*lee datos modo v<>deo:*/
|
||||
maxcol = v.numcolors; /*color m<>ximo*/
|
||||
dimx = v.numxpixels; /*l<>mites pantalla*/
|
||||
dimy = v.numypixels;
|
||||
centroX = dimx/2; /*calcula centro <2>*/
|
||||
centroY = dimy/2;
|
||||
cuadra = (dimx/(double)dimy)/(4.0/3.0); /*cuadratura <3>*/
|
||||
pi = 4.0*atan(1.0); /*n<>mero pi <4>*/
|
||||
grad = pi/180.0; /*constante convers. <5>*/
|
||||
|
||||
srand((unsigned int)time(NULL)); /*inicia random*/
|
||||
while (kbhit()) getch(); /*vac<61>a buffer*/
|
||||
|
||||
while (! kbhit()) { /*sale con una tecla*/
|
||||
Espiral(); /*dibuja una espiral*/
|
||||
t = time(NULL)+PAUSA; /*espera o tecla <6>*/
|
||||
while (! kbhit() && time(NULL) < t)
|
||||
;
|
||||
}
|
||||
if (kbhit()) getch(); /*vac<61>a posibles teclas*/
|
||||
|
||||
_setvideomode(_DEFAULTMODE); /*vuelve al modo texto*/
|
||||
}
|
||||
|
||||
/* Notas sobre main:
|
||||
<1> El paso al modo gr<67>fico es id<69>ntico al de REBOTE.
|
||||
<2> Dado que el n<>mero de pixels es par, no existe un centro exacto.
|
||||
<3> El factor de cuadratura se utilizar<61> para corregir la dimensi<73>n
|
||||
horizontal de forma que la figura aparezca con las mismas proporciones
|
||||
tanto en vertical como en horizontal, independientemente de la forma
|
||||
de los pixels en un determinado ordenador. Las operaciones con
|
||||
(double) son necesarias para evitar que dimx/dimy sea una divisi<73>n
|
||||
entera con p<>rdida del resto.
|
||||
<4> Aprovechando el hecho de que 45<34> es <20>/4 y que la tangente de 45<34> es
|
||||
1.0, se puede obtener el valor de pi sin tener que escribirlo.
|
||||
<5> Es m<>s c<>modo disponer de una constante para convertir entre grados
|
||||
sexagesimales (una vuelta = 360<36>) y radianes (una vuelta = 2<>).
|
||||
<6> El tiempo de espera establecido (PAUSA segundos) se interrumpe si el
|
||||
usuario pulsa una tecla para terminar el programa. Si se desea una
|
||||
mayor precisi<73>n, se deber<65>a utilizar clock en lugar de time.
|
||||
*/
|
||||
|
||||
|
||||
/********************************************************************
|
||||
* Espiral: dibuja una espiral poligonal aleatoria.
|
||||
********************************************************************/
|
||||
|
||||
void Espiral(void) /*<1>*/
|
||||
{
|
||||
double r; /*radio*/
|
||||
double ia; /*incremento <20>ngulo*/
|
||||
double ir; /*incremento radio*/
|
||||
double rlim; /*l<>mite radio*/
|
||||
double s,c; /*seno y coseno actuales <2>*/
|
||||
double ca; /*coseno anterior*/
|
||||
double isin,icos; /*incremento seno y coseno*/
|
||||
int x,y;
|
||||
|
||||
rlim = centroY*2.5; /*fija l<>mite*/
|
||||
ia = (double)((rand()%3600)/10.0); /*extrae incrementos <3>*/
|
||||
ir = 1.0+(double)((rand()%200)/100.0);
|
||||
isin = sin(ia*grad);
|
||||
icos = cos(ia*grad);
|
||||
r = 0.0; /*parte del centro*/
|
||||
s = sin(0.0); /*con <20>ngulo 0 grados*/
|
||||
c = cos(0.0);
|
||||
|
||||
_setcolor(1+rand()%maxcol); /*y color, no negro <4>*/
|
||||
_clearscreen(_GCLEARSCREEN); /*borra pantalla*/
|
||||
_moveto(centroX,centroY); /*va al centro*/
|
||||
while (r < rlim) {
|
||||
ca = c; /*copia coseno*/
|
||||
c = c*icos-s*isin; /*nuevo coseno <5>*/
|
||||
s = s*icos+ca*isin; /*nuevo seno*/
|
||||
x = centroX+(int)(floor(r*c*cuadra+0.5)); /*nuevas coordenadas <6>*/
|
||||
y = centroY+(int)(floor(r*s+0.5));
|
||||
lineto(x,y); /*traza l<>nea*/
|
||||
r += ir; /*incrementa radio*/
|
||||
}
|
||||
}
|
||||
|
||||
/* Notas sobre Espiral:
|
||||
<1> Una espiral poligonal se obtiene girando a velocidad constante
|
||||
alrededor del centro y aumentando progresivamente el radio. A
|
||||
intervalos regulares (en t<>rminos de <20>ngulo) se fija un punto y
|
||||
se une con un segmento rectil<69>neo al punto anterior.
|
||||
<2> La funci<63>n Espiral usa un truco para no tener que llamar a dos
|
||||
funciones trigonom<6F>tricas relativamente lentas (seno y coseno) en
|
||||
cada vuelta. Es posible calcular una sola vez, al principio, las dos
|
||||
variables isin y icos, y utilizarlas con simples multiplicaciones
|
||||
para calcular la posici<63>n sucesiva a lo largo de una circunferencia.
|
||||
<3> La rotaci<63>n se obtiene aumentando en cada vuelta el <20>ngulo actual un
|
||||
determinado valor (utilizamos el truco descrito en la nota 2).
|
||||
Ejecutando rand()%3600 se obtiene un valor entre 0 y 3599, y
|
||||
dividi<64>ndolo por 10.0 se subdivide el <20>ngulo de giro en d<>cimas de
|
||||
grado: el valor de ia resulta entonces comprendido entre 0.0 y 359.9
|
||||
grados. El valor de ir (incremento radio) estar<61> comprendido, sin
|
||||
embargo, entre 1.0 y 2.99.
|
||||
<4> Extrae un color entre los disponibles, excluido el cero. En el caso
|
||||
de un monitor monocromo, extrae siempre el blanco.
|
||||
<5> Este es el atajo utilizado para evitar calcular en cada vuelta el
|
||||
seno y el coseno del <20>ngulo actual. No profundizamos en la t<>cnica
|
||||
trigonom<6F>trica empleada.
|
||||
<6> La coordenada horizontal se multiplica por cuadra (el factor de
|
||||
cuadratura) para asegurar unas proporciones 'cuadradas'. Utilizamos
|
||||
el sistema habitual para aproximar un double al entero m<>s cercano:
|
||||
a<>adir 0.5 y aproximar con floor al entero inferior. La utilizaci<63>n
|
||||
de (int) no es estrictamente necesaria, pero muestra sin ninguna
|
||||
duda que se ejecuta un truncamiento de la parte decimal pasando de
|
||||
un double a un int (la parte decimal ya era cero, de todas formas,
|
||||
por el efecto de floor).
|
||||
*/
|
||||
|
||||
|
||||
#endif /*fin opci<63>n Turbo C/Quick C*/
|
||||
|
Reference in New Issue
Block a user