Página principal | Jerarquía de la clase | Lista alfabética | Lista de componentes | Lista de archivos | Miembros de las clases | Archivos de los miembros | Páginas relacionadas

colision.C

Ir a la documentación de este archivo.
00001 //===========================================================================
00002 //= colision.cc                                               Julio de 1999 =
00003 //=-------------------------------------------------------------------------=
00004 //= Declaraciones de las operaciones utilitarias para la deteccion general  =
00005 //= de colisiones.                                                          =
00006 //=-------------------------------------------------------------------------=
00007 //= ADVERTENCIA: ESTE SOFTWARE NO ESTA CONCEBIDO NI DISENNADO PARA EL USO   =
00008 //= EN EQUIPO DE CONTROL EN LINEA EN ENTORNOS PELIGROSOS QUE REQUIERAN UN   =
00009 //= DESEMPENNO LIBRE DE FALLAS, COMO LA OPERACION DE PLANTAS NUCLEARES,     = 
00010 //= SISTEMAS DE NAVEGACION O COMUNICACION EN AVIONES, TRAFICO AEREO,        =
00011 //= EQUIPO MEDICO DEL CUAL DEPENDAN VIDAS HUMANAS O SISTEMAS DE ARMAMENTO,  =
00012 //= EN LOS CUALES UNA FALLA EN EL SOFTWARE PUEDA IMPLICAR DIRECTAMENTE LA   =
00013 //= MUERTE, DANNOS PERSONALES O DANNOS FISICOS Y/O AMBIENTALES GRAVES       =
00014 //= ("ACTIVIDADES DE ALGO RIESGO").                                         =
00015 //=-------------------------------------------------------------------------=
00016 //= Autor original: Oscar J. Chavarro G.  A.K.A. JEDILINK. Copyright (c),   =
00017 //= 1997 - 2003, oscarchavarro@hotmail.com                                  =
00018 //= AQUYNZA es software libre, y se rige bajo los terminos de la licencia   =
00019 //= LGPL de GNU (http://www.gnu.org). Para mayor informacion respecto a la  =
00020 //= licencia de uso, consulte el archivo ./doc/LICENCIA en la distribucion. =
00021 //===========================================================================
00022 
00023 #include "core/simul/colision.h"
00024 #include "lista.cc"
00025 
00026 //===========================================================================
00027 //= Bromas globales                                                         =
00028 //===========================================================================
00029 
00030 static int COLOR_pareja = 0;
00031 static LISTA <CONTACTO *> contactos;
00032 
00033 LISTA <MINMAX *> TMP_debug_visual;
00034 static BOOLEAN visual_debug = TRUE;
00035 
00036 #define VERIFICAR(p)                                                    \
00037     if ( !p ) {                                                         \
00038         fprintf(stderr, "<COLISION> - ERROR: memoria insuficiente!\n"); \
00039         fflush(stderr);                                                 \
00040         return;                                                         \
00041     }
00042 
00043 //===========================================================================
00044 //= Clase utilitaria MINMAX                                                 =
00045 //===========================================================================
00046 
00047 MINMAX::MINMAX()
00048 {
00049     Rayito = NULL;
00050     switch ( COLOR_pareja ) {
00051       case 0: color.r = 1;  color.g = 1;  color.b = 1; break;
00052       case 1: color.r = 1;  color.g = 0;  color.b = 0; break;
00053       case 2: color.r = 0;  color.g = 1;  color.b = 0; break;
00054       case 3: color.r = 0;  color.g = 0;  color.b = 1; break;
00055       case 4: color.r = 1;  color.g = 1;  color.b = 0; break;
00056       case 5: color.r = 0;  color.g = 1;  color.b = 1; break;
00057       case 6: color.r = 1;  color.g = 0;  color.b = 1; break;
00058     }
00059     if ( COLOR_pareja >= 7 ) COLOR_pareja = 0;
00060 }
00061 
00062 MINMAX::~MINMAX()
00063 {
00064     if ( Rayito ) delete Rayito;
00065 }
00066 
00067 #ifdef GL_ENABLED
00068 void
00069 MINMAX::pintar_gl(void)
00070 {
00071     glColor3f(color.r, color.g, color.b);
00072     pintar_paralelepipedo(min, max);
00073     if ( Rayito ) {
00074         Rayito->pintar_gl();
00075     }
00076 }
00077 #endif
00078 
00079 //===========================================================================
00080 //= Clase CONTACTO                                                          =
00081 //===========================================================================
00082 
00083 CONTACTO::CONTACTO()
00084 {
00085     ;
00086 }
00087 
00088 CONTACTO::~CONTACTO()
00089 {
00090     ;
00091 }
00092 
00093 //===========================================================================
00094 //= Rutinas de deteccion de colisiones                                      =
00095 //===========================================================================
00096 
00097 #define SWAP(a, b) temp = (a); (a) = (b); (b) = temp;
00098 #define TA A->tipo_de_cosa()
00099 #define TB B->tipo_de_cosa()
00100 
00101 static void
00102 detector_colision_puntual_rigida(COSA *A, COSA *B,
00103     LISTA <CONTACTO *> *Colisiones, double udt, BOOLEAN visual_debug,
00104     MINMAX *m1, MINMAX *m2)
00123 {
00124     CONTACTO *Contacto = NULL;
00125     VECTOR nulo(0, 0, 0);
00126     VECTOR pos_actual, pos_anterior, punto_choque, normal_choque;
00127     RAYO rayo;
00128     double t;
00129 
00130     pos_actual = A->posicion_absoluta(nulo);
00131     pos_anterior = pos_actual - A->velocidad_absoluta()*udt;
00132     rayo.origen = pos_anterior;
00133     rayo.direccion = pos_actual - pos_anterior;
00134     if ( visual_debug ) {
00135         m1->Rayito = new RAYO();
00136         *(m1->Rayito) = rayo;
00137     }
00138     rayo.direccion.normalizar();
00139 
00140     t = B->interseccion(&rayo, &punto_choque, &normal_choque);
00141     punto_choque = punto_choque - rayo.direccion * (EPSILON * 4);  // OJO!
00142     if ( t < EPSILON || t > DISTANCIA_V(pos_actual, pos_anterior) ) {
00143         //printf("[falsa alarma](%.2f - %.2f)\n", t, 
00144         //    DISTANCIA_V(pos_actual, pos_anterior));
00145         //fflush(stdout);
00146       return;
00147     }
00148     else {
00149         //printf("[COLISION MASA_PUNTUAL/COSA_RIGIDA](%.2f - %.2f)\n", t,
00150         //    DISTANCIA_V(pos_actual, pos_anterior));
00151         //fflush(stdout);
00152         if ( visual_debug ) {
00153             m2->Rayito = new RAYO();
00154             m2->Rayito->origen = punto_choque;
00155             m2->Rayito->direccion = normal_choque * (0.3);
00156             ((MASA_PUNTUAL *)A)->en_colision = TRUE;
00157         }
00158         A->set_posicion_absoluta(punto_choque); // OJO: Esto es medio-machete!
00159         Contacto = new CONTACTO;
00160         VERIFICAR(Contacto);
00161         Contacto->A = A;
00162         Contacto->B = B;
00163         Contacto->p = punto_choque;
00164         // OJO: se supone que las dos normales son de igual direccion?
00165         Contacto->n_a = normal_choque * -1.0;
00166         Contacto->n_b = normal_choque;
00167         Contacto->t = t;
00168         Colisiones->anx(Contacto);
00169     }
00170 }
00171 
00172 static void
00173 detector_colision_tela_rigida(COSA *A, COSA *B,
00174     LISTA <CONTACTO *> *Colisiones, double udt, BOOLEAN visual_debug,
00175     MINMAX *m1, MINMAX *m2)
00183 {
00184     MASA_PUNTUAL *Mi;
00185     TELA *T = (TELA *)A;
00186     int i;
00187 
00188     for ( i = 0; i < T->num_masas(); i++ ) {
00189         Mi = T->masa_puntual(i);
00190         detector_colision_puntual_rigida(Mi, B, Colisiones, udt,
00191             visual_debug, m1, m2);
00192     }
00193 }
00194 
00195 static void
00196 detectar_par_colision(COSA *A, COSA *B, LISTA <CONTACTO *> *Colisiones,
00197                       double udt, BOOLEAN visual_debug)
00219 {
00220     //- Si las dos cosas son fijas no importa la colision! ------------------
00221     if ( A->estoy_fijo() && B->estoy_fijo() ) return;
00222 
00223     //- Pre-chequeo de condicion de la interseccion de min-max'es -----------
00224     MINMAX *m1, *m2;
00225 
00226     m1 = new MINMAX;
00227     A->minmax(&(m1->min), &(m1->max));
00228     m2 = new MINMAX;
00229     B->minmax(&(m2->min), &(m2->max));
00230 
00231     if ( ((m1->max.x >= m2->min.x) && (m1->min.x <= m2->max.x)) &&
00232          ((m1->max.y >= m2->min.y) && (m1->min.y <= m2->max.y)) &&
00233          ((m1->max.z >= m2->min.z) && (m1->min.z <= m2->max.z))     ) {
00234         if ( visual_debug ) {
00235             TMP_debug_visual.anx(m1); // Los min-max'es se intersectan
00236             TMP_debug_visual.anx(m2);
00237           }
00238           else {
00239             delete m1;
00240             delete m2;
00241         }
00242         COLOR_pareja++;
00243       }
00244       else {
00245         delete m1;                // Los min-max'es NO se intersectan
00246         delete m2;
00247         return;
00248     }
00249 
00250     //- Analisis detallado de colision --------------------------------------
00251     //- Aqui se analiza la pareja teniendo en cuenta el tipo de geometria   -
00252     //- de cada COSA.  Cada tipo de pareja posee un sistema de deteccion de -
00253     //- colisiones particular, y si no existe un sistema de deteccion para  -
00254     //- una pareja de tipos dada, la colision no se detectan (los objetos   -
00255     //- eventualmente se interpenetraran).                                  -
00256 
00257     //printf("[%s, %s]", A->nombre(), B->nombre());  fflush(stdout);
00258 
00259     // Preparacion: notese que la solucion de colision para cosas de dos
00260     // tipos A y B, es reciproca a la de los tipos B y A, por lo tanto, aqui
00261     // se verifica un "orden canonico".
00262     COSA *temp;
00263 
00264     if ( (TB == CC_MASA_PUNTUAL && TA == CC_COSA_RIGIDA) ||
00265          (TB == CC_TELA && TA == CC_COSA_RIGIDA)
00266        ) {
00267         SWAP(A, B);
00268     }
00269 
00270     // Procesamiento central
00271     if ( TA == CC_MASA_PUNTUAL && TB == CC_MASA_PUNTUAL ) {
00272         // En principio las masas infinitesimales no se estrellan...
00273         return;
00274       }
00275       else if ( TA == CC_MASA_PUNTUAL && TB == CC_COSA_RIGIDA ) {
00276         detector_colision_puntual_rigida(A, B, Colisiones, udt, visual_debug,
00277                                          m1, m2);
00278       }
00279       else if ( TA == CC_TELA && TB == CC_COSA_RIGIDA ) {
00280         detector_colision_tela_rigida(A, B, Colisiones, udt, visual_debug,
00281                                          m1, m2);
00282       }
00283     ;
00284 }
00285 
00286 //===========================================================================
00287 //= CLASE MANEJADOR_CONFLICTOS_COLISION                                     =
00288 //===========================================================================
00289 
00290 MANEJADOR_CONFLICTOS_COLISION::MANEJADOR_CONFLICTOS_COLISION()
00291 {
00292     ;
00293 }
00294 
00295 MANEJADOR_CONFLICTOS_COLISION::~MANEJADOR_CONFLICTOS_COLISION()
00296 {
00297     ;
00298 }
00299 
00300 //= Front-end de colisiones basado en el concepto de "conflicto" ============
00301 
00302 void
00303 MANEJADOR_CONFLICTOS_COLISION::detectar_conflictos(LISTA <COSA *> *Cosas,
00304                                                    double udt)
00335 {
00336     int i, j;
00337 
00338     //- Si se tiene una lista de chequeo visual, borrela --------------------
00339     for ( i = 0; i < TMP_debug_visual.tam(); i++ ) delete TMP_debug_visual[i];
00340     TMP_debug_visual.elim();
00341 
00342     //- Version inocente de verificacion de colision entre parejas ----------
00343     COLOR_pareja = 1;
00344 
00345     for ( i = 0; i < Cosas->tam()-1; i++ ) {
00346         for ( j = i+1; j < Cosas->tam(); j++ ) {
00347             detectar_par_colision((*Cosas)[i],(*Cosas)[j], &contactos,
00348                 udt,visual_debug);
00349         }
00350     }
00351 }
00352 
00353 //= Rutinas de respuesta a colisiones =======================================
00354 
00355 void
00356 MANEJADOR_CONFLICTOS_COLISION::resolver_conflictos(void)
00378 {
00379     int i;
00380 
00381     //- Algunas variables facilitan la notacion matematica... --------------
00382     COSA *A, *B;                                  // Temporales utilitarias
00383     CONTACTO *Contacto;                           //
00384     VECTOR centro_de_masa(0, 0, 0);               //
00385     double numerator, term1, term2, term3, term4; //
00386     VECTOR p;      // coordenadas globales del punto de contacto
00387     VECTOR n;      // normal a B en el punto de contacto
00388     VECTOR xa;     // posicion absoluta del centro de masa A
00389     VECTOR xb;     // posicion absoluta del centro de masa B
00390     VECTOR pa;     // coordenadas del punto de contacto en el sistema A
00391     VECTOR pb;     // coordenadas del punto de contacto en el sistema B
00392     VECTOR dot_pa; // velocidad puntual del punto de contacto en la cosa A
00393     VECTOR dot_pb; // velocidad puntual del punto de contacto en la cosa B
00394     double vrel;   // criterio de "en choque", "en contacto" o "separando".
00395     VECTOR J;      // es un vector en la direccion `n`, con magnitud `j`
00396     double j;      // magnitud de `J`
00397     VECTOR torque_impulsivo_a; // Torque impulsivo aplicado a A
00398     VECTOR torque_impulsivo_b; // Torque impulsivo aplicado a B
00399     double epsilon; // Coeficiente de restitucion absoluto para la colision
00400     MATRIZ_4x4 Ia_i; // Inversa del tensor de inercia de la cosa A
00401     MATRIZ_4x4 Ib_i; // Inversa del tensor de inercia de la cosa B
00402 
00403     //- Ciclo principal: el proceso se repite para cada pareja de COSAs ----
00404     for ( i = 0; i < contactos.tam(); i++ ) {
00405         // Esto esta aqui para aumentar la eficiencia...
00406         Contacto = contactos[i];
00407         A = Contacto->A;
00408         B = Contacto->B;
00409 
00410         //- 1. Calcule las velocidades puntuales en el lugar de colision ----
00411         p = Contacto->p;
00412         xa = A->posicion_absoluta(centro_de_masa);
00413         dot_pa = A->velocidad_absoluta() + 
00414             (A->velocidad_angular_absoluta().producto_cruz(p - xa));
00415 
00416         xb = B->posicion_absoluta(centro_de_masa);
00417         dot_pb = B->velocidad_absoluta() + 
00418             (B->velocidad_angular_absoluta().producto_cruz(p - xb));
00419 
00420         //- 2. Determine si la colision es un choque, un contacto o ninguno -
00421         // OJO: Aqui sobraria una normal en la representacion de CONTACTO,
00422         //      porque la idea es que n_a y n_b tienen la misma direccion!
00423         n = Contacto->n_b;
00424         n.normalizar();  // Por siaca'
00425         vrel = n.producto_punto(dot_pa - dot_pb);
00426         if ( vrel < -EPSILON ) {
00427             // 2.1. Las cosas se estan estrellando! 
00428 
00429             // Aqui se "retrocede" en el tiempo a cada pareja de cosas hasta
00430             // el instante en que supuestamente se habian chocado antes
00431             // de seguir... OJO!: ESTA IDEA TRAE PROBLEMAS!
00432             //A->actualizar(-Contacto->t);
00433             //B->actualizar(-Contacto->t);
00434 
00435             // Notese que `epsilon` modela una perdida de energia cinetica
00436             // en la colision, debida por ejemplo a que los objetos suenan o
00437             // se calientan
00438             epsilon = A->ke() * B->ke();  // Heuristica particular de AQUYNZA!
00439 
00440             // Se calcula `J`
00441             if ( A->estoy_fijo() ) Ia_i = Ia_i * 0;
00442             else Ia_i = (A->tensor_de_inercia()).inversa();
00443             if ( B->estoy_fijo() ) Ib_i = Ib_i * 0;
00444             else Ib_i = (B->tensor_de_inercia()).inversa();
00445             numerator = -((1 + epsilon) * vrel);
00446             if ( A->estoy_fijo() ) term1 = 0;
00447             else term1 = 1/A->masa();
00448             if ( B->estoy_fijo() ) term2 = 0;
00449             else term2 = 1/B->masa();
00450 
00451             pa = p - xa;
00452             pb = p - xb;
00453 
00454             term3 = n.producto_punto(
00455                       (Ia_i * (pa.producto_cruz(n))).producto_cruz(pa)
00456                     );
00457             term4 = n.producto_punto(
00458                       (Ib_i * (pb.producto_cruz(n))).producto_cruz(pb)
00459                     );
00460             j = numerator / (term1 + term2 + term3 + term4);
00461             J = n * j;
00462 
00463             // Se calcula el `torque impulsivo` 
00464             torque_impulsivo_a = pa.producto_cruz(J);
00465             torque_impulsivo_b = pb.producto_cruz(J*(-1));
00466 
00467             // Se aplican `J` y `torque_impulsivo`
00468             if ( !A->estoy_fijo() ) {
00469                 A->set_velocidad_absoluta(
00470                     A->velocidad_absoluta() + J * (1/A->masa()));
00471                 A->set_velocidad_angular_absoluta(
00472                     A->velocidad_angular_absoluta() + Ia_i*torque_impulsivo_a);
00473             }
00474             if ( !B->estoy_fijo() ) {
00475                 B->set_velocidad_absoluta(
00476                     B->velocidad_absoluta() - J * (1/B->masa()));
00477                 B->set_velocidad_angular_absoluta(
00478                     B->velocidad_angular_absoluta() + Ib_i*torque_impulsivo_b);
00479             }
00480 
00481             // Aqui se avanza de nuevo en el tiempo a cada pareja de cosas 
00482             // hasta el instante despues de chocarse
00483             // OJO!: ESTA IDEA TRAE PROBLEMAS!
00484             //A->actualizar(Contacto->t);
00485             //B->actualizar(Contacto->t);
00486           }
00487           else if ( vrel > EPSILON ) {
00488             // 2.2. Las cosas se estan alejando!
00489           }
00490           else {
00491             // 2.3. Las cosas estan en contacto!
00492           }
00493         ;
00494 
00495         //-------------------------------------------------------------------
00496         //printf("Colision #%d:[%s, %s]\n", i+1,
00497         //    A->nombre(), B->nombre());
00498         //fflush(stdout);
00499     }
00500 
00501     //- Al final del proceso elimine la lista de contactos -----------------
00502     for ( i = 0; i < contactos.tam(); i++ ) delete contactos[i];
00503     contactos.elim();
00504 }
00505 
00506 //===========================================================================
00507 //= EOF                                                                     =
00508 //===========================================================================
00509 

Este archivo HTML ha sido generado automáticamente a partir del código fuente AQUYNZA. NO LO EDITE. Para mayor información contacte al autor.