2 <TITLE>File: filtro.pas </TITLE>
\r
3 <META NAME="GENERATOR" CONTENT="PasToHTML(Bystricky Vladimir)">
\r
5 <BODY BGCOLOR="#FFFFFF">
\r
6 <A NAME=filtro.pas><CENTER><H3>filtro.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">{** Es una clase abstracta que representa filtro que recibe una lista de objetos y devuelve otra filtrada.<br>
\r
12 06/12/00: Se agregan nuevos métodos (protegidos) para obtener información del filtro para poder crear subclases,
\r
13 para lo cual tambien se hace virtual el método mVisible.
\r
14 08/12/00: Se cambia esta clase para que sea abstracta. Se deja la implementacion del método mVisible para las
\r
15 subclases exlusivamente ya que ahora es abstracto. El filtro frontal (que antes se implementaba en
\r
16 esta unidad), ahora está implementado la unidad Filtros al igual que el resto.
\r
18 <B>unit</B> Filtro;
\r
31 <I><FONT COLOR="Navy">{** Excepcion producida por el filtro si se utiliza cuando el observador fue destruido}</FONT></I>
\r
32 EObservadorDestruido = <B>class</B>( Exception )
\r
34 <I><FONT COLOR="Navy">{** Constructor}</FONT></I>
\r
35 <B>constructor</B> create;
\r
38 <I><FONT COLOR="Navy">{** Es una clase abstracta que representa un filtro que recibe una lista de objetos y devuelve otra filtrada.}</FONT></I>
\r
39 cFiltro = <B>class</B>( cObjetoPersistente )
\r
41 aObservador: cObjetoVolador; <I><FONT COLOR="Navy">// Objeto volador que observa a traves del filtro </FONT></I>
\r
42 aRadioMaximo: tLongitud; <I><FONT COLOR="Navy">// Alcance maximo del filtro (los </FONT></I>
\r
43 <I><FONT COLOR="Navy">// objetos mas lejanos no se veran) </FONT></I>
\r
44 aRadioMinimo: tLongitud; <I><FONT COLOR="Navy">// Alcance minimo del filtro (los </FONT></I>
\r
45 <I><FONT COLOR="Navy">// objetos mas cercanos no se veran) </FONT></I>
\r
46 aCosApertura: tAngulo; <I><FONT COLOR="Navy">// Coseno del Angulo de captación del filtro, </FONT></I>
\r
47 <I><FONT COLOR="Navy">// se almacena sólo el coseno porque el </FONT></I>
\r
48 <I><FONT COLOR="Navy">// ángulo en sí no se usa. </FONT></I>
\r
50 <I><FONT COLOR="Navy">{** Verifica que un objeto volador pueda ser visto por la cámara}</FONT></I>
\r
51 <B>function</B> <A HREF="#cFiltro.mVisible">mVisible</A>( ov: cObjetoVolador ): boolean; <B>virtual</B>; <B>abstract</B>;
\r
52 <I><FONT COLOR="Navy">{** Obtiene el radio mínimo}</FONT></I>
\r
53 <B>function</B> <A HREF="#cFiltro.mGetRadioMinimo">mGetRadioMinimo</A>: tLongitud;
\r
54 <I><FONT COLOR="Navy">{** Obtiene el radio máximo}</FONT></I>
\r
55 <B>function</B> <A HREF="#cFiltro.mGetRadioMaximo">mGetRadioMaximo</A>: tLongitud;
\r
56 <I><FONT COLOR="Navy">{** Obtiene el coseno de la apertura}</FONT></I>
\r
57 <B>function</B> <A HREF="#cFiltro.mGetCosApertura">mGetCosApertura</A>: tAngulo;
\r
59 <I><FONT COLOR="Navy">{** Constructor}</FONT></I>
\r
60 <B>constructor</B> create( observador: cObjetoVolador; angulo: tAngulo = PI/4; maximo: tLongitud = 5000; minimo: tLongitud = -1 );
\r
61 <I><FONT COLOR="Navy">{** Procesa una lista de objetos, devolviendo solo los visibles en una lista ordenada ascendentemente por la distancia
\r
62 (es decir, el objeto más cercano está primero en la lista).}</FONT></I>
\r
63 <B>function</B> <A HREF="#cFiltro.mFiltrar">mFiltrar</A>( l: TList ): TList;
\r
64 <I><FONT COLOR="Navy">{** Obtiene un puntero al observador}</FONT></I>
\r
65 <B>function</B> <A HREF="#cFiltro.mGetObservador">mGetObservador</A>: cObjetoVolador;
\r
66 <I><FONT COLOR="Navy">{** Establece el observador con un nuevo puntero}</FONT></I>
\r
67 <B>procedure</B> <A HREF="#cFiltro.mSetObservador">mSetObservador</A>( ov: cObjetoVolador );
\r
68 <I><FONT COLOR="Navy">{$IFDEF DebugAlgoWars}</FONT></I>
\r
69 <I><FONT COLOR="Navy">{** Método heredado que devuelve un string con el estado del Objeto. Se utiliza para depurar
\r
70 y la información entregada depende del parámetro tDebugInfo.}</FONT></I>
\r
71 <B>function</B> <A HREF="#cFiltro.mGetDebugInfo">mGetDebugInfo</A>( debugLevel: tDebugInfo = DI_MINI ): <B>string</B>; <B>override</B>;
\r
72 <I><FONT COLOR="Navy">{$ENDIF}</FONT></I>
\r
73 <I><FONT COLOR="Navy">// SERIALIZACION </FONT></I>
\r
74 <I><FONT COLOR="Navy">{** Devuelve una cadena de texto con el objeto serializado.}</FONT></I>
\r
75 <B>function</B> <A HREF="#cFiltro.mSerializar">mSerializar</A>: <B>string</B>; <B>override</B>;
\r
76 <I><FONT COLOR="Navy">{** Recrea el objeto a partir de una cadena de texto con el objeto
\r
77 serializado.}</FONT></I>
\r
78 <B>procedure</B> <A HREF="#cFiltro.mDesSerializar">mDesSerializar</A>( str: <B>string</B> ); <B>override</B>;
\r
81 <B>implementation</B>
\r
85 SerializacionUtils,
\r
88 <I><FONT COLOR="Navy">{ cFiltro }</FONT></I>
\r
90 <I><FONT COLOR="Navy">{** Contructor
\r
91 @param observador Objeto Volador en el que estará montado el filtro (obligatorio)
\r
92 @param angulo Angulo de apertura (visión) del filtro (default = pi/4)
\r
93 @param maximo Distancia máxima en la que se considera visible a un objeto (default = 5000)
\r
94 @param minimo Distancia mínima en la que se considera visible a un objeto (default = -1).
\r
95 Si se especifica un valor negativo o cero, se toma la dimension del objeto volador}</FONT></I>
\r
96 <B>constructor</B> cFiltro.create(observador: cObjetoVolador; angulo: tAngulo;
\r
97 maximo: tLongitud; minimo: tLongitud);
\r
99 <B>inherited</B> create;
\r
100 aObservador := observador;
\r
101 aRadioMaximo := maximo;
\r
102 aCosApertura := cos( angulo );
\r
103 <B>if</B> minimo > 0 <B>then</B> <I><FONT COLOR="Navy">// Si el radio minimo es positiva se lo asigna </FONT></I>
\r
104 aRadioMinimo := minimo
\r
105 <B>else</B> <I><FONT COLOR="Navy">// Si es negativo o cero (se paso como default o mal), lo extrae del objeto volador </FONT></I>
\r
106 aRadioMinimo := aObservador.mGetDimension;
\r
109 <I><FONT COLOR="Navy">{** Filtra una lista de objetos, devolviendo solo los visibles.
\r
110 @return Lista con los objetos visibles.
\r
111 @param l Lista con los objetos a procesar.}</FONT></I>
\r
112 <B>function</B> <A NAME=cFiltro.mFiltrar>cFiltro.mFiltrar</A>( l: TList ): TList;
\r
114 lProcesada: TList;
\r
115 oOV: cObjetoVolador;
\r
118 lProcesada := TList.create;
\r
119 <B>for</B> i:=0 <B>to</B> l.count - 1 <B>do</B> <B>begin</B> <I><FONT COLOR="Navy">// recorre la lista de objetos </FONT></I>
\r
120 oOV := l.items[i]; <I><FONT COLOR="Navy">// obtiene el ObjetoVolador actual </FONT></I>
\r
121 <B>if</B> mVisible( oOV ) <B>then</B>
\r
122 lProcesada.Add( oOV );
\r
124 result := lProcesada;
\r
127 <I><FONT COLOR="Navy">{$IFDEF DebugAlgoWars}</FONT></I>
\r
128 <I><FONT COLOR="Navy">{** Devuelve el estado del objeto basandose en la cantidad de datos requeridos:<br>
\r
129 Siempre devuelve los valores de las componentes x, y, z y si debugLevel es mayor que DI_NORMAL,
\r
130 también muestra el módulo.
\r
131 @return Cadena de texto con el estado del Objeto.
\r
132 @param debugLevel Cantidad de información requerida}</FONT></I>
\r
133 <B>function</B> <A NAME=cFiltro.mGetDebugInfo>cFiltro.mGetDebugInfo</A>( debugLevel: tDebugInfo ): <B>string</B>;
\r
135 <I><FONT COLOR="Navy">// Construye la cadena dependiendo de la cantidad de informacion que se quiera obtener </FONT></I>
\r
136 result := 'Radio Máximo: ' + FloatToStrF( aRadioMaximo, ffNumber, 5, 5 ) +
\r
137 ' | Radio Mínimo: ' + FloatToStrF( aRadioMinimo, ffNumber, 5, 5 );
\r
138 <B>try</B> <I><FONT COLOR="Navy">// Probamos que el cameraman no este destruido </FONT></I>
\r
139 <B>if</B> debugLevel = DI_NORMAL <B>then</B>
\r
140 result := result + #13 + #10 +
\r
141 'Cameraman: ' + aObservador.mGetDebugInfo;
\r
142 <B>if</B> debugLevel = DI_MAXI <B>then</B>
\r
143 result := result + #13 + #10 +
\r
144 'Cameraman: ' + aObservador.mGetDebugInfo( debugLevel ); <I><FONT COLOR="Navy">// + #13 + #10 + </FONT></I>
\r
145 <B>except</B> <I><FONT COLOR="Navy">// Si esta destruido cae en una excepcion </FONT></I>
\r
146 on e: EAccessViolation <B>do</B>
\r
147 <B>raise</B> EObservadorDestruido.create; <I><FONT COLOR="Navy">// Creamos una nueva excepcion especial </FONT></I>
\r
150 <I><FONT COLOR="Navy">{$ENDIF}</FONT></I>
\r
152 <I><FONT COLOR="Navy">{** Obtiene un puntero al observador
\r
153 @return Puntero al obervador}</FONT></I>
\r
154 <B>function</B> <A NAME=cFiltro.mGetObservador>cFiltro.mGetObservador</A>: cObjetoVolador;
\r
156 result := aObservador;
\r
159 <I><FONT COLOR="Navy">{** Establece el observador con un nuevo puntero
\r
160 @param Puntero al nuevo obervador}</FONT></I>
\r
161 <B>procedure</B> <A NAME=cFiltro.mSetObservador>cFiltro.mSetObservador</A>(ov: cObjetoVolador);
\r
163 aObservador := ov;
\r
166 <I><FONT COLOR="Navy">{** Recrea el objeto a partir de una cadena de texto con el objeto
\r
168 @param str Cadena de texto con el objeto serializado.}</FONT></I>
\r
169 <B>procedure</B> <A NAME=cFiltro.mDesSerializar>cFiltro.mDesSerializar</A>(str: <B>string</B>);
\r
173 <B>inherited</B> mDesSerializar( str ); <I><FONT COLOR="Navy">// SIEMPRE el ID debe ser el PRIMER atributo </FONT></I>
\r
174 r := TRegExpr.create;
\r
175 <I><FONT COLOR="Navy">// OBSERVADOR </FONT></I>
\r
176 <B>try</B> <I><FONT COLOR="Navy">// se fija si hay errores al extraer los datos </FONT></I>
\r
177 r.Expression := '<observador/s+class=([/w/d]+)/s*>/s*(.+)/s*</observador>'; <I><FONT COLOR="Navy">// contruye la expresion regular a buscar </FONT></I>
\r
178 <B>if</B> r.Exec ( str ) <B>then</B> <I><FONT COLOR="Navy">// Ejecuta la expresion. Si la encuentra... </FONT></I>
\r
179 <B>if</B> r.Match[1] <> '0' <B>then</B> <I><FONT COLOR="Navy">// Si tiene una clase determinada... </FONT></I>
\r
180 <B>if</B> aObservador <> <B>nil</B> <B>then</B> <I><FONT COLOR="Navy">// Si no es nulo </FONT></I>
\r
181 <I><FONT COLOR="Navy">// Puede caer en una EAccessViolation si esta destruido </FONT></I>
\r
182 aObservador.mDesSerializar( r.Match[2] ) <I><FONT COLOR="Navy">// Lo deserializa </FONT></I>
\r
183 <B>else</B> <I><FONT COLOR="Navy">// si es nulo </FONT></I>
\r
184 aObservador := restaurarObjeto( r.Match[1], r.Match[2] ) <I><FONT COLOR="Navy">// lo crea segun su clase </FONT></I>
\r
185 <B>else</B> <I><FONT COLOR="Navy">// Si no tiene una clase determinada, entonces se lo pone en nil </FONT></I>
\r
186 aObservador := <B>nil</B>
\r
187 <B>else</B> <I><FONT COLOR="Navy">// si no encontro la experesion... </FONT></I>
\r
188 <B>raise</B> ESerializacion.create( 'No se encontro el objetivo' ); <I><FONT COLOR="Navy">// cae en una excepcion </FONT></I>
\r
189 <B>except</B> <I><FONT COLOR="Navy">// Si hubieron errores ... </FONT></I>
\r
190 on e: ESerializacion <B>do</B> <B>begin</B> <I><FONT COLOR="Navy">// Si fueron de serializacion... </FONT></I>
\r
191 r.Free; <I><FONT COLOR="Navy">// libera memoria </FONT></I>
\r
192 <B>raise</B> ESerializacion.create( ClassName + ': Error al deserializar la posicion: ' + e.<B>Message</B> ); <I><FONT COLOR="Navy">// cae en una excepcion </FONT></I>
\r
194 on e: ERegExpr <B>do</B> <B>begin</B> <I><FONT COLOR="Navy">// si fueron de expresiones regulares... </FONT></I>
\r
195 r.Free; <I><FONT COLOR="Navy">// libera memoria </FONT></I>
\r
196 <B>raise</B> ESerializacion.create( ClassName + ': Error al extraer la posicion utilizando expresiones regulares: ' + e.<B>Message</B> ); <I><FONT COLOR="Navy">// cae en una excepcion </FONT></I>
\r
198 on e: EAccessViolation <B>do</B> <B>begin</B> <I><FONT COLOR="Navy">// si el Objetivo fue destruido... </FONT></I>
\r
199 aObservador := restaurarObjeto( r.Match[1], r.Match[2] ) <I><FONT COLOR="Navy">// lo crea segun su clase </FONT></I>
\r
202 <I><FONT COLOR="Navy">// RADIOMAXIMO </FONT></I>
\r
203 <B>try</B> <I><FONT COLOR="Navy">// se fija si hay errores al extraer los datos </FONT></I>
\r
204 r.Expression := '<radiomaximo>/s*([+/-]?/d+(/,/d+)?([eE][+/-]?/d+)?)/s*</radiomaximo>'; <I><FONT COLOR="Navy">// contruye la expresion regular a buscar </FONT></I>
\r
205 <B>if</B> r.Exec ( str ) <B>then</B> <I><FONT COLOR="Navy">// Ejecuta la expresion. Si la encuentra... </FONT></I>
\r
206 aRadioMaximo := StrToFloat( r.Match[1] )
\r
207 <B>else</B> <I><FONT COLOR="Navy">// si no encontro la experesion... </FONT></I>
\r
208 <B>raise</B> ESerializacion.create( 'No se encontro el radio maximo' ); <I><FONT COLOR="Navy">// cae en una excepcion </FONT></I>
\r
209 <B>except</B> <I><FONT COLOR="Navy">// Si hubieron errores ... </FONT></I>
\r
210 on e: ERegExpr <B>do</B> <B>begin</B> <I><FONT COLOR="Navy">// si fueron de expresiones regulares... </FONT></I>
\r
211 r.Free; <I><FONT COLOR="Navy">// libera memoria </FONT></I>
\r
212 <B>raise</B> ESerializacion.create( ClassName + ': Error al extraer el radio maximo utilizando expresiones regulares: ' + e.<B>Message</B> ); <I><FONT COLOR="Navy">// cae en una excepcion </FONT></I>
\r
215 <I><FONT COLOR="Navy">// RADIOMINIMO </FONT></I>
\r
216 <B>try</B> <I><FONT COLOR="Navy">// se fija si hay errores al extraer los datos </FONT></I>
\r
217 r.Expression := '<radiominimo>/s*([+/-]?/d+(/,/d+)?([eE][+/-]?/d+)?)/s*</radiominimo>'; <I><FONT COLOR="Navy">// contruye la expresion regular a buscar </FONT></I>
\r
218 <B>if</B> r.Exec ( str ) <B>then</B> <I><FONT COLOR="Navy">// Ejecuta la expresion. Si la encuentra... </FONT></I>
\r
219 aRadioMinimo := StrToFloat( r.Match[1] )
\r
220 <B>else</B> <I><FONT COLOR="Navy">// si no encontro la experesion... </FONT></I>
\r
221 <B>raise</B> ESerializacion.create( 'No se encontro el radio minimo' ); <I><FONT COLOR="Navy">// cae en una excepcion </FONT></I>
\r
222 <B>except</B> <I><FONT COLOR="Navy">// Si hubieron errores ... </FONT></I>
\r
223 on e: ERegExpr <B>do</B> <B>begin</B> <I><FONT COLOR="Navy">// si fueron de expresiones regulares... </FONT></I>
\r
224 r.Free; <I><FONT COLOR="Navy">// libera memoria </FONT></I>
\r
225 <B>raise</B> ESerializacion.create( ClassName + ': Error al extraer el radio minimo utilizando expresiones regulares: ' + e.<B>Message</B> ); <I><FONT COLOR="Navy">// cae en una excepcion </FONT></I>
\r
228 <I><FONT COLOR="Navy">// COSAPERTURA </FONT></I>
\r
229 <B>try</B> <I><FONT COLOR="Navy">// se fija si hay errores al extraer los datos </FONT></I>
\r
230 r.Expression := '<cosapertura>/s*([+/-]?/d+(/,/d+)?([eE][+/-]?/d+)?)/s*</cosapertura>'; <I><FONT COLOR="Navy">// contruye la expresion regular a buscar </FONT></I>
\r
231 <B>if</B> r.Exec ( str ) <B>then</B> <I><FONT COLOR="Navy">// Ejecuta la expresion. Si la encuentra... </FONT></I>
\r
232 aCosApertura := StrToFloat( r.Match[1] )
\r
233 <B>else</B> <I><FONT COLOR="Navy">// si no encontro la experesion... </FONT></I>
\r
234 <B>raise</B> ESerializacion.create( 'No se encontro el coseno de la apertura' ); <I><FONT COLOR="Navy">// cae en una excepcion </FONT></I>
\r
235 <B>except</B> <I><FONT COLOR="Navy">// Si hubieron errores ... </FONT></I>
\r
236 on e: ERegExpr <B>do</B> <B>begin</B> <I><FONT COLOR="Navy">// si fueron de expresiones regulares... </FONT></I>
\r
237 r.Free; <I><FONT COLOR="Navy">// libera memoria </FONT></I>
\r
238 <B>raise</B> ESerializacion.create( ClassName + ': Error al extraer el coseno de la apertura utilizando expresiones regulares: ' + e.<B>Message</B> ); <I><FONT COLOR="Navy">// cae en una excepcion </FONT></I>
\r
244 <I><FONT COLOR="Navy">{** Devuelve una cadena de texto con el objeto serializado.
\r
245 @return Cadena de texto con el objeto serializado.}</FONT></I>
\r
246 <B>function</B> <A NAME=cFiltro.mSerializar>cFiltro.mSerializar</A>: <B>string</B>;
\r
249 observador: <B>string</B>;
\r
251 <I><FONT COLOR="Navy">// Si el observador es nil o está destruido, se setea el atributo class del </FONT></I>
\r
252 <I><FONT COLOR="Navy">// TAG objetivo como '0' y entre el TAG se indica que es nil. Si no se </FONT></I>
\r
253 <I><FONT COLOR="Navy">// setea como el nombre de la clase y su expresion serializada respectivamente </FONT></I>
\r
254 observador := 'nil';
\r
256 <B>if</B> aObservador <> <B>nil</B> <B>then</B>
\r
258 observador := aObservador.mSerializar;
\r
259 clase := aObservador.ClassName;
\r
260 <B>except</B> <I><FONT COLOR="Navy">// Si esta destruido cambia la cadena de texto </FONT></I>
\r
261 on e: EAccessViolation <B>do</B> <B>begin</B>
\r
262 observador := 'nil';
\r
266 result := <B>inherited</B> mSerializar +
\r
267 '<observador class=' + clase + '>' + observador + '</observador>' +
\r
268 '<radiomaximo>' + FloatToStrF( aRadioMaximo, ffGeneral, 18, 0 ) + '</radiomaximo>' +
\r
269 '<radiominimo>' + FloatToStrF( aRadioMinimo, ffGeneral, 18, 0 ) + '</radiominimo>' +
\r
270 '<cosapertura>' + FloatToStrF( aCosApertura, ffGeneral, 18, 0 ) + '</cosapertura>';
\r
273 <I><FONT COLOR="Navy">{** Obtiene el radio máximo
\r
274 @return Radio máximo}</FONT></I>
\r
275 <B>function</B> <A NAME=cFiltro.mGetRadioMaximo>cFiltro.mGetRadioMaximo</A>: tLongitud;
\r
277 result := aRadioMaximo;
\r
280 <I><FONT COLOR="Navy">{** Obtiene el radio mínimo
\r
281 @return Radio mínimo}</FONT></I>
\r
282 <B>function</B> <A NAME=cFiltro.mGetRadioMinimo>cFiltro.mGetRadioMinimo</A>: tLongitud;
\r
284 result := aRadioMinimo;
\r
287 <I><FONT COLOR="Navy">{** Obtiene el coseno de la apertura
\r
288 @return Coseno de la apertura}</FONT></I>
\r
289 <B>function</B> <A NAME=cFiltro.mGetCosApertura>cFiltro.mGetCosApertura</A>: tAngulo;
\r
291 result := aCosApertura;
\r
294 <I><FONT COLOR="Navy">{ EObservadorDestruido }</FONT></I>
\r
296 <I><FONT COLOR="Navy">{** Constructor}</FONT></I>
\r
297 <B>constructor</B> EObservadorDestruido.create;
\r
299 <B>inherited</B> create( 'El Observador fue destruido.' );
\r