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