]> git.llucax.com Git - z.facultad/75.07/algowars.git/blob - src/modelo/Coordenadas.pas
Import inicial después del "/var incident". :(
[z.facultad/75.07/algowars.git] / src / modelo / Coordenadas.pas
1 {** Implementa un sistema de coordenadas y metodos para rotarlo.<br>\r
2     <i>Cambios:</i>\r
3     <PRE>\r
4     28/10/00: Se agregaron métodos para modificar el sistema de coordenadas, asignandole a un versor\r
5               particular la direccion de un vector arbitrario (mSetI, mSetJ, mSetK).\r
6     </PRE>}\r
7 unit Coordenadas;\r
8 \r
9 interface\r
10 \r
11 uses\r
12   Tipos,\r
13   ObjetoPersistente,\r
14   Vectores;\r
15 \r
16 type\r
17   {** Implementa un sistema de coordenadas y metodos para rotarlo.}\r
18   cCoordenadas = class( cObjetoPersistente )\r
19     private\r
20       aI,          // Versor i\r
21       aJ,          // Versor j\r
22       aK: cVector; // Versor k\r
23     public\r
24       {** Constructor}\r
25       constructor create; overload;\r
26       {** Constructor que se basa en otro sistema de coordenadas}\r
27       constructor create( c: cCoordenadas ); overload;\r
28       {** Rota el sistema de coordenadas sobre el eje i\r
29           (el sentido positivo es de j a k)}\r
30       function mRotarEnI( dAngulo: tAngulo ): cCoordenadas;\r
31       {** Rota el sistema de coordenadas sobre el eje j\r
32           (el sentido positivo es de i a k)}\r
33       function mRotarEnJ( dAngulo: tAngulo ): cCoordenadas;\r
34       {** Rota el sistema de coordenadas sobre el eje k\r
35           (el sentido positivo es de i a j)}\r
36       function mRotarEnK( dAngulo: tAngulo ): cCoordenadas;\r
37       {** Obtiene el versor i}\r
38       function mGetI: cVector;\r
39       {** Obtiene el versor j}\r
40       function mGetJ: cVector;\r
41       {** Obtiene el versor k}\r
42       function mGetK: cVector;\r
43       {** Setea la dirección del versor î igual que la del vector v.\r
44           Para lograr esto, rota primero sobre el eje k y luego sobre el eje j\r
45           (no se rota sobre el eje î).}\r
46       function mSetI( v: cVector ): cCoordenadas;\r
47       {** Setea la dirección del versor j igual que la del vector v.\r
48           Para lograr esto, rota primero sobre el eje î y luego sobre el eje k\r
49           (no se rota sobre el eje j).}\r
50       function mSetJ( v: cVector ): cCoordenadas;\r
51       {** Setea la dirección del versor k igual que la del vector v.\r
52           Para lograr esto, rota primero sobre el eje j y luego sobre el eje î\r
53           (no se rota sobre el eje k).}\r
54       function mSetK( v: cVector ): cCoordenadas;\r
55       {$IFDEF DebugAlgoWars}\r
56       {** Método heredado que devuelve un string con el estado del Objeto. Se utiliza para depurar\r
57           y la información entregada depende del parámetro tDebugInfo.}\r
58       function mGetDebugInfo( debugLevel: tDebugInfo = DI_MINI ): string; override;\r
59       {$ENDIF}\r
60       {** Destructor}\r
61       destructor destroy; override;\r
62       // SERIALIZACION\r
63       {** Devuelve una cadena de texto con el objeto serializado.}\r
64       function mSerializar: string; override;\r
65       {** Recrea el objeto a partir de una cadena de texto con el objeto\r
66           serializado.}\r
67       procedure mDesSerializar( str: string ); override;\r
68   end;\r
69 \r
70 implementation\r
71 \r
72 uses\r
73   RegExpr,\r
74   Math;\r
75 \r
76 { cCoordenadas }\r
77 \r
78 {** Constructor}\r
79 constructor cCoordenadas.create;\r
80 begin\r
81   inherited;\r
82   aI := cVector.create( 1, 0, 0 );\r
83   aJ := cVector.create( 0, 1, 0 );\r
84   aK := cVector.create( 0, 0, 1 );\r
85 end;\r
86 \r
87 {** Constructor que se basa en otro sistema de coordenadas\r
88     @param c Coordenadas en las que se basa para crear las nuevas}\r
89 constructor cCoordenadas.create(c: cCoordenadas);\r
90 var\r
91   v: cVector;\r
92 begin\r
93   inherited create;\r
94   v := c.mGetI;\r
95   aI := cVector.create( v );\r
96   v.free;\r
97   v := c.mGetJ;\r
98   aJ := cVector.create( v );\r
99   v.free;\r
100   v := c.mGetK;\r
101   aK := cVector.create( v );\r
102   v.free;\r
103 end;\r
104 \r
105 {** Destructor}\r
106 destructor cCoordenadas.destroy;\r
107 begin\r
108   aI.free;\r
109   aJ.free;\r
110   aK.free;\r
111   inherited;\r
112 end;\r
113 \r
114 {$IFDEF DebugAlgoWars}\r
115 {** Devuelve el estado del objeto basandose en la cantidad de datos requeridos.\r
116     @return            Cadena de texto con el estado del Objeto.\r
117     @param   debugLevel Cantidad de información requerida}\r
118 function cCoordenadas.mGetDebugInfo(debugLevel: tDebugInfo): string;\r
119 begin\r
120   result := 'Versor i: ' + aI.mGetDebugInfo( debugLevel ) + #13 + #10 +\r
121             'Versor j: ' + aJ.mGetDebugInfo( debugLevel ) + #13 + #10 +\r
122             'Versor k: ' + aK.mGetDebugInfo( debugLevel );\r
123 end;\r
124 {$ENDIF}\r
125 \r
126 {** Obtiene el versor i}\r
127 function cCoordenadas.mGetI: cVector;\r
128 begin\r
129   result := cVector.create( aI );\r
130 end;\r
131 \r
132 {** Obtiene el versor j}\r
133 function cCoordenadas.mGetJ: cVector;\r
134 begin\r
135   result := cVector.create( aJ );\r
136 end;\r
137 \r
138 {** Obtiene el versor k}\r
139 function cCoordenadas.mGetK: cVector;\r
140 begin\r
141   result := cVector.create( aK );\r
142 end;\r
143 \r
144 {** Rota el sistema de coordenadas sobre el eje i\r
145     @param angulo Ángulo a rotar}\r
146 function cCoordenadas.mRotarEnI(dAngulo: tAngulo): cCoordenadas;\r
147 var\r
148   oJ,               // componente en j\r
149   oK,               // componente en k\r
150   oNuevoJ,          // nueva coordenada j\r
151   oNuevoK: cVector; // nueva coordenada k\r
152 begin\r
153   // Primero se calcula el nuevo versor i utilizando la\r
154   //  transformacion lineal: j' = j * cos tAngulo + k * sin tAngulo\r
155   oJ := cVector.create( aJ ).mMultiplicar( cos( dAngulo ) );\r
156   oK := cVector.create( aK ).mMultiplicar( sin( dAngulo ) );\r
157   oNuevoJ := cVector.create( oJ ).mSumar( oK );\r
158   oJ.free;\r
159   oK.free;\r
160   // Ahora se calcula el nuevo versor k utilizando la\r
161   //  transformacion lineal: k' = k * cos tAngulo - j * sin tAngulo\r
162   oJ := cVector.create( aJ ).mMultiplicar( sin( dAngulo ) );\r
163   oK := cVector.create( aK ).mMultiplicar( cos( dAngulo ) );\r
164   oNuevoK := cVector.create( oK ).mRestar( oJ );\r
165   oJ.free;\r
166   oK.free;\r
167   // Se reemplazan los viejos versores por los nuevos\r
168   aJ.mSet( oNuevoJ );\r
169   aK.mSet( oNuevoK );\r
170   oNuevoJ.free;\r
171   oNuevoK.free;\r
172   result := self;\r
173 end;\r
174 \r
175 {** Rota el sistema de coordenadas sobre el eje j\r
176     @param angulo Ángulo a rotar}\r
177 function cCoordenadas.mRotarEnJ(dAngulo: tAngulo): cCoordenadas;\r
178 var\r
179   oI,               // componente en i\r
180   oK,               // componente en k\r
181   oNuevoI,          // nueva coordenada i\r
182   oNuevoK: cVector; // nueva coordenada k\r
183 begin\r
184   // Primero se calcula el nuevo versor i utilizando la\r
185   //  transformacion lineal: i' = i * cos tAngulo + k * sin tAngulo\r
186   oI := cVector.create( aI ).mMultiplicar( cos( dAngulo ) );\r
187   oK := cVector.create( aK ).mMultiplicar( sin( dAngulo ) );\r
188   oNuevoI := cVector.create( oI ).mSumar( oK );\r
189   oI.free;\r
190   oK.free;\r
191   // Ahora se calcula el nuevo versor k utilizando la\r
192   //  transformacion lineal: k' = k * cos tAngulo - i * sin tAngulo\r
193   oI := cVector.create( aI ).mMultiplicar( sin( dAngulo ) );\r
194   oK := cVector.create( aK ).mMultiplicar( cos( dAngulo ) );\r
195   oNuevoK := cVector.create( oK ).mRestar( oI );\r
196   oI.free;\r
197   oK.free;\r
198   // Se reemplazan los viejos versores por los nuevos\r
199   aI.mSet( oNuevoI );\r
200   aK.mSet( oNuevoK );\r
201   oNuevoI.free;\r
202   oNuevoK.free;\r
203   result := self;\r
204 end;\r
205 \r
206 {** Rota el sistema de coordenadas sobre el eje k\r
207     @param angulo Ángulo a rotar}\r
208 function cCoordenadas.mRotarEnK(dAngulo: tAngulo): cCoordenadas;\r
209 var\r
210   oI,               // componente en i\r
211   oJ,               // componente en j\r
212   oNuevoI,          // nueva coordenada i\r
213   oNuevoJ: cVector; // nueva coordenada j\r
214 begin\r
215   // Primero se calcula el nuevo versor i utilizando la\r
216   //  transformacion lineal: i' = i * cos tAngulo + j * sin tAngulo\r
217   oI := cVector.create( aI ).mMultiplicar( cos( dAngulo ) );\r
218   oJ := cVector.create( aJ ).mMultiplicar( sin( dAngulo ) );\r
219   oNuevoI := cVector.create( oI ).mSumar( oJ );\r
220   oI.free;\r
221   oJ.free;\r
222   // Ahora se calcula el nuevo versor j utilizando la\r
223   //  transformacion lineal: j' = j * cos tAngulo - i * sin tAngulo\r
224   oI := cVector.create( aI ).mMultiplicar( sin( dAngulo ) );\r
225   oJ := cVector.create( aJ ).mMultiplicar( cos( dAngulo ) );\r
226   oNuevoJ := cVector.create( oJ ).mRestar( oI );\r
227   oI.free;\r
228   oJ.free;\r
229   // Se reemplazan los viejos versores por los nuevos\r
230   aI.mSet( oNuevoI );\r
231   aJ.mSet( oNuevoJ );\r
232   oNuevoI.free;\r
233   oNuevoJ.free;\r
234   result := self;\r
235 end;\r
236 \r
237 {** Setea la dirección del versor î igual que la del vector v.\r
238     Para lograr esto, rota primero sobre el eje k y luego sobre el eje j\r
239     (no se rota sobre el eje î).\r
240     @param v Dirección a asignarle a î (no puede ser nulo!)}\r
241 function cCoordenadas.mSetI(v: cVector): cCoordenadas;\r
242 var\r
243   vProy,              // Proyección de v sobre el plano ij\r
244   vi,                 // ip.i (vector proyeccion de v en i)\r
245   vj: cVector;        // jp.j (vector proyeccion de v en j)\r
246   ip,                 // v.i  (proyeccion de v en i)\r
247   jp,                 // v.j  (proyeccion de v en j)\r
248   kp,                 // v.k  (proyeccion de v en k)\r
249   modulo: tLongitud;  // Módulo de vProy\r
250   alfa,               // Angulo formado entre i y vProy\r
251   beta: tAngulo;      // Angulo formado entre i' (i rotado sobre k) y v\r
252 begin\r
253   // Se calcula la proyeccion de v sobre el plano formado por î y j.\r
254   // Para hacer esto, se utiliza la farmula de proyeccion a partir de una base ortonormal\r
255   //  del subespacio en donde proyectar (en este caso el subespacio es el plano formado\r
256   //  por îj y los versores de la BON son î y j:\r
257   //    Proy ij (v) = (v.i).i + (v.j).j\r
258   // Se crea en base a i y se multiplica por el producto escalar entre v y î\r
259   ip := v.mMultiplicarEsc( aI );\r
260   vi := cVector.create( aI ).mMultiplicar( ip );\r
261   // Se crea en base a j y se multiplica por el producto escalar entre v y j\r
262   jp := v.mMultiplicarEsc( aJ );\r
263   vj := cVector.create( aJ ).mMultiplicar( jp );\r
264   // Ahora se calcula la proyección sumando vi y vj\r
265   vProy := cVector.create( vi ).mSumar( vj );\r
266   // Con esta proyección podemos calcular en ángulo que debemos rotar las coordenadas\r
267   //  sobre el eje k de la siguiente forma (se toman las proyecciones para que, dependiendo\r
268   //  del signo, se pueda establecer el ángulo correcto):\r
269   //    tg alfa = jp / ip  ==> alfa = arctg( jp / ip )\r
270   //  si ip = 0  ==>  v no tiene componentes en i  ==>  se sabe que el angulo es recto,\r
271   //   para saber si es PI/2 o -PI/2, verificamos si (vProy.j)/|vProy| = cos vProyj = 1,\r
272   //   entonces alfa = PI/2. Si (vProy.j)/|vProy| = cos vProyj = -1  ==>  alfa = -PI/2\r
273   modulo := vProy.mGetModulo;\r
274   if modulo > 0 then begin // solo hace falta rotarlo si la proyeccion no es nula\r
275     alfa := arctan2( jp, ip );\r
276     if alfa <> 0 then begin // Si el angulo es distinto de cero, hay que rotarlo\r
277       if alfa = PI/2 then // Si es PI/2 hay que verificar que no sea en realidad -PI/2\r
278         // Se compara tomando en cuenta si es menor que cero porque ya sabemos que\r
279         //  solo puede ser 1 o -1.\r
280         if jp / modulo < 0 then // cos vProyj = vProy . j / |vProy| = jp . |vProy|\r
281           alfa := -alfa; // alfa = -PI/2\r
282       mRotarEnK( alfa ); // rotamos sobre el eje k ese angulo\r
283     end;\r
284   end;\r
285   // Ahora tenemos que hallar beta, para esto se calculan las proyecciones sobre i y k\r
286   // Se calcula la proyeccion, para eso se multiplica por el producto escalar entre v y î\r
287   ip := v.mMultiplicarEsc( aI );\r
288   // Se calcula la proyeccion, para eso se multiplica por el producto escalar entre v y k\r
289   kp := v.mMultiplicarEsc( aK );\r
290   // Con estas proyecciones podemos calcular en ángulo que debemos rotar las coordenadas\r
291   //  sobre el eje k de la siguiente forma (se toman las proyecciones para que, dependiendo\r
292   //  del signo, se pueda establecer el ángulo correcto):\r
293   //    tg beta = kp / ip  ==> beta = arctg( kp / ip )\r
294   //  si ip = 0  ==>  v no tiene componentes en i  ==>  se sabe que el angulo es recto,\r
295   //   para saber si es PI/2 o -PI/2, verificamos si (v.k)/|v| = cos vk = 1,\r
296   //   entonces beta = PI/2. Si (v.k)/|v| = cos vk = -1  ==>  beta = -PI/2\r
297   modulo := v.mGetModulo;\r
298   if modulo > 0 then begin // solo hace falta rotarlo si la proyeccion no es nula\r
299     beta := arctan2( kp, ip );\r
300     if beta <> 0 then begin // Si el angulo es distinto de cero, hay que rotarlo\r
301       if beta = PI/2 then // Si es PI/2 hay que verificar que no sea en realidad -PI/2\r
302         // Se compara tomando en cuenta si es menor que cero porque ya sabemos que\r
303         //  solo puede ser 1 o -1.\r
304         if kp / modulo < 0 then // cos vk = v . k / |v| = kp . |v|\r
305           beta := -beta; // beta = -PI/2\r
306       mRotarEnJ( beta ); // rotamos sobre el eje j ese angulo\r
307     end;\r
308   end;\r
309   // Aca termina, ya que no se realiza ninguna rotacion sobre el eje i\r
310   result := self;\r
311 end;\r
312 \r
313 {** Setea la dirección del versor j igual que la del vector v.\r
314     Para lograr esto, rota primero sobre el eje î y luego sobre el eje k\r
315     (no se rota sobre el eje j).\r
316     @param v Dirección a asignarle a j (no puede ser nulo!)}\r
317 function cCoordenadas.mSetJ(v: cVector): cCoordenadas;\r
318 var\r
319   vProy,              // Proyección de v sobre el plano jk\r
320   vj,                 // jp.j (vector proyeccion de v en j)\r
321   vk: cVector;        // kp.k (vector proyeccion de v en k)\r
322   ip,                 // v.i  (proyeccion de v en i)\r
323   jp,                 // v.j  (proyeccion de v en j)\r
324   kp,                 // v.k  (proyeccion de v en k)\r
325   modulo: tLongitud;  // Módulo de vProy\r
326   alfa,               // Angulo formado entre j y vProy\r
327   beta: tAngulo;      // Angulo formado entre j' (j rotado sobre i) y v\r
328 begin\r
329   // Se calcula la proyeccion de v sobre el plano formado por j y k.\r
330   // Para hacer esto, se utiliza la farmula de proyeccion a partir de una base ortonormal\r
331   //  del subespacio en donde proyectar (en este caso el subespacio es el plano formado\r
332   //  por jk y los versores de la BON son j y k:\r
333   //    Proy jk (v) = (v.j).j + (v.k).k\r
334   // Se crea en base a j y se multiplica por el producto escalar entre v y j\r
335   jp := v.mMultiplicarEsc( aJ );\r
336   vj := cVector.create( aJ ).mMultiplicar( jp );\r
337   // Se crea en base a k y se multiplica por el producto escalar entre v y k\r
338   kp := v.mMultiplicarEsc( aK );\r
339   vk := cVector.create( aK ).mMultiplicar( kp );\r
340   // Ahora se calcula la proyección sumando vj y vk\r
341   vProy := cVector.create( vj ).mSumar( vk );\r
342   // Con esta proyección podemos calcular en ángulo que debemos rotar las coordenadas\r
343   //  sobre el eje i de la siguiente forma (se toman las proyecciones para que, dependiendo\r
344   //  del signo, se pueda establecer el ángulo correcto):\r
345   //    tg alfa = kp / jp  ==> alfa = arctg( kp / jp )\r
346   //  si jp = 0  ==>  v no tiene componentes en j  ==>  se sabe que el angulo es recto,\r
347   //   para saber si es PI/2 o -PI/2, verificamos si (vProy.k)/|vProy| = cos vProyk = 1,\r
348   //   entonces alfa = PI/2. Si (vProy.k)/|vProy| = cos vProyk = -1  ==>  alfa = -PI/2\r
349   modulo := vProy.mGetModulo;\r
350   if modulo > 0 then begin // solo hace falta rotarlo si la proyeccion no es nula\r
351     alfa := arctan2( kp, jp );\r
352     if alfa <> 0 then begin // Si el angulo es distinto de cero, hay que rotarlo\r
353       if alfa = PI/2 then // Si es PI/2 hay que verificar que no sea en realidad -PI/2\r
354         // Se compara tomando en cuenta si es menor que cero porque ya sabemos que\r
355         //  solo puede ser 1 o -1.\r
356         if kp / modulo < 0 then // cos vProyk = vProy . k / |vProy| = kp . |vProy|\r
357           alfa := -alfa; // alfa = -PI/2\r
358       mRotarEnI( alfa ); // rotamos sobre el eje i ese angulo\r
359     end;\r
360   end;\r
361   // Ahora tenemos que hallar beta, para esto se calculan las proyecciones sobre j y i\r
362   // Se calcula la proyeccion, para eso se multiplica por el producto escalar entre v y j\r
363   jp := v.mMultiplicarEsc( aJ );\r
364   // Se calcula la proyeccion, para eso se multiplica por el producto escalar entre v y i\r
365   ip := v.mMultiplicarEsc( aI );\r
366   // Con estas proyecciones podemos calcular en ángulo que debemos rotar las coordenadas\r
367   //  sobre el eje k de la siguiente forma (se toman las proyecciones para que, dependiendo\r
368   //  del signo, se pueda establecer el ángulo correcto):\r
369   //    tg beta = ip / jp  ==> beta = arctg( ip / jp )\r
370   //  si jp = 0  ==>  v no tiene componentes en j  ==>  se sabe que el angulo es recto,\r
371   //   para saber si es PI/2 o -PI/2, verificamos si (v.i)/|v| = cos vi = 1,\r
372   //   entonces beta = PI/2. Si (v.i)/|v| = cos vi = -1  ==>  beta = -PI/2\r
373   modulo := v.mGetModulo;\r
374   if modulo > 0 then begin // solo hace falta rotarlo si la proyeccion no es nula\r
375     beta := arctan2( ip, jp );\r
376     if beta <> 0 then begin // Si el angulo es distinto de cero, hay que rotarlo\r
377       if beta = PI/2 then // Si es PI/2 hay que verificar que no sea en realidad -PI/2\r
378         // Se compara tomando en cuenta si es menor que cero porque ya sabemos que\r
379         //  solo puede ser 1 o -1.\r
380         if ip / modulo < 0 then // cos vi = v . i / |v| = ip . |v|\r
381           beta := -beta; // beta = -PI/2\r
382       mRotarEnK( -beta ); // rotamos sobre el eje k ese angulo (el signo negativo es porque\r
383                           //  estamos rotando en sentido opuesto, de j a i)\r
384     end;\r
385   end;\r
386   // Aca termina, ya que no se realiza ninguna rotacion sobre el eje j\r
387   result := self;\r
388 end;\r
389 \r
390 {** Setea la dirección del versor k igual que la del vector v.\r
391     Para lograr esto, rota primero sobre el eje j y luego sobre el eje î\r
392     (no se rota sobre el eje k).\r
393     @param v Dirección a asignarle a k (no puede ser nulo!)}\r
394 function cCoordenadas.mSetK(v: cVector): cCoordenadas;\r
395 var\r
396   vProy,              // Proyección de v sobre el plano jk\r
397   vi,                 // ip.i (vector proyeccion de v en i)\r
398   vk: cVector;        // kp.k (vector proyeccion de v en k)\r
399   ip,                 // v.i  (proyeccion de v en i)\r
400   jp,                 // v.j  (proyeccion de v en j)\r
401   kp,                 // v.k  (proyeccion de v en k)\r
402   modulo: tLongitud;  // Módulo de vProy\r
403   alfa,               // Angulo formado entre j y vProy\r
404   beta: tAngulo;      // Angulo formado entre j' (j rotado sobre i) y v\r
405 begin\r
406   // Se calcula la proyeccion de v sobre el plano formado por k y i.\r
407   // Para hacer esto, se utiliza la farmula de proyeccion a partir de una base ortonormal\r
408   //  del subespacio en donde proyectar (en este caso el subespacio es el plano formado\r
409   //  por ki y los versores de la BON son k y i:\r
410   //    Proy ki (v) = (v.k).k + (v.i).i\r
411   // Se crea en base a k y se multiplica por el producto escalar entre v y k\r
412   kp := v.mMultiplicarEsc( aK );\r
413   vk := cVector.create( aK ).mMultiplicar( kp );\r
414   // Se crea en base a k y se multiplica por el producto escalar entre v y k\r
415   ip := v.mMultiplicarEsc( aI );\r
416   vi := cVector.create( aI ).mMultiplicar( ip );\r
417   // Ahora se calcula la proyección sumando vk y vi\r
418   vProy := cVector.create( vk ).mSumar( vi );\r
419   // Con esta proyección podemos calcular en ángulo que debemos rotar las coordenadas\r
420   //  sobre el eje j de la siguiente forma (se toman las proyecciones para que, dependiendo\r
421   //  del signo, se pueda establecer el ángulo correcto):\r
422   //    tg alfa = ip / kp  ==> alfa = arctg( ip / kp )\r
423   //  si kp = 0  ==>  v no tiene componentes en j  ==>  se sabe que el angulo es recto,\r
424   //   para saber si es PI/2 o -PI/2, verificamos si (vProy.i)/|vProy| = cos vProyi = 1,\r
425   //   entonces alfa = PI/2. Si (vProy.i)/|vProy| = cos vProyi = -1  ==>  alfa = -PI/2\r
426   modulo := vProy.mGetModulo;\r
427   if modulo > 0 then begin // solo hace falta rotarlo si la proyeccion no es nula\r
428     alfa := arctan2( ip, kp );\r
429     if alfa <> 0 then begin // Si el angulo es distinto de cero, hay que rotarlo\r
430       if alfa = PI/2 then // Si es PI/2 hay que verificar que no sea en realidad -PI/2\r
431         // Se compara tomando en cuenta si es menor que cero porque ya sabemos que\r
432         //  solo puede ser 1 o -1.\r
433         if ip / modulo < 0 then // cos vProyi = vProy . i / |vProy| = ip . |vProy|\r
434           alfa := -alfa; // alfa = -PI/2\r
435       mRotarEnJ( -alfa ); // rotamos sobre el eje j ese angulo (el signo negativo es porque\r
436                           //  estamos rotando en sentido opuesto, de k a i)\r
437     end;\r
438   end;\r
439   // Ahora tenemos que hallar beta, para esto se calculan las proyecciones sobre k y j\r
440   // Se calcula la proyeccion, para eso se multiplica por el producto escalar entre v y k\r
441   kp := v.mMultiplicarEsc( aK );\r
442   // Se calcula la proyeccion, para eso se multiplica por el producto escalar entre v y j\r
443   jp := v.mMultiplicarEsc( aJ );\r
444   // Con estas proyecciones podemos calcular en ángulo que debemos rotar las coordenadas\r
445   //  sobre el eje i de la siguiente forma (se toman las proyecciones para que, dependiendo\r
446   //  del signo, se pueda establecer el ángulo correcto):\r
447   //    tg beta = jp / kp  ==> beta = arctg( jp / kp )\r
448   //  si kp = 0  ==>  v no tiene componentes en k  ==>  se sabe que el angulo es recto,\r
449   //   para saber si es PI/2 o -PI/2, verificamos si (v.j)/|v| = cos vj = 1,\r
450   //   entonces beta = PI/2. Si (v.j)/|v| = cos vj = -1  ==>  beta = -PI/2\r
451   modulo := v.mGetModulo;\r
452   if modulo > 0 then begin // solo hace falta rotarlo si la proyeccion no es nula\r
453     beta := arctan2( jp, kp );\r
454     if beta <> 0 then begin // Si el angulo es distinto de cero, hay que rotarlo\r
455       if beta = PI/2 then // Si es PI/2 hay que verificar que no sea en realidad -PI/2\r
456         // Se compara tomando en cuenta si es menor que cero porque ya sabemos que\r
457         //  solo puede ser 1 o -1.\r
458         if ip / modulo < 0 then // cos vj = v . j / |v| = jp . |v|\r
459           beta := -beta; // beta = -PI/2\r
460       mRotarEnI( -beta ); // rotamos sobre el eje i ese angulo (el signo negativo es porque\r
461                           //  estamos rotando en sentido opuesto, de k a j)\r
462     end;\r
463   end;\r
464   // Aca termina, ya que no se realiza ninguna rotacion sobre el eje k\r
465   result := self;\r
466 end;\r
467 \r
468 {** Recrea el objeto a partir de una cadena de texto con el objeto\r
469     serializado.\r
470     @param str Cadena de texto con el objeto serializado.}\r
471 procedure cCoordenadas.mDesSerializar(str: string);\r
472 var\r
473   r: TRegExpr;\r
474 begin\r
475   inherited mDesSerializar( str ); // SIEMPRE el ID debe ser el PRIMER atributo\r
476   r := TRegExpr.create;\r
477   // VERSOR I\r
478   try // se fija si hay errores al extraer los datos\r
479     r.Expression := '<i>\s*(.+)\s*</i>'; // contruye la expresion regular a buscar\r
480     if r.Exec ( str ) then // Ejecuta la expresion. Si la encuentra...\r
481       if aI <> nil then // Si no es nulo\r
482         aI.mDesSerializar( r.Match[1] ) // Lo deserializa\r
483       else // si es nulo\r
484         aI := cVector.crearDeSerializado( r.Match[1] ) // lo crea\r
485     else // si no encontro la experesion...\r
486       raise ESerializacion.create( 'No se encontro el versor i' ); // cae en una excepcion\r
487   except // Si hubieron errores ...\r
488     on e: ESerializacion do begin // Si fueron de serializacion...\r
489       r.Free; // libera memoria\r
490       raise ESerializacion.create( ClassName + ': Error al deserializar el versor i: ' + e.Message ); // cae en una excepcion\r
491     end;\r
492     on e: ERegExpr do begin // si fueron de expresiones regulares...\r
493       r.Free; // libera memoria\r
494       raise ESerializacion.create( ClassName + ': Error al extraer el versor i utilizando expresiones regulares: ' + e.Message ); // cae en una excepcion\r
495     end;\r
496   end;\r
497   // VERSOR J\r
498   try // se fija si hay errores al extraer los datos\r
499     r.Expression := '<j>\s*(.+)\s*</j>';\r
500     if r.Exec ( str ) then\r
501       if aJ <> nil then\r
502         aJ.mDesSerializar( r.Match[1] )\r
503       else\r
504         aJ := cVector.crearDeSerializado( r.Match[1] )\r
505     else\r
506       raise ESerializacion.create( 'No se encontro el versor j' );\r
507   except\r
508     on e: ESerializacion do begin\r
509       r.Free;\r
510       raise ESerializacion.create( ClassName + ': Error al deserializar el versor j: ' + e.Message );\r
511     end;\r
512     on e: ERegExpr do begin\r
513       r.Free;\r
514       raise ESerializacion.create( ClassName + ': Error al extraer el versor j utilizando expresiones regulares: ' + e.Message );\r
515     end;\r
516   end;\r
517   // VERSOR K\r
518   try // se fija si hay errores al extraer los datos\r
519     r.Expression := '<k>\s*(.+)\s*</k>';\r
520     if r.Exec ( str ) then\r
521       if aK <> nil then\r
522         aK.mDesSerializar( r.Match[1] )\r
523       else\r
524         aK := cVector.crearDeSerializado( r.Match[1] )\r
525     else\r
526       raise ESerializacion.create( 'No se encontro el versor k' );\r
527   except\r
528     on e: ESerializacion do begin\r
529       r.Free;\r
530       raise ESerializacion.create( ClassName + ': Error al deserializar el versor k: ' + e.Message );\r
531     end;\r
532     on e: ERegExpr do begin\r
533       r.Free;\r
534       raise ESerializacion.create( ClassName + ': Error al extraer el versor k utilizando expresiones regulares: ' + e.Message );\r
535     end;\r
536   end;\r
537   r.free;\r
538 end;\r
539 \r
540 {** Devuelve una cadena de texto con el objeto serializado.\r
541     @return Cadena de texto con el objeto serializado.}\r
542 function cCoordenadas.mSerializar: string;\r
543 begin\r
544   result := inherited mSerializar +\r
545             '<i>' + aI.mSerializar + '</i>' +\r
546             '<j>' + aJ.mSerializar + '</j>' +\r
547             '<k>' + aK.mSerializar + '</k>';\r
548 end;\r
549 \r
550 end.\r