Documentos de Académico
Documentos de Profesional
Documentos de Cultura
Universidad Centroamericana
Jos Simen Caas
Eduardo NAVAS
versin 1.0
2010.03.08
Este libro fue desarrollado nicamente con software libre. Entre las herramientas usadas,
CC-BY-NC-SA
Este es un libro libre con la licencia
Prlogo
Descripcin general
Este libro est siendo desarrollado con el propsito de ser libro de texto para diversas
materias impartidas y a impartir para la carrera de Licenciatura en Ciencias de la Computacin y otras carreras de grado y postgrado en la Universidad Centroamericana Jos
Simen Caas en El Salvador. Est pensado para estudiantes que ya han aprobado los
cursos en los que se estudia clculo innitesimal, geometra analtica vectorial, estructura
de datos y programacin orientada a objetos.
La gracacin por computadora es una de las principales reas de estudio de las ciencias
de la computacin, con aplicacin en todos los mbitos de la computacin; desde la
necesidad de representar medianas o grandes cantidades de datos numricos que seran
ilegibles en texto, hasta el desarrollo de sosticadas aplicaciones cientcas de simulacin
de modelos matemticos del clima; desde el uso de software de edicin de fotografas,
hasta el desarrollo de videojuegos. En todos los mbitos, surge la necesidad de tener
conocimientos elementales de gracacin por computadora.
El contendio del libro comienza con una breve introduccin a SDL (y PyGame) que es la
biblioteca grca base a ser usada en los primeros captulos del libro. Se sigue con una
introduccin terica a la gracacin por computador, en la que se presentan algunos
conceptos elementales que son imprescindibles para la programacin de aplicaciones
grcas interactivas.
En el captulo siguiente se aborda mpliamente el tema de la discretizacin de lneas
rectas y circunferencias de un pixel de grosor. Se aborda tambin el tema de relleno
de circunferencias. Luego se procede a hacer un riguroso anlisis vectorial del tema de
cambio de coordenadas o cambio de marco de referencia. All se incluye una aplicacin
de ejemplo en la que se pone en prctica la teora presentada.
Despus, se describe la teora matemtica matricial relacionada con las transformaciones
geomtricas bidimensionales y tridimensionales. Se incluye entonces una aplicacin de
corte pedaggico que permite practicar transformaciones geomtricas tridimensionales
y permite ver en tiempo real sus efectos sobre un conjunto de objetos geomtricamente
sencillos.
El siguiente captulo, muestra la teora necesaria para comprender cmo transformar
Motivacin al lector
En general, el autor desea expresar su deseo de seguir mejorando y ampliando, en la
medida de lo posible, esta obra para benecio de la sociedad salvadorea. Y tambin
desea invitar al apreciable lector a que le saque todo el provecho posible, que aplique
sus aportes en todas las reas posibles de su trayectoria profesional; y tambin que no lo
considere una serie de armaciones incuestionables, sino una contribucin al desarrollo
tecnolgico salvadoreo y a la independencia tecnolgica de la regin centroamericana.
Como toda obra acadmica de programacin, o como la mayora, los cdigos (y programas) includos pretenden mantener simplicidad y claridad para no dicultar innecesariamente la comprensin, pero se recomienda hacer el ejercicio de optimizarlos.
10
SDL
para C.
pygame
ndice general
I. Gracacin por computadora
21
23
. . . . . . . . . . . . . . . . . . . .
23
1.1.1.
23
1.1.2.
24
1.1.3.
24
1.1.4.
Instalacin en openSuSE . . . . . . . . . . . . . . . . . . . . . . .
25
1.1.5.
1.1.6.
Otras distribuciones
. . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . .
25
. . . . . . . . . . . . . . . . . . . . . . . . .
26
1.2.
. . . . . . . . . . . .
26
1.3.
26
1.3.1.
26
1.3.2.
28
1.3.3.
Modos de video . . . . . . . . . . . . . . . . . . . . . . . . . . . .
29
1.3.4.
Eventos de ratn . . . . . . . . . . . . . . . . . . . . . . . . . . .
31
1.3.5.
Eventos de teclado . . . . . . . . . . . . . . . . . . . . . . . . . .
33
1.3.6.
Redimensionamiento de la ventana . . . . . . . . . . . . . . . . .
35
1.3.7.
Facilitar
36
1.3.8.
la compilacin
. . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . .
37
1.4.
1.5.
Instalacin de PyGAME . . . . . . . . . . . . . . . . . . . . . . . . . . .
45
1.6.
46
pygame):
42
1.6.1.
1.6.2.
47
1.6.3.
Modos de video . . . . . . . . . . . . . . . . . . . . . . . . . . . .
48
1.6.4.
Eventos de ratn . . . . . . . . . . . . . . . . . . . . . . . . . . .
50
1.6.5.
Eventos de teclado . . . . . . . . . . . . . . . . . . . . . . . . . .
51
1.6.6.
Redimensionamiento de la ventana . . . . . . . . . . . . . . . . .
1.7.
1.8.
Ejercicios
pygame
46
52
. . . . . . . . . . . . . . . . . .
53
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
54
11
ndice general
2.2.
2.3.
57
57
2.1.1.
El Modelado
. . . . . . . . . . . . . . . . . . . . . . . . . . . . .
57
2.1.2.
La Presentacin . . . . . . . . . . . . . . . . . . . . . . . . . . . .
58
2.1.3.
La Interaccin
. . . . . . . . . . . . . . . . . . . . . . . . . . . .
58
Ciclo de interaccin . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
59
2.2.1.
2.2.2.
. . . . . . . . . . . . . . . . . . . . . .
60
. . . . . . . . . . . . . . . . . . . . . . .
61
2.2.3.
2.2.4.
. . . . . . . . . . . . . . . . . . . .
69
74
2.3.1.
. . . . . . . . . . . . . . . . . . . . .
74
2.3.2.
Grcos vectoriales . . . . . . . . . . . . . . . . . . . . . . . . . .
75
2.3.3.
Representacin hbrida . . . . . . . . . . . . . . . . . . . . . . . .
75
2.4.
Paletas de colores . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
75
2.5.
76
. . . . . . . . . . . . . . . . . . . . . . . . .
2.5.1.
RGB . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
76
2.5.2.
RGBA . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
77
2.5.3.
CMY(K)
77
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2.6.
. . . . . . . . . . . . . . . . . . . . . . . .
2.7.
Ejercicios
78
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
79
81
3.1.
Recordatorio bsico . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
81
3.2.
Simbologa . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
82
3.3.
3.4.
. . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . .
83
84
. . . . . . . . . .
90
3.5.
La simetra de la circunferencia . . . . . . . . . . . . . . . . . . . . . . .
94
3.6.
95
3.7.
95
3.7.1.
. . . . . . . . . . . . . . . . . . . . .
99
3.7.2.
101
3.8.
Relleno de rectngulos . . . . . . . . . . . . . . . . . . . . . . . . . . . .
102
3.9.
Relleno de circunferencias
. . . . . . . . . . . . . . . . . . . . . . . . . .
103
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
105
3.10. Ejercicios
12
67
109
4.1.
Notacin . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
109
4.2.
110
4.2.1.
112
Ejemplo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
ndice general
4.3.
4.4.
Transformacin de distancias
4.5.
4.6.
. . . . . . . . . . . . . . .
114
. . . . . . . . . . . . . . . . . . . . . . . .
115
. . . . . . . . .
115
. . . . . . . . . . . . . . . . . . . . . . . . . . .
116
4.5.1.
Campo Elctrico
4.5.2.
. . . . . . . . . . . . . .
118
4.5.3.
119
4.5.4.
Programa principal . . . . . . . . . . . . . . . . . . . . . . . . . .
4.5.5.
El
Ejercicios
Makefile .
SDL_gfxPrimitives
129
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
130
121
. . . . . . . . . . . . . . . . . . . . . . . . . . . . .
133
. . . . . . . . . . . . . . . . . . . . . .
133
5.1.1.
Traslacin o Desplazamiento . . . . . . . . . . . . . . . . . . . . .
133
5.1.2.
Escalamiento
134
5.1.3.
. . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Rotacin . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
136
5.2.
Representacin matricial . . . . . . . . . . . . . . . . . . . . . . . . . . .
137
5.3.
. . . . . . . . . . . . . . .
138
5.4.
Atencin a la eciencia . . . . . . . . . . . . . . . . . . . . . . . . . . . .
139
5.5.
139
5.6.
140
5.7.
Ejercicios
143
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
145
6.1.
Sistemas de referencia
. . . . . . . . . . . . . . . . . . . . . . . . . . . .
6.2.
6.3.
6.4.
Ejercicios
. . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
145
145
150
151
7.1.
Proyeccin Ortogonal . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
7.2.
Proyeccin en Perspectiva
. . . . . . . . . . . . . . . . . . . . . . . . . .
153
7.3.
Portal de Visin . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
153
7.4.
156
7.5.
. . . . . . . . . . . . . .
158
7.6.
Ejercicios
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
162
8. Interaccin
151
163
8.1.
Posicionamiento . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
163
8.2.
Seleccin . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
164
8.2.1.
164
8.2.2.
. . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . .
165
13
ndice general
8.3.
Transformacin . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
165
8.4.
Conclusin . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
166
9. Curvas Paramtricas
9.1.
9.2.
169
Curvas suaves . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
169
9.2.2.
Tipos de continuidad . . . . . . . . . . . . . . . . . . . . . . . . .
170
Continuidad Geomtrica . . . . . . . . . . . . . . . . . . . . . . .
170
Continuidad Paramtrica
170
Interpolacin
. . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . .
171
172
9.3.1.
172
9.3.2.
Descripcin geomtrica . . . . . . . . . . . . . . . . . . . . . . . .
172
9.3.3.
Descripcin matemtica
173
9.3.4.
9.3.5.
. . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . .
. . . . . . . . . . .
173
175
175
175
176
. . . . .
El caso bidimensional
. . . . . . . . . . . . . . . . . . . . . . . .
176
El caso tridimensional
. . . . . . . . . . . . . . . . . . . . . . . .
176
. . . . . . . . . . . . . .
177
. . . . . . . . . . . . . .
178
9.3.7.
Ejemplo de implementacin . . . . . . . . . . . . . . . . . . . . .
178
9.3.8.
Curvas de Bzier
194
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
210
9.4.1.
Descripcin geomtrica . . . . . . . . . . . . . . . . . . . . . . . .
210
9.4.2.
Descripcin matemtica
. . . . . . . . . . . . . . . . . . . . . . .
210
9.4.3.
Polinomios de Bernstein . . . . . . . . . . . . . . . . . . . . . . .
211
9.4.4.
9.4.5.
214
9.4.6.
Ejemplos de implementacin
. . . . . . . . . . . . . . . . . . . .
215
bezier1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
215
bezier2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
221
editorBezier.py
. . . . . . . . . . . . . . . . . . . . . . . . . . . .
239
9.5.
240
9.6.
Ejercicios
240
. . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
10.Supercies paramtricas
10.1. Representacin algebrica de Supercies paramtricas
14
167
Continuidad . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
9.3.6.
9.4.
. . . . . . . . . . . .
9.2.1.
9.2.3.
9.3.
167
211
243
. . . . . . . . . .
243
ndice general
10.2. Ejercicios
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
11.Mallas Poligonales
245
247
247
249
. . . . . . . . . . . . . . . . . . . . .
250
253
11.5. Ejercicios
256
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
257
257
. . . . . . . . . . . . . . . . . . . . . . . .
262
. . . . . . . . . . . . . . . . . . . . . . . . . .
263
263
12.4.1. Denicin . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
263
12.4.2. Implementacin . . . . . . . . . . . . . . . . . . . . . . . . . . . .
271
. . . . . . . . . . . . . . . . . . . . . . . . . . .
272
12.5.1. Denicin . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
272
12.5.2. Implementacin . . . . . . . . . . . . . . . . . . . . . . . . . . . .
272
12.6. Ejercicios
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
275
277
279
283
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
283
284
287
. . . . . . . . . . . . . . . . . . . . . . . . . . . . .
III. Apndices
289
291
B. Referencias y manuales
297
297
297
B.1.2. Artculos
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
297
298
15
ndice general
16
B.3. Java Me . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
298
298
ndice de guras
1.1.
Display de 7 segmentos . . . . . . . . . . . . . . . . . . . . . . . . . . . .
55
2.1.
77
2.2.
2.3.
2.4.
3.1.
3.2.
. . . . . .
85
3.3.
. . . . . .
85
3.4.
92
3.5.
94
3.6.
96
3.7.
101
3.8.
Relleno de circunferencias
. . . . . . . . . . . . . . . . . . . . . . . . . .
104
3.9.
106
4.1.
110
4.2.
111
4.3.
. . . . . . . . . . . . . . . . . . . . . . . .
112
4.4.
Situacin de ejemplo . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
113
4.5.
114
4.6.
131
5.1.
. . . . . . . . . . . . . . . . . . . . . . . .
134
5.2.
135
5.3.
. . . . . . . . . . . . . . . . . . . .
135
5.4.
. . . . . . . . . . . . . . . . . . . . . . . . .
136
5.5.
137
5.6.
141
5.7.
141
5.8.
. . . . . . . . . . . . . . . . .
144
6.1.
146
. . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . .
. . .
78
79
80
82
17
ndice de guras
6.2.
6.3.
7.1.
152
7.2.
. . . . . . . . . . . . . . . . . . .
154
7.3.
. . . . . . . . . . . . . . . . . . .
158
7.4.
. . . . . . . . . . . . . . . . . .
159
9.1.
168
9.2.
169
9.3.
Interpolacin
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
171
9.4.
212
9.5.
213
y,
. . . . . . . . . . . . . . . . . .
. . . . .
146
147
. . . . . . . . . . . . . . . . . . . . . . .
244
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
244
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
245
248
248
248
11.4. Diagrama de clases de una malla poligonal en representacin de apuntadores a una lista de vrtices . . . . . . . . . . . . . . . . . . . . . . . . .
249
250
11.6. Diagrama de clases de una malla poligonal en representacin de apuntadores a una lista de aristas . . . . . . . . . . . . . . . . . . . . . . . . . .
251
251
252
254
transformaciones3D.jar
perspectiva3D.jar
. . . . . . . . . . . . .
255
12.1. Fractal natural: Brassica oleracea, un Romanescu fresco, cortesa del programa Botany Photo of the Day de http://www.ubcbotanicalgarden.org/. 258
12.2. Las ramas de los rboles siguen leyes fractales de distribuin volumtrica. 258
12.3. Las hojas de casi todos los helechos tienen la caracterstica de la autosimilitud nita. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
12.4. Helecho fractal
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
12.5. Espiral de satlites con islas de Julia, cortesa del Dr. Wolfgang Beyer
18
259
259
260
ndice de guras
12.6. Acercamiento del conjunto de Mandelbrot realzado por el autor de este
libro con el programa XaoS. . . . . . . . . . . . . . . . . . . . . . . . . .
260
mandelbrot.out
261
. . . . . . . . . . . . . . . . . . . . . . . . .
262
264
12.10.Carpeta de Sierpiski . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
265
12.11.Pirmide de Sierpiski . . . . . . . . . . . . . . . . . . . . . . . . . . . .
julia.out . . . . .
12.13.Segunda imgen del programa julia.out
12.14.Tercera imgen del programa julia.out .
12.15.Cuarta imgen del programa julia.out .
12.12.Imgen del programa
266
. . . . . . . . . . . . . . . . .
267
. . . . . . . . . . . . . . . . .
268
. . . . . . . . . . . . . . . . .
269
. . . . . . . . . . . . . . . . .
270
mandelbrot.out
273
12.17.Conjunto Mandelbrot con suavizacin de color interna y externa, generado con la aplicacin XaoS
12.18.Fractal de ejercicio
. . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
274
276
. . . . . . . . . . . . . . . . . . . . . . . . . . .
276
283
284
. . . . . . . . . . . . . . . . . . .
285
. . . . . . . . . . . . . . . . . . . . .
286
. . . . . . . . . . . . . . .
287
291
19
ndice de guras
20
Parte I
21
1.1.
$ sdl-config --version
Si devuelve algo como:
1.2.12
23
sdl-gfx
sdl-image
desde archivo (la biblioteca base es muy limitada en este aspecto, porque slo
puede abrir archivos
*.bmp).
Ver captulo 3
http://es.wikipedia.org/wiki/Antialiasing
http://en.wikipedia.org/wiki/Anti-aliasing
24
# yast --install
Hay que esperar a que se descargue y actualize la informacin de los repositorios en
lnea y entonces hay que buscar en la interfaz del YaST / YaST2 los paquetes del tipo
libSDL*-devel
e instalarlos.
Tambin se pueden instalar los paquetes desde la lnea de comandos. Para hacerlo, se
zypper:
# zypper install libSDL*-devel
utiliza el comando
Si no se desean instalar todos los paquetes de desarrollo, se pueden consultar todos los
paquetes que contengan el texto libSDL con el comando:
25
1.2.
gcc
1.3.
26
Hola Mundo de
27
1
2
3
4
5
6
7
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
28
27
28
if ( SDL_WasInit ( SDL_INIT_VIDEO ) )
printf ( " El video est encendido \ n " ) ;
else
printf ( " El video est apagado \ n " ) ;
29
30
31
32
33
if ( SDL_WasInit ( SDL_INIT_CDROM ) )
printf ( " El cdrom est encendido \ n " ) ;
else
printf ( " El cdrom est apagado \ n " ) ;
34
35
36
37
38
if ( SDL_WasInit ( SDL_INIT_AUDIO ) )
printf ( " El audio est encendido \ n " ) ;
else
printf ( " El audio est apagado \ n " ) ;
39
40
41
42
43
if ( SDL_WasInit ( SDL_INIT_JOYSTICK ) )
printf ( " El joystick est encendido \ n " ) ;
else
printf ( " El joystick est apagado \ n " ) ;
44
45
46
47
48
49
50
51
SDL_SWSURFACE
SDL_HWSURFACE
SDL_DOUBLEBUF
SDL_FULLSCREEN
SDL_OPENGL
SDL_RESIZABLE
SDL_NOFRAME
1
2
3
4
5
29
# define ALTO
400
11
12
13
14
15
16
17
/* Modos disponibles :
* SDL_SWSURFACE usa la memoria de sistema
* SDL_HWSURFACE usa la memoria de video
* SDL_DOUBLEBUF activa doble buffer en la memoria de video
* SDL_FULLSCREEN
* SDL_OPENGL
* SDL_RESIZABLE
* SDL_NOFRAME
* */
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
SDL_SWSURFACE ) ;
SDL_SWSURFACE |
34
35
36
37
38
39
40
41
42
43
44
45
SDL_SWSURFACE |
SDL_SWSURFACE |
SDL_SWSURFACE |
if ( pantalla == NULL ) {
printf ( " Error al inicializar el modo de video : ' %s '\ n " ,
SDL_GetError () ) ;
exit (1) ;
46
47
48
30
49
50
printf ( " Tamao de la pantalla : %dx %d \ n " , pantalla - >w , pantalla - > h ) ;
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
return 0;
31
case SDL_BUTTON_WHEELUP :
return nombreBotones [3];
case SDL_BUTTON_WHEELDOWN :
return nombreBotones [4];
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
while ( corriendo ) {
while ( SDL_PollEvent (& evento ) ) {
switch ( evento . type ) {
/*
Consultar el archivo :
/ usr / include / SDL / SDL_mouse . h
All se encuentra la declaracin de los botones
en forma de constantes
*/
case SDL_MOUSEBUTTONDOWN :
printf ( " Botn de ratn ' %s ' pulsado en ( %d, %d) \ n " ,
nombreBoton ( evento . button . button ) , evento . button .
x , evento . button . y ) ;
break ;
44
45
46
47
48
49
50
51
52
53
54
55
56
57
case SDL_MOUSEBUTTONUP :
printf ( " Botn de ratn ' %s ' liberado en ( %d, %d ) \ n " ,
nombreBoton ( evento . button . button ) , evento . button .
x , evento . button . y ) ;
break ;
58
59
60
61
62
case SDL_MOUSEMOTION :
63
32
64
65
66
67
68
69
70
71
72
73
74
75
76
case SDL_QUIT :
corriendo = 0;
break ;
return 0;
33
}
/*
33
34
35
36
37
38
39
40
41
42
43
44
45
46
Consultar el archivo :
/ usr / include / SDL / SDL_keysym . h
All se encuentra la declaracin de las teclas
en forma de constantes
*/
void mostrarTecla ( SDL_KeyboardEvent * tecla ) {
printf ( " Cdigo : %d , Nombre : %s \ n " , tecla - > keysym . sym ,
SDL_GetKeyName ( tecla - > keysym . sym ) ) ;
}
int main ( void ) {
SDL_Surface * pantalla = NULL ;
SDL_Event evento ;
int corriendo = 1;
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
while ( corriendo ) {
while ( SDL_PollEvent (& evento ) ) {
switch ( evento . type ) {
case SDL_KEYDOWN :
case SDL_KEYUP :
mostrarEstado (& evento . key ) ;
mostrarModificadores (& evento . key ) ;
mostrarTecla (& evento . key );
break ;
64
65
66
67
68
69
70
71
72
73
74
75
76
77
34
case SDL_QUIT :
corriendo = 0;
break ;
79
80
81
82
return 0;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
case SDL_QUIT :
corriendo = 0;
break ;
return 0;
1
2
3
4
5
6
7
8
9
10
Makefile:
# c01 / Makefile
LDFLAGS = $ ( shell sdl - config -- cflags )
LDLIBS = $ ( shell sdl - config -- libs )
CC = gcc
# Existiendo este archivo en el directorio ,
# se pueden compilar archivos *. c que usen SDL
# con slo ejecutar :
# '$ make < ejecutable > '
# ( claro que tiene que existir un archivo '< ejecutable >. c ')
11
36
make
de los sistemas
basados en Unix. De tal manera que slo haya que ejecutar la siguiente instruccin para
compilar un programa fuente:
$ make ejemplo-01
Con esta instruccin y el archivo mencionado, se buscar el archivo
compilar en el archivo
ejemplo-01.
ejemplo-01.c
y se
make
1
2
3
4
5
1
2
3
4
5
6
7
1
2
3
37
/*
* Enciende el pixel (x , y ) con el color dado .
*
* SDL no contiene de forma nativa una funcin para
* encender pixeles , a diferencia de otras bibliotecas grficas .
* Esto en s mismo es un tema de discucin , pero tpicamente
* el cdigo de esta funcin aplica en SDL .
*/
void ponerPixel ( SDL_Surface *s , int x , int y , Uint32 color ) ;
/*
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
if (( x > surface - > w ) ||( y > surface - > h ) ||( x <0) ||( y <0) ) return ;
22
23
switch ( bpp ) {
case 1:
* p = color ;
break ;
24
25
26
27
28
case 2:
*( Uint16 *) p = color ;
29
30
38
31
32
case 3:
if ( SDL_BYTEORDER == SDL_BIG_ENDIAN ) {
p [0] = ( color >> 16) & 0 xff ;
p [1] = ( color >> 8) & 0 xff ;
p [2] = color & 0 xff ;
}
else {
p [0] = color & 0 xff ;
p [1] = ( color >> 8) & 0 xff ;
p [2] = ( color >> 16) & 0 xff ;
}
break ;
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
case 4:
*( Uint32 *) p = color ;
break ;
}
Listing 1.12: Cdigo principal del ejemplo
39
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
while ( corriendo ) {
while ( SDL_PollEvent (& evento ) ) {
switch ( evento . type ) {
case SDL_VIDEORESIZE : {
ANCHO = evento . resize . w ;
ALTO = evento . resize . h ;
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
40
74
75
76
77
78
79
80
81
82
83
84
85
}
break ;
86
87
88
89
90
91
92
93
94
95
96
97
case SDL_QUIT :
corriendo = 0;
break ;
return 0;
Finalmente, para poder compilar fcilmente todo este cdigo, requerimos de un archivo
Makefile
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
como el siguiente:
Listing 1.13: Archivo Makele para varios fuentes usando SDL
20
41
La funcin
1.4.
Desafortunadamente, la biblioteca base de SDL no incluye funciones para encender pixeles ni para dibujar lneas, rectngulos, crculos, polgonos, etc (es decir, primitivas gr-
cas ). Esto es debido a que sus desarrolladores pretenden que se mantenga como una
biblioteca multimedia de bajo nivel para que sea ampliada al gusto (y habilidad) del
programador que la use, dando la libertad/responsabilidad de construirlas uno mismo.
Pero por cuestiones prcticas, en este libro vamos a preferir dibujar primitivas grcas con la ayuda de la biblioteca gfxPrimitives del paquete
sdl-gfx
mencionada en la
1
2
3
4
5
6
7
8
9
10
11
La denicin de Primitiva Grca aparece en el captulo 3 en la pgina 81, pero no es otra cosa que
lneas rectas, crculos, rectngulos, polgonos, etc.
42
/*
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
*/
Uint32 color ( Uint8 r , Uint8 g , Uint8 b ) {
return
r << 24 |
g << 16 |
b << 8 |
255;
// este valor es la opacidad del color
// y debe ser mxima para que sea slido
}
/*
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
stringColor ( pantalla , ANCHO /2 , ALTO /2 , " HOLA " , color (255 ,0 ,255) ) ;
stringRGBA ( pantalla , 3* ANCHO /4 , ALTO /4 , " BIENVENIDOS A SDL_gfx " ,
255 ,255 ,255 ,255) ;
43
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
// AS NO
case SDL_QUIT :
corriendo = 0;
break ;
return 0;
44
Listing 1.15: Makele necesario para usar gfxPrimitives
. PHONY : limpiar
. PHONY : limpiartodo
. PHONY : all
PROG = gfx
OBJ = primitivas . o
all : $ ( PROG ) limpiar
$ ( PROG ) : $( OBJ )
gcc -o $ ( PROG ) $ ( OBJ ) $ ( LINEA )
limpiar :
22
23
24
25
26
= / bin / rm -f
$ ( RM ) *~ $ ( OBJ )
limpiartodo :
make limpiar
$ ( RM ) $ ( PROG )
1.5.
Instalacin de PyGAME
# yast -i python-pygame
# yast2 -i python-pygame
y ejemplos de PyGAME.
45
in situ.
1.6.
Pygame tiene un diseo y un estilo muy parecido al tpico de los mdulos de Python. Por
lo cual, hay marcadas diferencias en la forma de programar con SDL en C y con PyGAME
en Python. Sin embargo, la nomenclatura de las funciones, constantes y objetos es muy
parecida o igual a la de SDL en C.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
Hola Mundo de
# coding : utf -8
' ' ' c01 / ejemplo -01. py
Hola Mundo en pygame
'''
import pygame
# Inicializar el Sistema de pygame
pygame . init ()
tam = ancho , alto = 323 , 400
# Abrir la ventana para grficos
pantalla = pygame . display . set_mode ( tam )
# Cambiar el ttulo de la ventana
pygame . display . set_caption ( " Hola Mundo ! " )
# Cargar una imagen :
4
46
# coding : utf -8
' ' ' c01 / ejemplo -02. py
Inicializacin de subsistemas en pygame .
Los subsistemas / mdulos disponibles son :
. - pygame . cdrom
. - pygame . display
. - pygame . font
. - pygame . joystick
. - pygame . mixer
. - pygame . scap
'''
import pygame
def mensaje ( nombre , valor_de_verdad ) :
' ' ' Esta funcin simplemente sirve para no escribir la misma cadena
varias veces .
La combinacin 'and - or ' en Python funciona como el operador ternario
de C
47
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
' ' ' La funcin ' init ' inicializa todos los subsistemas
disponibles y devuelve el nmero de subsistemas
que pudieron ser inicializados y los que no ' ' '
funcionando , no_funcionando = pygame . init ()
print ( " El nmero de submdulos de pygame funcionando es : " + str (
funcionando ) )
print ( " El nmero de submdulos de pygame que no estn funcionando es : " +
str ( no_funcionando ) )
mensaje ( " palanca de mandos " , pygame . joystick . get_init () )
mensaje ( " cdrom " , pygame . cdrom . get_init () )
# Apagar el mdulo de fuentes y de video :
pygame . font . quit ()
mensaje ( " fuentes " , pygame . font . get_init () )
pygame . display . quit ()
mensaje ( " video " , pygame . display . get_init () )
# Encender el mdulo de fuentes :
pygame . font . init ()
mensaje ( " fuentes " , pygame . font . get_init () )
print ( " Apagando pygame ... " )
' ' ' Esta funcin apaga todos los
pero es llamada automticamente
el programa termina , por lo que
en el caso que un programa deba
sin pygame .
'''
pygame . quit ()
mdulos ,
cuando
slo es necesario
seguir corriendo
pygame.FULLSCREEN
pantalla completa).
48
FULLSCREEN (en
pygame.RESIZABLE
pygame.NOFRAME
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
1
# coding : utf -8
' ' ' c01 / ejemplo -03. py
Modos de video en Pygame
'''
import pygame
def mostrarImagen () :
# Copiar la imagen al buffer temporal en ' pantalla ':
pantalla . blit ( imagen , (0 ,0) )
# Volcar el buffer a la memoria de video :
pygame . display . flip ()
# Espera un tiempo de 10 segundos
pygame . time . delay (10000)
# Apaga manualmente el sistema de video
pygame . display . quit ()
print ( " Tamao de la pantalla : {0} x {1} " . format ( pantalla . get_width ,
pantalla . get_height ) )
pygame . init ()
tam = ancho , alto = 400 , 400
titulo = " Modos de video ! - "
imagen = pygame . image . load ( " logo_uca . bmp " )
raw_input ( " Ventana normal de tamao fijo : " + str ( tam ) )
pantalla = pygame . display . set_mode ( tam )
pygame . display . set_caption ( titulo + " Ventana normal de tamao fijo : " +
str ( tam ) )
mostrarImagen ()
raw_input ( " Ventana normal de tamao variable " )
pantalla = pygame . display . set_mode ( tam , pygame . RESIZABLE )
pygame . display . set_caption ( titulo + " Ventana normal de tamao variable " )
mostrarImagen ()
raw_input ( " Ventana normal de tamao fijo maximizada ( tamao igual a
pantalla completa ) " )
pantalla = pygame . display . set_mode ()
mostrarImagen ()
41
49
raw_input ( " Ventana sin borde de tamao fijo : " + str ( tam ) )
pantalla = pygame . display . set_mode ( tam , pygame . NOFRAME )
mostrarImagen ()
raw_input ( " Pantalla completa con resolucin fija : " + str ( tam ) )
pantalla = pygame . display . set_mode ( tam , pygame . FULLSCREEN )
mostrarImagen ()
raw_input ( " Pantalla completa con resolucin mxima " )
pantalla = pygame . display . set_mode ((0 ,0) , pygame . FULLSCREEN )
mostrarImagen ()
# coding : utf -8
' ' ' c01 / ejemplo -04. py
Eventos del ratn en pygame
'''
import pygame
pygame . init ()
tam = ancho , alto = 400 , 400
titulo = " Eventos del ratn "
botones = [ " izquierdo " , " medio " , " derecho " , " rueda arriba " , " rueda abajo "
]
pantalla = pygame . display . set_mode ( tam )
pygame . display . set_caption ( titulo )
corriendo = True
while corriendo :
for evento in pygame . event . get () :
if evento . type == pygame . MOUSEBUTTONDOWN :
print ( " Botn de ratn '{0} ' presionado en {1} " . format (\
botones [ evento . button -1] , evento . pos ) )
elif evento . type == pygame . MOUSEBUTTONUP :
print ( " Botn de ratn '{0} ' liberado en {1} " . format (\
botones [ evento . button -1] , evento . pos ) )
elif evento . type == pygame . MOUSEMOTION :
print ( " El ratn se movi {0} pixeles hasta {1} " . format (\
evento . rel , evento . pos ) )
print ( " Los botones presionados son : {0}. " . format ( evento .
buttons ) )
print ( " \ tBotn izq : {0}\ n \ tBotn cen : {1}\ n \ tBotn der : {2} " .
format (\
50
31
32
33
34
35
36
# coding : utf -8
' ' ' c01 / ejemplo -05. py
Eventos del teclado en pygame
'''
import pygame
def devolverModificadores ( m ) :
c = ' << '
c += m & pygame . KMOD_NUM and " NUMLOCK " or " "
c += m & pygame . KMOD_CAPS and " CAPSLOCK " or " "
c += m & pygame . KMOD_MODE and " MODE " or " "
c += m & pygame . KMOD_LCTRL and " LCTRL " or " "
c += m & pygame . KMOD_RCTRL and " RCTRL " or " "
c += m & pygame . KMOD_LSHIFT and " LSHIFT " or " "
c += m & pygame . KMOD_RSHIFT and " RSHIFT " or " "
c += m & pygame . KMOD_LALT and " LALT " or " "
c += m & pygame . KMOD_RALT and " RALT " or " "
c += m & pygame . KMOD_LMETA and " LMETA " or " "
c += m & pygame . KMOD_RMETA and " RMETA " or " "
c += ' >> '
return c
def devolverTecla ( tecla ) :
return " Cdigo {0} , nombre : '{1} ' " . format ( tecla , pygame . key . name (
tecla ) )
pygame . init ()
tam = ancho , alto = 400 , 400
titulo = " Eventos del teclado "
pantalla = pygame . display . set_mode ( tam )
pygame . display . set_caption ( titulo )
corriendo = True
while corriendo :
51
37
38
39
40
41
42
43
44
45
46
47
48
49
50
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# coding : utf -8
' ' ' c01 / ejemplo -06. py
Redimensionamiento de la ventana en pygame
'''
import pygame
pygame . init ()
tam = ancho , alto = 400 , 400
titulo = " Redimensionamiento de la ventana "
pantalla = pygame . display . set_mode ( tam , pygame . RESIZABLE )
pygame . display . set_caption ( titulo )
corriendo = True
while corriendo :
for evento in pygame . event . get () :
if evento . type == pygame . VIDEORESIZE :
pantalla = pygame . display . set_mode ( evento . size , pygame .
RESIZABLE )
print ( " La ventana se ha redimensionado de {0} pixeles a {1} "
.\
format ( tam , evento . size ) )
tam = evento . size
# Aqu habra que redibujar lo que se estaba mostrando
# ya que ' pantalla ' aparece borrada .
26
27
52
corriendo = False
1.7.
En
pygame,
pygame.display, que
mdulo es pygame.draw.
contiene las
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# coding : utf -8
' ' ' c01 / ejemplo -08/ primitivas . py
Primitivas grficas
'''
import pygame , random
ancho , alto = 400 , 400
titulo = " Primitivas grficas "
rojo , verde , blanco , negro = (255 ,0 ,0) , (0 ,255 ,0) , (255 ,255 ,255) , (0 ,0 ,0)
def dibujar () :
# Borrar la pantalla
pantalla . fill ( negro )
# Dibujar un rectngulo rojo y otro verde
pygame . draw . rect ( pantalla , rojo , pygame . Rect (0 ,0 , ancho /2 , alto /2) )
pygame . draw . rect ( pantalla , verde , pygame . Rect ( ancho /2 , alto /2 , ancho
/2 , alto /2) )
# Lineas ( notar la diferencia visual entre ambas ) :
pygame . draw . line ( pantalla , blanco , (0 ,0) , ( ancho , alto ) )
pygame . draw . aaline ( pantalla , blanco , (0 , alto ) , ( ancho , 0) ) ;
# Lnea horizontal amarilla
pygame . draw . line ( pantalla , (255 , 255 , 0) , (0 , alto /2) , ( ancho , alto
/2) )
# Inicializar la fuente TrueType por defecto
fuente = pygame . font . Font ( None , alto /20)
' ' ' Las fuentes de sistema pueden encontrarse tpicamente en
/ usr / share / fonts /...
y dependen de cada sistema / distribucin . ' ''
# Crear el texto
saludo
= fuente . render ( " HOLA " , True , (255 ,0 ,255) )
53
35
36
# Copiar el texto
pantalla . blit ( saludo , ( ancho /2 , alto /2) )
pantalla . blit ( bienvenida , (3* ancho /4 , alto /4) )
37
38
39
40
# Redibujar el buffer
pygame . display . flip ()
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
pygame . init ()
pantalla = pygame . display . set_mode (( ancho , alto ) , pygame . RESIZABLE )
pygame . display . set_caption ( titulo )
corriendo = True
# Hacer primer dibujo
dibujar ()
while corriendo :
for evento in pygame . event . get () :
if evento . type == pygame . VIDEORESIZE :
pantalla = pygame . display . set_mode ( evento . size , pygame .
RESIZABLE )
print ( " La ventana se ha redimensionado de {0} pixeles a {1} "
.\
format (( ancho , alto ) , evento . size ) )
ancho , alto = evento . size
dibujar ()
61
62
63
1.8.
Ejercicios
1. Construya una aplicacin grca que muestre en pantalla un display de 7 segmentos segn las teclas numricas que presione el usuario. Por ejemplo, si el usuario
presiona el nmero 2 (ya sea del teclado numrico o del teclado normal) debera
ver algo parecido a lo que aparece en la gura 1.1.
54
1.8 Ejercicios
55
56
2.1.1. El Modelado
Cmo se modelan las cosas en la computadora?
Tiene que describirse, de algn modo, cmo es aquello que queremos representar en la
computadora y hasta qu nivel de detalle lo necesitamos representar. Esta descripcin,
es el modelo.
Obviamente, la forma de modelar las cosas, est supeditada al hecho que debe facilitar el
proceso de dibujado de tal modelo y de su respectiva manipulacin por parte del usuario
(si es que esto ltimo es parte del propsito de la aplicacin).
Por ejemplo, pinsese en cmo modelar una esfera. . .
(c) por las coordenadas de la mayor cantidad posible de puntos que la conforman (para
formar una nube densa de puntos),
(d) etc.
57
2.1.2. La Presentacin
Cmo se dibuja el modelo?
Dado el modelo, hay que describir las tcnicas necesarias (o al menos tenerlas muy claras)
para poder proyectar o representar el modelo en la pantalla de la computadora (o en
algn otro tipo de dispositivo de salida grca). Usualmente esa proyeccin es hacia dos
dimensiones (y eso ser as, al menos, mientras no tengamos monitores tridimensionales).
Se espera que una buena presentacin describa el modelo lo sucientemente bien como
para que el usuario lo comprenda y pueda manipularlo (o al menos imaginrselo) sin
necesidad de entender los mecanismos internos de representacin de dicho modelo.
Hay que tener en cuenta que la rapidez de los algoritmos empleados para este proceso
debe ser, en general, lo ms alta posible para que la aplicacin pueda presentar una
interaccin con rapidez humana. Es decir, que el proceso de dibujo del modelo no debe
ser muy lento. Tampoco debe ser demasiado rpido, pero eso es un problema menor, la
mayora de las veces.
2.1.3. La Interaccin
Cmo interacta el usuario con el modelo?
El modelo no necesariamente tiene una estructura idntica a lo que el usuario ve por
medio de la presentacin descrita en la subseccin anterior. Por ello tambin hay que
denir la forma en que el usuario interactuar con el modelo (rotar un objeto tridimensional, desplazarlo o cambiarle el tamao).
Dependiendo de la naturaleza de la aplicacin, el usuario nal, no necesariamente debe
comprender cmo es almacenado y manipulado el modelo internamente, sino que debera
poder manipularlo nicamente a travs de lo que ve en la pantalla.
Sobre este tema se hablar ms en el captulo 8 en la pgina 163.
58
2.2.
Ciclo de interaccin
tiempo . Con un ciclo de juego, no hay forma de garantizar que todas las acciones del
usuario sern percibidas y procesadas por la aplicacin, pero el procesamiento tiende
menos a retrasarse con respecto a las acciones del usuario.
El ciclo de eventos itera a travs de la secuencia de eventos generados, pudiendo estos
ocurrir en diferentes lapsos de tiempo, mientras que el ciclo de juego itera tan rpido
como la computadora es capaz, o itera aproximadamente cada cierto tiempo, denido
por el programador.
De manera esquemtica, un ciclo de eventos tiene la siguiente estructura:
Listing 2.1: Ciclo de ventos
1
2
3
4
5
6
7
8
9
10
hayQueEjecutar = Verdadero
.
.
.
MIENTRAS ( hayQueEjecutar ) {
MIENTRAS ( hayEventos () ) {
evento = siguienteEvento ()
procesarEvento ( evento ) ;
}
}
1
2
3
4
hayQueEjecutar = Verdadero
.
.
.
1
Hace mucho tiempo para una aplicacin grca podra signicar un par de segundos.
59
MIENTRAS ( hayQueEjecutar ) {
t = ahora () ;
estado = leerEstadoDeDispositivosRelevantes () ;
actualizarObjetosYPosiciones ( estado );
redibujarObjetosVisibles () ;
8
9
10
11
12
13
14
15
16
dt = ahora () - t ;
SI ( dt < TiempoPorCiclo ) {
hacerPausa ( TiempoPorCiclo - dt );
}
evento
1
2
3
4
5
6
7
8
9
10
60
SDL_Event evento ;
int corriendo = 1;
.
.
.
while ( corriendo ) {
while ( SDL_PollEvent (& evento ) ) {
switch ( evento . type ) {
case SDL_MOUSEBUTTONDOWN :
SDL_PollEvent
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
break ;
case ...:
.
.
.
case SDL_QUIT :
corriendo = 0;
break ;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
SDL_WaitEvent
SDL_Event evento ;
.
.
.
while ( SDL_WaitEvent (& evento ) ) {
switch ( evento . type ) {
case SDL_MOUSEBUTTONDOWN :
.
.
.
break ;
case ...:
.
.
.
case SDL_QUIT :
break ;
}
}
Uint32 SDL_GetTicks(void);
cializacin de SDL. Esta funcin es til para el control del tiempo que dura cada
61
numteclas si no es NULL.
SDLK_*. Cada casilla
de la forma
est presionada o un 0 que indica que no est presionada. Para poder usar esta
funcin, es necesario llamar primero a la funcin
void SDL_PumpEvents(void);
para actualizar el estado del arreglo. Hay que tener en cuenta que las funciones
SDL_PollEvent
SDL_WaitEvent
llaman internamente a
SDL_PumpEvents,
por lo
SDLMod SDL_GetModState(void);
KMOD_*
a nivel de bits.
SDL_BUTTON_(L/M/R)MASK combinadas con disyuncin a nivel de bits. Si las direcciones x y y no son NULL, se almacena all la coordenada del ratn en el momento
de la llamada. Al igual que SDL_GetKeyState, esta funcin requiere una llamada
previa a SDL_PumpEvents, que puede ser ejecutada a travs de SDL_PollEvent o
SDL_WaitEvent.
Uint8 SDL_GetRelativeMouseState(int *dx, int *dy); Devuelve el estado de
los botones del ratn igual que la funcin anterior, pero almacena en dx y dy (si
no son NULL) los cambios de posicin del cursor desde la ltima llamada a esta
misma funcin o desde la inicializacin de SDL.
La plantilla para un ciclo de eventos con SDL podra ser:
1
2
3
4
5
6
7
8
9
# define MARCOS_POR_SEGUNDO 20
{
SDL_Event evento ;
Uint8 * teclas ;
int corriendo = 1;
Uint32 t , dt ;
Uint32 TiempoCiclo = ( int ) (1000.0 / MARCOS_POR_SEGUNDO ) ;
.
.
62
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
redibujarObjetosVisibles () ;
33
34
35
36
37
38
39
dt = SDL_GetTicks () - t ;
if ( dt < TiempoCiclo )
SDL_Delay ( TiempoCiclo - dt ) ;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
/* *
* Programa de ejemplo para ciclos de juego
* */
# include < SDL / SDL .h >
# include < stdio .h >
# include < stdlib .h >
# define ANCHO 640
# define ALTO 480
# define INCREMENTO_DESPLAZAMIENTO 10
# define INCREMENTO_DESPLAZAMIENTO_PELOTA 4
63
# define
# define
# define
# define
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
MARCOS_POR_SEGUNDO 25
FONDO " fondo - trabajar . bmp "
PELOTA " pelotita . bmp "
TITULO " Tenis ! - Partida %d "
46
Uint32 t , dt ;
Uint32 TiempoCiclo = ( int ) (1000.0 / MARCOS_POR_SEGUNDO ) ;
47
48
49
int corriendo = 1;
int marcador1 = 0 , marcador2 = 0;
int partida = 1;
char titulo [50];
50
51
52
53
54
/* Inicializacin */
{
srand ( time ( NULL ) ) ;
55
56
57
58
59
60
61
62
63
64
// Cargar el fondo :
imgFondo = SDL_LoadBMP ( FONDO ) ;
if ( imgFondo == NULL ) {
printf ( " Error al cargar el fondo : ' %s '\ n " , SDL_GetError () ) ;
exit (1) ;
}
// Cargar la Pelota :
imgPelota = SDL_LoadBMP ( PELOTA ) ;
if ( imgPelota == NULL ) {
printf ( " Error al cargar la pelota : ' %s '\ n " , SDL_GetError () ) ;
exit (1) ;
}
SDL_SetColorKey ( imgPelota , SDL_SRCCOLORKEY , SDL_MapRGB ( imgPelota
- > format ,255 ,255 ,255) ) ;
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
reiniciarPosiciones () ;
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
while ( corriendo ) {
t = SDL_GetTicks () ;
/* Actualizacin */
{
SDL_PollEvent (& evento ) ;
if ( evento . type == SDL_QUIT ) {
corriendo = 0;
break ;
}
// Movimiento de la pelota
65
112
113
114
// Rebotes laterales
if ( pelota . x < 0 || pelota . x + pelota . w > ANCHO )
velx *= -1;
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
// Rebotes verticales
if ( puntoEnRectangulo ( pelota . x + pelota . w /2 , pelota .y ,
& jugador1 ) ||
puntoEnRectangulo ( pelota . x + pelota . w /2 , pelota . y +
pelota .h , & jugador2 ) ) {
vely *= -1;
continue ;
}
134
135
136
137
138
139
140
141
142
143
if ( teclas [ SDLK_ESCAPE ]) {
corriendo =0;
break ;
}
144
145
146
147
148
if ( teclas [ SDLK_LEFT ]) {
jugador2 . x -= INCREMENTO_DESPLAZAMIENTO ;
if ( jugador2 . x < 0) jugador2 . x = 0;
}
149
150
151
152
153
if ( teclas [ SDLK_RIGHT ]) {
jugador2 . x += INCREMENTO_DESPLAZAMIENTO ;
if ( jugador2 . x + jugador2 . w > pantalla - > w )
jugador2 . x = pantalla - >w - jugador2 . w ;
}
154
155
156
157
158
159
66
160
161
162
163
164
165
166
167
168
169
170
171
/* Redibujar */
{
172
173
174
// Borra la pantalla
SDL_BlitSurface ( imgFondo , NULL , pantalla , NULL ) ;
// SDL_FillRect ( pantalla , NULL , color_fondo ) ;
175
176
177
178
179
180
181
182
// Dibujo de la bola
SDL_BlitSurface ( imgPelota , NULL , pantalla , & pelota );
183
184
185
186
187
188
189
190
191
192
193
194
196
198
/* Sincronizacin de tiempo */
dt = SDL_GetTicks () - t ;
if ( dt < TiempoCiclo ) SDL_Delay ( TiempoCiclo - dt ) ;
printf ( " \n < < < < < < < < < < < Marcador final : > > > > > > > > > > >\ nJugador 1: %d \
nJugador 2: %d \n \ n " , marcador1 , marcador2 ) ;
195
197
if ( teclas [ SDLK_d ]) {
jugador1 . x += INCREMENTO_DESPLAZAMIENTO ;
if ( jugador1 . x + jugador1 . w > pantalla - > w )
jugador1 . x = pantalla - >w - jugador1 .w ;
}
return 0;
Se juega con las teclas a y d para el jugador 1 y con los cursores izquierda y derecha
para el jugador 2. Cuando un jugador gana, se inicia una nueva partida.
67
pygame.NOEVENT
si no hay
pygame.event.wait()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
pygame.event.poll()
corriendo = True
.
.
.
while corriendo :
evento = pygame . event . poll ()
if evento == pygame . NOEVENT :
continue
if evento . type == pygame . MOUSEBUTTONDOWN :
.
.
.
elif evento . type == ...:
.
.
.
elif evento . type == pygame . QUIT :
corriendo = False
3
1
2
3
4
5
6
7
8
pygame.event.wait()
corriendo = True
.
.
.
while corriendo :
evento = pygame . event . wait ()
if evento . type == pygame . MOUSEBUTTONDOWN :
.
2
3
68
c02/ejemplo-raton-poll.py
c02/ejemplo-raton-wait.py
9
10
11
12
13
14
15
16
pygame.event.get().
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
pygame.event.get()
corriendo = True
.
.
.
while corriendo :
for evento in pygame . event . get () :
if evento . type == pygame . MOUSEBUTTONDOWN :
.
.
.
elif evento . type == ...:
.
.
.
elif evento . type == pygame . QUIT :
corriendo = False
break
pygame.time.get_ticks()
izacin de pygame.
69
el estado (presionado o no) de cada tecla del teclado. Se usan las constantes de
pygame.key.get_mods()
pygame.KMOD_*
combinadas
pygame.mouse.get_pressed()
el estado (presionado o no) de los tres botones del ratn. El primero siempre es
el botn izquierdo, el segundo el botn central y el tercero es el botn derecho.
Al igual que
pygame.mouse.get_pos()
(x,y)
1
2
3
4
5
6
7
8
9
MARCOS_POR_SEGUNDO = 20
t =0; dt =0
TiempoCiclo = int (1000.0 / MARCOS_POR_SEGUNDO ) ;
corriendo = True
.
.
.
while corriendo :
t = pygame . time . get_ticks ()
10
11
12
13
14
15
16
17
18
19
20
70
21
22
23
24
25
26
27
28
29
30
redibujarObjetosVisibles ()
31
32
33
34
35
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
X, Y = 0, 1
MARCOS_POR_SEGUNDO = 25
FONDO = " fondo - trabajar . bmp "
PELOTA = " pelotita . bmp "
TITULO = " Tenis ! - Partida {0} "
def reiniciarPosiciones () :
jugador1 . x = jugador2 . x = ANCHO /2 - jugador1 . w /2;
jugador1 . y = 25;
jugador2 . y = ALTO - 25 - jugador2 . h ;
pelota . x = ( ANCHO /2) - ( pelota . w /2) ;
pelota . y = ( ALTO /2) - ( pelota . h /2) ;
vel [ X ] = ( random . randint (0 ,1) and -1 or 1) *
INCREMENTO_DESPLAZAMIENTO_PELOTA
vel [ Y ] = ( random . randint (0 ,1) and -1 or 1) *
INCREMENTO_DESPLAZAMIENTO_PELOTA
71
# Inicializacin :
t =0; dt =0
TiempoCiclo = int (1000.0 / MARCOS_POR_SEGUNDO ) ;
marcador1 = 0; marcador2 = 0
partida = 1
corriendo = True
pygame . init ()
# Cargar el fondo :
imgFondo = pygame . image . load ( FONDO )
# Cargar la Pelota :
imgPelota = pygame . image . load ( PELOTA )
imgPelota . set_colorkey ((255 ,255 ,255) )
jugador1 = pygame . Rect ((0 ,0) , (40 ,10) )
jugador2 = pygame . Rect ((0 ,0) , (40 ,10) )
pelota = imgPelota . get_rect ()
vel = [0 ,0]
reiniciarPosiciones ()
pygame . display . set_icon ( imgPelota )
pantalla = pygame . display . set_mode (( ANCHO , ALTO ) )
pygame . display . set_caption ( TITULO . format ( partida ) )
color_fondo = (255 ,255 ,255)
color1 = (255 ,0 ,0)
color2 = (0 ,0 ,255)
while corriendo :
t = pygame . time . get_ticks ()
64
# Actualizacin : ######################
for evento in pygame . event . get () :
if evento . type == pygame . QUIT :
pygame . display . quit ()
corriendo = False
break
65
66
67
68
69
70
71
if not corriendo :
break
# Movimiento de la pelota
pelota . x += vel [ X ];
pelota . y += vel [ Y ];
72
73
74
75
76
77
72
# Rebotes laterales
if pelota . left < 0 or pelota . right > ANCHO :
vel [ X ] *= -1;
# Deteccin de choque vertical
if pelota . top < 0 or pelota . bottom > ALTO :
if pelota . top < 0:
print ( " Jugador 2 gana !\ n " )
marcador2 += 1
else :
print ( " Jugador 1 gana !\ n " )
marcador1 += 1
partida += 1
pygame . display . set_caption ( TITULO . format ( partida ) )
reiniciarPosiciones ()
continue
# Rebotes verticales
if jugador1 . collidepoint ( pelota . midtop ) or \
jugador2 . collidepoint ( pelota . midbottom ) :
vel [ Y ] *= -1
continue
# Movimiento de los jugadores
teclas = pygame . key . get_pressed ()
if teclas [ pygame . K_ESCAPE ]:
corriendo = False
break
if teclas [ pygame . K_LEFT ]:
jugador2 . x -= INCREMENTO_DESPLAZAMIENTO
if jugador2 . left < 0: jugador2 . left = 0;
if teclas [ pygame . K_RIGHT ]:
jugador2 . x += INCREMENTO_DESPLAZAMIENTO
if jugador2 . right > pantalla . get_width () :
jugador2 . x = pantalla . get_width () - jugador2 . w
if teclas [ pygame . K_a ]:
jugador1 . x -= INCREMENTO_DESPLAZAMIENTO
if jugador1 . x < 0: jugador1 . x = 0
if teclas [ pygame . K_d ]:
jugador1 . x += INCREMENTO_DESPLAZAMIENTO
if jugador1 . x + jugador1 . w > pantalla . get_width () :
jugador1 . x = pantalla . get_width () - jugador1 . w
125
126
127
# Redibujar : #############################
73
# Borra la pantalla
pantalla . blit ( imgFondo , (0 ,0) )
# pantalla . fill ( color_fondo )
129
130
131
132
133
134
135
136
# Dibujo de la bola
pantalla . blit ( imgPelota , pelota )
137
138
139
140
141
142
143
144
145
146
147
print ( " \n < << < < < < < < < < Marcador final : > > > > > > > > > > >\ nJugador 1: {0}\ nJugador
2: {1}\ n \ n " . format ( marcador1 , marcador2 ) )
Se juega con las teclas a y d para el jugador 1 y con los cursores izquierda y derecha
para el jugador 2. Cuando un jugador gana, se inicia una nueva partida.
2.3.
74
2.4.
Paletas de colores
00H
28 = 256
sea negro, el
01H
sea blanco,. . ., el
09H
sea azul, el
0AH
sea verde,
etc.
75
2.5.
2.5.1. RGB
[Red, Green, Blue]
Un color en este formato se suele especicar en la forma de un conjunto de tres bytes
continuos (24 bits), donde los primeros ocho bits, de derecha a izquierda, representan
la intensidad de luz azul. Los segundos ocho bits, de derecha a izquierda, la intensidad
de luz verde, y los ltimos ocho, de derecha a izquierda, la intensidad de luz roja. En la
gura 2.1 podemos ver el tpo diagrama de colores en el modelo RGB.
Este modelo representa un color mediante la mezcla por adicin de los tres colores
primarios de la luz, rojo, verde y azul. De tal manera que en una supercie negra, su
suma a nula intensidad, resulta en negro; y su suma a mxima intensidad, resulta en
blanco.
Eventualmente, y dependiendo de la arquitectura del procesador, el orden en que se
indican estas intensidades puede ser al revs de explicado arriba . Este es un detalle de
poca o nula importancia cuando que utilizan APIs de alto nivel.
4
5
es decir, la diferencia entre un color y otro, es menor que el umbral diferencial de la luz, en los
humanos.
Para mayor informacin, vanse los artculos:
//en.wikipedia.org/wiki/Endianness
76
http://es.wikipedia.org/wiki/Big-endian
http:
2.5.2. RGBA
[Red, Green, Blue, Alpha]
Este otro modo de especicacin de color, es similar al anterior, excepto que usa 32 bits.
Los ocho que se han agregado (normalmente al nal), representan la medida de opacidad/transparencia (en el caso de SDL,
00H
es transparencia total y
F FH
es opacidad
total, pero en otras bibliotecas grcas, es al revs). E igual que en el caso del RGB, su
representacin binaria vara dependiendo del hardware.
2.5.3. CMY(K)
[Cyan, Magenta, Yellow, Black (o Key)]
Este modelo representa un color mediante la mezcla sustractiva de los colores cyan,
magente y amarillo. De tal manera que impresos sobre un papel blanco, su mezcla a
mnima intensidad no absorbe nada y la luz se reeja completamente blanca, pero si se
mezclan a mxima intensidad, absorben la luz completamente, por lo que no vemos luz
reejada (eso es el color negro).
Esta es la forma en que se especican los colores para los dispositivos de impresin con
algn tipo de tinta. Y la inclusin de tinta de color negro directamente, se debe a razones
tcnicas especcas .
77
2.6.
color, es la porcin del espacio de color de la luz visible que se puede representar con ese
dispositivo o proceso.
Es obvio que existen limitaciones fsicas en todos los dispositivos y procesos, que les
impiden mostrar la gama completa del espacio de color de la luz visible (que es bastante
grande). Por eso se habla de una porcin del espacio de color de la luz visible.
Tambin se podra denir como el lugar geomtrico de los puntos del plano matiz-
78
2.7 Ejercicios
En la gura 2.4 se presentan (sin pretender ofrecer una gran precisin) las diferencias
de los gamuts de RGB y de CMYK.
El gamut del modelo RGB es el tringulo y la otra gura es el gamut del modelo CMYK.
2.7.
Ejercicios
clic derecho+ctrl,
clic izquierdo+shift,
etc.
79
80
3.1.
Recordatorio bsico
y = mx + B
(3.1)
y y0 = m(x x0 )
(3.2)
y y0 =
y1 y0
x1 x0
(x x0 )
(3.3)
ax + by + c = 0
(3.4)
(x x0 )2 + (y y0 )2 = R2
(3.5)
81
3.2.
Simbologa
Antes que nada, consideremos que los dispositivos principales sobre los que vamos a
trabajar, son monitores cuyas pantallas estn compuestas por pixeles. Los pixeles estn
dispuestos en forma de una matriz rectangular de puntos casi perfectamente cuadrados
y cada uno puede brillar de un color independiente de los dems.
La gura 3.1 es la imgen que se usar para esquematizar en este captulo cmo funcionan
los algoritmos presentados
La cuadrcula de la gura 3.1 representa un grupo de nueve pixeles de una computadora. Las lneas gruesas de guiones representan las fronteras entre dichos pixeles y las
intersecciones de las lneas continuas delgadas representan los centros geomtricos de
ellos.
Por simplicidad, vamos a suponer, en las deducciones, que la numeracin de los pixeles
se extiende desde la esquina inferior izquierda, el pixel
(0, 0)
82
3.3.
En esta seccin, se proceder a describir un algoritmo para dibujar lneas rectas que es
sencillo y eciente desde el punto de vista matemtico.
Analicemos el problema de dibujar una lnea del punto
(x0, y0 ),
al
(x1, y1 ).
yi = mxi + B
la ecuacin
que dene la linea, y los pixeles a encender (o a colorear) sern los pares ordenados:
Evidentemente,
m=
y1 y0
x1 x0 y
B = y0
y1 y0
x1 x0
x0 .
xi = x
xi+1
plantear lo siguiente:
yi+1 = mxi+1 + B
= m(xi + x) + B
= mxi + mx + B
= mx + (mxi + B)
yi+1 = yi + mx
y si asumimos que
(3.6)
xi+i = xi + 1
Esta idea es la base para el algoritmo que se conoce como Analizador Diferencial Digital
(DDA, Digital Dierential Analyzer ). Que est restringido al caso en que
Para otros valores de
m,
1 m 1.
1
2
3
4
5
6
7
8
9
10
11
83
y += m ;
A pesar de que esta solucin funciona y se puede adaptar a cualquier pendiente, tiene
un detalle indeseable: Utiliza artimtica de coma otante . Por ello, en las siguientes
secciones se presenta una elegante solucin que utiliza nicamente aritmtica entera.
3.4.
de lnea de Bresenham ).
Antes de abordar la resolucin general del dibujo de segmentos de recta, se abordar un
caso particular ms sencillo que permite describir la lgica del algoritmo.
(x0 , y0 ), hasta el pixel superior derecho (x1 , y1 ) usando nicamente aritmtica entera.
Considere la lnea que se representa en la gura 3.2, donde el pixel previamente seleccionado aparece sombreado y los dos pixeles candidatos a ser seleccionados en el siguiente
paso, son el pixel a la derecha del marcado, el pixel ESTE
del anterior, el pixel NOR-ESTE
geomtricos de
y de
N E.
El punto
N E.
P , en las coordenadas (x0 , y0 ) y ahora
N E . Eso lo hacemos averiguando si la recta ideal
de E o de N E .
y el
1
2 de pixel.
N E,
y en el caso de la
E.
M . Para ello se
ax + by + c = 0.
84
85
F (x, y) = ax + by + c
Esta tiene la siguiente caracterstica: El valor de
(3.7)
b,
el coeciente de
sea negativo.
. . . . . . . . . . . . . . F (x, y)
Entonces, tenemos
1
1
= a (xp + 1) + b yp +
+c
d = F xp + 1, yp +
2
2
(3.8)
d > 0,
se elige el pixel
N E;
si
d 0,
se elige el pixel
convencin, eligimos
(si
d = 0,
E ).
Una vez tomada la decisin y marcado el pixel, se pasa al siguiente punto y se hace lo
dnuevo = F (ME ) = F (xp + 1) + 1, yp + 12 si se eligi el pixel E , y
= F (MN E ) = F (xp + 1) + 1, (yp + 1) + 12 si se eligi el pixel N E .
mismo.
dnuevo
a, b
c.
Sea
P (x) = mx + B
y sea
xi+1 = xi + 1
P (xi+1 ) = mxi+1 + B
= m(xi + 1) + B
= (mxi + B) + m
P (xi+1 ) = P (xi ) + m
P (xi+1 ) P (xi ) = m
Ahora veamoslo aplicado a nuestro problema de
En el caso de elegir el pixel
86
E:
xi
N E:
N E
respectivamente.
(equivale al valor
dviejo
del primer
paso):
dinicial
dinicial
= F (M )
1
1
= F (x0 + 1, y0 + ) = a(x0 + 1) + b(y0 + ) + c
2
2
1
= ax0 + a + by0 + b + c
2
1
= ax0 + by0 + c + a + b
2
1
= (ax0 + by0 + c) + a + b
2
1
= F (x0, y0 ) + a + b; F (x0, y0 ) = 0
2
1
= a+ b
2
y=
y
x x
+ B,
b (c
as:
87
y
x+B
x
x y = y x + x B
y =
0 = y x x y + x B
F (x, y) = y x x y + x B
por lo que:
a = y
b = x
c = x B
Note que el coeciente
es desconocido
(se puede calcular, porque conocemos al menos dos puntos de la recta), pero como no
necesitamos
c,
Tenemos entonces:
E =
F (xi+1 , yi ) F (xi , yi ) = a
= y
d.
y
x+B
x
y
2y = 2
x + 2B
x
2x y = 2y x + 2x B
y =
F (x, y) = 2y x 2x y + 2x B
por lo que ahora:
88
(3.9)
a = 2y
b = 2x
c = 2x B
1
F (xi+1 , yi ) F (xi , yi ) = a
E =
= 2y
dinicial =
= 2y x
d.
Ahora, el algoritmo usa exclusivamente artimtica entera, sin el costoso tiempo para
hacer operaciones en coma otante.
El cdigo en lenguaje C es:
Listing 3.2: Algoritmo de lnea de punto medio en la mitad de un cuadrante
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
89
marcarPixel (x , y ) ;
hacia atrs, para poder aceptar los puntos en cualquier orden sin tener que intercambiar
las variables de entrada.
El primer problema se resuelve, averiguando la relacin de orden de
a eso, se decide hacer el recorrido sobre
o sobre
y.
y .
En base
As:
Listing 3.3: Algoritmo de lnea de punto medio de un cuadrante (o dos mitades de cuad-
1
rante)
3
4
5
6
7
8
9
// Inicializaciones
if ( horizontal ) {
d = ( delta_y *2) - delta_x ;
delta_E = delta_y *2;
delta_NE = ( delta_y - delta_x ) *2;
} else {
d = ( delta_x *2) - delta_y ;
delta_E = delta_x *2;
delta_NE = ( delta_x - delta_y ) *2;
}
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
90
else
34
35
36
37
38
39
40
41
42
43
44
45
x ++;
marcarPixel (x , y );
Llegamos a lo siguiente :
d = F xp 1, yp
2y
O =
SO
0
dinicial
1
2
1
= a (xp 1) + b yp
+c
2
= E
2y + 2x
= N E
2y + x
= dinicial
d0 0,
se elige el pixel
O;
si
d0 < 0,
SO.
4
Aunque esto parezca bastante complicado, no hace falta darle muchas vueltas al asunto .
Basta con tomar conciencia del siguiente razonamiento:
Si el valor inicial de
pero de signo opuesto, y el criterio se basa en el signo de dicha variable, signica que se
pueden sustituir los valores
O , SO
d0inicial
por
E , N E
dinicial
respectivamente
sin afectar gravemente el algoritmo. Basta con invertir el criterio de incremento, de tal
manera que quede as: Si
el pixel
(sumar
E ).
d0 > 0,
se elige el pixel
SO
(sumar
N E );
si
d0 0,
se elige
3
4
91
Listing 3.4: Algoritmo de lnea de punto medio de dos mitades de cuadrantes opuestos
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
92
x += dir_y ;
marcarPixel (x , y ) ;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
93
while ( y != y1 ) {
if ( d <= 0) {
d += delta_E ;
} else {
d += delta_NE ;
x += dir_x ;
}
y += dir_y ;
marcarPixel (x , y ) ;
}
39
40
41
42
43
44
45
46
47
48
49
3.5.
La simetra de la circunferencia
1
2
3
4
94
marcarPixel ( x , - y ) ;
marcarPixel ( -x , -y ) ;
marcarPixel ( -y , -x ) ;
marcarPixel ( -y , x ) ;
marcarPixel ( -x , y ) ;
3.6.
Existen varias alternativas para dibujar un crculo. Entre ellas, dibujarla a partir de la
ecuacin:
p
x2 + y 2 = R 2 y = R 2 x2
(3.10)
x R,
adems del
es menos ineciente, pero an demasiado, debido al clculo de las funciones trigonomtricas (que se realizan con series de potencias).
3.7.
F (x, y) = x2 + y 2 R2 = 0
El valor de
(3.11)
los coecientes de
x2
y2
sean positivos.
d:
1
1
dviejo = F (M ) = F (xp + 1, yp ) = (xp + 1)2 + (yp )2 R2
2
2
95
Si
dviejo < 0,
E:
1
(xp + 1) + 1, yp
2
dE
nuevo
= F
dE
nuevo
= dviejo + E
E = dE
nuevo dviejo
Si
96
dviejo 0,
= F (ME ) F (M )
1
1
= F (xp + 2, yp ) F (xp + 1, yp )
2
2
1
= (xp + 2)2 + (yp )2 R2
2
1
2
(xp + 1) (yp )2 + R2
2
= 2xp + 3
elegimos el pixel
SE :
dSE
nuevo
1
= F (xp + 1) + 1, (yp 1)
2
dSE
nuevo
= dviejo + SE
SE = dSE
nuevo dviejo
= F (MSE ) F (M )
3
1
= F (xp + 2, yp ) F (xp + 1, yp )
2
2
3
= (xp + 2)2 + (yp )2 R2
2
1
2
(xp + 1) (yp )2 + R2
2
= (2xp + 3) + (2yp + 2)
SE = 2xp 2yp + 5
Lo que falta es entonces, calcular la condicin inicial. Sabemos, que el punto inicial es
(0, R)
(1, R 21 ):
1
dinicial = F (1, R )
2
1 2
= 1 + (R ) R2
2
1
= 1 + (R2 R + ) R2
4
5
dinicial =
R
4
1
2
3
4
5
6
7
8
9
97
10
11
12
13
14
15
16
while ( y > x ) {
if ( d < 0) {
d += x * 2.0 + 3;
} else {
d += ( x - y ) * 2.0 + 5;
y - -;
}
x ++;
marcarPixel ( x , y ) ;
marcarPixel ( y , x ) ;
marcarPixel ( y ,- x ) ;
marcarPixel ( x ,- y ) ;
marcarPixel ( -x , - y );
marcarPixel ( -y , - x );
marcarPixel ( -y , x ) ;
marcarPixel ( -x , y ) ;
}
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
Sin embargo, persiste el desagradable asunto de tener que operar con una variable de
coma otante slo por el valor inicial de
como
como
en
El algoritmo resultante, usando slo aritmtica entera para dibujar crculos en lenguaje
C es:
1
2
Listing 3.8: Algoritmo de circunferencia de punto medio slo con aritmtica entera
x = 0;
y = radio ;
d = 1 - radio ;
marcarPixel ( x , y ) ;
marcarPixel ( y , x ) ;
marcarPixel ( y ,- x ) ;
4
5
6
7
8
9
98
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
while ( y > x ) {
if ( d < 0) {
d += x * 2 + 3;
} else {
d += ( x - y ) * 2 + 5;
y - -;
}
x ++;
marcarPixel ( x , y ) ;
marcarPixel ( y , x ) ;
marcarPixel ( y , - x ) ;
marcarPixel ( x , - y ) ;
marcarPixel ( -x , -y ) ;
marcarPixel ( -y , -x ) ;
marcarPixel ( -y , x ) ;
marcarPixel ( -x , y ) ;
}
d,
d,
d. As:
Si elegimos
(xp + 1, yp ).
(xp , yp )
Eviejo = 2xp + 3
Enuevo = 2(xp + 1) + 3
Enuevo Eviejo = 2
SEviejo = 2xp 2yp + 5
y tenemos adems:
SE en la iteracin actual,
(xp + 1, yp 1). Tenemos lo siguiente:
Pero si elegimos
a
(xp , yp )
99
De este anlisis, surge una tercera versin del algoritmo (mucho ms rpida que las
anteriores, ya que slo contiene una multiplicacin):
1
2
x = 0;
y = radio ;
d = 1 - radio ;
delta_E = 3;
delta_SE = 5 - radio * 2;
marcarPixel ( x , y ) ;
marcarPixel ( y , x ) ;
marcarPixel ( y ,- x ) ;
marcarPixel ( x ,- y ) ;
marcarPixel ( -x , - y );
marcarPixel ( -y , - x );
marcarPixel ( -y , x ) ;
marcarPixel ( -x , y ) ;
4
5
6
7
8
9
10
11
12
13
14
15
16
17
while ( y > x ) {
if ( d < 0) {
d += delta_E ;
delta_E += 2;
delta_SE += 2;
} else {
d += delta_SE ;
delta_E += 2;
delta_SE += 4;
y - -;
}
x ++;
marcarPixel ( x , y ) ;
marcarPixel ( y , x ) ;
marcarPixel ( y ,- x ) ;
marcarPixel ( x ,- y ) ;
marcarPixel ( -x , - y );
marcarPixel ( -y , - x );
marcarPixel ( -y , x ) ;
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
100
37
38
39
marcarPixel ( -x , y ) ;
(xc , yc ),
es precsamente el vector
(x0 , y 0 )
C = (xc , yc ).
centro en
Entonces
(x0 , y 0 ) = (x + xc , y + yc ).
En base a este sencillo anlisis, presentamos el siguiente algoritmo de dibujo de circunferencias con centro arbitrario, basado en el algoritmo 3.8:
101
// Funcin auxiliar
void marcarPixelesCicunferencia ( int x , int y , int xc , int yc ) {
marcarPixel ( x +xc , y + yc ) ;
marcarPixel ( x +xc , - y + yc ) ;
marcarPixel ( - x + xc , y + yc ) ;
marcarPixel ( - x + xc ,- y + yc ) ;
marcarPixel ( y +xc , x + yc ) ;
marcarPixel ( y +xc , - x + yc ) ;
marcarPixel ( - y + xc , x + yc ) ;
marcarPixel ( - y + xc ,- x + yc ) ;
}
void circunferencia_punto_medio ( int xc , int yc , int radio ) {
int x ,y , d ;
x =0;
y = radio ;
d =1 - radio ;
marcarPixelesCicunferencia (x ,y , xc , yc ) ;
while (y > x ) {
if (d <0) {
d += x * 2 + 3;
} else {
d += ( x - y ) * 2 + 5;
y - -;
}
x ++;
marcarPixelesCicunferencia (x ,y , xc , yc ) ;
}
}
3.8.
Relleno de rectngulos
1
2
3
4
5
6
7
8
9
10
11
12
102
}
if ( y1 > y2 ) {
i = y1 ;
y1 = y2 ;
y2 = y1 ;
}
for ( i = y1 ; i <= y2 ; i ++) {
marcarPixel ( x1 , i ) ;
marcarPixel ( x2 , i ) ;
}
El primer algoritmo recibe como parmetros dos puntos opuestos del rectngulo (ntese
que no importa el orden en que se especiquen). El segundo recibe el punto ms cercano
al origen y el ancho y alto del rectngulo (ntese que tanto
ancho
como
alto,
deben ser
positivos).
Una de las alternativas ms usuales entre las bibliotecas grcas, es ofrecer al programador una funcin de relleno de rectngulos que requiere del punto inicial del rectngulo
y su ancho y su alto. Esta es una propuesta de implementacin en lenguaje C:
1
2
3
4
5
6
3.9.
Relleno de circunferencias
103
(0, y)
hasta
(x, y)
SE , aprovechar para
marcar los pixeles correspondientes con la misma idea de la simetra de ocho octantes).
1
2
3
4
5
6
7
8
9
10
11
12
13
14
104
3.10 Ejercicios
y - -;
x ++;
for ( i =0; i <= x ; i ++) {
marcarPixelesCicunferencia (i ,y , x0 , y0 ) ;
marcarPixelesCicunferencia (y ,i , x0 , y0 ) ;
}
15
16
17
18
19
20
}
}
r_x = x0 - x ;
r_y = y0 - y ;
r_ancho = 2* x ;
r_alto = 2* y ;
dibujar_rectangulo_relleno ( r_x , r_y , r_ancho , r_alto ) ;
21
22
23
24
25
26
27
28
3.10.
Ejercicios
1. Construya un algoritmo que use la idea del DDA (cdigo 3.1 en la pgina 83) para
pendientes arbitrarias.
2. Describa cmo funciona el algoritmo de dibujo de lneas conocido como algoritmo
de lnea de punto medio.
3. Implementar un programa de dibujo usando la ecuacin 3.10 en la pgina 95.
4. En la cuadrcula de la gura 3.9, marque (sombree, tache, repinte, etc.) los pixeles
que encendera el algoritmo de lnea 3.5, al unir a los puntos (2,2) y (9,5) y a los
puntos (0,2) y (3,9). El centro geomtrico de los pixeles est en el centro de los
cuadritos negros. Las lneas grices son slo guas.
5. En la cuadrcula de la gura 3.9, marque (sombree, tache, repinte, etc.) los pixeles
que encendera el algoritmo de crculo 3.10 en la pgina 102, con centro (4,4) y
radio 4. El centro geomtrico de los pixeles est en el centro de los cuadritos negros.
Las lneas grices son slo guas.
6. Modicar el algoritmo 3.9 en la pgina 100 para dibujar crculos con centro arbitrario.
7. Modicar el algoritmo del ejercicio anterior para implementar el dibujo de crculos
rellenos.
8. Considere los cdigos siguientes para rellenar crculos y explique por qu el primero
es preferible frente al segundo:
1
2
105
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
106
marcarPixel ( x ,- y ) ;
marcarPixel ( -x , y ) ;
marcarPixel ( -x , - y) ;
marcarPixel ( y , x ) ;
marcarPixel ( y ,- x ) ;
marcarPixel ( -y , x ) ;
marcarPixel ( -y , - x) ;
3.10 Ejercicios
x ++;
for ( i =0; i <= x ; i ++) {
marcarPixelesCicunferencia (i , y ) ;
marcarPixelesCicunferencia (y , i ) ;
}
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
}
}
dibujar_rectangulo_relleno ( -x , -y , 2* x ,2* y ) ;
1
2
3
4
5
6
7
8
9
10
11
12
10. Implementar una funcin de dibujo de rectngulos que reciba uno de los vrtices
del rectngulo y su ancho y alto. Pero el alto y el ancho debe aceptarlos con
signo negativo, lo que signica que el rectngulo debe dibujarse hacia atrs en esa
dimensin.
11. Implementar una funcin de relleno de rectngulos que reciba como parmetros,
dos puntos opuestos del mismo.
12. Implemente la siguiente funcin en lenguaje C estndar
polgono cerrado, nos referimos a que el ltimo punto se une con el primero aunque
no sean iguales.
13. Construir una funcin de dibujo de elipses, dados su centro y sus dos radios.
107
108
4.1.
Notacin
Sea
(R)
en el marco de referencia
R,
en
R.
Las componentes rectangulares de
(R)
(R)
Sea
(R)
una distancia
y la componente
R,
(R)
px
del vector
y se lee en
R.
109
en el marco de referencia
V,
y en el marco de referencia
R.
En cada uno de ellos, el punto tendr sus coordenadas medidas en una escala diferente,
apropiada para cada marco.
Usualmente trabajaremos con dos marcos de referencia, uno Virtual, propio de la lgica de nuestra aplicacin, y uno Real, propio de la API grca que estemos utilizando
(tpicamente coincidente con los pixeles fsicos del monitor).
El problema a analizar en este captulo es bsicamente el siguiente:
Disponemos de
(V )
p
,
y deseamos conocer
(R)
4.2.
referencia a otro.
Bueno, el problema puede abordarse de muy diversas maneras. Una de ellas es la perspectiva vectorial.
110
p,
(R)
(V )
(V )
(R)
p
= V
+ E RV
p
p
= T RV
.
Veamos estos nuevos elementos:
T RV
en
R. E RV
El vector
es
(R)
V
(R)
V
al
R.
E RV
(R)
x =
(R)
(V )
Ay y y
Ntese que
(R)
By
B.
(R)
(R)
(V )
(V )
(V )
(R)
(V )
E RV
p
=
(R)
(V )
px ,
(V )
x
(R)
(V )
py
(V )
y
111
As, la forma completa para la ecuacin vectorial de transformacin de marcos de referencia es:
(R)
(R)
(V )
p
= T RV
p
= V
+
(R)
(V )
(R)
(V ) y
(V )
p x , (V )
py
y
!
(4.1)
(V )
(R) , procedemos
p
, dado un p
de forma inversa:
(V )
p
"
#
(V )
(V )
(V
)
x
y
(R)
(R)
(R)
= T V R
p
= R
+
p x , (R)
py
(R)
x
y
(4.2)
4.2.1. Ejemplo
Planteemos un escenario en el que es necesario el cambio de marco de referencia: Tenemos
una aplicacin grca como en la gura 4.4. La aplicacin tiene su propio marco de
referencia establecido por la API grca que estamos utilizando. Esta API establece
(y la mayora lo hace de la misma manera) que el origen est en la esquina superior
izquierda del interior de la ventana. Todas las coordenadas delimitadas por parntesis
pertenecen al sistema de coordenadas de la API. Este marco ser
R.
Dentro de nuestra aplicacin grca tenemos un cuadro (en este caso, punteado) a travs
del cual mostramos un juego que tiene su propio marco de referencia, que establece que
112
el origen est en la esquina inferior izquierda del cuadro, y que las coordenadas visibles para el usuario se extienden hacia la esquina superior derecha hasta la coordenada
[1000, 1000],
ordendadas delimitadas por corchetes estn en el marco de referencia del juego, que
llamaremos
V.
Ntese que los ejes verticales avanzan en direccin opuesta, uno del otro. Y que por
convencin en este texto, las coordenadas en el marco de referencia virtual se delimitan
con corchetes:
con parntesis:
[500, 500].
(V )
p
=
Pero nuestra API grca no funciona con ese marco de referencia. Necesi-
B.
(R)
V
= (100, 300).
(V )
y necesitamos
(R)
p
.
Podemos tomar estos de las esquinas inferior izquierda y superior derecha del
[1000, 1000].
B (V ) =
Ahora sustitumos:
113
(R)
p
=
(V )
T RV
p
!
(R)
(V ) y
(V )
=
p x , (V ) p y
(V )
x
y
350 100
50 300
= (100, 300) +
500,
500
1000 0
1000 0
= (100, 300) + (125, 125)
(R)
V
+
(R)
(R)
p
= (225, 175)
4.3.
(225, 175)
[500, 500]
en el marco de
de la aplicacin.
Hay un caso particular que es muy usual en aplicaciones de corte acadmico: Aquel en
el el que toda la pantalla (o al menos toda la ventana) de la aplicacin, se usa para el
despliegue grco en un marco de referencia con origen en la esquina inferior izquierda,
tal como puede verse en la gura 4.5.
En este caso, tal como en el ejemplo de la seccin 4.4, los puntos a elegir como referencias,
son las esquinas inferior izquierda y superior derecha del marco virtual en el marco real.
(R)
V
= (0, AltoR). Adems A(R) = (0, AltoR), B (R) = (AnchoR, 0),
B (V ) = [XmaxV, Y maxV ] y sustituimos:
A(V ) = [0, 0]
114
(R)
p
=
=
=
=
(R)
p
=
(V )
T RV
p
!
(R)
(V ) y
(V )
p x , (V ) p y
(V )
x
y
AnchoR 0
0 AltoR
(V )
(V )
(0, AltoR) +
px ,
py
XmaxV 0
Y maxV 0
AnchoR
AltoR
(V )
(V )
p x , AltoR
py
XmaxV
Y maxV
!!
(V )
p
AnchoR
y
(V
)
p x , AltoR 1
XmaxV
Y maxV
(R)
V
+
(R)
(R)
(V )
px
px
=
AnchoR
XmaxV
y
(R)
(V )
py
py
=1
AltoR
Y maxV
4.4.
Transformacin de distancias
(R)
(R)
x
(V )
x
dx
(V ) para las magnitudes en
dx
xy
(V )
y
(R)
dy
(V )
dy
y . De hecho,
4.5.
A continuacin se expone brevemente una sencila aplicacin grca interactiva que simula el campo elctrico producido por un conjunto de cargas puntuales en un espacio
115
continuo bidimensional .
en el punto
Q,
en el
es:
E =
1
q
3 QP
40
QP
i = 0, 1, . . . , n,
entonces el campo
E =
(4.3)
n
1 X qi
3 Qi P
40
i=0 Qi P
con
(4.4)
Los siguientes dos archivos proporcionan la funcionalidad bsica para manipular campo
elctrico.
Listing 4.1: Archivo de cabecera de funciones de campo elctrico
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Para ms detalles del dicho fenmeno fsico, consltese cualquier texto introductorio de Electromagnetismo
116
Vector posicion ;
double valor ;
} CargaElectrica ;
/*
Calcula el vector de Campo Elctrico
en el punto < punto > , por efecto de la
carga < carga >.
El resultado se almacena en < campo >.
*/
void campoElectrico ( CargaElectrica * carga , Vector * punto , Vector * campo ) ;
/*
* Calcula el vector de Campo Elctrico
* en el punto < punto > , por efecto del
* arreglo de cargas < cargas >.
* El resultado se almacena en < campo >
* */
void campoElectricoCargas ( CargaElectrica * cargas , int cantidad , Vector *
punto , Vector * campo ) ;
/*
* Calcula la magnitud de un vector
* */
double magnitudVector ( Vector * v ) ;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
117
Ntese que el cdigo de este ltimo archivo es altamente suceptible de ser optimizado
para mejorar el rendimiento general de la aplicacin.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
22
23
24
25
20
21
*/
Uint32 colorGfx ( Uint8 r , Uint8 g , Uint8 b ) ;
26
27
118
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
1
2
3
119
1
2
3
4
5
6
7
120
clic izquierdo
Sobre una carga no tiene efecto. Sobre el campo tiene el efecto de imprimir
N/C .
121
Sobre una carga tiene el efecto desplazar esa carga a otro punto
clic derecho
en la macro
CARGA_INICIAL)
clic medio
1C
MAX_CARGAS).
1 C cada
INCREMENTO_CARGA). Sobre
10 %
1C
INCREMENTO_CARGA).
10 %
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
MAX_CARGAS 20
CARGA_INICIAL 1.0
INCREMENTO_CARGA 1.0
MIN_CANT_CUADROS 5
struct configuracion {
int numCuadrosH ;
int numCuadrosV ;
19
Uint32
Uint32
Uint32
Uint32
Uint32
20
21
22
23
24
25
122
colorFondo ;
colorFlecha ;
colorPuntaFlecha ;
colorCargaPositiva ;
colorCargaNegativa ;
123
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
// dibujar puntas
filledCircleColor ( pantalla ,
tR_Vx ( punto .x , & conf . e ) + ( int ) (( campo . x / magnitudVector (&
campo ) ) *( conf . e . AnchoR / conf . numCuadrosH -1) ) ,
tR_Vy ( punto .y , & conf . e ) - ( int ) (( campo . y / magnitudVector (&
campo ) ) *( conf . e . AltoR / conf . numCuadrosV -1) ) ,
1,
conf . colorPuntaFlecha ) ;
106
107
108
109
110
111
112
113
114
115
116
124
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
/*
* Dado un arreglo de cargas elctricas ,
* y una coordenada en el marco Real ,
* retorna el ndice del arreglo que se corresponde
* con la carga seleccionada .
* Si no coincide con ninguna , retorna -1
*
* */
int seleccionarCarga ( CargaElectrica * cargas , int cantidad , int xR , int yR
){
int i ;
int x1 , x2 , y1 , y2 ;
for ( i =0; i < cantidad ; i ++) {
x1 = tR_Vx ( cargas [ i ]. posicion .x ,& conf . e ) - mR_Vx ( conf . radioCarga
,& conf . e ) ;
x2 = tR_Vx ( cargas [ i ]. posicion .x ,& conf . e ) + mR_Vx ( conf . radioCarga
,& conf . e ) ;
y1 = tR_Vy ( cargas [ i ]. posicion .y ,& conf . e ) + mR_Vy ( conf . radioCarga
,& conf . e ) ;
y2 = tR_Vy ( cargas [ i ]. posicion .y ,& conf . e ) - mR_Vy ( conf . radioCarga
,& conf . e ) ;
if ( x1 <= xR && xR <= x2 && y1 <= yR && yR <= y2 )
return i ;
}
return -1;
}
int main ( int argc , char * argv []) {
SDL_Surface * pantalla = NULL ;
SDL_Event evento ;
int corriendo = 1;
int seleccion = -1;
configurar () ;
configurarVideo (& pantalla ) ;
// hacer primer dibujo
stringColor ( pantalla ,0 , conf . e . AltoR /2 , " Haga clic derecho para agregar
una carga elctrica " , conf . colorFlecha ) ;
159
125
160
161
162
while ( corriendo ) {
while ( SDL_PollEvent (& evento ) ) {
switch ( evento . type ) {
case SDL_VIDEORESIZE : {
conf . e . AnchoR = evento . resize . w ;
conf . e . AltoR = evento . resize . h ;
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
}
break ;
187
188
189
case SDL_MOUSEBUTTONDOWN :{
// Seleccionar / evaluar campo
if ( evento . button . button == SDL_BUTTON_LEFT ) {
seleccion = seleccionarCarga ( conf . cargas , conf .
cantidadActualCargas , evento . button .x , evento . button . y )
;
if ( seleccion == -1) {
Vector punto ;
Vector campo ;
punto . x = tV_Rx ( evento . button .x ,& conf . e ) ;
punto . y = tV_Ry ( evento . button .y ,& conf . e ) ;
campoElectricoCargas ( conf . cargas , conf .
cantidadActualCargas , & punto , & campo ) ;
printf ( " Campo electrico : ( %f, %f ) , magnitud : %f \ n " ,
campo .x , campo .y , magnitudVector (& campo ) ) ;
}
190
191
192
193
194
195
196
197
198
199
200
201
126
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
}
// Agregar una carga
else if ( evento . button . button == SDL_BUTTON_RIGHT ) {
if ( conf . cantidadActualCargas < MAX_CARGAS ) {
conf . cargas [ conf . cantidadActualCargas ]. valor =
CARGA_INICIAL ;
conf . cargas [ conf . cantidadActualCargas ]. posicion . x =
tV_Rx ( evento . button .x ,& conf . e ) ;
conf . cargas [ conf . cantidadActualCargas ]. posicion . y =
tV_Ry ( evento . button .y ,& conf . e ) ;
conf . cantidadActualCargas ++;
actualizar ( pantalla ) ;
SDL_Flip ( pantalla ) ;
}
else
printf ( " Ya se alcanz el mximo nmero de cargas
permitidas \ n" ) ;
}
else if ( evento . button . button == SDL_BUTTON_MIDDLE ) {
int s ;
if (( s = seleccionarCarga ( conf . cargas , conf .
cantidadActualCargas , evento . button .x , evento . button . y )
) > -1) {
conf . cargas [ s ]. valor = - conf . cargas [ s ]. valor ;
actualizar ( pantalla ) ;
SDL_Flip ( pantalla ) ;
}
}
else if ( evento . button . button == SDL_BUTTON_WHEELUP ) {
int s ;
if (( s = seleccionarCarga ( conf . cargas , conf .
cantidadActualCargas , evento . button .x , evento . button . y )
) > -1) {
conf . cargas [ s ]. valor += INCREMENTO_CARGA ;
printf ( " Nuevo valor de la carga : %fC \ n " , conf . cargas [
s ]. valor ) ;
}
else { // alejarse un 10 %
double incrementoAncho , incrementoAlto ;
incrementoAncho = abs ( conf . e . XmaxV - conf . e . XminV )
*0.10;
incrementoAlto = abs ( conf . e . YmaxV - conf . e . YminV ) *0.10;
conf . e . XminV -= incrementoAncho /2;
conf . e . XmaxV += incrementoAncho /2;
conf . e . YminV -= incrementoAlto /2;
conf . e . YmaxV += incrementoAlto /2;
}
127
244
245
actualizar ( pantalla ) ;
SDL_Flip ( pantalla ) ;
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
}
break ;
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
case SDL_KEYDOWN :{
285
128
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
}
break ;
305
306
307
308
309
310
311
312
313
314
315
316
317
318
SDL_Quit () ;
return 0;
4.5.5. El Makefile
Finalmente, este es el archivo
Makefile
compilacin :
Listing 4.8: Archivo Makele para el simulador
1
2
3
$ make
129
= / bin / rm -f
4.6.
Ejercicios
int tR_Vx(double
int tR_Vy(double
double tV_Rx(int
double tV_Ry(int
xV);
yV);
xR);
yR);
para convertir puntos del marco de referencia virtual al real y viceversa. Asuma
130
4.6 Ejercicios
mejor rendimiento .
8. Modique el programa de la seccin 4.5 para que el aumento de la cantidad de
el campo elctrico
configuracion
un buen lugar para empezar es en el archivo campo.c, y el siguiente lugar, es el programa principal
131
132
5 Transformaciones Geomtricas
Bidimencionales
En este captulo analizaremos los procedimientos estndares para realizar transformaciones geomtricas bidimensionales sobre objetos grcos inmersos en algn marco de
referencia especco (real o virtual).
Todo el anlisis girar en torno a la representacin matricial de las coordenadas, por
lo que se recomienda hacer un concienzudo repaso de operaciones con matrices, ya que
el estudio de este captulo depende transversalmente de dichas habilidades. Adems, es
preferible recordar algunos tpicos bsicos de trigonometra analtica para poder tener
una lectura ms uda.
5.1.
(2, 3)
P 0.
y la nueva es
(5, 2).
El mismo desplazamiento ha
133
5.1.2. Escalamiento
El escalamiento es la operacin que nos permite agrandar o empequeecer un conjunto
de puntos o un objeto compuesto. La operacin requiere de dos parmetros: el factor
de escalamiento a aplicar en
y.
La operacin
1
con factores de escalamiento
3 en
x, y 21 en
que
plo anterior) tomando como referencia a su esquina inferior derecha y con factores de
escalamiento
134
1
2 en
x,
1
2 en
y.
135
5.1.3. Rotacin
La rotacin es la ms compleja de las operaciones o transformaciones geomtricas bsicas.
Consiste en girar un punto, un conjunto de puntos o un cuerpo compuesto, al rededor
de un punto de referencia (el cetnro de rotacin), tpicamente el origen del marco de
referencia.
Veamos un ejemplo:
En la gura 5.4, se ilustra la rotacin de
rotacin es de
P,
(6, 2). La
x+ . El
punto de referencia es el origen del marco de referencia. Las coordenadas del punto
inferior izquierdo de
P0
son
(4,1962, 4,7321)1 .
Un ejemplo ms:
En la gura 5.5, se ilustra la rotacin de
P,
P 000
son
(5,1716, 4).
136
5.2.
Representacin matricial
Aunque existen diversas maneras de representar las coordendas de los objetos grcos y
de representar las transformaciones geomtricas que operan sobre ellos, vamos a elegir
aqu la ms estndar y exible.
Los puntos se representan como vectores columna de tamao
3 1:
x
P = y
1
1 0 dx
T (dx , dy ) = 0 1 dy
0 0 1
(5.1)
3 3:
(5.2)
sx 0 0
S (sx , sy ) = 0 sy 0
0 0 1
(5.3)
137
cos sin 0
R () = sin cos 0
0
0
1
(5.4)
P 0 = T (dx , dy ) P
signica que
P0
es
con un desplazamiento de
P 0 = S (sx , sy ) P
signica que
P0
es
(dx , dy ).
sx
en
sy
en
P 0 = R () P
signica que
P0
es
5.3.
1
2 . Luego, habra que re-desplazar el
cuadro transformado, a su posicin nal, con la esquina inferior derecha a donde estaba
antes.
Expresado de otra manera:
Q = (8, 7) la esquina inferior derecha del cuadro original P . Si aplicamos la transT (8, 7) a todos los puntos de P , lo habremos movido de tal manera que Q0
1 1
0
0
de P ha quedado en el origen. Posteriormente, aplicamos a P el escalamiento S
2, 2
00
para obtener P , que es un cuadro de ancho y alto igual a 1, con su esquina inferior
00
derecha tambin en el origen. Despus, aplicamos la traslacin T (8, 7) a P , con lo que
000
obtenemos P .
Sea
formacin
138
pasos intermedios.
Sigamos la secuencia de transformacin para el punto
como ejemplo:
Q0 = T (8, 7) Q
1 1
1 1
00
0
Q = S
Q =S
T (8, 7) Q
,
,
2 2
2 2
1 1
000
00
Q
= T (8, 7) Q = T (8, 7) S
T (8, 7) Q
,
2 2
5.4.
Atencin a la eciencia
r11 r12 tx
M = r21 r22 ty
0
0 1
x
P = y
1
Sin embargo, al realizar las operaciones, se puede apreciar que el resultado es previsible.
El resultado siempre ser que
x0 = xr11 + yr12 + tx
y 0 = xr21 + yr22 + ty .
Lo cual
5.5.
A continuacin analizaremos otra perspectiva del cambio de coordenadas entre dos marcos de referencia. Esta vez usando transformaciones matriciales.
Reconsideremos la gura 4.2 en la pgina 111 y la ecuacin 4.1 en la pgina 112. De ellas
podemos concluir que lo primero que hacemos para hacer un cambio de coordenadas, es
un escalamiento, y luego hacemos un desplazamiento.
139
MRV = T
(R)
(R)
V x ,V y
(R)
(R)
S
(V )
!
(5.5)
(V )
(R)
(V )
p
= T RV
p
,
tam-
(R)
(V )
px
px
(V )
(R)
p y = MRV
py
1
1
(R)
px
(R)
(R)
(R)
S
py = T V x ,V y
1
(R)
x
,
(V )
x
(R)
y
(V )
y
(V )
px
(V )
py
1
(5.6)
Hay un punto muy importante que recalcar en este punto, y es que as como hemos
denido
MRV ,
sucesivas para pasar de un marco de referencia a otro, pasando por intermedio de otros
ms as:
V al R es:
(R)
(V )
px
px
(V )
(R)
p y = MRV
py
1
1
(R)
px
(R)
(R)
(R)
(R)
y
(R)
x
R ()
S (V
py =T V x , V y
),
(V )
x
y
1
referencia
(V )
px
(V )
py
1
Desde la perspectiva vectorial, habra sido difcil ofrecer una solucin sencilla.
5.6.
140
141
P0 = M P
M 1 P 0 = M 1 M P
= M 1 M P
= I P
M
= P
(A B)1 = B 1 A1
0
Esto signica que si tenemos P
T
(V )
=T
(R)
(R)
V x ,V y
(R)
(R)
V x ,V y
(R)
S
(V )
x
S
(R)
(R)
(R)
y
x
(V ) ,
(V )
x
y
P,
entonces:
!!1
P 0 = I3 P
(V )
y
!!1
1
(R)
(R)
T V x ,V y
P0 = P
(V )
(R)
(R)
y
y
y entonces basta con encontrar las respectivas matrices inversas y obtendremos la matriz
de retro-transformacin para
P0
P0
P ).
T (dx , dy )1 = T (dx , dy )
1 1
1
S (sx , sy )
= S
,
sx sy
R()1 = R()
Esto signica, segn la explicacin en la que estabamos, que:
142
(5.7)
(5.8)
(5.9)
5.7 Ejercicios
(R)
(V )
!!1
1
(R)
(R)
T
V
,
V
P0 = P
x
y
(V )
(R)
y
y
(V )
(V )
(R)
(R)
(R)
(R)
T V x , V y
P0 = P
Por lo que la idea general es que para invertir una serie de transformaciones geomtricas,
basta con aplicar las transformaciones inversas (siguiendo las ecuaciones 5.7, 5.8 y 5.9)
en orden inveso .
5.7.
Ejercicios
1. Cul es la matriz de transformacin necesaria para lograr la transformacin presentada en la gura 5.5?
2. Realizar la transformacin de las otras aristas del cuadro analizado en la seccin
5.3.
3. Considere la gura 5.8. Rote el tringulo -45 respecto de su esquina inferior
derecha segn la regla de la mano derecha, con la ayuda de una matriz de transformacin bidimensional
M1 .
a ) Cul es la denicin de
M1 ?
a ) Cul es la denicin de
M2 .
M2 ?
M3 .
a ) Cul es la denicin de
M3 ?
143
144
6 Transformaciones Geomtricas
Tridimencionales
En este captulo se presentan los tpicos bsicos y las herramientas matemticas bsicas para realizar transformaciones geomtricas tridimensionales en marcos de referencia
tridimensionales.
6.1.
Sistemas de referencia
S(1, 1, 1).
6.2.
x
y
P =
z
1
4 1:
(6.1)
145
146
1
0
T (dx , dy , dz ) =
0
0
0
1
0
0
0 dx
0 dy
1 dz
0 1
4 4:
(6.2)
sx 0 0
0 sy 0
S (sx , sy , sz ) =
0 0 sz
0 0 0
0
0
0
1
(6.3)
Las operaciones de rotacin (respecto de cada eje principal, siguiendo la regla de la mano
derecha) se representa as:
1
0
0
0 cos sin
Rx () =
0 sin cos
0
0
0
0
0
0
1
(6.4)
147
cos
0
Ry () =
sin
0
0 sin 0
1
0
0
0 cos 0
0
0
1
(6.5)
0
0
0
1
(6.6)
cos sin
sin cos
Rz () =
0
0
0
0
Ntese la similitud entre esta ltima ecuacin
Rz ()
0
0
1
0
y la ecuacin de
R()
que es para
6.3.
Las transformaciones geomtricas tridimensionales, al igual que las bidimensionales, tambin pueden componerse e invertirse . La lgica matemtica es idntica, por lo que
nos limitaremos en este captulo a presentar las inversas de dichas transformaciones:
T (dx , dy , dz )1 = T (dx , dy , dz )
1 1 1
1
S (sx , sy , sz )
= S
, ,
sx sy sz
Rx ()1 = Rx ()
(6.7)
(6.8)
(6.9)
Ry ()
= Ry ()
(6.10)
Rz ()
= Ry ()
(6.11)
transformaciones3D.jar1
aplicacin permite, de una manera muy simple, practicar las transformaciones geomtricas tridimensionales y ver sus efectos sobre dos objetos con volumen y un objeto plano
que pueden traslaparse.
Para ejecutar la aplicacin, se requiere de la mquina virtual de java (se recomienda la
versin 1.6), procediendo as:
148
x+ , y +
z+
x-y-z y la regla de la mano derecha). Con la rueda del ratn se puede acercar y alejar la
imagen.
A travs de la ventana grca no se pueden alterar los objetos mencionados, para eso es
el intrprete de comandos en la consola (si escribe
:ayuda
:reiniciar
: %<comentario>
:<objeto> mostrar
:<objeto> ocultar
cin).
provoca un desplazamiento
T (dx , dy , dz )
en el objeto es-
pecicado.
provoca un escalamiento
cado.
:<objeto> eu <s>
S (s, s, s),
en el objeto especica-
do.
:salir
termina la aplicacin.
43
y el ojo
todos.
3 es una pirmide de
el programa muestra lo que el usuario escribi y la ayuda. El ojo est por defecto oculto .
2
3
4
149
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
: plano ocultar
: cubo t 2 0 0
: cubo eu 2
: cubo t 0 -4 -4
: cubo t -8 0 0
: cubo t 4 4 4
: cubo e 1 1 .5
: cubo e 1 .5 1
: cubo rx 30
: cubo rx -30
: cubo ry 60
: cubo ry 30
: cubo rz 45
: cubo e 1 1 .5
: cubo rz 45
: cubo ocultar
:%%%%%%%%%%%
: ojo mostrar
: ojo ry 30
: ojo ry -30
: % prstese atencin a estas ltimas transformaciones :
: ojo t 5 0 0
: ojo rz 30
: ojo rx 60
: ojo t 0 2 0
: ojo t 0 -2 0
: ojo rx -60
: ojo rz -30
: ojo t -5 0 0
Note que las ltimas cuatro transformaciones invirtieron exactamente las anteriores cuatro.
6.4.
Ejercicios
150
7.1.
Proyeccin Ortogonal
x, y
NO existe
Como comentario personal del autor, es curioso que modelemos realidades tridimensionales en modelos de almacenamiento lineales (la memoria de la computadora es unidimensional) que a su vez,
151
152
1
2
3
4
: plano
: plano
: plano
: plano
ry 90
t -50 0 0
rz 25
ry -25
7.2.
Proyeccin en Perspectiva
En la proyeccin en perspectiva se proyectan las guras sobre el mismo plano de proyeccin que en la proyeccin ortogonal, pero cada punto en una direccin oblicua al plano,
alineada con un foco de proyeccin (ver la gura 7.3 en la pgina 158).
Veamos algunos ejemplos en la gura 7.2 en la pgina siguiente.
En todas las imgenes podemos ver los ejes principales x-y-z de la misma manera que
en la gura 7.1 en la pgina anterior. De nuevo, los detalles geomtricos formales no son
de nuestro inters en este momento.
La principal caracterstica a resaltar, es que
existe
7.3.
Portal de Visin
presentados en las secciones anteriores? Y a estas alturas del libro, una parte
de la respuesta es obvia: Segursimo que se logran con transformaciones geomtricas
tridimensionales .
La pregunta consecuente es:
por que si no, no habra tenido sentido estudiar todo eso. . . verdad. . . ?
153
154
Portal
de Visin de una aplicacin grca tridimensional es una ventana, un rectngulo otante (desplazable o no) en el espacio tridimensional de la aplicacin. Este
representa la pantalla bidimensional a travs de la cual, el usuario (o los usuarios)
perciben esta realidad virtual tridimensional.
transformaciones3D.jar:
aplicacin grca tridimensional imaginaria y vamos a realizar las transformaciones geomtricas necesarias para transformar todo el escenario de tal manera que el portal de
visin quede sobre el plano
xy .
de visin
transformaciones3D.jar
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
155
5
denada
r : 5, : 6 , :
(r, , ).
T (0, 0, r) Rz
Ry () Rz ()
2
(7.1)
Luego podramos alinear la esquina inferior izquierda del portal de visin con el origen,
agregando
7.4.
En este momento ya casi disponemos de los recursos tericos para proceder a disear
una estrategia de sistematizacin de proyecciones ortogonales. Un detalle importante que
falta es considerar que la ecuacin 7.1 no es la versin ms apropiada de las alternativas
disponibles. A continuacin presentamos una secuencia de transformaciones que es ms
apropiada:
M2D3D = T (0, 0, r) Rz
Ry ( ) Rz ()
2
(7.2)
5
6
43
156
z+
y con el eje
y+
hacia abajo
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
Luego de hacer esta transformacin, convendr hacer una transformacin extra hacia el
marco de referencia real, con la transformacin 5.5 en la pgina 140 o alguna equivalente
P 0 = MRV M2D3D P
AnchoR AltoR
0
P = S(sx , sy , sz ) T
,
, 0 M2D3D P
2
2
Es en este punto donde la aplicacin
(7.3)
PortaldeVision.java.
7
y+
colocarPuntodeVision
del archivo
157
7.5.
Antes que nada, veamos ahora algunos detalles geomtricos anteriormente postergados
de los tipos de proyecciones estudiados.
La gura 7.3 nos muestra la diferencia fundamental entre ambos tipos de proyecciones:
En las proyecciones ortogonales las guras se aplastan contra el plano en direccin siempre perpendicular a este (lo que se logra simplemente ignorando las componentes en
xy ,
xper
158
que es
semejantes:
(x, y, z)
xper
d
x
d+z
d
dx
=
x
d+z
d+z
xper =
(7.4)
d 6= 0):
yper
d
yper =
y
d+z
dx
d
=
y
d+z
d+z
(7.5)
zper = 0
(7.6)
d
d
d+z , d+z , 0
para realizar la
0
Pper
=S
d
d
d+z , d+z , 0
M2D3D P
de cada punto a
M2D3D
P 0 = M2D3D P
proyeccin ortogonal)
159
a proyectar, hacer
d
Px0
d + Pz0
d
=
Py0
d + Pz0
= 0
Px00 =
Py00
Pz00
Pper = MRV P 00
Recomendamos, a manera de prctica, el uso de la aplicacin
perspectiva3D.jar9
que
se encuentra en el material adjunto a esta obra. Esta aplicacin permite hacer las mismas
cosas que su hermana
no ortogonal.
Para ejecutar la aplicacin, tambin escrita en lenguaje java:
PortaldeVision.java de
transformaciones3d.jar, en ellos podemos
perspectiva3D.jar
y el de
/*
* Recibe el centro del portal de visin en coordenadas
* esfricas (d , theta , phi )
*/
public void colocarPuntodeVision ( Objeto3DSimple objetos [] , float
theta , float phi , float distancia ) {
this . theta = theta ;
this . phi = phi ;
this . distancia = distancia ;
38
39
40
41
42
43
44
45
46
matriz . identidad () ;
47
48
49
50
51
52
53
9
160
54
55
56
57
58
59
60
61
62
// traslamiento final :
matriz . trasladar ( tamanhoR . width /2 , tamanhoR . height /2 , 0) ;
63
64
65
66
67
68
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
/*
* Recibe el punto de visin en coordenadas esfricas ( distancia ,
theta , phi )
*
* Asumimos que dicha distancia representa tanto la
* distancia del origen virtual al centro del portal de visin
* como a la distancia del centro de proyeccin
* al centro del portal de visin .
* Esto es por simplicidad en este cdigo
* pero no necesariamente debe ser as siempre .
*/
public void colocarPuntodeVision ( Objeto3DSimple objetos [] , float
theta , float phi , float distancia ) {
this . theta = theta ;
this . phi = phi ;
this . distancia = this . distanciaProyeccion = distancia ;
matriz . identidad () ;
matriz . rotarZ ( - theta ) ;
matriz . rotarY (180 - phi ) ;
matriz . rotarZ ( -90) ;
matriz . trasladar (0 , 0 , distancia ) ;
for ( int i =0; i < objetos . length ; i ++)
objetos [ i ]. transformarProyeccion ( matriz , this , true ) ;
matriz . identidad () ;
// la media del ancho y alto real entre
// la media del ancho y alto virtual , por
// un factor de aumento
matriz . escalar (( float )(
161
75
76
77
78
79
// traslamiento final :
matriz . trasladar ( tamanhoR . width /2 , tamanhoR . height /2 , 0) ;
80
81
82
83
84
85
7.6.
Ejercicios
1. En la aplicacin
quiere decir que eventualmente los objetos a proyectar se encuentran detrs del
Portal de Visin de la aplicacin. Por qu la imgen no se distorciona como sucede
con
perspectiva3D.jar?
162
8 Interaccin
Este captulo no pretende ser un tratado completo sobre tcnicas de interaccin humanomquina, sino una breve reexin sobre la importancia de hacer aplicaciones grcas
interactivas amigables, fciles de usar e intuitivas.
La razn por la que es importante que nuestras aplicaciones sean amigables (y el grado
de amigabilidad depender de los usuarios a los que est orientada) es porque gran
parte del xito en la difusin de una aplicacin, ya sea un juego de video, una aplicacin
educativa, de entretenimiento, un simulador de algn fenmeno fsico, social, econmico,
etc. depender del hecho que el usuario logre sus objetivos y que no se frustre al intentar
aprender a usarlas. El respeto de estndares ociales o de facto, es muy importante
en estos das. Ya no estamos en los das en los que se podan denir arbitrariamente
paradigmas de interaccin.
8.1.
Posicionamiento
En una aplicacin con varios objetos (en dos o tres dimensiones), el usuario debera
poder ser capaz de abrise paso, de algn modo, para lograr posicionarse al alcance de
algn objeto especco que quisiera ver o modicar.
Como programadores, a veces olvidamos las reacciones lgicas de una persona nor-
Pgina Anterior
Pgina Siguiente
Tabulacin
y las teclas
de trabajo de las aplicaciones que hacemos. A veces se nos olvida programar esas teclas
y otras combinaciones que son obvias para todo el mundo en estos das.
Por ello es importante presentarle la aplicacin a usuarios no familiarizados con el desarrollo de la aplicacin (de preferencia personas normales) para evaluar objetivamente
si la aplicacin no tiene un interaccin excesivamente compleja o confusa antes de darla
por terminada.
En el caso de aplicaciones bidimensionales, el problema de posicionamiento suele resolverse con barras de desplazamiento al rededor del espacio de trabajo. Y en las ocaciones
163
8 Interaccin
en que se operan objetos que pueden traslaparse, es conveniente disponer funciones del
tipo Enviar al fondo, Enviar atrs, Traer adelante y Traer al frente.
En el caso de aplicaciones tridimensionales, el problema de posicionamiento representa comunmente un problema de navegacin espacial. En donde usualmente habr que
disear una estrategia de limitar el volumen visible. Usualmente no todo lo que est en
el universo virtual debera ser visible por el usuario en cada posicin especca. Este
fenmeno puede verse en diversos juegos de video 3D de carreras, en las que el paisaje
va apareciendo a medida que el jugador se va desplazando por la pista. Esto por
supuesto se debe a dos factores: El primero es que requerira demasiado procesamiento
para mostrar todos los detalles lejanos y el segundo es que sera demasiada informacin
para que un usuario tpico la procese.
Partes importantes del problema de navegacin, son el problema del cambio de direccin
y la magnitud del desplazamiento lineal. El primero se reere a cmo cambiar la direccin
de movimiento o la orientacin en general del portal de visin, y el segundo se reere
a la cantidad de desplazamiento a realizar en una direccin especca o en general en
cualquier direccin.
En el caso de nuestras aplicaciones de ejemplo de los ltimos captulos, el problema de
la navegacin espacial est limitado ya que el portal de visin siempre mira jamente
en direccin del origen de coordenadas del universo virtual. Sin embargo, s existe el
problema del cambio de direccin, resuelto con arrastre del ratn; y tambin existe el
problema de la magnitud de desplazamiento lineal, resuelto con la rueda del ratn.
La aplicacin
perspectiva3D.jar
itacin del volumen visible, y es que no limita el volumen visible, por lo que proyecta
incluso objetos detrs del centro de proyeccin (lo cual genera una distorcin visual ).
8.2.
Seleccin
ms cerca del usuario, es decir, del portal de visin. Esto es porque no debera tener
164
;-)
8.3 Transformacin
sentido seleccionar objetos que estn detrs del portal de visin, en el caso de proyeccin
ortogonal, o detrs del centro de proyeccin, en el caso de proyeccin en perspectiva.
Y
(b) Averguar a qu punto del universo virtual, corresponde el punto sobre el que el
usuario hizo
clic.
8.3.
Transformacin
de la
165
8 Interaccin
coordenada del centro del portal. Esta tcnica es usada en las aplicaciones usadas
en los ltimos captulos.
Para realizar acercamiento o alejamiento en una escena 3D, puede usarse la ya
tradicional rueda del ratn, tal vez en combinacin con la tecla
ctrl
shift.
Para el desplazamiento de objetos o de toda una escena 3D, o del origen del marco
de referencia podra usarse arrastre del ratn combinado con alguna tecla como
ctrl
8.4.
shift.
Conclusin
Evidentemente, existen diversas (y tal vez ilimitadas) formas de interaccin entre los
usuarios y las aplicaciones grcas interactivas, por lo que, lo que nalmente podemos
decir a manera de recomendacin general, es seguir el principio que la magnitud de las
acciones del usuario sea proporcional a la magnitud de las transformaciones que estas
acciones realizan. Obviamente esta proporcin tambin debe ser ergonmica , apropiada
para la naturaleza humana.
A manera de ejemplo de esto ltimo, recomendamos examinar el archivo
Config3D.java
de las aplicaciones usadas en los ltimos captulos. En ellos aparecen varias constantes
que controlan el funcionamiento de las aplicaciones. Estos valores fueron denidos debido
a que proporcionan un comportamiento ms cmodo que otros valores. En particular
las constantes que controlan la relacin entre pixeles arrastrados con el ratn y el giro
del universo virtual son:
41
42
43
44
45
46
47
166
9 Curvas Paramtricas
9.1.
(
x = f (t)
y = g(t)
restricciones
g,
segn la notacin).
se representa as:
(x1 , y1 )
al
(x2 , y2 )
as:
en
en
y:
(x1 , y1 ) = (2, 1)
(x2 , y2 ) = (4, 5)
R = 5, un
a=2y
b = 3.
167
9 Curvas Paramtricas
168
9.2 Continuidad
y,
R alrededor del
x = R cos
z = R sin
y=
eje
y:
scritp de Octave:
1
2
3
4
5
6
9.2.
Continuidad
169
9 Curvas Paramtricas
si
lm f (x) = f (c)
xc
(Lo que a su vez se cumple cuando el lmite por la izquierda y por la derecha son
iguales).
Concepto de
f (x)
curva suave:
[a, b]
si
f (x)
[a, b].
~r(t) es una
en ]a, b[.
curva suave en
[a, b]
si
r~0 (t)
[a, b]
r~0 6= ~0
Continuidad Geomtrica
Se dice que hay continuidad geomtrica de grado 0, denotada por
curvas suaves
S~1
curvas se unen en
S~2
en el punto
con
t = ,
si
S~1 ( ) = S~2 ( ).
entre dos
Es decir, si las
p.
~1
curvas suaves S
G0 ,
G1 ,
entre dos
~2
y S
0
en el punto p con t = , si hay continuidad G (en ese mismo
~0 ( ) = k S~0 ( ), k > 0. Es decir, si las
punto y con el mismo valor de parmetro) y S
1
2
curvas se unen en p y los vectores tangentes tienen la misma direccin y sentido.
Ntese que
G1
S~1
S~2
sea suave.
Continuidad Paramtrica
Se dice que hay continuidad paramtrica de grado 1 (o de primer grado), denotada
por
170
S~2
en el punto
(en
9.2 Continuidad
S~10 ( ) = S~20 ( ).
G1
con
S~1
C 1 G1 ,
Ntese que
C1
pero
Es decir,
C1
k = 1.
G1 ; C 1 .
S~2
es suave en todo
su trayecto.
Se dice que hay continuidad paramtrica de grado n, denotada por
curvas
S~1
S~2
en el punto
con
t=
S~1
S~2
C n,
entre dos
(n)
(n)
S1 ( ) = S2 ( ).
C1
2
suave y velocidad continua, y C all mismo, garantiza velocidad suave y aceleracin
continua. Esto es muy deseable para representar desplazamientos sin irregularidades.
9.2.3. Interpolacin
Interpolacin segn [RAE]: Calcular el valor aproximado de una magnitud en un intervalo, cuando se conocen algunos de los valores que toma a uno
intervalo.
171
9 Curvas Paramtricas
Veamos la gura 9.3. En ella, el intervalo mencionado en la denicin es
los puntos negros. Y el punto griz es un valor aproximado a partir de los puntos negros
que s son conocidos.
9.3.
Spline
comunmente
llamados nodos entre s; y que adems, pueden ser utilizados para interpolar puntos
desconocidos al interior de dicha serie de puntos.
Existen diversas maneras de construir trazadores interpolantes cbicos, cada una con
sus peculiaridades matemticas y geomtricas. En este libro nos concentraremos en un
tipo particular:
dependen simultaneamente de todos los puntos de control, mientras que los segmentos
de las B-spline dependen slo de los puntos de control ms cercanos.
Una tercera diferencia
incidental si se quiere
es que
mucho ms rpido que las Spline, debido a la alta complejidad del algoritmo para calcular
las ltimas.
C2
las prensas.
En la actualidad, los dibujantes y arquitectos usan tiras semirgidas de plstico para
dibujar curvas suaves, necesitando a veces, que interpolen ciertos puntos preestablecidos.
Es el mismo principio que con los fuselajes.
172
Spline
denida en
[a, b]
S
S(x)
1.
Sj (x),
denotado por
en el subintervalo
2.
S(xj ) = f (xj )
3.
0
4. Sj+1 (xj+1 )
00
5. Sj+1 (xj+1 )
=
=
para cada
[xj , xj+1 ]
para cada
j = 0, 1, . . . , n 1;
j = 0, 1, . . . , n;
para cada
j = 0, 1, . . . , n 2;
a)
b)
El trazador
S(x) =
S0 (x)
S1 (x)
x0 x < x1
x1 x < x2
.
.
.
.
.
.
Sj (x) = aj + bj (x xj ) + cj (x xj )2 + dj (x xj )3
claro que Sj (xj ) = aj = f (xj ).
donde
Est
para cada
j = 0, 1, . . . , n 1.
ms cercano por la izquierda. Por otro lado, es de recalcar que las condiciones 3, 4 y 5
garantizan continuidad
C 2.
los nodos.
y que satisface
la siguiente manera (algoritmo adaptado del algoritmo 3.4 de [Burden y Faires 2002, p.
146]):
Valores de entrada:
173
9 Curvas Paramtricas
a)
hi = xi+1 xi
3. PARA
a)
i = 0, 1, ..., n 1
i = 1, 2, ..., n 1
i =
3
hi
(ai+1 ai )
3
hi1
(ai ai1 )
4. HACER :
l0 = 1
0 = 0
z0 = 0
5. PARA
i = 1, 2, ..., n 1
a ) HACER:
cn = 0
7. PARA
j = n 1, n 2, ..., 0
a ) HACER:
cj = zj j cj+1
a
a
h (c
+2c )
bj = j+1hj j j j+13 j
dj =
cj+1 cj
3hj
8. FIN
Valores de salida:
aj , bj , cj , dj
1
para
j = 0, 1, ..., n 1
Los pasos 4, 5, 6 y parte del 7 resuelven un sistema lineal tridiagonal descrito en el algoritmo 6.7 de
[Burden y Faires 2002, p. 408]
174
Spline
x; n; x0 , x1 , . . . , xn
aj , bj , cj , dj
para
j = 0, 1, . . . , n 1
1. INICIO
2. SI
x x0
a)
j=0
b ) MIENTRAS
1)
j =j+1
j<n
c ) SI
1) HACER:
y = aj + bj (x xj ) + cj (x xj )2 + dj (x xj )3
o bien con la regla de Horner:
x,
S .
4. FIN
Valores de salida:
para obtener
(x, y) S
ERROR!.
p+1
puntos uniformemente
[x0 , xn ]).
Valores de entrada:
p; n; x0 , x1 , . . . , xn
aj , bj , cj , dj
para
j = 0, 1, . . . , n 1
1. INICIO
2. HACER:
3. PARA
i=1
k = 0, 1, . . . , p
x
ek = x0 + kp (xn x0 )
MIENTRAS (e
xk > xi )
a ) HACER:
b)
2
Este algoritmo implementa bsqueda lineal, pero podra ser ms eciente con bsqueda binaria.
175
9 Curvas Paramtricas
i=i+1
i=i1
1) HACER:
c ) HACER
d ) HACER:
yek = ai + bi (e
xk xi ) + ci (e
xk xi )2 + di (e
xk xi )3
o bien con la regla de Horner:
yek = ai + (e
xk xi ) (bi + (e
xk xi ) (ci + (e
xk xi )di ))
4. FIN
Valores de salida:
x
e0 , x
e1 , . . . , x
ep
El caso bidimensional
(x0, y0 ) , (x1, y1 ) , . . . , (xn , yn ), en el orden dado, an cuando
no formen una funcin, se usa una nueva variable t en un intervalo [t0, tn ] (tpicamente
[t0 = 0, tn = 1]) con t0 < t1 < . . . < tn (la distribucin puede ser uniforme o no).
Se recomponen los pares ordenados dados como si fueran dos problemas diferentes, as:
x = S (x) (t)
y = S (y) (t).
(x, y) =
(x)
(y)
S
(t),
S
(t)
0
..
t0 t < t1
t1 t < t2
.
.
.
(y)
(x)
(x)
(x)
(x)
(x)
Sj (t) = aj + bj (t tj ) + cj (t tj )2 + dj (t tj )3
(y)
(y)
(y)
(y)
Sj (t) = aj + bj (t tj ) + cj (t tj )2 + dj (t tj )3
para cada
j = 0, 1, ..., n 1.
El caso tridimensional
Para conectar los puntos
una nueva variable
176
en un intervalo
Spline
Se recomponen los pares ordenados dados como si fueran tres problemas diferentes, as:
z=
S (z) (t). As que los valores que interpolan los puntos originales son:
(x, y, z) =
(x)
(y)
(z)
S
(t),
S
(t),
S
(t)
0
0
0
t0 t < t1
t1 t < t2
..
.
.
.
(x)
(y)
(z)
S
tn1 t tn
n1 (t), Sn1 (t), Sn1 (t)
donde
(x)
(x)
(x)
(x)
(x)
Sj (t) = aj + bj (t tj ) + cj (t tj )2 + dj (t tj )3 ,
(y)
(y)
(y)
(y)
(y)
(z)
(z)
(z)
(z)
(z)
Sj (t) = aj + bj (t tj ) + cj (t tj )2 + dj (t tj )3
Sj (t) = aj + bj (t tj ) + cj (t tj )2 + dj (t tj )3
y
para cada
j = 0, 1, ..., n 1.
(x)
(x)
(x)
(x)
t; n; t0 , t1 , . . . , tn ; aj , bj , cj , dj ;
(y)
(y)
(y)
(y)
aj , bj , cj , dj
para
j=
0, 1, ..., n 1
1. INICIO
2. SI
t t0
a)
j=0
b ) MIENTRAS
1)
c ) SI
j =j+1
j<n
177
9 Curvas Paramtricas
1) HACER:
(x)
(x)
(x)
(x)
(y)
(y)
(y)
(y)
x = aj + bj (t tj ) + cj (t tj )2 + dj (t tj )3
y = aj + bj (t tj ) + cj (t tj )2 + dj (t tj )3
2) FIN
3. ERROR: El valor de
t,
S .
4. FIN
Valores de salida:
x; y ,
para obtener
(x, y) S
ERROR!.
p+1
[t0 , tn ]):
Valores de entrada:
(x)
(x)
(x)
(x)
p; n; t0 , t1 , . . . , tn ; aj , bj , cj , dj
(y)
(y)
(y)
(y)
aj , bj , cj , dj
para
j =
0, 1, . . . , n 1
1. INICIO
2. HACER:
3. PARA
i=1
k = 0, 1, . . . , p
= t0 + kp (tn t0 )
tk > ti
MIENTRAS e
a ) HACER: e
tk
b)
i=i+1
i=i1
1) HACER:
c ) HACER
d ) HACER:
(x)
(x)
(x)
(x)
x
ek = ai + bi (e
tk ti ) + ci (e
tk ti )2 + di (e
tk ti )3
(y)
(y)
(y)
(y)
yek = ai + bi (e
tk ti ) + ci (e
tk ti )2 + di (e
tk ti )3
4. FIN
Valores de salida:
x
e0 , x
e1 , . . . , x
ep
178
Spline
En los siguientes archivos se especican la estructura de datos usada y las funciones que
la operarn (ntese que es de propsito general).
Listing 9.1: Archivo de cabecera de funciones de Trazadores
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
TIC_COD_EXITO 0
TIC_MSG_EXITO " xito \ n"
TIC_COD_ERROR_PARAMETROS -1
TIC_MSG_ERROR_PARAMETROS " Error de parmetro ( s ) \ n "
TIC_COD_ERROR_DOMINIO -2
TIC_MSG_ERROR_DOMINIO " Error de dominio \ n "
TIC_COD_ERROR_MEMORIA -3
TIC_MSG_ERROR_MEMORIA " Error de solicitud de memoria dinmica \ n "
# define
# define
# define
# define
# define
H
ALFA
L
MIU
Z
/*
0
1
2
3
4
*/
typedef struct trazadores {
179
9 Curvas Paramtricas
46
// nmero de polinomios
int num_trazadores ;
47
48
49
50
51
52
53
} trazadores ;
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
/*
Entradas :
( ' x ','y ') define los nodos
' num_nodos ' indica el nmero de nodos
Salida :
Se devuelve un puntero a la estructura creada o NULL si hubo error .
*/
trazadores * TIC_crear_trazadores ( double x [] , double y [] , int num_nodos ) ;
/*
Toma el valor 'x ' y calcula su imagen
en funcin del trazador que le corresponda
y la deposita en 'y '
*/
int TIC_calcular ( trazadores * tr , double x , double * y ) ;
/*
Entradas :
( ' x ','y ') define los nodos
Salida :
Se devuelve un codigo de resultado .
Se asume que los arreglos son de la misma longitud entre s
y con el valor ' num_nodos ' usado para crear a ' tr '
*/
int TIC_modificar_trazador ( trazadores * tr , double x [] , double y []) ;
82
83
84
85
86
87
88
89
90
91
92
93
94
95
/*
180
Spline
181
9 Curvas Paramtricas
145
146
147
148
149
150
*/
int TIC_actualizar_trazadorP ( trazadoresP * tr ) ;
void TIC_liberar_memoriaP ( trazadoresP * tr ) ;
void TIC_imprimirP ( trazadoresP * tr , FILE * f ) ;
1
2
3
4
5
6
7
8
10
11
12
13
14
15
/*
'x ', 'y ' y 'a ' requieren ' num_nodos ' elementos ,
'b ', 'c ' y 'd ' slo ' num_nodos -1= num_trazadores ',
pero si 'c ' tiene ' num_nodos ', se simplifica la parte final del
algoritmo
*/
if (( tr - > x = ( double *) malloc (5 * num_nodos * sizeof ( double ) ) ) == NULL ) {
fprintf ( stderr , TIC_MSG_ERROR_MEMORIA ) ;
TIC_liberar_memoria ( tr ) ;
free ( tr ) ;
return NULL ;
}
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
tr - > a = tr - > y
tr - > x
tr - > b = tr - > a
tr - > c = tr - > b
tr - > d = tr - > c
31
32
33
34
35
36
=
+
+
+
+
num_nodos ;
num_nodos ;
num_nodos ;
num_nodos ;
37
38
if (! TIC_modificar_trazador ( tr , x , y ) )
return tr ;
39
40
182
Spline
else {
TIC_liberar_memoria ( tr ) ;
free ( tr ) ;
return NULL ;
}
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
183
9 Curvas Paramtricas
);
// paso 4...
tmp [ L ][0] = 1;
tmp [ MIU ][0] = 0;
tmp [ Z ][0] = 0;
89
90
91
92
93
94
// paso 5...
for ( i =1; i < n ; i ++) {
tmp [ L ][ i ] = 2 * ( tr -> x [ i +1] - tr - > x [i -1]) - tmp [ H ][ i -1]* tmp [ MIU ][
i -1];
tmp [ MIU ][ i ] = tmp [ H ][ i ] / tmp [ L ][ i ];
tmp [ Z ][ i ] = ( tmp [ ALFA ][ i] - tmp [ H ][ i -1]* tmp [ Z ][ i -1]) / tmp [L ][ i ];
}
// paso 6...
tr - > c [ n ] = 0;
95
96
97
98
99
100
101
102
103
// paso 7...
for ( i =n -1; i >=0; i - -) {
tr - > c [ i ] = tmp [ Z ][ i ] - tmp [ MIU ][ i ] * tr - > c[ i +1];
tr - > b [ i ] = ( tr - > a [ i +1] - tr - > a [ i ]) / tmp [ H ][ i ]
- tmp [ H ][ i ] * (tr - > c [ i +1] + 2* tr -> c [ i ]) / 3;
tr - > d [ i ] = ( tr - > c [ i +1] - tr - > c [ i ]) / (3* tmp [ H ][ i ]) ;
}
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
return TIC_COD_EXITO ;
119
if ( tr == NULL || y == NULL ) {
fprintf ( stderr , TIC_MSG_ERROR_PARAMETROS ) ;
return TIC_COD_ERROR_PARAMETROS ;
}
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
184
138
139
140
141
142
143
144
145
146
147
148
149
151
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
150
152
Spline
}
void TIC_liberar_memoria ( trazadores * tr ){
free ( tr - > x ) ;
}
void TIC_imprimir ( trazadores * tr , FILE * f ) {
int i ;
fprintf (f , " \ nTrazadores :\ n ") ;
fprintf (f , " i \ tx_i \ ty_i \ ta_i \ tb_i \ tc_i \ td_i \ n " ) ;
for ( i =0; i <= tr - > num_trazadores ; i ++)
fprintf (f , " %d \ t %3.2 g \ t %3.2 g\ t %3.2 g \ t %3.2 g \ t %3.2 g \t %3.2 g \ n " ,
i , tr - > x [ i ] , tr - >y [ i ] ,
tr - > a [ i ] , tr - > b [ i ] , tr - > c [ i ] , tr - > d [ i ]) ;
}
/* *** Paramtricos ******************** */
trazadoresP * TIC_crear_trazadoresP ( double x [] , double y [] , int num_nodos )
{
trazadoresP * tr = NULL ;
int i ;
if (( tr = ( trazadoresP *) malloc ( sizeof ( trazadoresP ) ) ) == NULL ) {
fprintf ( stderr , TIC_MSG_ERROR_MEMORIA ) ;
return NULL ;
}
tr - > x = tr - > y = tr - > t
= tr - > ax = tr - > bx = tr -> cx = tr - > dx
= tr - > ay = tr - > by = tr -> cy = tr - > dy = NULL ;
/*
'x ', 'y ' y 'a ' requieren ' num_nodos ' elementos ,
'b ', 'c ' y 'd ' slo ' num_nodos -1= num_trazadores ',
185
9 Curvas Paramtricas
pero si 'c ' tiene ' num_nodos ', se simplifica la parte final del
algoritmo ,
por lo que todos tendrn el mismo tamao de ' num_nodos '.
*/
if (( tr - > t = ( double *) malloc (9 * num_nodos * sizeof ( double ) ) ) == NULL ) {
fprintf ( stderr , TIC_MSG_ERROR_MEMORIA ) ;
free ( tr ) ;
return NULL ;
}
185
186
187
188
189
190
191
192
193
194
195
196
tr - > ax = tr - > x =
tr - > t + num_nodos ;
tr - > bx = tr - > ax + num_nodos ;
tr - > cx = tr - > bx + num_nodos ;
tr - > dx = tr - > cx + num_nodos ;
197
198
199
200
201
202
tr - > ay = tr - > y =
tr - > dx +
tr - > by = tr - > ay +
tr - > cy = tr - > by +
tr - > dy = tr - > cy +
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
num_nodos ;
num_nodos ;
num_nodos ;
num_nodos ;
if (! TIC_modificar_trazadorP ( tr , x , y ) )
return tr ;
else {
TIC_liberar_memoriaP ( tr ) ;
free ( tr ) ;
return NULL ;
}
221
222
223
224
225
226
227
228
229
230
231
232
233
186
238
239
241
243
240
242
* x = tr -> ax [ j ] + tmpT
tmpT * tr - > dx [ j ] )
* y = tr -> ay [ j ] + tmpT
tmpT * tr - > dy [ j ] )
return TIC_COD_EXITO ;
Spline
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
187
9 Curvas Paramtricas
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
// paso 5...
for ( i =1; i < n ; i ++) {
tmp [ L ][ i ] = 2 * ( tr -> t [ i +1] - tr - > t [i -1]) - tmp [ H ][ i -1]* tmp [ MIU ][
i -1];
tmp [ MIU ][ i ] = tmp [ H ][ i ] / tmp [ L ][ i ];
tmp [ Z ][ i ] = ( tmp [ ALFA ][ i] - tmp [ H ][ i -1]* tmp [ Z ][ i -1]) / tmp [L ][ i ];
}
// paso 6...
// tmp [ L ][ n ] = 1;
// tmp [ Z ][ n ] = 0;
tr - > cx [ n ] = 0;
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
// paso 7...
for ( i =n -1; i >=0; i - -) {
tr - > cx [ i ] = tmp [ Z ][ i ] - tmp [ MIU ][ i ] * tr - > cx [ i +1];
tr - > bx [ i ] = ( tr - > ax [ i +1] - tr - > ax [ i ]) / tmp [ H ][ i ]
- tmp [ H ][ i ] * (tr - > cx [ i +1] + 2* tr - > cx [ i ]) / 3;
tr - > dx [ i ] = ( tr - > cx [ i +1] - tr - > cx [ i ]) / (3* tmp [ H ][ i ]) ;
}
/* *** en y **************** */
// paso 3...
for ( i =1; i < n ; i ++)
tmp [ ALFA ][ i ] = 3 * (
( tr - > ay [ i +1] - tr - > ay [ i ]) / tmp [ H ][ i ] ( tr - > ay [ i ] - tr - > ay [i -1]) / tmp [ H ][ i -1]
);
// paso 4...
188
328
329
330
331
// paso 5...
for ( i =1; i < n ; i ++) {
tmp [ L ][ i ] = 2 * ( tr - > t [ i +1] - tr - > t [i -1]) - tmp [ H ][ i -1]* tmp [ MIU ][
i -1];
tmp [ MIU ][ i ] = tmp [ H ][ i ] / tmp [ L ][ i ];
tmp [ Z ][ i ] = ( tmp [ ALFA ][ i ] - tmp [ H ][ i -1]* tmp [ Z ][ i -1]) / tmp [ L ][ i ];
}
// paso 6...
// tmp [ L ][ n ] = 1;
// tmp [ Z ][ n ] = 0;
tr - > cy [ n ] = 0;
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
// paso 7...
for ( i =n -1; i >=0; i - -) {
tr - > cy [ i ] = tmp [ Z ][ i ] - tmp [ MIU ][ i ] * tr - > cy [ i +1];
tr - > by [ i ] = ( tr - > ay [ i +1] - tr - > ay [ i ]) / tmp [ H ][ i ]
- tmp [ H ][ i ] * ( tr - > cy [ i +1] + 2* tr -> cy [ i ]) / 3;
tr - > dy [ i ] = ( tr - > cy [ i +1] - tr - > cy [ i ]) / (3* tmp [ H ][ i ]) ;
}
/* ******************* */
351
352
353
354
355
356
Spline
return TIC_COD_EXITO ;
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
Este es el programa principal, que utiliza el cdigo de los dos archivos anteriores. No
189
9 Curvas Paramtricas
es nada espectacular, ni aplicado. Es simplemente para comprender la naturaleza geomtrica de las curvas spline.
Listing 9.3: Programa principal
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
XMIN 0.0
XMAX 15.0
YMIN 0.0
YMAX 3.0
TPASO 0.005
# define TAM 21
static inline int x_real ( double x_virtual ) {
return ( int ) ( ANCHO * x_virtual / XMAX ) ;
}
static inline int y_real ( double y_virtual ) {
return ( int ) ( ALTO * (1.0 - y_virtual / YMAX ) ) ;
}
static inline double x_virtual ( int x_real ) {
return ( XMAX * x_real ) / ANCHO ;
}
static inline double y_virtual ( int y_real ) {
return YMAX * (1.0 - y_real / ( double ) ALTO ) ;
}
// Variables globales
double x [ TAM ] = {0.9 , 1.3 , 1.9 , 2.1 , 2.6 , 3.0 , 3.9 , 4.4 , 4.7 , 5.0 , 6.0 ,
7.0 , 8.0 , 9.2 , 10.5 , 11.3 , 11.6 , 12.0 , 12.6 , 13.0 , 13.3};
double y [ TAM ] = {1.3 , 1.5 , 1.85 , 2.1 , 2.6 , 2.7 , 2.4 , 2.15 , 2.05 , 2.1 ,
2.25 , 2.3 , 2.25 , 1.95 , 1.4 , 0.9 , 0.7 , 0.6 , 0.5 , 0.4 , 0.25};
trazadoresP * tr = NULL ;
int i , j , k , l ;
double tvar , xvar , yvar ;
Uint32 color_fondo , color1 , color2 ;
Uint32 gfxColor ( Uint8 r , Uint8 g , Uint8 b ) {
return
r << 24 |
g << 16 |
190
45
46
47
48
49
50
51
52
// Borra la pantalla
SDL_FillRect ( pantalla , NULL , color_fondo );
54
55
56
57
58
59
60
61
62
63
64
65
// dibujo de la curva
tvar = 0.0;
TIC_calcularP ( tr , tvar , & xvar , & yvar ) ;
i = x_real ( xvar ) ;
j = y_real ( yvar ) ;
for ( tvar = TPASO ; tvar <= 1; tvar += TPASO ) {
if (! TIC_calcularP ( tr , tvar , & xvar , & yvar ) ) {
aalineColor ( pantalla , i , j , k = x_real ( xvar ) , l = y_real ( yvar ) ,
color1 ) ;
i=k; j=l;
}
}
TIC_calcularP ( tr , 1.0 , & xvar , & yvar ) ;
aalineColor ( pantalla , i , j , k = x_real ( xvar ) , l = y_real ( yvar ) , color1 ) ;
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
82
83
84
85
86
87
88
89
90
91
92
|
// este valor es la opacidad del color
// y debe ser mxima para que sea slido
53
81
Spline
191
9 Curvas Paramtricas
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
dibujo ( pantalla ) ;
127
128
while ( corriendo ) {
while ( SDL_PollEvent (& evento ) ) {
switch ( evento . type ) {
case SDL_MOUSEMOTION :{
if ( seleccionado ) {
// actualizar el punto
tr - > x [ i ]= x_virtual ( evento . button .x ) ;
tr - > y [ i ]= y_virtual ( evento . button .y ) ;
TIC_actualizar_trazadorP ( tr ) ;
dibujo ( pantalla ) ;
}
129
130
131
132
133
134
135
136
137
138
139
192
140
break ;
case SDL_MOUSEBUTTONDOWN :{
for ( i =0; i <= tr - > num_trazadores ; i ++) {
if ( evento . button . button == SDL_BUTTON_LEFT && //
si hace clic sobre un nodo ...
(( evento . button . x > x_real ( tr - > x [ i ]) ANCHO_RECTANGULO /2) &&
( evento . button . y > y_real ( tr - > y [ i ]) ANCHO_RECTANGULO /2) &&
( evento . button . x < x_real ( tr - > x [ i ]) +
ANCHO_RECTANGULO /2) &&
( evento . button . y < y_real ( tr - > y [ i ]) +
ANCHO_RECTANGULO /2) )
){
// se selecciona y el ndice queda en 'i '
seleccionado = 1;
// printf (" seleccionado \n ") ;
break ;
}
}
}
break ;
case SDL_MOUSEBUTTONUP :
seleccionado = 0;
break ;
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
2
3
4
5
6
7
8
9
10
case SDL_QUIT :
corriendo = 0;
break ;
SDL_Quit () ;
return 0;
Spline
Listing 9.4: Archivo Makele para la aplicacin
193
9 Curvas Paramtricas
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
. PHONY : limpiartodo
. PHONY : all
# se puede por ejemplo ejecutar en la consola
# lo siguiente :
# ' make limpiartodo ' , etc .
# Nombre del programa ejecutable :
PROG = trazadores
# Un '*.o ' por cada '*.c '
OBJ = tic . o main . o
# Cuando se ejecuta ' make ' , se ejecuta esto :
all : $ ( PROG ) limpiar
$ ( PROG ) : $ ( OBJ )
gcc -o $ ( PROG ) $ ( OBJ ) $ ( LDLIBS ) $ ( LDFLAGS )
# Borra todos los archivos intermedios y de copia de seguridad
limpiar :
$ ( RM ) *~ $ ( OBJ )
# Borra todos los archivos intermedios , de copia de seguridad
# y el programa ejecutable , si es que existe
limpiartodo :
make limpiar
$ ( RM ) $ ( PROG )
194
Spline
el cual debe ocurrir, a partir del inicio de la animacin. Luego se calcula una curva
Spline paramtrica para cada punto de control, como se explica en la seccin 9.3.6 en la
pgina 176, donde el parmetro adicional es el tiempo.
Luego, pueden crearse tantos cuadros como se desee, aplicando un algoritmo basado en
el algoritmo en la pgina 178.
Un ejemplo aplicado, sencillo, puede estudiarse en la aplicacin
editorSplines.py
que
se describe a continuacin:
mite moverlos.
Sobre el fondo blanco, mueve el marco virtual.
CTRL+tecla L Alterna dibujo de las lneas rectas que unen los puntos de control.
CTRL+tecla C Alterna dibujo de los rectngulos que marcan los puntos de control.
CTRL+tecla G Guarda el archivo (interfaz de lnea de comandos).
CTRL+tecla Arriba/Abajo Aumento/disminucin del grueso de los cuadros de control.
tecla Espacio Inicia la animacin desde el primer cuadro hasta el ltimo y regresa al
cuadro en el que se encontraba antes de la animacin.
1
2
3
4
5
6
7
8
9
195
9 Curvas Paramtricas
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
# Borrar la pantalla
if actualizarCurvas :
pantalla . fill ( __colorFondo )
50
51
52
53
# Dibujar la curva :
if __dibujarCurvas and actualizarCurvas :
pass
54
55
56
57
58
59
196
Spline
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
197
9 Curvas Paramtricas
pantalla . fill ( __colorFondo )
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
# Redibujar el buffer
pygame . display . flip ()
119
120
121
# Hacer pausa
pygame . time . delay ( PAUSA )
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
198
Spline
199
9 Curvas Paramtricas
yclic < py + matriz . anchoRectangulo /2 :
l = []
if i == len ( matriz . puntos ) -1: # est al final
for k in range ( len ( matriz . puntos [0]) ) :
l . append ([
matriz . puntos [ i ][ k ][0] , # ponerlo
sobre el anterior
matriz . puntos [ i ][ k ][1]
])
else :
for k in range ( len ( matriz . puntos [0]) ) :
l . append ([
( matriz . puntos [ i ][ k ][0] + matriz .
puntos [ i +1][ k ][0]) /2 ,
( matriz . puntos [ i ][ k ][1] + matriz .
puntos [ i +1][ k ][1]) /2
])
matriz . puntos . insert ( i +1 , l )
dibujar ( matriz , ixSecuencia , pantalla )
break
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
200
Spline
else :
porcentajeDistanciaX = 0.05*( matriz . e . maxxv - matriz . e .
minxv )
porcentajeDistanciaY = 0.05*( matriz . e . maxyv - matriz . e .
minyv )
teclas = pygame . key . get_pressed ()
if evento . button == RUEDA_ABAJO : # acercamiento
if not teclas [ pygame . K_x ] and not teclas [ pygame .
K_y ]:
matriz . e . minxv += porcentajeDistanciaX
matriz . e . maxxv -= porcentajeDistanciaX
matriz . e . minyv += porcentajeDistanciaY
matriz . e . maxyv -= porcentajeDistanciaY
elif teclas [ pygame . K_x ]:
matriz . e . minxv += porcentajeDistanciaX
matriz . e . maxxv -= porcentajeDistanciaX
elif teclas [ pygame . K_y ]:
matriz . e . minyv += porcentajeDistanciaY
matriz . e . maxyv -= porcentajeDistanciaY
else : # alejamiento
if not teclas [ pygame . K_x ] and not teclas [ pygame .
K_y ]:
matriz . e . minxv -= porcentajeDistanciaX
matriz . e . maxxv += porcentajeDistanciaX
matriz . e . minyv -= porcentajeDistanciaY
matriz . e . maxyv += porcentajeDistanciaY
elif teclas [ pygame . K_x ]:
matriz . e . minxv -= porcentajeDistanciaX
matriz . e . maxxv += porcentajeDistanciaX
elif teclas [ pygame . K_y ]:
matriz . e . minyv -= porcentajeDistanciaY
matriz . e . maxyv += porcentajeDistanciaY
dibujar ( matriz , ixSecuencia , pantalla )
# Eliminar un punto
elif evento . type == pygame . MOUSEBUTTONDOWN \
and not ratonPresionado \
and evento . button == BOTON_CEN :
xclic , yclic = evento . pos
for i in range ( len ( matriz . puntos ) ) :
px , py = matriz . e . vr ( matriz . puntos [ i ][ ixSecuencia ])
if xclic > px - matriz . anchoRectangulo /2 and \
yclic > py - matriz . anchoRectangulo /2 and \
xclic < px + matriz . anchoRectangulo /2 and \
yclic < py + matriz . anchoRectangulo /2 :
matriz . puntos . pop ( i )
dibujar ( matriz , ixSecuencia , pantalla )
break
# Detener el movimiento
201
9 Curvas Paramtricas
elif evento . type == pygame . MOUSEBUTTONUP :
if evento . button == ratonPresionado == BOTON_IZQ :
ratonPresionado = 0
punto = None
ixPunto = -1
286
287
288
289
290
291
292
293
294
295
296
297
# Otras acciones
elif evento . type == pygame . KEYDOWN and \
( modificadores & pygame . KMOD_CTRL ) :
if evento . key == pygame . K_LEFT :
if ixSecuencia > 0:
ixSecuencia -= 1
print ( " Cuadro {0}/{1} " . format ( ixSecuencia +1 , len (
matriz . puntos [0]) ) )
dibujar ( matriz , ixSecuencia , pantalla )
elif evento . key == pygame . K_RIGHT :
if ixSecuencia == len ( matriz . puntos [0]) -1:
for l in matriz . puntos :
l . append ([ l [ -1][0] , l [ -1][1] ])
ixSecuencia += 1
print ( " Cuadro {0}/{1} " . format ( ixSecuencia +1 , len (
matriz . puntos [0]) ) )
dibujar ( matriz , ixSecuencia , pantalla )
elif evento . key == pygame . K_l :
__dibujarLineas = not __dibujarLineas
if __dibujarLineas :
print ( " Dibujo de lneas encendido " )
else :
print ( " Dibujo de lneas apagado " )
dibujar ( matriz , ixSecuencia , pantalla )
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
202
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
Spline
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# coding : utf -8
" " " c09 / trazadores_py / splines . py - Modulo para procesar un arreglo Spline
.
Los datos se guardan en archivos xml .
"""
import xml . dom . minidom
__H
__ALFA
__L
__MIU
__Z
=
=
=
=
=
0
1
2
3
4
A = 0
203
9 Curvas Paramtricas
16
17
18
19
20
21
22
23
24
B = 1
C = 2
D = 3
def coeficientesTrazador ( independiente , dependiente ) :
' ' ' Devuelve la matriz de coeficientes
de los 'n ' trazadores interpolantes cbicos paramtricos
para la secuencia de nodos descritos en
la matriz { independiente x dependiente }.
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
# paso 2...
for i in range ( n ) :
tmp [ __H ][ i ] = independiente [ i +1] - independiente [ i ]
51
52
53
54
# paso 3...
for i in range (1 , n ):
tmp [ __ALFA ][ i ] = 3 * (
( coef [ A ][ i +1] - coef [ A ][ i ]) / tmp [ __H ][ i ] - \
( coef [ A ][ i ] - coef [ A ][ i -1]) / tmp [ __H ][ i -1]
)
55
56
57
58
59
60
61
# paso 4...
tmp [ __L ][0] = 1
tmp [ __MIU ][0] = 0
62
63
64
204
Spline
205
9 Curvas Paramtricas
return len ( self . puntos )
def numCuadros ( self ) :
return len ( self . puntos [0])
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
ix_t = 1
for t in [ float ( x ) / self . __numPasos for x in range ( self . __numPasos
+1) ]:
157
158
206
Spline
207
9 Curvas Paramtricas
documentoxml = implementacionxml . createDocument ( None , " splines " ,
None )
raiz = documentoxml . documentElement
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
class Escala () :
" " " Clase de Escalas bidimensionales de ventana completa .
242
243
244
245
246
247
248
208
Spline
def rv ( self , ( xr , yr )) :
' ' ' Convierte un par (x ,y ) Real en su correspondiente Virtual ' ' '
return self . rvx ( xr ) , self . rvy ( yr )
def vr ( self , ( xv , yv )) :
' ' ' Convierte un par (x ,y ) Virtual en su correspondiente Real ' ' '
return self . vrx ( xv ) , self . vry ( yv )
def magnitudvrx ( self , deltaxv ) :
' ' ' Convierte una ' distancia ' deltaxv en la escala Virtual
a su correspondiente ' distancia ' en la escala Real ' ' '
return deltaxv * self . maxxr / ( self . maxxv - self . minxv )
def magnitudvry ( self , deltayv ) :
209
9 Curvas Paramtricas
' ' ' Convierte una ' distancia ' deltayv en la escala Virtual
a su correspondiente ' distancia ' en la escala Real ' ' '
return deltayv * self . maxyr / ( self . minyv - self . maxyv )
295
296
297
298
299
300
301
302
303
304
305
306
9.4.
Curvas de
Bzier
3
Las curvas de Bzier fueron nombradas as en honor de Pierre Bzier , quien las utiliz
para el diseo de carroceras de automviles en 1962 en la empresa Rnault.
P0 , P1 , P2 , P3
~
B(t)
= (1 t)3 P~0 + 3t(1 t)2 P~1 + 3t2 (1 t)P~2 + t3 P~3 , 0 6 t 6 1
(9.1)
es decir:
210
y adems,
(si es que aplica), etc...
9.4 Curvas de
Bzier
Polinomios de Bernstein, y
se denen as:
n
b(i, n, t) =
(1 t)ni ti
i
donde
n
i
n!
i!(ni)! ,
(9.2)
0 6 i 6 n N, 0 6 t 6 1.
es el ndice del
b(0, 3, t) = (1 t)3
b(1, 3, t) = 3t(1 t)2
b(2, 3, t) = 3t2 (1 t)
b(3, 3, t) = t3
Sus grcas pueden apreciarse en la gura 9.4 en la pgina siguiente. Pero su caracterstica ms importante, servir para generar un promedio ponderado puede apreciarse en
la gura 9.5 en la pgina 213: El hecho de que su suma siempre resulte en 1 es lo que
permite usarlos para clculos de promedios ponderados uniformemente espaciados.
Bzier de grado n
~ n (t) =
B
n
X
b(i, n, t)P~i
(9.3)
i=0
De modo que podemos enunciar las siguientes curvas de Bzier de primero, segundo, tercer, cuarto y quinto grado (los coecientes numricos responden al Tringulo de Pascal):
211
9 Curvas Paramtricas
212
9.4 Curvas de
Bzier
213
9 Curvas Paramtricas
B4 (t) = (1 t)4 P0 + 4t(1 t)3 P1 + 6t2 (1 t)2 P2 + 4t3 (1 t)P3 + t4 P4 , 0 6 t 6 1
B5 (t) = (1 t)5 P0 + 5t(1 t)4 P1 + 10t2 (1 t)3 P2 + 10t3 (1 t)2 P3 + 5t4 (1 t)P4 + t5 P5 ,
06t61
Usar curvas de Bzier de grado muy alto no reportan signicativas ventajas respecto de
los de tercer grado desde el punto de vista de la eciencia de los algoritmos necesarios
para manipularlas, pero presentan un comportamiento muy interesante, como puede
verse en la seccin Constructing Bzier Curves de [Wikipedia-Bzier Curve].
Debido a que en general slo se usan curvas de Bzier de tercer grado, el nombre de
estas se ha generalizado, de tal forma que cuando uno se reere sin ms, a Curvas de
G0
Q,
es
Q:
P3 = Q0
G1 , es necesario que haya continuidad G0 , y es necesario
tangente de P sea linealmente dependiente del primero de Q
P2 P3 = k Q0 Q1 , k > 0
Para que haya continuidad
C1
Q:
G1 ,
sea
P2 P3 = Q0 Q1
Para poder, entonces, tener una secuencia de segmentos de Bzier (de tercer grado) que
generen una curva suave, es necesario garantizar que se cumplan estas tres caractersticas
descritas.
214
9.4 Curvas de
Bzier
bezier1 y bezier2.
bezier1
Los siguientes archivos presentan una implementacin de segmentos independientes de
Bzier:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
BEZIER_COD_EXITO 0
BEZIER_MSG_EXITO " xito \ n "
BEZIER_COD_ERROR_PARAMETROS -1
BEZIER_MSG_ERROR_PARAMETROS " Error de parmetro ( s ) \ n "
BEZIER_COD_ERROR_DOMINIO -2
BEZIER_MSG_ERROR_DOMINIO " Error de dominio \ n"
BEZIER_COD_ERROR_MEMORIA -3
BEZIER_MSG_ERROR_MEMORIA " Error de solicitud de memoria dinmica \
*/
typedef struct {
// coordenadas de los cuatro nodos
double x [4];
double y [4];
double z [4];
} segmentoBezier ;
215
9 Curvas Paramtricas
31
32
/*
33
34
35
36
37
38
39
40
*/
int BEZIER_calcular ( segmentoBezier * sb , double t , double *x , double *y ,
double * z ) ;
/*
41
42
43
44
45
46
47
48
49
*/
52
53
50
51
*/
void BEZIER_imprimir ( segmentoBezier * sb , FILE * f ) ;
1
2
3
4
5
6
7
8
double
double
double
double
double
10
11
12
13
14
15
*x =
+
*y =
+
*z =
+
16
17
18
216
_1_t1 = 1 - t ;
_1_t2 = _1_t1 * _1_t1 ;
_1_t3 = _1_t2 * _1_t1 ;
t2 = t* t ;
t3 = t2 * t ;
_1_t3
t3 *
_1_t3
t3 *
_1_t3
t3 *
9.4 Curvas de
19
20
21
22
23
24
25
26
double
double
double
double
double
28
29
30
31
32
33
34
35
37
38
39
40
41
42
43
44
45
46
return BEZIER_COD_EXITO ;
27
36
Bzier
_1_t1 = 1 - t ;
_1_t2 = _1_t1 * _1_t1 ;
_1_t3 = _1_t2 * _1_t1 ;
t2 = t * t ;
t3 = t2 * t ;
El siguiente cdigo es una sencilla aplicacin que usa el cdigo de los archivos anteriores
para permitirle al usuario, como se mencion antes, manipular un solo segmento de
Bzier:
1
2
3
4
5
6
7
8
9
10
11
12
217
9 Curvas Paramtricas
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
// Borra la pantalla
SDL_FillRect ( pantalla , NULL , color_fondo ) ;
53
54
55
56
57
58
59
60
61
tvar = 0.0;
62
218
9.4 Curvas de
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
Bzier
219
9 Curvas Paramtricas
}
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
dibujo ( pantalla ) ;
133
134
while ( corriendo ) {
while ( SDL_PollEvent (& evento ) ) {
switch ( evento . type ) {
case SDL_MOUSEMOTION :{
if ( seleccionado ) {
// actualizar el punto
sb . x [ i ]= x_virtual ( evento . button . x ) ;
sb . y [ i ]= y_virtual ( evento . button . y ) ;
dibujo ( pantalla ) ;
}
}
break ;
case SDL_MOUSEBUTTONDOWN :{
for ( i =0; i <4; i ++) {
if ( evento . button . button == SDL_BUTTON_LEFT && //
si hace clic sobre un nodo ...
(( evento . button . x > x_real ( sb . x [ i ]) ANCHO_RECTANGULO /2) &&
( evento . button . y > y_real ( sb .y [ i ]) ANCHO_RECTANGULO /2) &&
( evento . button . x < x_real ( sb .x [ i ]) +
ANCHO_RECTANGULO /2) &&
( evento . button . y < y_real ( sb .y [ i ]) +
ANCHO_RECTANGULO /2) )
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
220
9.4 Curvas de
){
154
155
156
157
158
159
160
161
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
180
break ;
case SDL_MOUSEBUTTONUP :
seleccionado = 0;
break ;
162
179
Bzier
case SDL_KEYDOWN :
if ( evento . key . keysym . sym == SDLK_SPACE )
dibujo ( pantalla ) ;
break ;
case SDL_QUIT :
corriendo = 0;
break ;
SDL_Quit () ;
return 0;
bezier2
Este programa, presenta una implementacin de una secuencia de tres segmentos de
Bzier, con la funcionalidad de forzar continuidad
C1
0
slo continuidad G .
Veamos su uso:
C1
en las
letra l Alterna el dibujo de las lneas guas entre los nodos de control.
letra c Alterna el dibujo de los cuadros que marca la posicin de los nodos de control.
letra i Imprime en consola las coordenadas de los nodos de control.
letra x Alterna entre forzar continuidad C 1 entre los segmentos (por defecto) o mantener
slo continuidad
G0 .
C1
la posicin de algunos
221
9 Curvas Paramtricas
Los siguientes archivos presentan una implementacin de una secuencia de segmentos
de Bzier de longitud arbitraria:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
*/
typedef struct nodoBezier {
// coordenadas de los tres nodos ,
// el ltimo coincide con el primero
// del siguiente segmento .
double x [3];
double y [3];
double z [3];
struct nodoBezier * ant ;
struct nodoBezier * sig ;
} nodoBezier ;
/*
26
27
28
29
30
31
32
33
34
35
36
37
38
39
42
43
44
45
*/
typedef struct {
// la coordenada del primer punto
// del primer segmento :
double x , y , z ;
nodoBezier primero ;
int numNodos ;
// representa el nmero de estructuras , no de puntos
int continuidad ; // indica si se garantizar la continuidad de 3 er
orden
} listaBezier ;
/*
40
41
*/
void BEZIER_imprimir2 ( listaBezier * lista , FILE * f ) ;
/*
222
9.4 Curvas de
46
47
48
49
50
51
52
53
54
55
56
57
58
/*
60
62
63
64
65
68
69
70
71
/*
/*
73
74
76
77
78
79
/*
81
82
84
85
86
87
88
89
90
*/
int BEZIER_calculardeLista ( listaBezier * lista , double t , double *x ,
double *y , double * z ) ;
80
83
*/
void BEZIER_liberarLista ( listaBezier * lista ) ;
72
75
La longitud de los arreglos de entrada 'x ', 'y ' y 'z '
se asume a '3* lista - > numNodos +1 '.
Se asume que la ' lista ' ya ha sido creada .
*/
int BEZIER_modificarLista ( listaBezier * lista , double *x , double *y ,
double * z ) ;
66
67
*/
int BEZIER_modificarLista2d ( listaBezier * lista , double *x , double * y ) ;
59
61
Bzier
*/
int BEZIER_calculardeLista2d ( listaBezier * lista , double t , double *x ,
double * y ) ;
/*
223
9 Curvas Paramtricas
91
92
/*
93
94
95
96
97
98
*/
int BEZIER_recuperarNodo2d ( listaBezier * lista , int ix , double *x , double
*y);
/*
99
100
101
102
103
104
107
108
109
110
/*
/*
112
114
115
116
117
/*
119
121
122
123
124
125
126
Copia los valores de todos los puntos a los arreglos 'x ' y 'y '.
Estos arreglos deben contener suficiente espacio .
Asume que los puntos son coplanares en xy .
*/
int BEZIER_recuperarNodos2d ( listaBezier * lista , double *x , double * y ) ;
118
120
Copia los valores de todos los puntos a los arreglos 'x ', 'y ' y 'z '.
Estos arreglos deben contener suficiente espacio .
*/
int BEZIER_recuperarNodos ( listaBezier * lista , double *x , double *y ,
double * z ) ;
111
113
*/
int BEZIER_recuperarNodo ( listaBezier * lista , int ix , double *x , double *y
, double * z ) ;
105
106
*/
int BEZIER_acomodarContinua ( listaBezier * lista ) ;
127
128
129
130
131
132
133
134
135
136
137
/*
* Agrega un segmento nuevo de Bzier
* al final de la Lista especificada
* */
int BEZIER_agregarNodoNuevoaLista ( listaBezier * lista , int valorInicial ) ;
/*
* Agrega un segmento especificado de Bzier
* al final de la Lista especificada
224
9.4 Curvas de
138
139
* */
int BEZIER_agregarNodoaLista ( listaBezier * lista , nodoBezier * nb ) ;
1
2
3
4
5
6
7
8
9
10
11
14
15
16
17
18
19
20
21
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
13
23
12
22
Bzier
225
9 Curvas Paramtricas
temp - > sig = NULL ;
temp - > ant = &( lista - > primero ) ;
} else { // ya hay un nodo anterior en ' temp2 '
temp - > sig = NULL ;
temp - > ant = temp2 ;
temp2 - > sig = temp ;
temp2 = temp ;
}
temp - > x [0]= temp - > x [1]= temp - > x [2]=
temp - > y [0]= temp - > y [1]= temp - > y [2]= valorInicial ;
temp = NULL ;
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
lista - > x = x [ i ];
lista - > y = y [ i ++];
lista - > z = 0.0;
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
}
return BEZIER_COD_EXITO ;
for ( temp = &( lista - > primero ) ; temp != NULL ; temp = temp - > sig )
for ( j =0; j <3; j ++) {
temp - > x [ j ] = x [ i ];
temp - > y [ j ] = y [ i ++];
temp - > z [ j ] = 0.0;
}
if ( lista - > continuidad )
BEZIER_acomodarContinua ( lista ) ;
return BEZIER_COD_EXITO ;
84
lista - > x = x [ i ];
lista - > y = y [ i ];
lista - > z = z [ i ++];
85
86
87
88
for ( temp = &( lista - > primero ) ; temp != NULL ; temp = temp - > sig )
for ( j =0; j <3; j ++) {
temp - > x [ j ] = x [ i ];
89
90
91
226
9.4 Curvas de
temp - > y [ j ] = y [ i ];
temp - > z [ j ] = z [ i ++];
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
Bzier
}
if ( lista - > continuidad )
BEZIER_acomodarContinua ( lista ) ;
return BEZIER_COD_EXITO ;
t1 = t ;
t2 = t * t ;
t3 = t2 * t ;
_1_t1 = 1 - t ;
_1_t2 = _1_t1 * _1_t1 ;
_1_t3 = _1_t1 * _1_t2 ;
227
9 Curvas Paramtricas
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
i ++;
for ( temp = temp - > sig ; temp != NULL ; temp = temp - > sig )
if ( i == ixBezier ) {
nb = temp ;
break ;
}
else i ++;
// aqu se asume que siempre lo encuentra ...
* x = _1_t3 * nb - > ant - > x [2] + 3* t1 * _1_t2 * nb - > x [0] + 3* t2 * _1_t1 *
nb - > x [1] + t3 * nb - > x [2];
* y = _1_t3 * nb - > ant - > y [2] + 3* t1 * _1_t2 * nb - > y [0] + 3* t2 * _1_t1 *
nb - > y [1] + t3 * nb - > y [2];
return BEZIER_COD_EXITO ;
159
160
161
162
163
164
165
166
167
168
169
double
double
double
double
double
double
170
171
172
173
174
175
176
t1 = t;
t2 = t* t ;
t3 = t2 * t ;
_1_t1 = 1 - t ;
_1_t2 = _1_t1 * _1_t1 ;
_1_t3 = _1_t1 * _1_t2 ;
177
178
179
180
181
182
228
+ 3* t2 * _1_t1 * nb - >
+ 3* t2 * _1_t1 * nb - >
+ 3* t2 * _1_t1 * nb - >
se calcular 't '
9.4 Curvas de
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
Bzier
i ++;
for ( temp = temp - > sig ; temp != NULL ; temp = temp - > sig )
if ( i == ixBezier ) {
nb = temp ;
break ;
}
else i ++;
// aqu se asume que siempre lo encuentra ...
* x = _1_t3 * nb - > ant - > x [2] + 3* t1 * _1_t2 * nb - > x [0] + 3* t2 * _1_t1 *
nb - > x [1] + t3 * nb - > x [2];
* y = _1_t3 * nb - > ant - > y [2] + 3* t1 * _1_t2 * nb - > y [0] + 3* t2 * _1_t1 *
nb - > y [1] + t3 * nb - > y [2];
* z = _1_t3 * nb - > ant - > z [2] + 3* t1 * _1_t2 * nb - > z [0] + 3* t2 * _1_t1 *
nb - > z [1] + t3 * nb - > z [2];
return BEZIER_COD_EXITO ;
229
9 Curvas Paramtricas
en las uniones de los
*/
if ( temp - > ant ) {
temp - > ant - > x [1] =
- > x [2]) ;
temp - > ant - > y [1] =
- > y [2]) ;
temp - > ant - > z [1] =
- > z [2]) ;
}
228
229
230
231
232
233
234
segmentos de Bzier .
temp - > ant - > x [2] - (x - temp - > ant
temp - > ant - > y [2] - (y - temp - > ant
temp - > ant - > z [2] - (z - temp - > ant
}
break ;
case 1:{
/*
Desplazar el primer punto
del nodo siguiente ,
si hay nodo siguiente .
Esto es para garantizar la colinealidad
en las uniones de los segmentos de Bzier .
*/
if ( temp - > sig ) {
temp - > sig - > x [0] = temp - > x [2] - (x - temp - > x [2]) ;
temp - > sig - > y [0] = temp - > y [2] - (y - temp - > y [2]) ;
temp - > sig - > z [0] = temp - > z [2] - (z - temp - > z [2]) ;
}
}
break ;
case 2:{
/*
Desplazar el punto anterior
y el siguiente , si es que
hay un siguiente .
*/
if ( temp - > sig ) {
temp - > x [1] += x - temp - > x [2];
temp - > y [1] += y - temp - > y [2];
temp - > z [1] += z - temp - > z [2];
temp - > sig - > x [0] += x - temp - > x [2];
temp - > sig - > y [0] += y - temp - > y [2];
temp - > sig - > z [0] += z - temp - > z [2];
}
}
break ;
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
}
temp - > x [ j ]= x ;
temp - > y [ j ]= y ;
temp - > z [ j ]= z ;
return BEZIER_COD_EXITO ;
268
269
270
271
272
}
else i ++;
273
274
230
9.4 Curvas de
275
276
277
278
279
280
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
return BEZIER_COD_ERROR_DOMINIO ;
281
299
Bzier
if ( ix ==0) {
* x = lista - > x ;
* y = lista - > y ;
return BEZIER_COD_EXITO ;
}
i ++;
for ( temp = &( lista - > primero ) ; temp != NULL ; temp = temp - > sig )
for ( j =0; j <3; j ++)
if ( i == ix ) {
* x = temp - > x [ j ];
* y = temp - > y [ j ];
return BEZIER_COD_EXITO ;
}
else i ++;
return BEZIER_COD_ERROR_DOMINIO ;
231
9 Curvas Paramtricas
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
351
352
353
354
355
356
357
358
359
360
362
363
364
365
366
x [ i ] = lista - > x ;
y [ i ] = lista - > y ;
z [ i ++]= lista - > z ;
for ( temp = &( lista - > primero ) ; temp != NULL ; temp = temp - > sig )
for ( j =0; j <3; j ++) {
x [ i ] = temp - > x [ j ];
y [ i ] = temp - > y [ j ];
z [ i ++]= temp - > z [ j ];
}
return BEZIER_COD_EXITO ;
350
361
}
else i ++;
return BEZIER_COD_ERROR_DOMINIO ;
x [ i ] = lista - > x ;
y [ i ++]= lista - > y ;
for ( temp = &( lista - > primero ) ; temp != NULL ; temp = temp - > sig )
for ( j =0; j <3; j ++) {
x [ i ] = temp - > x [ j ];
y [ i ++]= temp - > y [ j ];
}
return BEZIER_COD_EXITO ;
367
368
369
for ( temp = (&( lista - > primero ) ) -> sig ; temp != NULL ; temp = temp - > sig ){
/*
370
371
232
9.4 Curvas de
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
Bzier
return BEZIER_COD_EXITO ;
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
return BEZIER_COD_EXITO ;
421
233
9 Curvas Paramtricas
for ( temp2 =&( lista - > primero ) ; temp2 - > sig ; temp2 = temp2 - > sig ) ;
422
423
424
425
426
427
428
429
430
431
return BEZIER_COD_EXITO ;
C1
G0 :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
Bzier
XMIN 0.0
XMAX 15.0
YMIN 0.0
YMAX 15.0
TPASO 0.01
# define TAM 10
// Debe cumplirse la siguiente relacin :
// numPuntos = 3* numNodos +1;
double x [ TAM ] = {1.3 , 3.0 , 6.0 , 5.0 , 4.0 , 5.0 , 6.0 , 8.0 , 10.0 , 9.0};
double y [ TAM ] = {1.3 , 5.0 , 7.4 , 9.2 , 2.0 , 3.0 , 4.0 , 5.0 , 7.0 , 4.0};
listaBezier lista ;
23
24
25
26
27
28
29
30
31
32
33
234
9.4 Curvas de
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
Bzier
79
235
9 Curvas Paramtricas
// dibujar lneas entre los nodos
if ( mostrar_lineas )
for ( i =1; i < TAM ; i ++) {
lineColor ( pantalla ,
x_real ( x [i -1]) , y_real ( y [i -1]) ,
x_real ( x [ i ]) , y_real ( y [ i ]) , color_lineas ) ;
}
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
int corriendo = 1;
int seleccionado = 0;
114
115
116
mostrar_cuadrados = 1;
mostrar_lineas = 1;
117
118
119
120
121
122
123
124
125
126
127
236
9.4 Curvas de
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
Bzier
237
9 Curvas Paramtricas
175
176
177
){
178
179
180
181
182
183
184
185
break ;
case SDL_MOUSEBUTTONUP :
seleccionado = 0;
break ;
186
187
188
189
190
case SDL_KEYDOWN :
switch ( evento . key . keysym . sym ) {
case SDLK_i : {
BEZIER_imprimir2 (& lista , stdout ) ;
}
break ;
case SDLK_l : {
mostrar_lineas = ! mostrar_lineas ;
dibujo ( pantalla ) ;
}
break ;
case SDLK_c : {
mostrar_cuadrados = ! mostrar_cuadrados ;
dibujo ( pantalla ) ;
}
break ;
case SDLK_r : {
dibujo ( pantalla ) ;
}
break ;
case SDLK_x : {
lista . continuidad = ! lista . continuidad ;
if ( lista . continuidad ) {
BEZIER_acomodarContinua (& lista ) ;
BEZIER_recuperarNodos2d (& lista , x , y ) ;
}
dibujo ( pantalla ) ;
}
break ;
}
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
238
9.4 Curvas de
break ;
221
222
case SDL_QUIT :
corriendo = 0;
break ;
223
224
225
226
227
228
229
230
231
232
Bzier
SDL_Quit () ;
return 0;
editorBezier.py
Este programa fue implementado con el doble propsito de servir como ejemplo para
este captulo y para hacer la parte principal de la cartula de este libro.
Sirve para crear una serie de Secuencias de segmentos de Bzier. Las opciones de interaccin son:
mite moverlos.
Sobre el fondo blanco, mueve el marco virtual de todas las secuencias.
CTRL+tecla L Alterna dibujo de las lneas rectas que unen los puntos de control.
CTRL+tecla C Alterna dibujo de los rectngulos que marcan los puntos de control.
CTRL+tecla A Agrega una nueva Secuencia de segmentos de Bzier de manera aleatoria.
CTRL+tecla X
C1
0
o mantener slo continuidad G . Cuando se activa la continuidad
C1
la posicin
9 Curvas Paramtricas
9.5.
Las curvas de Bzier no requieren de clculos previos para el clculo de los puntos que
la componen, a diferencia de las curvas splines. Adems, el clculo de cada punto no
requiere una bsqueda como en el caso de splines.
Esto permite que las curvas de Bzier sean ms atractivas para el uso de diseo interactivo que las splines. Aunque hay que considerar que los puntos de control de Bzier,
no pertenecen todos a la curva generada, y en consecuencia, su uso es menos natural
que sus contrapartes splines. Adems, el usuario tendr que distinguir cules puntos de
control s interpolan la curva y cules controlan los vectores tangentes. Para poder lograr
esto, habr que enriquecer ms la interfaz, lo que requiere clculos adicionales.
Para que un usuario no matemtico modele algo usando splines, slo tendra que aprender a agregar y eliminar puntos de control de la curva, mientras que si usa Bzier, tendr
que pasar por un proceso de aprendizaje mayor para entender los efectos de cambiar los
puntos de control sobre las curvas o supercies.
9.6.
Ejercicios
(t) = 2ti + 52 t2 j para 0 6 t 6 1 y sea (t) = (4t 2) i t4 + 3t2 32 j
5
para 1 6 t 6 2. Observe que (1) = 2,
2 = (1), de manera que ambas curvas
0
se unen con continuidad C .
2. Sea
a ) Graque
b)
c)
f (t) =
1 4
2 3
7 2
1
5 3
2 t + 318
j , con 0 6 t 6 1 y
t
+
t
+
t
i
+
t
t
2
9
6
3
3
3 3
2
16
12
sin(2t) + 9 i 3 cos 3 t j , con 1 6 t 6 2 tienen continuidad
g(t) =
G1 cuando
240
se unen en
f (1) = g(1).
C1
9.6 Ejercicios
4. Modique el programa presentado en la subseccin 9.3.7 en la pgina 178, para
que permita al usuario agregar y eliminar nodos de control.
5. Modique el programa presentado en el apartado bezier2 de la subseccin 9.4.6 en
la pgina 221, para que adems de permitir elegir entre mantener continuidad
y
G0
G1
(sin
C 1,
C1
obviamente).
241
9 Curvas Paramtricas
242
10 Supercies paramtricas
10.1.
x = x(s, t)
y = y(s, t) , restricciones
z = z(s, t)
Veamos algunos ejemplos de supercies paramtricas:
Cilindro hueco de altura
R:
x = R cos
z = R sin
y=v
y radio
0 2
0vH
R = 4 y H = 6,
plot3d([4*cos(th),v,4*sin(th)], [th, 0, 2* %pi], [v,
0, 6]);
de Maxima.
x = (r cos + R) cos
0 2
y = r sin
,
0 2
z = (r cos + R) sin
243
10 Supercies paramtricas
244
10.2 Ejercicios
R y un ancho de la cinta A:
u
x = Av sin 2 + R cos u
0 u 2
y = Av sin u2 + R sin u ,
1
1
2 v 2
u
z = Av cos 2 + R
A=2
R = 5,
generada con el
script de Maxima:
1
2
3
4
5
6
A: 2$
R: 5$
x : ( A * v * sin ( u /2) + R ) * cos ( u ) $
y : ( A * v * sin ( u /2) + R ) * sin ( u ) $
z : A * v * cos ( u /2) + R$
plot3d ([ x ,y , z ] , [u , 0 ,2* % pi ] , [v , -1/2 , 1/2] , [ ' grid , 60 ,20]) ;
~r(r, t) es una curva suave en {[a, b] [c, d]} si la derivada direccional Du~r(s, t) es continua
en todos los puntos de {[a, b] [c, d]} para cualquier direccin u
.
10.2.
Ejercicios
245
10 Supercies paramtricas
base en el plano
xy
y la punta en
(0, 0, 15).
246
11 Mallas Poligonales
Una manera alternativa de modelar cuerpos tridimensionales arbitrarios, es aproximando
sus superces con lo que se conoce como Mallas Poligonales. Las mallas poligonales son
conjuntos de puntos, aristas (lneas) y polgonos relacionados entre s con el objetivo de
aproximar un cuerpo o una supercie.
Existen diversas maneras de implementar tales estructuras de datos. Algunas requieren
ms memoria que otras, algunas requieren algoritmos ms sosticados para operarlas que
otras, algunas posibilitan ciertos anlisis que otras no. Todo depender de las necesidades
concretas de la aplicacin a desarrollar.
En este punto es conveniente volver a tener frescos los conceptos de geometra analtica vectorial relacionados con planos. Tambin recomendamos leer el captulo 14 en la
pgina 283 para poder comprender mejor las descripcines de las estructuras de datos.
A continuacin se presentarn algunas representaciones genricas diferentes de mallas
poligonales (las primeras tres, adaptadas de [Foley et al., p. 366-367]):
11.1.
Representacin explcita
247
11 Mallas Poligonales
248
11.2.
o aristas
polgonos, se dibujaran dos veces (en realidad tantas veces como polgonos unan un
mismo par de vrtices). Entonces, para una gura compleja, habra que ejecutar el
cdigo de dibujo de lneas una alta cantidad de veces sin necesidad, porque ya habran
249
11 Mallas Poligonales
se hace slo
una modicacin y automticamente todos los polgonos que incluyen tal punto estarn
actualizados.
11.3.
250
o arista
ser dibujada
slo una vez, ya que el recorrido del algoritmo de dibujo puede hacerse sobre la lista
de aristas y no sobre la de polgonos. Adems no hay redundancia de vrtices. Por otro
251
11 Mallas Poligonales
252
11.4.
Como se dijo al principio del captulo, existen diversas maneras de modelar cuerpos
tridimensionales y que el modelo a implementar depende de las necesidades concretas
de las aplicaciones. As, la estructura de datos usada para implementar las aplicaciones
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
253
11 Mallas Poligonales
transformaciones3D.jar
18
19
20
21
22
23
24
25
26
27
28
29
30
31
33
34
35
36
37
38
39
40
41
42
perspectiva3D.jar
17
32
puntos [ i
+ m.e
puntos [ i
+ m.e
puntos [ i
+ m.e
}
class VerticeSimple {
Punto3d puntoReal , puntoProyectado ;
public VerticeSimple () {
puntoProyectado = new Punto3d (0 f ,0 f ,0 f ) ;
}
}
class AristaSimple {
VerticeSimple punto1 , punto2 ;
255
11 Mallas Poligonales
43
44
11.5.
Ejercicios
256
12.1.
1
2
3
4
257
Figura 12.1: Fractal natural: Brassica oleracea, un Romanescu fresco, cortesa del programa Botany Photo of the Day de http://www.ubcbotanicalgarden.org/.
Figura 12.2: Las ramas de los rboles siguen leyes fractales de distribuin volumtrica.
258
Figura 12.3: Las hojas de casi todos los helechos tienen la caracterstica de la autosimilitud nita.
259
Figura 12.5: Espiral de satlites con islas de Julia, cortesa del Dr. Wolfgang Beyer
Figura 12.6: Acercamiento del conjunto de Mandelbrot realzado por el autor de este
libro con el programa XaoS.
260
Figura 12.7: Otro acercamiento del conjunto de Mandelbrot realizado con la aplicacin
mandelbrot.out
261
12.2.
El copo de nieve de
El copo de nieve de
von Koch 5
Niels Fabian Helge von Koch, es una gura sencilla que exhibe
Podemos apreciar una representacin hecha con la aplicacin XaoS mencionada anteriormente en la gura 12.8.
262
12.3 El tringulo de
12.3.
El tringulo de
Sierpiski
Sierpiski 6
Sierpiski y la carpeta de Sierpiski. Estas pueden verse en las guras 12.9 y 12.10. Las
ideas bsicas de estas guras planas se pueden extender para guras tridimensionales,
como vemos en la gura 12.11 en la pgina 266.
12.4.
Los Conjuntos
Julia-Fatou
12.4.1. Denicin
Llamados as, en honor de
son guras concretas, sino una familia de guras fractales, con todo el esplendor de la
expresin. Se obtienen al analizar el acotamiento de ciertas funciones recursivas en el
dominio de
z,
fc (z)
con semilla
c C,
denotado por
Jc (f ),
es el
z0 = z
zn+1 = fc (zn )
Jc (f )
con
fc (z) = z + c.
Fc (f ) es el complemento de Jc (f ), Fc (f ) = C Jc (f ).
Fc (f ) contiene todos los z para los que la sucesin antes descrita, no es acotada.
z
/ Jc (f ).
|zn | > 2
entonces
consideraremos que dicha sucesin es acotada. Vale recalcar que mientras mayor sea el
mximo, ms nos acercaremos al conjunto real (el cual, por supuesto, es imposible de
alcanzar).
A continuacin presentamos algunas imgenes del programa
las ventanas aparecen los valores
julia.out.
En el ttulo de
12.14 y 12.15.
lase sierpiski
263
264
Julia-Fatou
265
266
Julia-Fatou
julia.out
267
268
julia.out
Julia-Fatou
julia.out
269
270
julia.out
Julia-Fatou
12.4.2. Implementacin
En el material adjunto a este libro se encuentra la aplicacin
julia.out,
cuyo fun-
clic izquerdo
El primer clic, dene una de las esquinas de un rectngulo que ser usado
como rea de aumento. El segundo clic, dene la esquina opuesta del rectngulo y
se efecta el aumento correspondiente.
clic derecho
i/6.
Debido a la alta complejidad del algoritmo que decide si cada pixel pertenece o no al
conjunto, la respuesta de la aplicacin no es inmediata. Dependiendo del procesador en
el que se ejecute, la aplicacin puede ser un poco lenta para responder a la rueda del
ratn.
A continuacin se presenta una de las funciones de dibujo de la aplicacin mencionada
(tomada del archivo
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
calculos.c):
271
12.5.
Conjunto de
Mandelbrot
12.5.1. Denicin
En honor a
M,
cC
z0 = 0 + 0i
zn+1 = zn + c
Y se utilizan los mismos criterios de seleccin que para los conjuntos Julia.
Presentamos la forma clsica de este famoso conjunto fractal en la gura 12.16 y una
versin estilizada con XaoS en la gura 12.17.
12.5.2. Implementacin
En el material adjunto a este libro se encuentra la aplicacin
mandelbrot.out,
cuyo
clic izquerdo
El primer clic, dene una de las esquinas de un rectngulo que ser usado
como rea de aumento. El segundo clic, dene la esquina opuesta del rectngulo y
se efecta el aumento correspondiente.
clic derecho
272
i/8.
12.5 Conjunto de
Mandelbrot
mandelbrot.out
273
Figura 12.17: Conjunto Mandelbrot con suavizacin de color interna y externa, generado con la aplicacin XaoS
274
12.6 Ejercicios
El algoritmo que decide si cada pixel pertenece o no al conjunto de Mandelbrot es de la
misma complejidad que el del caso de los conjuntos de Julia, por lo que la respuesta de
la aplicacin tiene en general, la misma velocidad.
A continuacin se presenta una de las funciones de dibujo de la aplicacin mencionada
(tomada del archivo
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
calculos.c):
numPasos = 0;
z . r = z .i = 0.0;
while ( numPasos < MAXPASOS && ( sq ( z . r ) + sq ( z . i ) < LIMITEMODULO2 ) )
{
CX_suma ( CX_cuadrado (& z ) , & c ) ;
numPasos ++;
}
if ( numPasos == MAXPASOS ) {
pixelColor ( pantalla , j , i , COLOR_ADENTRO ) ;
}
else
pixelColor ( pantalla , j , i , colorGfx (
numPasos *256/ MAXPASOS ,
( MAXPASOS - numPasos ) *256/ MAXPASOS ,
numPasos *256/ MAXPASOS ) ) ;
12.6.
Ejercicios
Jc (f ).
275
276
Parte II
Otras Yerbas
277
1
2
3
4
5
6
7
8
/* c13 / principal . c
* */
# include " otro . h "
int main ( int argc , char * argv []) {
funcion () ;
return 0;
}
1
2
3
2
3
4
5
6
7
8
9
/* c13 / otro . h
* */
int funcion ( void ) ;
Listing 13.3: Otro cdigo fuente
/* c13 / otro . c
* */
# include " otro . h "
# include < stdio .h >
int funcion ( void ) {
printf ( " hola a todos y todas \ n " ) ;
return 0;
}
make
automtica:
Debemos crear en ese mismo directorio un archivo
Makefile
para orientar a
make.
El
279
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# c13 / Makefile
# Esto es un comentario
# El comando para borrar archivos
RM = / bin / rm -f
# Un '*.o ' por cada '*.c ' que pertenezca al proyecto
OBJS = principal . o otro . o
# Nombre del programa ejecutable :
PROG = programa
# Esto indica que los siguientes identificadores ,
# no son archivos , sino comandos de make :
. PHONY : limpiar
. PHONY : limpiartodo
. PHONY : all
# se puede , por ejemplo , ejecutar en la consola
# lo siguiente :
# '$ make limpiartodo ' , etc .
# Cuando se ejecuta '$ make ' , se evalan
# las reglas '$ ( PROG ) ' y ' limpiar ':
all : $ ( PROG ) limpiar
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
La presencia de dicho archivo y su contenido nos permiten ejecutar las siguientes rdenes
en esa carpeta:
$ make limpiar
Borra los archivos de copia de seguridad que se hayan creado y tambin borra
los archivos de cdigo objeto intermedios (los
280
*.o)
*.c).
$ make limpiartodo
Invoca la instruccin anterior y adems borra el programa ensamblado o ejecutable
(su nombre depende de lo que hayamos puesto en la variable
$ make
Se ejecuta lo que hayamos indicado en la regla
all.
PROG.
PROG, que a su vez invoca la compilacin individual de cada archivo fuente (los *.c)
y posteriormente invoca el ensamblaje de estos con el comando gcc. Posteriormente
invoca la regla limpiar.
Esta pequea gua no pretende ser altamente exhaustiva. Simplemente pretende orientar
para la compilacin asistida en proyectos de programacin en lenguaje C estndar de
mediana escala en ambientes tipo UNIX. Si se necesita mayor detalle o explicacin, por
favor rerase el lector a la documentacin apropiada. Por ejemplo:
$ man make
O en los sitios siguientes:
http://www.chuidiang.com/clinux/herramientas/makele.php
http://www.calcifer.org/documentos/make/makele.html
http://atc1.aut.uah.es/lsotm/Makele.htm
http://en.wikipedia.org/wiki/Make_(software)
http://www.opussoftware.com/tutorial/TutMakele.htm
281
282
14.1.
Notacin de clases
En UML una clase se representa como un rectngulo con tres espacios. En el primero
va el nombre de la clase, en el segundo sus atributos y en el tercero sus operaciones.
Veamos un ejemplo en la gura 14.1.
La clase se llama
retorna un String y recibe dos parmetros: semilla que es entero con valor por defecto
de 3, y objeto de tipo Estructura.
283
Los niveles de acceso pblico y privado son los ms usuales en los lenguajes de programacin orientados a objetos, pero algunos lenguajes denen otros niveles de acceso. En el
caso de Java, tambin existen los niveles de acceso protegido y de paquete, representados
por los signos # y ~ respectivamente.
Por otro lado, la informacin de los atributos y de las operaciones de las clases a veces
no es relevante o no es conveniente mostrarla (generalmente por cuestiones de espacio),
por lo que pueden omitirse esas secciones y mostrar nicamente un rectngulo con el
nombre de la clase, como vemos en la gura 14.2.
14.2.
En la gura 14.3 se presenta un resumen de la notacin bsica de asociaciones en diagramas de clases. Veamos cada uno de ellos:
1. Indica simplemente que hay una relacin uno-a-uno entre una instancia de
y una de
Clase1
Clase2.
2. Indica que hay una relacin uno-a-uno entre las instancias, pero agrega semntica
a la relacin: indica que las instancias de
Clase2.
3. Indica que hay una relacin uno-a-uno entre las clases, y el nombre de la relacin,
pero sin indicar la direccin de la relacin.
4. Indica que una instancia de
muchas instancias de
referencias a instancias de
Clase1.
a instancias de
Clase1.
6. Indica que hay una relacin uno-a-uno, pero indicando que para las instancias de
284
dichas colecciones.
8. Indica que una instancia de
y que las instancias de
Clase1.
Los diagramas de clase no obligan al diseador a especicar cmo, en concreto, se implementarn tales referencias o colecciones de referencias. Se podran implementar con
arreglos, con listas, rboles, grafos, etc.
En la gura 14.4 se presentan ms tipos de asociaciones en diagramas de clases:
1. Indica una agregacin, en la que las instancias de
286
Clase2, y
Clase2, y
referencia a ellas.
3. Indica una composicin, que es una agregacin muy restrictiva, ya que indica que
si la instancia compuesta de
Hay ms tipos de relaciones en la notacin UML, pero como el ttulo de este captulo
dice, es slo una untadita.
14.3.
Notacin de objetos
Las instancias de una clase se representan como rectngulos con dos partes. La primera
tiene el siguiente formato:
<nombreInstancia>: <nombreClase>
La otra parte est reservada para los valores de sus atributos. Al igual que en el caso de
los diagramas de clases, esta parte se puede obviar cuando no es necesaria.
Podemos ver un ejemplo de un diagrama de objetos en la gura 14.5, en la que hay dos
instancias de la clase
Clase.
287
En los diagramas de objetos tambin se pueden incluir las referencias entre s, con o sin
nombre y con o sin direccin, segn sea el caso, tal como se ve en las guras 11.3, 11.5
y 11.8.
288
Parte III
Apndices
289
transformaciones3D.jar
perspectiva3D.jar.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/* cA / Controlador . java
* Objeto controlador
*/
import java . awt . Graphics ;
import java . awt . event .*;
/*
* Controlador de la aplicacin
*/
public class Controlador {
/* *
* Funcin principal independiente de instancias .
*/
public static void main ( String args []) {
new Controlador ( args ) ;
291
17
18
Ventana vista ;
Modelo modelo ;
19
20
21
/* *
22
Hilo principal
*/
public Controlador ( String args []) {
vista = new Ventana ( this ) ;
modelo = new Universo3D () ;
23
24
25
26
27
28
// mostrar la ventana
vista . setVisible ( true ) ;
System . out . println ( " Iniciando aplicacin " ) ;
29
30
31
32
// accin principal o
// conjunto de acciones principales
modelo . hacerAlgo () ;
33
34
35
36
37
38
39
40
41
/* *
* Simple delegacin del proceso
* */
public void dibujar ( Graphics g ) {
modelo . dibujar ( g ) ;
}
42
43
44
45
46
47
48
/* *
* Implementar los eventos generados desde la vista .
* Como el de cerrar la ventana :
* */
public WindowAdapter AdaptadorVentana = new WindowAdapter () {
public void windowClosing ( java . awt . event . WindowEvent evt ) {
System . out . println () ;
System . exit (0) ;
}
};
49
50
51
52
53
54
55
56
57
58
59
60
}
// fin de la clase Controlador
1
2
3
/* cA / Modelo . java
* Objeto principal de la lgica
* de la aplicacin
292
4
5
6
7
*/
import java . awt .*;
public class Modelo {
public Modelo () {
/* *
* Echar a andar todos
* los mecanismos del modelo
* y toda su lgica .
* */
}
9
10
11
12
13
14
15
16
public hacerAlgo () {
/* *
* Aqu debera estar el corazn
* de la ejecucin del modelo .
* */
}
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
1
2
3
4
5
6
7
/* *
* El modelo no tiene conciencia
* de la procedencia del contexto
* grfico en el que se le
* est solicitando trabajar .
*
* Simplemente responde por delegacin .
* */
public void dibujar ( Graphics g ) {
/* *
* Aqu hay que hacer lo propio .
*
* Aqu hay que dibujar lo que haya
* que dibujar de acuerdo al estado
* actual del modelo y de otros
* factores relevantes .
* */
}
Listing A.3: Clase vista
/* cA / Ventana . java
* Objeto vista ,
* tpicamente la Ventana de la aplicacin
*/
import java . awt .*;
public class Ventana extends javax . swing . JFrame implements Config3D {
293
9
10
11
12
13
14
15
/* *
* Objeto especial para lograr
* la delegacin de las solicitudes
* de refrescamiento
* */
private PanelEspecial panelprin ;
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
/* *
* Agregar todos los " escuchadores " ,
* que deberan estar implementados
* en el controlador .
*
* Todas las respuestas a los eventos
* diparados desde este objeto grfico
* y sus includos , deberan ser respondidos
* por el controlador con asistencia de
* los datos del modelo .
* */
addWindowListener ( control . AdaptadorVentana ) ;
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
294
57
58
59
60
61
62
63
64
65
66
67
68
}
}
// fin de la clase vista
1
2
3
4
5
6
7
8
9
Controlador control ;
11
12
13
14
15
/* *
* Mtodo llamado cuando es necesario
* redibujar la pantalla .
* La tarea se delega de la vista al
* controlador y de este al modelo .
* */
public void paintComponent ( Graphics g) {
control . dibujar ( g ) ;
}
16
17
18
19
20
21
22
23
25
26
/* cA / PanelEspecial . java
* Un componente que puede ponerse en un contenedor ...
* y mostrar las figuras
*/
import java . awt .*;
import javax . swing .*;
import java . awt . event .*;
public class PanelEspecial extends JPanel {
10
24
}
// fin de la clase PanelEspecial
Luego de este breve ejemplo, conviene mencionar cmo compilar el cdigo fuente y cmo
ensamblarlo en un slo archivo
.jar
.class.
$ javac Controlador.java
295
main.
Esto provocar la compilacin en cascada de todos las clases necesarias para que el
main
de
Controlador.java
$ java Controlador
Pero en lugar de dejar todos los archivos
.class,
.jar,
La opcin f indica que el siguiente parmetro debe ser el nombre del archivo a crear
(o del archivo a operar).
La opcin e indica que el siguiente parmetro (en este caso, despus del nombre del
archivo a operar), es el nombre de la clase con el punto de entrada (donde est el main
que queremos que se ejecute primero).
Finalmente listamos todos los archivos que queremos incluir en el archivo creado (en
este caso, todos los archivos
.class
jar,
ver
http://java.sun.com/docs/books/tutorial/deployment/jar/ o ejecutar:
$ man jar
296
B Referencias y manuales
B.1.
B.1.2. Artculos
Por qu SDL? (en espaol):
http://www.losersjuegos.com.ar/referencia/articulos/why_sdl/why_sdl.php
http://es.wikipedia.org/wiki/Grcos_3D_por_computadora
Artculo sobre juegos libres
http://www.marevalo.net/creacion/unmundofeliz/1999_12_06_juegos_libres.html
http://es.wikipedia.org/wiki/Desarrollo_de_videojuegos
http://en.wikipedia.org/wiki/Game_programming
http://www.losersjuegos.com.ar/referencia/articulos/articulos.php
Game Programming Wiki
http://wiki.gamedev.net/
297
B Referencias y manuales
B.2.
Python y pygame
http://inventwithpython.com/
http://en.wikibooks.org/wiki/Python_Programming
http://openbookproject.net//thinkCSpy/
http://pyspanishdoc.sourceforge.net/
http://www.pygame.org/
http://vpython.wikidot.com/
http://www.vpython.org/
http://www.diveintopython.org/
B.3.
Java Me
298
Bibliografa
[Foley et al.]
Foley, James D.; van Dam, Andries; Feiner, Steven K.; Hughes, John F.; Phillips, Richard L.
Introduccin a la gra-
Anlisis Numrico.
RAE,
Wikipedia - Bzier
Curve. Edicin del 26 de Febrero de 2010, 13:20 UTC. Revisado el 4 de Marzo de 2010 a las 8:42am, hora local de El Salvador. Enlace permanente: Bzier curve - oldid=346486604.
299