shape_doc 0.1
/Users/mourrain/Devel/mmx/shape/src/ssiqts.cpp
Go to the documentation of this file.
00001 # include <shape/ssiqts.hpp>
00002 # include <shape/surface_parametric.hpp>
00003 # define  ParametricSurface shape::surface_parametric<double>
00004 
00005 namespace mmx {
00006 #include <shape/ssiqts_offsets.hpp>
00007 
00008 static bool swap;
00009 
00010 SSIQTS::sample::sample( ParametricSurface * s, int m, int n )
00011 {
00012   m_uvals = new double[3*m*n+m+n];
00013   m_vvals = m_uvals + m;
00014   m_svals = (fxv<double,3>*)(m_vvals + n);
00015   m_nrows = m;
00016   m_ncols = n;
00017   swap = true; s->sample((double*)m_svals,m,n,m_uvals,m_vvals);
00018   //  for ( int i = 0; i < m*n; i ++ ) std::cout << m_svals[i]  << std::endl;
00019 };
00020 
00021 SSIQTS::sample::~sample() { delete[] m_uvals; };
00022 
00023 static SSIQTS::aabb3 * alloc( int& l, int m, int& s )
00024 {
00025   int c = m*m;
00026   s = 0;
00027   l = 0;
00028   while ( c ) { s += c; c /= 4; l ++;  };
00029   return new SSIQTS::aabb3[s];
00030 };
00031 
00032 static void fillpatchbox( SSIQTS::aabb3& b, const SSIQTS::vector3 * a, SSIQTS& ssi )
00033 {
00034   //  unsigned nrows = ssi.m*ssi.udeg+1;
00035   unsigned ncols = ssi.m*ssi.vdeg+1;
00036   //  unsigned srows = ssi.udeg*ncols;      
00037   const SSIQTS::vector3 *  la = a;
00038   const SSIQTS::vector3 * ela = a + (ssi.udeg+1)*ncols;
00039   const SSIQTS::vector3 * ca;
00040   for ( int d = 0; d < 3;  d ++ ) b[d][0] = b[d][1] = (*a)[d];
00041   for ( ca = a+1; ca != la + ssi.vdeg+1; ca++ )
00042     for ( int d = 0; d < 3; d ++ )
00043       {
00044         if ( (*ca)[d] < b[d][0] ) b[d][0] = (*ca)[d];
00045         else if ( (*ca)[d] > b[d][1]) b[d][1] = (*ca)[d];
00046       };
00047   
00048   for ( la = a+ncols; la != ela; la += ncols )
00049     for ( ca = la; ca != la + ssi.vdeg+1; ca ++ )
00050       for ( int d = 0; d < 3; d ++ )
00051         {
00052           if ( (*ca)[d] < b[d][0] ) b[d][0] = (*ca)[d];
00053           else if ( (*ca)[d] > b[d][1] ) b[d][1] = (*ca)[d];
00054         };
00055 };
00056 
00057 
00058 static void fillboxes( SSIQTS::aabb3 * qta, const SSIQTS::vector3 * base, SSIQTS& ssi )
00059 {
00060   unsigned nrows = ssi.m*ssi.udeg+1;
00061   unsigned ncols = ssi.m*ssi.vdeg+1;
00062   unsigned srows = ssi.udeg*ncols;
00063   const SSIQTS::vector3 * lptr  = base;
00064   const SSIQTS::vector3 * cptr;
00065   const SSIQTS::vector3 * elptr = base + nrows*(ncols-1);
00066   for ( lptr = base; lptr != elptr; lptr += srows )
00067     for ( cptr = lptr; cptr != lptr + ncols-1; cptr += ssi.vdeg, qta++  )
00068       fillpatchbox( *qta, cptr, ssi );
00069 };
00070 
00071 static bool intersectp( const SSIQTS::aabb3 & a, const SSIQTS::aabb3 & b )
00072 {
00073   for ( int i = 0; i < 3; i ++ ) 
00074     if ( a[i][1] < b[i][0] || b[i][1] < a[i][0] ) return false;
00075   return true;
00076 };
00077 
00078 static void merge( SSIQTS::aabb3 & box, const SSIQTS::aabb3& a, const SSIQTS::aabb3 & b )
00079 {
00080   for ( unsigned i = 0; i < 3; i ++ )
00081     {
00082       box[i][0] = std::min(a[i][0],b[i][0]);
00083       box[i][1] = std::max(a[i][1],b[i][1]);
00084     };
00085 };
00086 
00087 static void update( SSIQTS::aabb3& box, const SSIQTS::aabb3& a, const SSIQTS::aabb3& b )
00088 {
00089   double tmp;
00090   for ( int i = 0; i < 3; i ++ )
00091     {
00092       tmp = std::min(a[i][0],b[i][0]);
00093       if ( tmp < box[i][0] ) box[i][0] = tmp;
00094       tmp = std::max(a[i][1],b[i][1]);
00095       if ( tmp > box[i][1] ) box[i][1] = tmp;
00096     };
00097 };
00098 
00099 static void build( SSIQTS::aabb3 * base, const SSIQTS & ssi )
00100 {
00101   int N = ssi.m;
00102   SSIQTS::aabb3 * cptr,*eptr,*next,*enext;
00103   cptr  = base;
00104   eptr  = base + N;
00105   next  = base + N*N;
00106   enext = next + (N/2*N/2);
00107   
00108   while ( next < enext )
00109     {
00110       base = next;
00111       do
00112         {
00113           for ( ;cptr < eptr; cptr += 2, next++ )
00114             {  
00115               merge(*next,*cptr,*(cptr+1));
00116               update(*next,*(cptr+N),*(cptr+1+N));
00117             };
00118           
00119           cptr += N;
00120           eptr  = cptr + N;
00121         }
00122       while ( next < enext );
00123       cptr = base;
00124       N /= 2;
00125       eptr = cptr + N;
00126       enext = next + (N/2)*(N/2);
00127     };
00128 };
00129   
00130 
00131 /* tests de collision sur un niveau de subdivision */
00132 static int cfhunt( 
00133                   SSIQTS::aabb3 * lbb, /* ensemble des boites de la surface "gauche" au niveau actuel de subdivision */
00134                   SSIQTS::aabb3 * rbb, /* ensemble des boites de la surface "droite" au niveau actuel de subdivision */
00135                   int * bcf,   /* debut de la liste des conflits */
00136                   int * ecf )  /* fin   de la liste des conflits */
00137 {
00138   int s = 0;
00139   int * rqp;  // right-quad pointer
00140   int *  cf;
00141   int * lrqp; // the last right-quad pointer...
00142   
00143   /* pour tous les conflits encore presents a la resolution actuelle */
00144   for ( cf = bcf; cf != ecf; cf += *cf ) 
00145     {
00146       const int lq = cf[cflq_];              // addresse de l'element de la surface "gauche"
00147       lrqp = cf+cfbg_;                       // debut de la liste des elements de "droite"
00148        /* pour tout les elements de droite test d'intersection avec l'element de gauche */
00149        for ( rqp = lrqp; rqp != cf + *cf; rqp ++ ) 
00150          {
00151            /* si les boites s'intersectent, tassement de la liste  */
00152            if ( intersectp(*(lbb+lq),*(rbb+*rqp)) ) { *lrqp++ = *rqp; };
00153          };
00154        if ( lrqp != rqp ) *lrqp = -1; // marque la fin de liste
00155        int nc = lrqp-(cf+cfbg_);          // nombre de collisions restantes
00156        s += (nc)?4*(cfhsz+4*nc):0;        // taille necessaire pour leurs subdivisions
00157     };
00158   return s; // taille totale necessaire apres traitement d'un niveau de subdivision
00159 }
00160 
00161 
00162 static int * cfsimplify( int * bcf, int * ecf )
00163 {
00164   int * necf = bcf;
00165   for ( int * cf = bcf; cf != ecf; )
00166     {
00167       int * rp = cf+cfbg_;
00168       //      int i = 0;
00169       int * dst = necf+cfbg_;
00170       while( *rp != -1 && rp < cf + *cf ) *dst++ = *rp++;
00171       necf[cflq_] = cf[cflq_];
00172       
00173       cf += *cf;
00174       *necf = dst-necf;
00175       necf += *necf;
00176     };
00177   return necf;
00178 };
00179 
00180 static  int * expandcf( int * cf, int * ncf, int m )
00181 {
00182   int * ecf, * rpq, *pncf;
00183   ecf = cf + cf[cfsz_];
00184   rpq = cf + cfbg_;
00185   while ( *rpq != -1 && rpq != ecf ) rpq++;
00186   if ( rpq == cf + cfbg_ ) return ncf;
00187   *ncf = 4*(rpq-(cf+cfbg_))+cfhsz;
00188   rpq = cf + cfbg_;
00189   for ( pncf = ncf + cfbg_; pncf != ncf + *ncf; pncf += 4 , rpq ++  )
00190     {
00191       int i =  *rpq / m;
00192       int j =  *rpq % m;
00193       int a =  i*(4*m)+2*j;
00194       pncf[0] = a;//2**rpq;
00195       pncf[1] = a+1;//2**rpq+1;
00196       pncf[2] = a+2*m;//2*(*rpq+m);
00197       pncf[3] = a+2*m+1;//2*(*rpq+m)+1;
00198     };
00199   // they are all the same 
00200   for ( pncf = ncf + *ncf; pncf != ncf + 4**ncf; pncf += *ncf )
00201     std::copy(ncf,ncf+*ncf,pncf);
00202   // with a change on the left quad ...
00203   int i =  cf[cflq_]/ m;
00204   int j =  cf[cflq_]% m;
00205   int a =  i*(4*m)+2*j;
00206   (ncf+0**ncf)[cflq_] = a;//2*cf[1];
00207   (ncf+1**ncf)[cflq_] = a+1;//2*cf[1]+1;
00208   (ncf+2**ncf)[cflq_] = a+2*m;//2*(cf[1]+m);
00209   (ncf+3**ncf)[cflq_] = a+2*m+1;//2*(cf[1]+m)+1;
00210   return ncf + 4**ncf;
00211 };
00212 
00213 static void cfforward( int * ncf, int * bcf, int * ecf, int m )
00214 {
00215   for ( int * cf = bcf; cf != ecf; ncf = expandcf(cf,ncf,m), cf += *cf  );
00216 };
00217 
00218 
00219 static void search( SSIQTS::aabb3 * lroot, SSIQTS::aabb3 * rroot, SSIQTS & ssi  )
00220 {
00221   int S, M;
00222   int *  bcf, * ecf, * ncf;
00223   
00224   // nxt,ext,lq,b0,b1...
00225   /* conflits de depart: (0, 0) */
00226   bcf = new int[cfhsz+1];
00227   bcf[cfsz_]   = cfhsz+1;
00228   bcf[cflq_]   = 0;
00229   bcf[cfbg_]   = 0;
00230   ecf = bcf + bcf[cfsz_];
00231   int s = 0;
00232   
00233   SSIQTS::aabb3 *lbb = lroot; /* represente le niveau courant dans le quadtree "gauche" */
00234   SSIQTS::aabb3 *rbb = rroot; /* represente le niveau courant dans le quadtree "droit" */
00235     
00236   /* pour toutes resolutions M = 1 .. m=2^p */
00237   for ( S = 1, M = 1, lbb = lroot, rbb = rroot; M != ssi.m;  M *= 2, S *= 4, lbb -= S, rbb -= S )
00238     {
00239       /* traitement des collisions pour chaque conflit */
00240       s = cfhunt( lbb, rbb, bcf, ecf );
00241       /* si pas de collisions retour */
00242       if ( !s ) { delete[] bcf; return; };
00243       /* sinon allocation de l'espace necessaire */
00244       ncf = new int[ s ];
00245       /* definition des nouveaux conflits a tester */
00246       //      std::cout << "cfforward\n";
00247       cfforward(ncf,bcf,ecf,M);
00248       /* suppression des anciens conflits */
00249       delete[] bcf;
00250       bcf = ncf;
00251       ecf = ncf + s;
00252       };
00253   
00254   /* traitement du dernier niveau */
00255   s = cfhunt(lbb,rbb,bcf,ecf);
00256   ecf = cfsimplify(bcf,ecf);
00257   ssi.m_bcf = bcf;
00258   ssi.m_ecf = ecf;
00259 };
00260 
00261 /* print a la gnuplot des conflits */
00262 static void cfprint( std::ostream& gp, std::ostream& gpl , int * bcf, int * ecf, int m )
00263 {
00264   for( int * cf = bcf; cf != ecf; cf += *cf )
00265     {
00266       if ( cf[cfbg_] != -1 )
00267           {
00268             gp << (cf[cflq_]/m) << " " << (cf[cflq_]%m) << std::endl;
00269             int * rpq = cf+cfbg_;
00270             while ( *rpq != -1 && rpq != cf+*cf ) 
00271               {
00272                 gpl << (*rpq/m) << " " << (*rpq%m) << std::endl;
00273                 rpq++;
00274               };
00275           }
00276     };
00277 };  
00278 void SSIQTS::cfprint( std::ostream& gp, std::ostream& gpl ) 
00279 { 
00280   mmx::cfprint(gp, gpl, m_bcf, m_ecf, m ); 
00281 };
00282 
00283 SSIQTS::SSIQTS( ParametricSurface * srfa, ParametricSurface * srfb, int n, int degu, int degv )
00284 {
00285   udeg = degu;
00286   vdeg = degv; 
00287   int p = 0;
00288   m = 1;
00289   while( n ) { p++; n/=2; m *= 2; };
00290   smpa = new sample(srfa,m*degu+1,m*degv+1);
00291   smpb = new sample(srfb,m*degu+1,m*degv+1);  
00292   int s;
00293   int deep;
00294   boxa = alloc(deep,m,s);
00295   //  std::cout << deep << " " << s << std::endl;
00296   boxb = alloc(deep,m,s);
00297   //  std::cout << deep << " " << s << std::endl;
00298   // switch u interpolant
00299   // switch v interpolant
00300   fillboxes( boxa, smpa->m_svals, *this);
00301   fillboxes( boxb, smpb->m_svals, *this);
00302   build(boxa,*this);
00303   build(boxb,*this);
00304   search(boxa+s-1,boxb+s-1,*this); 
00305   //  std::cout << "end search\n";
00306 };
00307 
00308 SSIQTS::~SSIQTS()
00309 {
00310   if ( smpa ) delete   smpa;
00311   if ( smpb ) delete   smpb;
00312   if ( boxa ) delete[] boxa;
00313   if ( boxb ) delete[] boxb;
00314 };
00315 
00316 } //namespace mmx
00317 
00318 #undef ParametricSurface