]> git.llucax.com Git - z.facultad/75.07/algowars.git/blob - src/vista/Camara.pas
Import inicial después del "/var incident". :(
[z.facultad/75.07/algowars.git] / src / vista / Camara.pas
1 {** Implementa una cámara que se encarga de representar los objetos en 2D.<br>\r
2     <i>Cambios:</i>\r
3     <PRE>\r
4     10/11/00: Se agrega el manejo de excepciones para evitar usar la camara cuando el cameraman fue destruido.\r
5               Para lograr esto se crea una excepcion (ECameramanDestruido) que se lanza cuando hay una excepcion\r
6               de violacion de acceso a memoria. Esta excepcion debe ser manejada por quien meneje la camara y puede\r
7               ser lanzada por mGetDebugInfo o mProyectar.\r
8     01/12/00: Se elimina el atributo aApertura porque era absolutamente inecesario.\r
9               Se cambia la estructura interna para que el filtrado de los objetos los realice un cFiltro.\r
10     07/12/00: Se agregan nuevos métodos (protegidos) para obtener información de la cámara para poder crear subclases,\r
11               para lo cual tambien se hace virtual el método mProyectar.\r
12     08/12/00: Se quita el método para setear el filtro y se agrega un contructor que admite un filtro para reemplazarlo.\r
13               Se cambia esta clase para que sea abstracta. Se deja la implementacion del método mProyectar para las\r
14               subclases exlusivamente ya que ahora es abstracto. La cámara frontal (que antes se implementaba en\r
15               esta unidad), ahora está implementado la unidad Camaras al igual que el resto.\r
16     </PRE>}\r
17 unit Camara;\r
18 \r
19 interface\r
20 \r
21 uses\r
22   {$IFDEF DebugAlgoWars}\r
23   Objeto,\r
24   {$ENDIF}\r
25   Tipos,\r
26   Coordenadas,\r
27   Vectores,\r
28   ObjetoVolador,\r
29   NavePropia,\r
30   Espacio,\r
31   Classes,\r
32   Sysutils,\r
33   Filtro,\r
34   Lista;\r
35 \r
36 type\r
37   {** Datos de un Objeto Volador procesado por una cámara }\r
38   tProyectado = record\r
39     oOV:  cObjetoVolador;\r
40     x:    tLongitud;\r
41     y:    tLongitud;\r
42     tam:  tLongitud;\r
43   end;\r
44 \r
45   {** Puntero a tProyectado}\r
46   tPProy = ^tProyectado;\r
47 \r
48   {** Excepcion producida por la cámara si se utiliza cuando el cameraman fue destruido}\r
49   ECameramanDestruido = class( Exception )\r
50     public\r
51       {** Constructor}\r
52       constructor create;\r
53   end;\r
54 \r
55   {** Implementa una cámara que se encarga de representar los objetos en 2D.}\r
56   cCamara = class{$IFDEF DebugAlgoWars}( cObjeto ){$ENDIF}\r
57     private\r
58       aCameraman:     cObjetoVolador; // Objeto volador que porta la camara\r
59       aRadioMaximo:   tLongitud;      // Alcance maximo de la camara (los\r
60                                       //  objetos mas lejanos no se veran)\r
61       aRadioMinimo:   tLongitud;      // Alcance minimo de la camara (los\r
62                                       //  objetos mas cercanos no se veran)\r
63       // Estos 3 ultimos atributos están ligados entre si (y son en parte redundantes)\r
64       aRadioPantalla: tLongitud;      // Radio de la pantalla.\r
65       aDistPantalla:  tLongitud;      // Distancia (mínima) hasta la pantalla\r
66       aCosApertura:   tAngulo;        // Coseno del Angulo de vision de la camara,\r
67                                       //   se almacena sólo el coseno porque el\r
68                                       //   ángulo en sí no se usa.\r
69       aFiltro:        cFiltro;        // Filtro que utiliza la cámara para evaluar\r
70                                       //  cuales objetos están visibles y cuales no.\r
71 \r
72     protected\r
73       {** Obtiene la proyección del objeto volador en X, Y}\r
74       procedure mProyectar(ov: cObjetoVolador; var x, y, tam: tLongitud); virtual; abstract;\r
75       {** Devuelve el objeto portador de la cámara}\r
76       function mGetCameraman: cObjetoVolador;\r
77       {** Permite asignar un nuevo portador de la cámara}\r
78       procedure mSetCameraman( oOV: cObjetoVOlador );\r
79       {** Devuelve distancia a la pantalla}\r
80       function mGetDistPantalla: tLongitud;\r
81       {** Devuelve el radio mínimo de detección}\r
82       function mGetRadioMinimo: tLongitud;\r
83       {** Devuelve el radio máximo de detección}\r
84       function mGetRadioMaximo: tLongitud;\r
85       {** Asigna un nuevo filtro}\r
86       Procedure mSetFiltro( filtro: cFiltro );\r
87     public\r
88       {** Constructor}\r
89       constructor create( cameraman: cObjetoVolador; angulo: tAngulo = PI/4; maximo: tLongitud = 5000; distPantalla: tLongitud = 0 ); overload;\r
90       {** Procesa una lista de objetos, devolviendo solo los visibles en una lista de records tProyectado\r
91           ordenada ascendentemente por el tamaño proporcional (es decir, el objeto de tamaño menor está primero en la lista).}\r
92       function mProcesar( l: TList ): cLista;\r
93       {$IFDEF DebugAlgoWars}\r
94       {** Método heredado que devuelve un string con el estado del Objeto. Se utiliza para depurar\r
95           y la información entregada depende del parámetro tDebugInfo.}\r
96       function mGetDebugInfo( debugLevel: tDebugInfo = DI_MINI ): string; override;\r
97       {$ENDIF}\r
98       {** Obtiene el radio de la pantalla}\r
99       function mGetRadioPantalla: tLongitud;\r
100   end;\r
101 \r
102 \r
103 implementation\r
104 \r
105 uses\r
106   Filtros,\r
107   Math;\r
108 \r
109 {** Funcion para ordenar los elementos de la lista que se devuelve\r
110     @param  item1 Item a comparar (puntero)\r
111     @param  item2 Item a comparar (puntero)\r
112     @return       <b>1</b> si item1 > item2<br>&nbsp;&nbsp;&nbsp;\r
113                   <b>-1</b> si item1 < item2<br>&nbsp;&nbsp;&nbsp;\r
114                   <b>0</b> si item1 = item2}\r
115 function listSort( item1, item2: pointer ): integer;\r
116 var\r
117   p1,\r
118   p2: tPProy;\r
119 begin\r
120   p1 := tPProy( item1 );\r
121   p2 := tPProy( item2 );\r
122   result := 0;\r
123   if p1^.tam > p2^.tam then\r
124     result := 1\r
125   else\r
126     if p1^.tam < p2^.tam then\r
127       result := -1\r
128 end;\r
129 \r
130 { cCamara }\r
131 \r
132 {** Contructor\r
133     @param cameraman Objeto Volador en el que estará montada la cámara (obligatorio)\r
134     @param angulo         Angulo de apertura (visión) de la cámara (default = pi/4)\r
135     @param maximo         Distancia máxima en la que se considera visible a un objeto (default = 5000)\r
136     @param distPantalla   Distancia hasta la pantalla de proyección (default = 0). Si tiene el valor por default\r
137                             o cualquier valor menor o igual a cero, se usa el tamaño del objeto volador}\r
138 constructor cCamara.create(cameraman: cObjetoVolador;\r
139   angulo: tAngulo; maximo: tLongitud;\r
140   distPantalla: tLongitud );\r
141 begin\r
142   inherited create;\r
143   aCameraman    := cameraman;\r
144   aRadioMaximo  := maximo;\r
145   aCosApertura  := cos( angulo );\r
146   if distPantalla > 0 then begin // Si la distancia es positiva, se la asigna y calcula el radio minimo\r
147     aDistPantalla := distPantalla;\r
148     // El radio minimo se calcula basado en la formula sen(a) = adyacente / HIPOTENUSA\r
149     aRadioMinimo  := aDistPantalla / sin( angulo );\r
150   end else begin // Si es negativo o cero (se paso como default o mal), lo extrae del objeto volador\r
151     aRadioMinimo  := aCameraman.mGetDimension;\r
152     // La distancia a la pantalla se calcula basado en la formula sen(a) = ADYACENTE / hipotenusa\r
153     aDistPantalla := sin( angulo ) * aRadioMinimo;\r
154   end;\r
155   // El radio de la pantalla se calcula basado en la formula cos(a) = OPUESTO / hipotenusa\r
156   aRadioPantalla := aCosApertura * aRadioMinimo;\r
157   // Crea un filtro frontal\r
158   aFiltro := cFiltroFrontal.create( aCameraman, angulo, aRadioMaximo, aRadioMinimo )\r
159 end;\r
160 \r
161 {** Procesa una lista de objetos, devolviendo solo los visibles en una lista de records tProyectado\r
162     ordenada ascendentemente por el tamaño proporcional (es decir, el objeto de tamaño menor está primero en la lista).\r
163     @return  Lista con los objetos visibles y sus posiciones y tamaños, en un registro\r
164              del tipo <i>tProyectado</i>, ordenados de forma ascendente según el tamaño.\r
165     @param l Lista con los objetos a procesar}\r
166 function cCamara.mProcesar( l: TList ): cLista;\r
167 var\r
168   lFiltrada:  TList;\r
169   lProcesada: cLista;\r
170   proy: tPProy;\r
171   oOV: cObjetoVolador;\r
172   i: integer;\r
173   x,\r
174   y,\r
175   tam: tLongitud;\r
176   sort: TListSortCompare;\r
177 \r
178 begin\r
179   lProcesada := cLista.create;\r
180   try\r
181     lFiltrada  := aFiltro.mFiltrar( l );\r
182   except\r
183     on e: EObservadorDestruido do\r
184       raise ECameramanDestruido.create;\r
185   end;\r
186   for i:=0 to lFiltrada.count - 1 do begin // recorre la lista de objetos\r
187     oOV := lFiltrada.items[i]; // obtiene el ObjetoVolador actual\r
188     new( proy );\r
189     mProyectar( oOV, x, y, tam );\r
190     proy^.oOV := oOV;\r
191     proy^.x := x;\r
192     proy^.y := y;\r
193     proy^.tam := tam;\r
194     lProcesada.Add( proy );\r
195   end;\r
196   sort := listSort;\r
197   lProcesada.Sort( sort );\r
198   result := lProcesada;\r
199   lFiltrada.free;\r
200 end;\r
201 \r
202 {$IFDEF DebugAlgoWars}\r
203 {** Devuelve el estado del objeto basandose en la cantidad de datos requeridos:<br>\r
204     Siempre devuelve los valores de las componentes x, y, z y si debugLevel es mayor que DI_NORMAL,\r
205     también muestra el módulo.\r
206     @return             Cadena de texto con el estado del Objeto.\r
207     @param   debugLevel Cantidad de información requerida}\r
208 function cCamara.mGetDebugInfo( debugLevel: tDebugInfo ): string;\r
209 begin\r
210   // Construye la cadena dependiendo de la cantidad de informacion que se quiera obtener\r
211   result := 'Radio Máximo: ' + FloatToStrF( aRadioMaximo, ffNumber, 5, 5 ) +\r
212             ' | Radio Mínimo: ' + FloatToStrF( aRadioMinimo, ffNumber, 5, 5 ) +\r
213             ' | Radio de Pantalla: ' + FloatToStrF( aRadioPantalla, ffNumber, 5, 5 ) +\r
214             ' | Distancia de Pantalla: ' + FloatToStrF( aDistPantalla, ffNumber, 5, 5 );\r
215   try // Probamos que el cameraman no este destruido\r
216     if debugLevel = DI_NORMAL then\r
217       result := result + #13 + #10 +\r
218                 'Cameraman: ' + aCameraman.mGetDebugInfo;\r
219     if debugLevel = DI_MAXI then\r
220       result := result + #13 + #10 +\r
221                 'Cameraman: ' + aCameraman.mGetDebugInfo( debugLevel ); // + #13 + #10 +\r
222   except // Si esta destruido cae en una excepcion\r
223     on e: EAccessViolation do\r
224       raise ECameramanDestruido.create; // Creamos una nueva excepcion especial\r
225   end;\r
226 end;\r
227 {$ENDIF}\r
228 \r
229 {** Obtiene el radio de la pantalla\r
230     @return Radio de la pantalla}\r
231 function cCamara.mGetRadioPantalla: tLongitud;\r
232 begin\r
233   result := aRadioPantalla;\r
234 end;\r
235 \r
236 {** Devuelve el objeto portador de la cámara\r
237     @return Objeto portador de la cámara}\r
238 function cCamara.mGetCameraman: cObjetoVolador;\r
239 begin\r
240   result := aCameraman;\r
241 end;\r
242 \r
243 {** Permite asignar un nuevo portador de la cámara\r
244     @param oOV Objeto volador que será en nuevo portador de la cámara}\r
245 procedure cCamara.mSetCameraman(oOV: cObjetoVOlador);\r
246 begin\r
247   aCameraman := oOV;\r
248   aFiltro.mSetObservador( oOV );\r
249 end;\r
250 \r
251 {** Devuelve distancia a la pantalla\r
252     @return Distancia a la pantalla}\r
253 function cCamara.mGetDistPantalla: tLongitud;\r
254 begin\r
255   result:=aDistPantalla;\r
256 end;\r
257 \r
258 {** Devuelve el radio mínimo de detección\r
259     @return Radio mínimo de detección}\r
260 function cCamara.mGetRadioMaximo: tLongitud;\r
261 begin\r
262   result:=aRadioMaximo;\r
263 end;\r
264 \r
265 {** Devuelve el radio máximo de detección\r
266     @return Radio máximo de detección}\r
267 function cCamara.mGetRadioMinimo: tLongitud;\r
268 begin\r
269   result:=aRadioMinimo;\r
270 end;\r
271 \r
272 {** Asigna un nuevo filtro}\r
273 procedure cCamara.mSetFiltro(filtro: cFiltro);\r
274 begin\r
275   aFiltro.free;\r
276   aFiltro := filtro;\r
277 end;\r
278 \r
279 { ECameramanDestruido }\r
280 \r
281 {** Constructor}\r
282 constructor ECameramanDestruido.create;\r
283 begin\r
284   inherited create( 'El Cameraman fue destruido.' );\r
285 end;\r
286 \r
287 end.\r