2 <TITLE>File: camara.pas </TITLE>
\r
3 <META NAME="GENERATOR" CONTENT="PasToHTML(Bystricky Vladimir)">
\r
5 <BODY BGCOLOR="#FFFFFF">
\r
6 <A NAME=camara.pas><CENTER><H3>camara.pas</H3></A><I> from <A HREF=/proyecto/doc/src-html/AlgoWars.html> Project: AlgoWars.dpr</A></I></CENTER>
\r
9 <I><FONT COLOR="Navy">{** Implementa una cámara que se encarga de representar los objetos en 2D.<br>
\r
12 10/11/00: Se agrega el manejo de excepciones para evitar usar la camara cuando el cameraman fue destruido.
\r
13 Para lograr esto se crea una excepcion (ECameramanDestruido) que se lanza cuando hay una excepcion
\r
14 de violacion de acceso a memoria. Esta excepcion debe ser manejada por quien meneje la camara y puede
\r
15 ser lanzada por mGetDebugInfo o mProyectar.
\r
16 01/12/00: Se elimina el atributo aApertura porque era absolutamente inecesario.
\r
17 Se cambia la estructura interna para que el filtrado de los objetos los realice un cFiltro.
\r
18 07/12/00: Se agregan nuevos métodos (protegidos) para obtener información de la cámara para poder crear subclases,
\r
19 para lo cual tambien se hace virtual el método mProyectar.
\r
20 08/12/00: Se quita el método para setear el filtro y se agrega un contructor que admite un filtro para reemplazarlo.
\r
21 Se cambia esta clase para que sea abstracta. Se deja la implementacion del método mProyectar para las
\r
22 subclases exlusivamente ya que ahora es abstracto. La cámara frontal (que antes se implementaba en
\r
23 esta unidad), ahora está implementado la unidad Camaras al igual que el resto.
\r
25 <B>unit</B> Camara;
\r
30 <I><FONT COLOR="Navy">{$IFDEF DebugAlgoWars}</FONT></I>
\r
32 <I><FONT COLOR="Navy">{$ENDIF}</FONT></I>
\r
45 <I><FONT COLOR="Navy">{** Datos de un Objeto Volador procesado por una cámara }</FONT></I>
\r
46 tProyectado = <B>record</B>
\r
47 oOV: cObjetoVolador;
\r
53 <I><FONT COLOR="Navy">{** Puntero a tProyectado}</FONT></I>
\r
54 tPProy = ^tProyectado;
\r
56 <I><FONT COLOR="Navy">{** Excepcion producida por la cámara si se utiliza cuando el cameraman fue destruido}</FONT></I>
\r
57 ECameramanDestruido = <B>class</B>( Exception )
\r
59 <I><FONT COLOR="Navy">{** Constructor}</FONT></I>
\r
60 <B>constructor</B> create;
\r
63 <I><FONT COLOR="Navy">{** Implementa una cámara que se encarga de representar los objetos en 2D.}</FONT></I>
\r
64 cCamara = <B>class</B><I><FONT COLOR="Navy">{$IFDEF DebugAlgoWars}</FONT></I>( cObjeto )<I><FONT COLOR="Navy">{$ENDIF}</FONT></I>
\r
66 aCameraman: cObjetoVolador; <I><FONT COLOR="Navy">// Objeto volador que porta la camara </FONT></I>
\r
67 aRadioMaximo: tLongitud; <I><FONT COLOR="Navy">// Alcance maximo de la camara (los </FONT></I>
\r
68 <I><FONT COLOR="Navy">// objetos mas lejanos no se veran) </FONT></I>
\r
69 aRadioMinimo: tLongitud; <I><FONT COLOR="Navy">// Alcance minimo de la camara (los </FONT></I>
\r
70 <I><FONT COLOR="Navy">// objetos mas cercanos no se veran) </FONT></I>
\r
71 <I><FONT COLOR="Navy">// Estos 3 ultimos atributos están ligados entre si (y son en parte redundantes) </FONT></I>
\r
72 aRadioPantalla: tLongitud; <I><FONT COLOR="Navy">// Radio de la pantalla. </FONT></I>
\r
73 aDistPantalla: tLongitud; <I><FONT COLOR="Navy">// Distancia (mínima) hasta la pantalla </FONT></I>
\r
74 aCosApertura: tAngulo; <I><FONT COLOR="Navy">// Coseno del Angulo de vision de la camara, </FONT></I>
\r
75 <I><FONT COLOR="Navy">// se almacena sólo el coseno porque el </FONT></I>
\r
76 <I><FONT COLOR="Navy">// ángulo en sí no se usa. </FONT></I>
\r
77 aFiltro: cFiltro; <I><FONT COLOR="Navy">// Filtro que utiliza la cámara para evaluar </FONT></I>
\r
78 <I><FONT COLOR="Navy">// cuales objetos están visibles y cuales no. </FONT></I>
\r
81 <I><FONT COLOR="Navy">{** Obtiene la proyección del objeto volador en X, Y}</FONT></I>
\r
82 <B>procedure</B> <A HREF="#cCamara.mProyectar">mProyectar</A>(ov: cObjetoVolador; <B>var</B> x, y, tam: tLongitud); <B>virtual</B>; <B>abstract</B>;
\r
83 <I><FONT COLOR="Navy">{** Devuelve el objeto portador de la cámara}</FONT></I>
\r
84 <B>function</B> <A HREF="#cCamara.mGetCameraman">mGetCameraman</A>: cObjetoVolador;
\r
85 <I><FONT COLOR="Navy">{** Permite asignar un nuevo portador de la cámara}</FONT></I>
\r
86 <B>procedure</B> <A HREF="#cCamara.mSetCameraman">mSetCameraman</A>( oOV: cObjetoVOlador );
\r
87 <I><FONT COLOR="Navy">{** Devuelve distancia a la pantalla}</FONT></I>
\r
88 <B>function</B> <A HREF="#cCamara.mGetDistPantalla">mGetDistPantalla</A>: tLongitud;
\r
89 <I><FONT COLOR="Navy">{** Devuelve el radio mínimo de detección}</FONT></I>
\r
90 <B>function</B> <A HREF="#cCamara.mGetRadioMinimo">mGetRadioMinimo</A>: tLongitud;
\r
91 <I><FONT COLOR="Navy">{** Devuelve el radio máximo de detección}</FONT></I>
\r
92 <B>function</B> <A HREF="#cCamara.mGetRadioMaximo">mGetRadioMaximo</A>: tLongitud;
\r
93 <I><FONT COLOR="Navy">{** Asigna un nuevo filtro}</FONT></I>
\r
94 <B>Procedure</B> <A HREF="#cCamara.mSetFiltro">mSetFiltro</A>( filtro: cFiltro );
\r
96 <I><FONT COLOR="Navy">{** Constructor}</FONT></I>
\r
97 <B>constructor</B> create( cameraman: cObjetoVolador; angulo: tAngulo = PI/4; maximo: tLongitud = 5000; distPantalla: tLongitud = 0 ); overload;
\r
98 <I><FONT COLOR="Navy">{** Procesa una lista de objetos, devolviendo solo los visibles en una lista de records tProyectado
\r
99 ordenada ascendentemente por el tamaño proporcional (es decir, el objeto de tamaño menor está primero en la lista).}</FONT></I>
\r
100 <B>function</B> <A HREF="#cCamara.mProcesar">mProcesar</A>( l: TList ): cLista;
\r
101 <I><FONT COLOR="Navy">{$IFDEF DebugAlgoWars}</FONT></I>
\r
102 <I><FONT COLOR="Navy">{** Método heredado que devuelve un string con el estado del Objeto. Se utiliza para depurar
\r
103 y la información entregada depende del parámetro tDebugInfo.}</FONT></I>
\r
104 <B>function</B> <A HREF="#cCamara.mGetDebugInfo">mGetDebugInfo</A>( debugLevel: tDebugInfo = DI_MINI ): <B>string</B>; <B>override</B>;
\r
105 <I><FONT COLOR="Navy">{$ENDIF}</FONT></I>
\r
106 <I><FONT COLOR="Navy">{** Obtiene el radio de la pantalla}</FONT></I>
\r
107 <B>function</B> <A HREF="#cCamara.mGetRadioPantalla">mGetRadioPantalla</A>: tLongitud;
\r
111 <B>implementation</B>
\r
117 <I><FONT COLOR="Navy">{** Funcion para ordenar los elementos de la lista que se devuelve
\r
118 @param item1 Item a comparar (puntero)
\r
119 @param item2 Item a comparar (puntero)
\r
120 @return <b>1</b> si item1 > item2<br>
\r
121 <b>-1</b> si item1 < item2<br>
\r
122 <b>0</b> si item1 = item2}</FONT></I>
\r
123 <B>function</B> listSort( item1, item2: pointer ): integer;
\r
128 p1 := tPProy( item1 );
\r
129 p2 := tPProy( item2 );
\r
131 <B>if</B> p1^.tam > p2^.tam <B>then</B>
\r
134 <B>if</B> p1^.tam < p2^.tam <B>then</B>
\r
138 <I><FONT COLOR="Navy">{ cCamara }</FONT></I>
\r
140 <I><FONT COLOR="Navy">{** Contructor
\r
141 @param cameraman Objeto Volador en el que estará montada la cámara (obligatorio)
\r
142 @param angulo Angulo de apertura (visión) de la cámara (default = pi/4)
\r
143 @param maximo Distancia máxima en la que se considera visible a un objeto (default = 5000)
\r
144 @param distPantalla Distancia hasta la pantalla de proyección (default = 0). Si tiene el valor por default
\r
145 o cualquier valor menor o igual a cero, se usa el tamaño del objeto volador}</FONT></I>
\r
146 <B>constructor</B> cCamara.create(cameraman: cObjetoVolador;
\r
147 angulo: tAngulo; maximo: tLongitud;
\r
148 distPantalla: tLongitud );
\r
150 <B>inherited</B> create;
\r
151 aCameraman := cameraman;
\r
152 aRadioMaximo := maximo;
\r
153 aCosApertura := cos( angulo );
\r
154 <B>if</B> distPantalla > 0 <B>then</B> <B>begin</B> <I><FONT COLOR="Navy">// Si la distancia es positiva, se la asigna y calcula el radio minimo </FONT></I>
\r
155 aDistPantalla := distPantalla;
\r
156 <I><FONT COLOR="Navy">// El radio minimo se calcula basado en la formula sen(a) = adyacente / HIPOTENUSA </FONT></I>
\r
157 aRadioMinimo := aDistPantalla / sin( angulo );
\r
158 <B>end</B> <B>else</B> <B>begin</B> <I><FONT COLOR="Navy">// Si es negativo o cero (se paso como default o mal), lo extrae del objeto volador </FONT></I>
\r
159 aRadioMinimo := aCameraman.mGetDimension;
\r
160 <I><FONT COLOR="Navy">// La distancia a la pantalla se calcula basado en la formula sen(a) = ADYACENTE / hipotenusa </FONT></I>
\r
161 aDistPantalla := sin( angulo ) * aRadioMinimo;
\r
163 <I><FONT COLOR="Navy">// El radio de la pantalla se calcula basado en la formula cos(a) = OPUESTO / hipotenusa </FONT></I>
\r
164 aRadioPantalla := aCosApertura * aRadioMinimo;
\r
165 <I><FONT COLOR="Navy">// Crea un filtro frontal </FONT></I>
\r
166 aFiltro := cFiltroFrontal.create( aCameraman, angulo, aRadioMaximo, aRadioMinimo )
\r
169 <I><FONT COLOR="Navy">{** Procesa una lista de objetos, devolviendo solo los visibles en una lista de records tProyectado
\r
170 ordenada ascendentemente por el tamaño proporcional (es decir, el objeto de tamaño menor está primero en la lista).
\r
171 @return Lista con los objetos visibles y sus posiciones y tamaños, en un registro
\r
172 del tipo <i>tProyectado</i>, ordenados de forma ascendente según el tamaño.
\r
173 @param l Lista con los objetos a procesar}</FONT></I>
\r
174 <B>function</B> <A NAME=cCamara.mProcesar>cCamara.mProcesar</A>( l: TList ): cLista;
\r
177 lProcesada: cLista;
\r
179 oOV: cObjetoVolador;
\r
184 sort: TListSortCompare;
\r
187 lProcesada := cLista.create;
\r
189 lFiltrada := aFiltro.mFiltrar( l );
\r
191 on e: EObservadorDestruido <B>do</B>
\r
192 <B>raise</B> ECameramanDestruido.create;
\r
194 <B>for</B> i:=0 <B>to</B> lFiltrada.count - 1 <B>do</B> <B>begin</B> <I><FONT COLOR="Navy">// recorre la lista de objetos </FONT></I>
\r
195 oOV := lFiltrada.items[i]; <I><FONT COLOR="Navy">// obtiene el ObjetoVolador actual </FONT></I>
\r
197 mProyectar( oOV, x, y, tam );
\r
202 lProcesada.Add( proy );
\r
205 lProcesada.Sort( sort );
\r
206 result := lProcesada;
\r
210 <I><FONT COLOR="Navy">{$IFDEF DebugAlgoWars}</FONT></I>
\r
211 <I><FONT COLOR="Navy">{** Devuelve el estado del objeto basandose en la cantidad de datos requeridos:<br>
\r
212 Siempre devuelve los valores de las componentes x, y, z y si debugLevel es mayor que DI_NORMAL,
\r
213 también muestra el módulo.
\r
214 @return Cadena de texto con el estado del Objeto.
\r
215 @param debugLevel Cantidad de información requerida}</FONT></I>
\r
216 <B>function</B> <A NAME=cCamara.mGetDebugInfo>cCamara.mGetDebugInfo</A>( debugLevel: tDebugInfo ): <B>string</B>;
\r
218 <I><FONT COLOR="Navy">// Construye la cadena dependiendo de la cantidad de informacion que se quiera obtener </FONT></I>
\r
219 result := 'Radio Máximo: ' + FloatToStrF( aRadioMaximo, ffNumber, 5, 5 ) +
\r
220 ' | Radio Mínimo: ' + FloatToStrF( aRadioMinimo, ffNumber, 5, 5 ) +
\r
221 ' | Radio de Pantalla: ' + FloatToStrF( aRadioPantalla, ffNumber, 5, 5 ) +
\r
222 ' | Distancia de Pantalla: ' + FloatToStrF( aDistPantalla, ffNumber, 5, 5 );
\r
223 <B>try</B> <I><FONT COLOR="Navy">// Probamos que el cameraman no este destruido </FONT></I>
\r
224 <B>if</B> debugLevel = DI_NORMAL <B>then</B>
\r
225 result := result + #13 + #10 +
\r
226 'Cameraman: ' + aCameraman.mGetDebugInfo;
\r
227 <B>if</B> debugLevel = DI_MAXI <B>then</B>
\r
228 result := result + #13 + #10 +
\r
229 'Cameraman: ' + aCameraman.mGetDebugInfo( debugLevel ); <I><FONT COLOR="Navy">// + #13 + #10 + </FONT></I>
\r
230 <B>except</B> <I><FONT COLOR="Navy">// Si esta destruido cae en una excepcion </FONT></I>
\r
231 on e: EAccessViolation <B>do</B>
\r
232 <B>raise</B> ECameramanDestruido.create; <I><FONT COLOR="Navy">// Creamos una nueva excepcion especial </FONT></I>
\r
235 <I><FONT COLOR="Navy">{$ENDIF}</FONT></I>
\r
237 <I><FONT COLOR="Navy">{** Obtiene el radio de la pantalla
\r
238 @return Radio de la pantalla}</FONT></I>
\r
239 <B>function</B> <A NAME=cCamara.mGetRadioPantalla>cCamara.mGetRadioPantalla</A>: tLongitud;
\r
241 result := aRadioPantalla;
\r
244 <I><FONT COLOR="Navy">{** Devuelve el objeto portador de la cámara
\r
245 @return Objeto portador de la cámara}</FONT></I>
\r
246 <B>function</B> <A NAME=cCamara.mGetCameraman>cCamara.mGetCameraman</A>: cObjetoVolador;
\r
248 result := aCameraman;
\r
251 <I><FONT COLOR="Navy">{** Permite asignar un nuevo portador de la cámara
\r
252 @param oOV Objeto volador que será en nuevo portador de la cámara}</FONT></I>
\r
253 <B>procedure</B> <A NAME=cCamara.mSetCameraman>cCamara.mSetCameraman</A>(oOV: cObjetoVOlador);
\r
255 aCameraman := oOV;
\r
256 aFiltro.mSetObservador( oOV );
\r
259 <I><FONT COLOR="Navy">{** Devuelve distancia a la pantalla
\r
260 @return Distancia a la pantalla}</FONT></I>
\r
261 <B>function</B> <A NAME=cCamara.mGetDistPantalla>cCamara.mGetDistPantalla</A>: tLongitud;
\r
263 result:=aDistPantalla;
\r
266 <I><FONT COLOR="Navy">{** Devuelve el radio mínimo de detección
\r
267 @return Radio mínimo de detección}</FONT></I>
\r
268 <B>function</B> <A NAME=cCamara.mGetRadioMaximo>cCamara.mGetRadioMaximo</A>: tLongitud;
\r
270 result:=aRadioMaximo;
\r
273 <I><FONT COLOR="Navy">{** Devuelve el radio máximo de detección
\r
274 @return Radio máximo de detección}</FONT></I>
\r
275 <B>function</B> <A NAME=cCamara.mGetRadioMinimo>cCamara.mGetRadioMinimo</A>: tLongitud;
\r
277 result:=aRadioMinimo;
\r
280 <I><FONT COLOR="Navy">{** Asigna un nuevo filtro}</FONT></I>
\r
281 <B>procedure</B> <A NAME=cCamara.mSetFiltro>cCamara.mSetFiltro</A>(filtro: cFiltro);
\r
284 aFiltro := filtro;
\r
287 <I><FONT COLOR="Navy">{ ECameramanDestruido }</FONT></I>
\r
289 <I><FONT COLOR="Navy">{** Constructor}</FONT></I>
\r
290 <B>constructor</B> ECameramanDestruido.create;
\r
292 <B>inherited</B> create( 'El Cameraman fue destruido.' );
\r