quadric5.h
Go to the documentation of this file.
00001 /****************************************************************************
00002 * MeshLab                                                           o o     *
00003 * A versatile mesh processing toolbox                             o     o   *
00004 *                                                                _   O  _   *
00005 * Copyright(C) 2005                                                \/)\/    *
00006 * Visual Computing Lab                                            /\/|      *
00007 * ISTI - Italian National Research Council                           |      *
00008 *                                                                    \      *
00009 * All rights reserved.                                                      *
00010 *                                                                           *
00011 * This program is free software; you can redistribute it and/or modify      *
00012 * it under the terms of the GNU General Public License as published by      *
00013 * the Free Software Foundation; either version 2 of the License, or         *
00014 * (at your option) any later version.                                       *
00015 *                                                                           *
00016 * This program is distributed in the hope that it will be useful,           *
00017 * but WITHOUT ANY WARRANTY; without even the implied warranty of            *
00018 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             *
00019 * GNU General Public License (http://www.gnu.org/licenses/gpl.txt)          *
00020 * for more details.                                                         *
00021 *                                                                           *
00022 ****************************************************************************/
00023 /****************************************************************************
00024   History
00025 $Log$
00026 Revision 1.7  2008/04/26 13:45:48  pirosu
00027 improved loss of precision minimization
00028 
00029 Revision 1.6  2008/04/26 12:50:32  pirosu
00030 commented assert
00031 
00032 Revision 1.5  2008/04/04 10:03:51  cignoni
00033 Solved namespace ambiguities caused by the removal of a silly 'using namespace' in meshmodel.h
00034 
00035 Revision 1.4  2008/03/02 15:15:50  pirosu
00036 loss of precision management
00037 
00038 Revision 1.3  2008/02/29 20:37:27  pirosu
00039 fixed zero area faces management
00040 
00041 Revision 1.2  2007/03/20 15:51:15  cignoni
00042 Update to the new texture syntax
00043 
00044 Revision 1.1  2007/02/08 13:39:59  pirosu
00045 Added Quadric Simplification(with textures) Filter
00046 
00047 
00048 ****************************************************************************/
00049 
00050 #ifndef __VCGLIB_QUADRIC5
00051 #define __VCGLIB_QUADRIC5
00052 
00053 #include <vcg/math/quadric.h>
00054 
00055 namespace vcg
00056 {
00057 namespace math {
00058 
00059   typedef double ScalarType;
00060 
00061   // r = a-b
00062   void inline sub_vec5(const ScalarType a[5], const ScalarType b[5], ScalarType r[5])
00063   {
00064     r[0] = a[0] - b[0];
00065     r[1] = a[1] - b[1];
00066     r[2] = a[2] - b[2];
00067     r[3] = a[3] - b[3];
00068     r[4] = a[4] - b[4];
00069   }
00070 
00071   // returns the in-product a*b
00072   ScalarType inline inproduct5(const ScalarType a[5], const ScalarType b[5])
00073   {
00074     return a[0]*b[0]+a[1]*b[1]+a[2]*b[2]+a[3]*b[3]+a[4]*b[4];
00075   }
00076 
00077   // r = out-product of a*b
00078   void inline outproduct5(const ScalarType a[5], const ScalarType b[5], ScalarType r[5][5])
00079   {
00080     for(int i = 0; i < 5; i++)
00081       for(int j = 0; j < 5; j++)
00082         r[i][j] = a[i]*b[j];
00083   }
00084 
00085   // r = m*v
00086   void inline prod_matvec5(const ScalarType m[5][5], const ScalarType v[5], ScalarType r[5])
00087   {
00088     r[0] = inproduct5(m[0],v);
00089     r[1] = inproduct5(m[1],v);
00090     r[2] = inproduct5(m[2],v);
00091     r[3] = inproduct5(m[3],v);
00092     r[4] = inproduct5(m[4],v);
00093   }
00094 
00095   // r = (v transposed)*m
00096   void inline prod_vecmat5(ScalarType v[5],ScalarType m[5][5], ScalarType r[5])
00097   {
00098     for(int i = 0; i < 5; i++)
00099       for(int j = 0; j < 5; j++)
00100         r[j] = v[j]*m[j][i];
00101   }
00102 
00103   void inline normalize_vec5(ScalarType v[5])
00104   {
00105     ScalarType norma = sqrt(v[0]*v[0]+v[1]*v[1]+v[2]*v[2]+v[3]*v[3]+v[4]*v[4]);
00106 
00107     v[0]/=norma;
00108     v[1]/=norma;
00109     v[2]/=norma;
00110     v[3]/=norma;
00111     v[4]/=norma;
00112   }
00113 
00114   void inline normalize_vec3(ScalarType v[3])
00115   {
00116     ScalarType norma = sqrt(v[0]*v[0]+v[1]*v[1]+v[2]*v[2]);
00117 
00118     v[0]/=norma;
00119     v[1]/=norma;
00120     v[2]/=norma;
00121 
00122   }
00123 
00124   // dest -= m
00125 
00126   void inline sub_mat5(ScalarType dest[5][5],ScalarType m[5][5])
00127   {
00128     for(int i = 0; i < 5; i++)
00129       for(int j = 0; j < 5; j++)
00130         dest[i][j] -= m[i][j];
00131   }
00132 
00133   /* computes the symmetric matrix v*v */
00134   void inline symprod_vvt5(ScalarType dest[15],ScalarType v[5])
00135   {
00136     dest[0] = v[0]*v[0];
00137     dest[1] = v[0]*v[1];
00138     dest[2] = v[0]*v[2];
00139     dest[3] = v[0]*v[3];
00140     dest[4] = v[0]*v[4];
00141     dest[5] = v[1]*v[1];
00142     dest[6] = v[1]*v[2];
00143     dest[7] = v[1]*v[3];
00144     dest[8] = v[1]*v[4];
00145     dest[9] = v[2]*v[2];
00146     dest[10] = v[2]*v[3];
00147     dest[11] = v[2]*v[4];
00148     dest[12] = v[3]*v[3];
00149     dest[13] = v[3]*v[4];
00150     dest[14] = v[4]*v[4];
00151 
00152   }
00153 
00154   /* subtracts symmetric matrix */
00155   void inline sub_symmat5(ScalarType dest[15],ScalarType m[15])
00156   {
00157     for(int i = 0; i < 15; i++)
00158       dest[i] -= m[i];
00159   }
00160 
00161 }
00162 template<typename  Scalar>
00163 class Quadric5
00164 {
00165 public:
00166     typedef Scalar ScalarType;
00167 //      typedef  CMeshO::VertexType::FaceType FaceType;
00168 
00169     // the real quadric
00170     ScalarType a[15];
00171     ScalarType b[5];
00172     ScalarType c;
00173 
00174     inline Quadric5() { c = -1;}
00175 
00176     // Necessari se si utilizza stl microsoft
00177     // inline bool operator <  ( const Quadric & q ) const { return false; }
00178     // inline bool operator == ( const Quadric & q ) const { return true; }
00179 
00180     bool IsValid() const { return (c>=0); }
00181     void SetInvalid() { c = -1.0; }
00182 
00183     void Zero()                                                                                                                         // Azzera le quadriche
00184     {
00185         a[0] = 0;
00186         a[1] = 0;
00187         a[2] = 0;
00188         a[3] = 0;
00189         a[4] = 0;
00190         a[5] = 0;
00191         a[6] = 0;
00192         a[7] = 0;
00193         a[8] = 0;
00194         a[9] = 0;
00195         a[10] = 0;
00196         a[11] = 0;
00197         a[12] = 0;
00198         a[13] = 0;
00199         a[14] = 0;
00200 
00201         b[0] = 0;
00202         b[1] = 0;
00203         b[2] = 0;
00204         b[3] = 0;
00205         b[4] = 0;
00206 
00207         c    = 0;
00208     }
00209 
00210     void swapv(ScalarType *vv, ScalarType *ww)
00211     {
00212         ScalarType tmp;
00213         for(int i = 0; i < 5; i++)
00214         {
00215             tmp = vv[i];
00216             vv[i] = ww[i];
00217             ww[i] = tmp;
00218         }
00219     }
00220 
00221     // Add the right subset of the current 5D quadric to a given 3D quadric.
00222   void AddtoQ3(math::Quadric<double> &q3) const
00223     {
00224         q3.a[0] += a[0];
00225         q3.a[1] += a[1];
00226         q3.a[2] += a[2];
00227         q3.a[3] += a[5];
00228         q3.a[4] += a[6];
00229 
00230         q3.a[5] += a[9];
00231 
00232         q3.b[0] += b[0];
00233         q3.b[1] += b[1];
00234         q3.b[2] += b[2];
00235 
00236         q3.c += c;
00237 
00238         assert(q3.IsValid());
00239     }
00240 
00241 
00242     // computes the real quadric and the geometric quadric using the face
00243     // The geometric quadric is added to the parameter qgeo
00244   template <class FaceType>
00245   void byFace(FaceType &f, math::Quadric<double> &q1, math::Quadric<double> &q2, math::Quadric<double> &q3, bool QualityQuadric, ScalarType BorderWeight)
00246     {
00247     typedef typename FaceType::VertexType::CoordType CoordType;
00248         double q = QualityFace(f);
00249 
00250         // if quality==0 then the geometrical quadric has just zeroes
00251         if(q)
00252         {
00253             byFace(f,true);                     // computes the geometrical quadric
00254             AddtoQ3(q1);
00255             AddtoQ3(q2);
00256             AddtoQ3(q3);
00257             byFace(f,false);            // computes the real quadric
00258             for(int j=0;j<3;++j)
00259             {
00260                 if( f.IsB(j) || QualityQuadric )
00261                 {
00262                     Quadric5<double> temp;
00263                     TexCoord2f newtex;
00264                     CoordType newpoint = (f.P0(j)+f.P1(j))/2.0 + (f.N()/f.N().Norm())*Distance(f.P0(j),f.P1(j));
00265                     newtex.u() = (f.WT( (j+0)%3 ).u()+f.WT( (j+1)%3 ).u())/2.0;
00266                     newtex.v() = (f.WT( (j+0)%3 ).v()+f.WT( (j+1)%3 ).v())/2.0;
00267                     CoordType oldpoint = f.P2(j);
00268                     TexCoord2f oldtex = f.WT((j+2)%3);
00269 
00270                     f.P2(j)=newpoint;
00271                     f.WT((j+2)%3).u()=newtex.u();
00272                     f.WT((j+2)%3).v()=newtex.v();
00273 
00274                     temp.byFace(f,false);                       // computes the full quadric
00275                     if(! f.IsB(j) ) temp.Scale(0.05);
00276           else temp.Scale(BorderWeight);
00277                     *this+=temp;
00278 
00279                     f.P2(j)=oldpoint;
00280                     f.WT((j+2)%3).u()=oldtex.u();
00281                     f.WT((j+2)%3).v()=oldtex.v();
00282                 }
00283             }
00284 
00285         }
00286         else if(
00287             (f.WT(1).u()-f.WT(0).u()) * (f.WT(2).v()-f.WT(0).v()) -
00288             (f.WT(2).u()-f.WT(0).u()) * (f.WT(1).v()-f.WT(0).v())
00289             )
00290             byFace(f,false); // computes the real quadric
00291         else // the area is zero also in the texture space
00292         {
00293             a[0]=a[1]=a[2]=a[3]=a[4]=a[5]=a[6]=a[7]=a[8]=a[9]=a[10]=a[11]=a[12]=a[13]=a[14]=0;
00294             b[0]=b[1]=b[2]=b[3]=b[4]=0;
00295             c=0;
00296         }
00297     }
00298 
00299 
00300     // Computes the geometrical quadric if onlygeo == true and the real quadric if onlygeo == false
00301   template<class FaceType>
00302   void byFace(FaceType &fi, bool onlygeo)
00303     {
00304       //assert(onlygeo==false);
00305         ScalarType p[5];
00306         ScalarType q[5];
00307         ScalarType r[5];
00308 //              ScalarType A[5][5];
00309         ScalarType e1[5];
00310         ScalarType e2[5];
00311 
00312         // computes p
00313         p[0] = fi.P(0).X();
00314         p[1] = fi.P(0).Y();
00315         p[2] = fi.P(0).Z();
00316         p[3] = fi.WT(0).u();
00317         p[4] = fi.WT(0).v();
00318 
00319         //  computes q
00320         q[0] = fi.P(1).X();
00321         q[1] = fi.P(1).Y();
00322         q[2] = fi.P(1).Z();
00323         q[3] = fi.WT(1).u();
00324         q[4] = fi.WT(1).v();
00325 
00326         //  computes r
00327         r[0] = fi.P(2).X();
00328         r[1] = fi.P(2).Y();
00329         r[2] = fi.P(2).Z();
00330         r[3] = fi.WT(2).u();
00331         r[4] = fi.WT(2).v();
00332 
00333         if(onlygeo)             {
00334             p[3] = 0; q[3] = 0; r[3] = 0;
00335             p[4] = 0; q[4] = 0; r[4] = 0;
00336         }
00337 
00338         ComputeE1E2(p,q,r,e1,e2);
00339         ComputeQuadricFromE1E2(e1,e2,p);
00340 
00341         if(IsValid())   return;
00342 //              qDebug("Warning: failed to find a good 5D quadric try to permute stuff.");
00343 
00344         /*
00345         When c is very close to 0, loss of precision causes it to be computed as a negative number,
00346         which is invalid for a quadric. Vertex switches are performed in order to try to obtain a smaller
00347         loss of precision. The one with the smallest error is chosen.
00348         */
00349         double minerror = std::numeric_limits<double>::max();
00350         int minerror_index = 0;
00351         for(int i = 0; i < 7; i++) // tries the 6! configurations and chooses the one with the smallest error
00352         {
00353             switch(i)
00354             {
00355             case 0:
00356                 break;
00357             case 1:
00358             case 3:
00359             case 5:
00360                 swapv(q,r);
00361                 break;
00362             case 2:
00363             case 4:
00364                 swapv(p,r);
00365                 break;
00366             case 6: // every swap has loss of precision
00367                 swapv(p,r);
00368                 for(int j = 0; j <= minerror_index; j++)
00369                 {
00370                     switch(j)
00371                     {
00372                     case 0:
00373                         break;
00374                     case 1:
00375                     case 3:
00376                     case 5:
00377                         swapv(q,r);
00378                         break;
00379                     case 2:
00380                     case 4:
00381                         swapv(p,r);
00382                         break;
00383                     default:
00384                         assert(0);
00385                     }
00386                 }
00387                 minerror_index = -1;
00388                 break;
00389             default:
00390                 assert(0);
00391             }
00392 
00393       ComputeE1E2(p,q,r,e1,e2);
00394             ComputeQuadricFromE1E2(e1,e2,p);
00395 
00396             if(IsValid())
00397                 return;
00398             else if (minerror_index == -1) // the one with the smallest error has been computed
00399                 break;
00400             else if(-c < minerror)
00401             {
00402                 minerror = -c;
00403                 minerror_index = i;
00404             }
00405         }
00406         // failed to find a valid vertex switch
00407 
00408         // assert(-c <= 1e-8); // small error
00409 
00410         c = 0; // rounds up to zero
00411     }
00412 
00413 // Given three 5D points it compute an orthonormal basis e1 e2
00414 void ComputeE1E2 (const ScalarType p[5],        const   ScalarType q[5],        const   ScalarType r[5], ScalarType e1[5], ScalarType e2[5]) const
00415 {
00416         ScalarType diffe[5];
00417         ScalarType tmpmat[5][5];
00418         ScalarType tmpvec[5];
00419 //  computes e1
00420         math::sub_vec5(q,p,e1);
00421         math::normalize_vec5(e1);
00422 
00423         //  computes e2
00424         math::sub_vec5(r,p,diffe);
00425         math::outproduct5(e1,diffe,tmpmat);
00426         math::prod_matvec5(tmpmat,e1,tmpvec);
00427         math::sub_vec5(diffe,tmpvec,e2);
00428         math::normalize_vec5(e2);
00429 }
00430 
00431 // Given two orthonormal 5D vectors lying on the plane and one of the three points of the triangle compute the quadric.
00432 // Note it uses the same notation of the original garland 98 paper.
00433 void ComputeQuadricFromE1E2(ScalarType e1[5], ScalarType e2[5], ScalarType p[5] )
00434 {
00435     // computes A
00436     a[0] = 1;
00437     a[1] = 0;
00438     a[2] = 0;
00439     a[3] = 0;
00440     a[4] = 0;
00441     a[5] = 1;
00442     a[6] = 0;
00443     a[7] = 0;
00444     a[8] = 0;
00445     a[9] = 1;
00446     a[10] = 0;
00447     a[11] = 0;
00448     a[12] = 1;
00449     a[13] = 0;
00450     a[14] = 1;
00451 
00452         ScalarType tmpsymmat[15];  // a compactly stored 5x5 symmetric matrix.
00453     math::symprod_vvt5(tmpsymmat,e1);
00454     math::sub_symmat5(a,tmpsymmat);
00455     math::symprod_vvt5(tmpsymmat,e2);
00456     math::sub_symmat5(a,tmpsymmat);
00457 
00458         ScalarType pe1;
00459         ScalarType pe2;
00460 
00461     pe1 = math::inproduct5(p,e1);
00462     pe2 = math::inproduct5(p,e2);
00463 
00464     //  computes b
00465         ScalarType tmpvec[5];
00466 
00467     tmpvec[0] = pe1*e1[0] + pe2*e2[0];
00468     tmpvec[1] = pe1*e1[1] + pe2*e2[1];
00469     tmpvec[2] = pe1*e1[2] + pe2*e2[2];
00470     tmpvec[3] = pe1*e1[3] + pe2*e2[3];
00471     tmpvec[4] = pe1*e1[4] + pe2*e2[4];
00472 
00473     math::sub_vec5(tmpvec,p,b);
00474 
00475     //  computes c
00476     c = math::inproduct5(p,p)-pe1*pe1-pe2*pe2;
00477 }
00478 
00479   static bool Gauss55( ScalarType x[], ScalarType C[5][5+1] )
00480     {
00481         const ScalarType keps = (ScalarType)1e-6;
00482         int i,j,k;
00483 
00484         ScalarType eps;                                 // Determina valore cond.
00485             eps = math::Abs(C[0][0]);
00486         for(i=1;i<5;++i)
00487         {
00488             ScalarType t = math::Abs(C[i][i]);
00489             if( eps<t ) eps = t;
00490         }
00491         eps *= keps;
00492 
00493         for (i = 0; i < 5 - 1; ++i)             // Ciclo di riduzione
00494         {
00495             int ma = i;                         // Ricerca massimo pivot
00496             ScalarType vma = math::Abs( C[i][i] );
00497             for (k = i + 1; k < 5; k++)
00498             {
00499                 ScalarType t = math::Abs( C[k][i] );
00500                 if (t > vma)
00501                 {
00502                     vma = t;
00503                     ma  = k;
00504                 }
00505             }
00506             if (vma<eps)
00507                 return false;                           // Matrice singolare
00508             if(i!=ma)                           // Swap del massimo pivot
00509                 for(k=0;k<=5;k++)
00510                 {
00511                     ScalarType t = C[i][k];
00512                     C[i][k] = C[ma][k];
00513                     C[ma][k] = t;
00514                 }
00515 
00516             for (k = i + 1; k < 5; k++)         //  Riduzione
00517             {
00518                 ScalarType s;
00519                 s = C[k][i] / C[i][i];
00520                 for (j = i+1; j <= 5; j++)
00521                     C[k][j] -= C[i][j] * s;
00522                 C[k][i] = 0.0;
00523             }
00524         }
00525 
00526             // Controllo finale singolarita'
00527         if( math::Abs(C[5-1][5- 1])<eps)
00528             return false;
00529 
00530         for (i=5-1; i>=0; i--)                  // Sostituzione
00531         {
00532             ScalarType t;
00533             for (t = 0.0, j = i + 1; j < 5; j++)
00534                 t += C[i][j] * x[j];
00535             x[i] = (C[i][5] - t) / C[i][i];
00536       if(math::IsNAN(x[i])) return false;
00537       assert(!math::IsNAN(x[i]));
00538         }
00539 
00540         return true;
00541     }
00542 
00543 
00544     // computes the minimum of the quadric, imposing the geometrical constraint (geo[3] and geo[4] are obviosly ignored)
00545   bool MinimumWithGeoContraints(ScalarType x[5],const ScalarType geo[5]) const
00546     {
00547         x[0] = geo[0];
00548         x[1] = geo[1];
00549         x[2] = geo[2];
00550 
00551         ScalarType C3 = -(b[3]+geo[0]*a[3]+geo[1]*a[7]+geo[2]*a[10]);
00552         ScalarType C4 = -(b[4]+geo[0]*a[4]+geo[1]*a[8]+geo[2]*a[11]);
00553 
00554         if(a[12] != 0)
00555         {
00556             double tmp = (a[14]-a[13]*a[13]/a[12]);
00557 
00558             if(tmp == 0)
00559                 return false;
00560 
00561             x[4] = (C4 - a[13]*C3/a[12])/ tmp;
00562             x[3] = (C3 - a[13]*x[4])/a[12];
00563         }
00564         else
00565         {
00566             if(a[13] == 0)
00567                 return false;
00568 
00569             x[4] = C3/a[13];
00570             x[3] = (C4 - a[14]*x[4])/a[13];
00571         }
00572     for(int i=0;i<5;++i)
00573       if( math::IsNAN(x[i])) return false;
00574       //assert(!math::IsNAN(x[i]));
00575 
00576         return true;
00577     }
00578 
00579     // computes the minimum of the quadric
00580   bool Minimum(ScalarType x[5]) const
00581     {
00582             ScalarType C[5][6];
00583 
00584             C[0][0] = a[0];
00585             C[0][1] = a[1];
00586             C[0][2] = a[2];
00587             C[0][3] = a[3];
00588             C[0][4] = a[4];
00589             C[1][0] = a[1];
00590             C[1][1] = a[5];
00591             C[1][2] = a[6];
00592             C[1][3] = a[7];
00593             C[1][4] = a[8];
00594             C[2][0] = a[2];
00595             C[2][1] = a[6];
00596             C[2][2] = a[9];
00597             C[2][3] = a[10];
00598             C[2][4] = a[11];
00599             C[3][0] = a[3];
00600             C[3][1] = a[7];
00601             C[3][2] = a[10];
00602             C[3][3] = a[12];
00603             C[3][4] = a[13];
00604             C[4][0] = a[4];
00605             C[4][1] = a[8];
00606             C[4][2] = a[11];
00607             C[4][3] = a[13];
00608             C[4][4] = a[14];
00609 
00610             C[0][5]=-b[0];
00611             C[1][5]=-b[1];
00612             C[2][5]=-b[2];
00613             C[3][5]=-b[3];
00614             C[4][5]=-b[4];
00615 
00616             return Gauss55(&(x[0]),C);
00617     }
00618 
00619     void operator = ( const Quadric5<double> & q )                      // Assegna una quadrica
00620     {
00621         //assert( IsValid() );
00622         assert( q.IsValid() );
00623 
00624         a[0] = q.a[0];
00625         a[1] = q.a[1];
00626         a[2] = q.a[2];
00627         a[3] = q.a[3];
00628         a[4] = q.a[4];
00629         a[5] = q.a[5];
00630         a[6] = q.a[6];
00631         a[7] = q.a[7];
00632         a[8] = q.a[8];
00633         a[9] = q.a[9];
00634         a[10] = q.a[10];
00635         a[11] = q.a[11];
00636         a[12] = q.a[12];
00637         a[13] = q.a[13];
00638         a[14] = q.a[14];
00639 
00640         b[0] = q.b[0];
00641         b[1] = q.b[1];
00642         b[2] = q.b[2];
00643         b[3] = q.b[3];
00644         b[4] = q.b[4];
00645 
00646         c    = q.c;
00647     }
00648 
00649     // sums the geometrical and the real quadrics
00650     void operator += ( const Quadric5<double> & q )
00651     {
00652         //assert( IsValid() );
00653         assert( q.IsValid() );
00654 
00655         a[0] += q.a[0];
00656         a[1] += q.a[1];
00657         a[2] += q.a[2];
00658         a[3] += q.a[3];
00659         a[4] += q.a[4];
00660         a[5] += q.a[5];
00661         a[6] += q.a[6];
00662         a[7] += q.a[7];
00663         a[8] += q.a[8];
00664         a[9] += q.a[9];
00665         a[10] += q.a[10];
00666         a[11] += q.a[11];
00667         a[12] += q.a[12];
00668         a[13] += q.a[13];
00669         a[14] += q.a[14];
00670 
00671         b[0] += q.b[0];
00672         b[1] += q.b[1];
00673         b[2] += q.b[2];
00674         b[3] += q.b[3];
00675         b[4] += q.b[4];
00676 
00677         c    += q.c;
00678 
00679     }
00680 
00681 /*
00682 it sums the real quadric of the class with a quadric obtained by the geometrical quadric of the vertex.
00683 This quadric is obtained extending to five dimensions the geometrical quadric and simulating that it has been
00684 obtained by sums of 5-dimension quadrics which were computed using vertexes and faces with always the same values
00685 in the fourth and fifth dimensions (respectly the function parameter u and the function parameter v).
00686 this allows to simulate the inexistant continuity in vertexes with multiple texture coords
00687 however this continuity is still inexistant, so even if the algorithm makes a good collapse with this expedient,it obviously
00688 computes bad the priority......this should be adjusted with the extra weight user parameter through.....
00689 
00690 */
00691     void inline Sum3 (const math::Quadric<double> & q3, float u, float v)
00692   {
00693         assert( q3.IsValid() );
00694 
00695         a[0] += q3.a[0];
00696         a[1] += q3.a[1];
00697         a[2] += q3.a[2];
00698 
00699         a[5] += q3.a[3];
00700         a[6] += q3.a[4];
00701 
00702         a[9] += q3.a[5];
00703 
00704         a[12] += 1;
00705         a[14] += 1;
00706 
00707         b[0] += q3.b[0];
00708         b[1] += q3.b[1];
00709         b[2] += q3.b[2];
00710 
00711         b[3] -= u;
00712         b[4] -= v;
00713 
00714         c    += q3.c + u*u + v*v;
00715 
00716     }
00717 
00718     void Scale(ScalarType val)
00719     {
00720      for(int i=0;i<15;++i)
00721          a[i]*=val;
00722      for(int i=0;i<5;++i)
00723          b[i]*=val;
00724      c*=val;
00725     }
00726 
00727   // returns the quadric value in v
00728     ScalarType Apply(const ScalarType v[5]) const
00729     {
00730 
00731         assert( IsValid() );
00732 
00733         ScalarType tmpmat[5][5];
00734         ScalarType tmpvec[5];
00735 
00736         tmpmat[0][0] = a[0];
00737         tmpmat[0][1] = tmpmat[1][0] = a[1];
00738         tmpmat[0][2] = tmpmat[2][0] = a[2];
00739         tmpmat[0][3] = tmpmat[3][0] = a[3];
00740         tmpmat[0][4] = tmpmat[4][0] = a[4];
00741 
00742         tmpmat[1][1] = a[5];
00743         tmpmat[1][2] = tmpmat[2][1] = a[6];
00744         tmpmat[1][3] = tmpmat[3][1] = a[7];
00745         tmpmat[1][4] = tmpmat[4][1] = a[8];
00746 
00747         tmpmat[2][2] = a[9];
00748         tmpmat[2][3] = tmpmat[3][2] = a[10];
00749         tmpmat[2][4] = tmpmat[4][2] = a[11];
00750 
00751         tmpmat[3][3] = a[12];
00752         tmpmat[3][4] = tmpmat[4][3] = a[13];
00753 
00754         tmpmat[4][4] = a[14];
00755 
00756         math::prod_matvec5(tmpmat,v,tmpvec);
00757 
00758         return  math::inproduct5(v,tmpvec) + 2*math::inproduct5(b,v) + c;
00759 
00760     }
00761 };
00762 
00763 } // end namespace vcg;
00764 #endif


shape_reconstruction
Author(s): Roberto Martín-Martín
autogenerated on Sat Jun 8 2019 18:34:50