refine.h
Go to the documentation of this file.
00001 /***********F*****************************************************************
00002 * VCGLib                                                            o o     *
00003 * Visual and Computer Graphics Library                            o     o   *
00004 *                                                                _   O  _   *
00005 * Copyright(C) 2004                                                \/)\/    *
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 #ifndef __VCGLIB_REFINE
00025 #define __VCGLIB_REFINE
00026 
00027 #include <functional>
00028 #include <map>
00029 #include <vcg/space/sphere3.h>
00030 #include <vcg/space/plane3.h>
00031 #include <vcg/simplex/face/pos.h>
00032 #include <vcg/simplex/face/topology.h>
00033 #include <vcg/complex/algorithms/update/topology.h>
00034 #include <vcg/complex/algorithms/update/flag.h>
00035 #include <vcg/complex/algorithms/clean.h>
00036 #include <vcg/space/texcoord2.h>
00037 #include <vcg/space/triangle3.h>
00038 
00039 namespace vcg{
00040 namespace tri{
00041 
00042 /* A very short intro about the generic refinement framework,
00043     the main fuction is the
00044 
00045  template<class MESH_TYPE,class MIDPOINT, class EDGEPRED>
00046  bool RefineE(MESH_TYPE &m, MIDPOINT mid, EDGEPRED ep,bool RefineSelected=false, CallBackPos *cb = 0)
00047 
00048  You have to provide two functor objects to this, one for deciding what edge has to be spltted and one to decide position and new values for the attributes of the new point.
00049 
00050  for example the minimal EDGEPRED is
00051 
00052  template <class MESH_TYPE, class FLT> class EdgeLen
00053  {
00054    public:
00055      FLT thr2;
00056      bool operator()(face::Pos<typename MESH_TYPE::FaceType> ep) const
00057      {
00058             return SquaredDistance(ep.f->V(ep.z)->P(), ep.f->V1(ep.z)->P())>thr2;
00059      }
00060  };
00061 
00062  With a bit of patience you can customize to make also slicing operation.
00063 
00064 */
00065 
00066 
00067 /* The table which encodes how to subdivide a triangle depending
00068    on the splitted edges is organized as such:
00069 
00070     TriNum (the first number):    encodes the number of triangles
00071     TV (the following 4 triples): encodes the resulting triangles where
00072           0, 1, 2 are the original vertices of the triangles and 3, 4, 5
00073           (mp01, mp12, mp20) are the midpoints of the three edges.
00074 
00075    In the case two edges are splitted the triangle has 2 possible splittings:
00076 we need to choose a diagonal of the resulting trapezoid.
00077 'swap' encodes the two diagonals to test: if diag1 < diag2 we swap the diagonal
00078 like this (140, 504 -> 150, 514) (the second vertex of each triangles is replaced
00079  by the first vertex of the other one).
00080             2
00081            / \
00082           5---4
00083          /     \
00084         0-------1
00085 
00086 */
00087 
00088 class Split {
00089 public:
00090     int TriNum;                 // number of triangles
00091     int TV[4][3];   // The triangles coded as the following convention
00092                                     //     0..2 vertici originali del triangolo
00093                                     //     3..5 mp01, mp12, mp20 midpoints of the three edges
00094     int swap[2][2]; // the two diagonals to test for swapping
00095     int TE[4][3];   // the edge-edge correspondence between refined triangles and the old one
00096                                     //      (3) means the edge of the new triangle is internal;
00097 };
00098 
00099 const Split SplitTab[8]={
00100 /* m20 m12 m01 */
00101 /*  0   0   0 */        {1, {{0,1,2},{0,0,0},{0,0,0},{0,0,0}}, {{0,0},{0,0}},  {{0,1,2},{0,0,0},{0,0,0},{0,0,0}} },
00102 /*  0   0   1 */        {2, {{0,3,2},{3,1,2},{0,0,0},{0,0,0}}, {{0,0},{0,0}},  {{0,3,2},{0,1,3},{0,0,0},{0,0,0}} },
00103 /*  0   1   0 */        {2, {{0,1,4},{0,4,2},{0,0,0},{0,0,0}}, {{0,0},{0,0}},  {{0,1,3},{3,1,2},{0,0,0},{0,0,0}} },
00104 /*  0   1   1 */        {3, {{3,1,4},{0,3,2},{4,2,3},{0,0,0}}, {{0,4},{3,2}},  {{0,1,3},{0,3,2},{1,3,3},{0,0,0}} },
00105 /*  1   0   0 */        {2, {{0,1,5},{5,1,2},{0,0,0},{0,0,0}}, {{0,0},{0,0}},  {{0,3,2},{3,1,2},{0,0,0},{0,0,0}} },
00106 /*  1   0   1 */        {3, {{0,3,5},{3,1,5},{2,5,1},{0,0,0}}, {{3,2},{5,1}},  {{0,3,2},{0,3,3},{2,3,1},{0,0,0}} },
00107 /*  1   1   0 */        {3, {{2,5,4},{0,1,5},{4,5,1},{0,0,0}}, {{0,4},{5,1}},  {{2,3,1},{0,3,2},{3,3,1},{0,0,0}} },
00108 /*  1   1   1 */        //{4, {{0,3,5},{3,1,4},{5,4,2},{3,4,5}}, {{0,0},{0,0}},  {{0,3,2},{0,1,3},{3,1,2},{3,3,3}} },
00109 /*  1   1   1 */        {4, {{3,4,5},{0,3,5},{3,1,4},{5,4,2}}, {{0,0},{0,0}},  {{3,3,3},{0,3,2},{0,1,3},{3,1,2}} },
00110 };
00111 
00112 
00113 template <class MeshType>
00114 struct BaseInterpolator
00115 {
00116   typedef typename face::Pos<typename MeshType::FaceType> PosType;
00117   typedef typename MeshType::VertexType VertexType;
00118   void operator()(VertexType &, PosType  ){}
00119 };
00120 
00121 // Basic subdivision class
00122 // This class must provide methods for finding the position of the newly created vertices
00123 // In this implemenation we simply put the new vertex in the MidPoint position.
00124 // Color and TexCoords are interpolated accordingly.
00125 // This subdivision class allow also the correct interpolation of userdefined data by
00126 // providing, in the constructor, an interpolator functor that will be called for each new vertex to be created.
00127 
00128 template<class MESH_TYPE, class InterpolatorFunctorType = BaseInterpolator< MESH_TYPE> >
00129 struct MidPoint : public   std::unary_function<face::Pos<typename MESH_TYPE::FaceType> ,  typename MESH_TYPE::CoordType >
00130 {
00131      typedef typename face::Pos<typename MESH_TYPE::FaceType> PosType;
00132      typedef typename MESH_TYPE::VertexType VertexType;
00133 
00134      MidPoint(MESH_TYPE *_mp,
00135                 InterpolatorFunctorType *_intFunc=0) {
00136        mp=_mp;
00137        intFunc =_intFunc;
00138      }
00139 
00140      MESH_TYPE *mp;
00141      InterpolatorFunctorType *intFunc; 
00142 
00143     void operator()(VertexType &nv, PosType  ep){
00144         assert(mp);
00145         VertexType *V0 = ep.V() ;
00146         VertexType *V1 = ep.VFlip() ;
00147         if(V0 > V1) std::swap(V1,V0);
00148 
00149         nv.P()=   (V0->P()+V1->P())/2.0;
00150 
00151         if( tri::HasPerVertexNormal(*mp))
00152             nv.N()= (V0->N()+V1->N()).normalized();
00153 
00154         if( tri::HasPerVertexColor(*mp))
00155             nv.C().lerp(V0->C(),V1->C(),.5f);
00156 
00157         if( tri::HasPerVertexQuality(*mp))
00158             nv.Q() = (V0->Q()+V1->Q()) / 2.0;
00159 
00160         if( tri::HasPerVertexTexCoord(*mp))
00161             nv.T().P() = (V0->T().P()+V1->T().P()) / 2.0;
00162         if(intFunc)
00163           (*intFunc)(nv,ep);
00164     }
00165 
00166     Color4<typename MESH_TYPE::ScalarType> WedgeInterp(Color4<typename MESH_TYPE::ScalarType> &c0, Color4<typename MESH_TYPE::ScalarType> &c1)
00167     {
00168         Color4<typename MESH_TYPE::ScalarType> cc;
00169         return cc.lerp(c0,c1,0.5f);
00170     }
00171 
00172     template<class FL_TYPE>
00173     TexCoord2<FL_TYPE,1> WedgeInterp(TexCoord2<FL_TYPE,1> &t0, TexCoord2<FL_TYPE,1> &t1)
00174     {
00175         TexCoord2<FL_TYPE,1> tmp;
00176         assert(t0.n()== t1.n());
00177         tmp.n()=t0.n();
00178         tmp.t()=(t0.t()+t1.t())/2.0;
00179         return tmp;
00180     }
00181 };
00182 
00183 
00184 
00185 template<class MESH_TYPE>
00186 struct MidPointArc : public std::unary_function<face::Pos<typename MESH_TYPE::FaceType> ,  typename MESH_TYPE::CoordType>
00187 {
00188     void operator()(typename MESH_TYPE::VertexType &nv, face::Pos<typename MESH_TYPE::FaceType> ep)
00189     {
00190         const typename MESH_TYPE::ScalarType EPS =1e-10;
00191         typename MESH_TYPE::CoordType vp = (ep.f->V(ep.z)->P()+ep.f->V1(ep.z)->P())/2.0;
00192         typename MESH_TYPE::CoordType  n = (ep.f->V(ep.z)->N()+ep.f->V1(ep.z)->N())/2.0;
00193         typename MESH_TYPE::ScalarType w =n.Norm();
00194         if(w<EPS) { nv.P()=(ep.f->V(ep.z)->P()+ep.f->V1(ep.z)->P())/2.0; return;}
00195         n/=w;
00196         typename MESH_TYPE::CoordType d0 = ep.f->V(ep.z)->P() - vp;
00197         typename MESH_TYPE::CoordType d1 = ep.f->V1(ep.z)->P()- vp;
00198         typename MESH_TYPE::ScalarType d=Distance(ep.f->V(ep.z)->P(),ep.f->V1(ep.z)->P())/2.0;
00199 
00200         typename MESH_TYPE::CoordType  nn = ep.f->V1(ep.z)->N() ^ ep.f->V(ep.z)->N();
00201         typename MESH_TYPE::CoordType  np = n ^ d0; //vector perpendicular to the edge plane, normal is interpolated
00202         np.Normalize();
00203         double sign=1;
00204         if(np*nn<0) sign=-1; // se le normali non divergono sposta il punto nella direzione opposta
00205 
00206         typename MESH_TYPE::CoordType n0=ep.f->V(ep.z)->N() -np*(ep.f->V(ep.z)->N()*np);
00207         n0.Normalize();
00208         typename MESH_TYPE::CoordType n1=ep.f->V1(ep.z)->N()-np*(ep.f->V1(ep.z)->N()*np);
00209         assert(n1.Norm()>EPS);
00210         n1.Normalize();
00211         typename MESH_TYPE::ScalarType cosa0=n0*n;
00212         typename MESH_TYPE::ScalarType cosa1=n1*n;
00213         if(2-cosa0-cosa1<EPS) {nv.P()=(ep.f->V(ep.z)->P()+ep.f->V1(ep.z)->P())/2.0;return;}
00214         typename MESH_TYPE::ScalarType cosb0=(d0*n)/d;
00215         typename MESH_TYPE::ScalarType cosb1=(d1*n)/d;
00216         assert(1+cosa0>EPS);
00217         assert(1+cosa1>EPS);
00218         typename MESH_TYPE::ScalarType delta0=d*(cosb0 +sqrt( ((1-cosb0*cosb0)*(1-cosa0))/(1+cosa0)) );
00219         typename MESH_TYPE::ScalarType delta1=d*(cosb1 +sqrt( ((1-cosb1*cosb1)*(1-cosa1))/(1+cosa1)) );
00220         assert(delta0+delta1<2*d);
00221         nv.P()=vp+n*sign*(delta0+delta1)/2.0;
00222         return ;
00223     }
00224 
00225     // Aggiunte in modo grezzo le due wedgeinterp
00226     Color4<typename MESH_TYPE::ScalarType> WedgeInterp(Color4<typename MESH_TYPE::ScalarType> &c0, Color4<typename MESH_TYPE::ScalarType> &c1)
00227     {
00228         Color4<typename MESH_TYPE::ScalarType> cc;
00229         return cc.lerp(c0,c1,0.5f);
00230     }
00231 
00232     template<class FL_TYPE>
00233     TexCoord2<FL_TYPE,1> WedgeInterp(TexCoord2<FL_TYPE,1> &t0, TexCoord2<FL_TYPE,1> &t1)
00234     {
00235         TexCoord2<FL_TYPE,1> tmp;
00236         assert(t0.n()== t1.n());
00237         tmp.n()=t0.n();
00238         tmp.t()=(t0.t()+t1.t())/2.0;
00239         return tmp;
00240     }
00241 
00242 };
00243 
00244 /*
00245 Versione Della Midpoint basata sul paper:
00246 S. Karbacher, S. Seeger, G. Hausler
00247 A non linear subdivision scheme for triangle meshes
00248 
00249     Non funziona!
00250     Almeno due problemi:
00251     1) il verso delle normali influenza il risultato (e.g. si funziona solo se le normali divergono)
00252          Risolvibile controllando se le normali divergono
00253   2) gli archi vanno calcolati sul piano definito dalla normale interpolata e l'edge.
00254          funziona molto meglio nelle zone di sella e non semplici.
00255 
00256 */
00257 template<class MESH_TYPE>
00258 struct MidPointArcNaive : public std::unary_function< face::Pos<typename MESH_TYPE::FaceType> , typename MESH_TYPE::CoordType>
00259 {
00260     typename MESH_TYPE::CoordType operator()(face::Pos<typename MESH_TYPE::FaceType>  ep)
00261     {
00262 
00263         typename MESH_TYPE::CoordType vp = (ep.f->V(ep.z)->P()+ep.f->V1(ep.z)->P())/2.0;
00264         typename MESH_TYPE::CoordType  n = (ep.f->V(ep.z)->N()+ep.f->V1(ep.z)->N())/2.0;
00265         n.Normalize();
00266         typename MESH_TYPE::CoordType d0 = ep.f->V(ep.z)->P() - vp;
00267         typename MESH_TYPE::CoordType d1 = ep.f->V1(ep.z)->P()- vp;
00268         typename MESH_TYPE::ScalarType d=Distance(ep.f->V(ep.z)->P(),ep.f->V1(ep.z)->P())/2.0;
00269 
00270         typename MESH_TYPE::ScalarType cosa0=ep.f->V(ep.z)->N()*n;
00271         typename MESH_TYPE::ScalarType cosa1=ep.f->V1(ep.z)->N()*n;
00272         typename MESH_TYPE::ScalarType cosb0=(d0*n)/d;
00273         typename MESH_TYPE::ScalarType cosb1=(d1*n)/d;
00274 
00275         typename MESH_TYPE::ScalarType delta0=d*(cosb0 +sqrt( ((1-cosb0*cosb0)*(1-cosa0))/(1+cosa0)) );
00276         typename MESH_TYPE::ScalarType delta1=d*(cosb1 +sqrt( ((1-cosb1*cosb1)*(1-cosa1))/(1+cosa1)) );
00277 
00278         return vp+n*(delta0+delta1)/2.0;
00279     }
00280 };
00281 
00282 
00283 // Basic Predicate that tells if a given edge must be splitted.
00284 // the constructure requires the threshold.
00285 // VERY IMPORTANT REQUIREMENT: this function must be symmetric
00286 // e.g. it must return the same value if the Pos is VFlipped.
00287 // If this function is not symmetric the Refine can crash.
00288 
00289 template <class MESH_TYPE, class FLT>
00290 class EdgeLen
00291 {
00292     FLT squaredThr;
00293 public:
00294     EdgeLen(){};
00295     EdgeLen(FLT threshold) {setThr(threshold);}
00296     void setThr(FLT threshold) {squaredThr = threshold*threshold; }
00297     bool operator()(face::Pos<typename MESH_TYPE::FaceType> ep) const
00298     {
00299         return SquaredDistance(ep.V()->P(), ep.VFlip()->P())>squaredThr;
00300     }
00301 };
00302 
00303 /*********************************************************/
00304 /*********************************************************
00305 
00306 Given a mesh the following function refines it according to two functor objects:
00307 
00308 - a predicate that tells if a given edge must be splitted
00309 
00310 - a functor that gives you the new poistion of the created vertices (starting from an edge)
00311 
00312 If RefineSelected is true only selected faces are taken into account for being splitted.
00313 
00314 Requirement: FF Adjacency and Manifoldness
00315 
00316 **********************************************************/
00317 /*********************************************************/
00318 template <class VertexPointer>
00319 class RefinedFaceData
00320     {
00321         public:
00322         RefinedFaceData(){
00323             ep[0]=0;ep[1]=0;ep[2]=0;
00324             vp[0]=0;vp[1]=0;vp[2]=0;
00325         }
00326         bool ep[3];
00327         VertexPointer vp[3];
00328     };
00329 
00330 template<class MESH_TYPE,class MIDPOINT, class EDGEPRED>
00331 bool RefineE(MESH_TYPE &m, MIDPOINT &mid, EDGEPRED &ep,bool RefineSelected=false, CallBackPos *cb = 0)
00332 {
00333     // common typenames
00334     typedef typename MESH_TYPE::VertexIterator VertexIterator;
00335     typedef typename MESH_TYPE::FaceIterator FaceIterator;
00336     typedef typename MESH_TYPE::VertexPointer VertexPointer;
00337     typedef typename MESH_TYPE::FacePointer FacePointer;
00338     typedef typename MESH_TYPE::FaceType FaceType;
00339     typedef typename MESH_TYPE::FaceType::TexCoordType TexCoordType;
00340     assert(tri::HasFFAdjacency(m));
00341     tri::UpdateFlags<MESH_TYPE>::FaceBorderFromFF(m);
00342     typedef face::Pos<FaceType>  PosType;
00343 
00344     int j,NewVertNum=0,NewFaceNum=0;
00345 
00346     typedef RefinedFaceData<VertexPointer> RFD;
00347     typedef typename MESH_TYPE :: template PerFaceAttributeHandle<RFD> HandleType;
00348     HandleType RD  = tri::Allocator<MESH_TYPE>:: template AddPerFaceAttribute<RFD> (m,std::string("RefineData"));
00349 
00350     // Callback stuff
00351     int step=0;
00352     int PercStep=std::max(1,m.fn/33);
00353 
00354     // First Loop: We analyze the mesh to compute the number of the new faces and new vertices
00355     FaceIterator fi;
00356   for(fi=m.face.begin(),j=0;fi!=m.face.end();++fi) if(!(*fi).IsD())
00357     {
00358         if(cb && (++step%PercStep)==0) (*cb)(step/PercStep,"Refining...");
00359         // skip unselected faces if necessary
00360         if(RefineSelected && !(*fi).IsS()) continue;
00361 
00362         for(j=0;j<3;j++)
00363             {
00364                 if(RD[fi].ep[j]) continue;
00365 
00366                 PosType edgeCur(&*fi,j);
00367                 if(RefineSelected && ! edgeCur.FFlip()->IsS()) continue;
00368                 if(!ep(edgeCur)) continue;
00369 
00370                 RD[edgeCur.F()].ep[edgeCur.E()]=true;
00371                 ++NewFaceNum;
00372                 ++NewVertNum;
00373                 assert(edgeCur.IsManifold());
00374                 if(!edgeCur.IsBorder())
00375                 {
00376                     edgeCur.FlipF();
00377                     edgeCur.F()->SetV();
00378                     RD[edgeCur.F()].ep[edgeCur.E()]=true;
00379                     ++NewFaceNum;
00380                 }
00381             }
00382 
00383   } // end face loop
00384 
00385     if(NewVertNum ==0 )
00386         {
00387             tri::Allocator<MESH_TYPE> :: template DeletePerFaceAttribute<RefinedFaceData<VertexPointer> >  (m,RD);
00388             return false;
00389         }
00390     VertexIterator lastv = tri::Allocator<MESH_TYPE>::AddVertices(m,NewVertNum);
00391 
00392     // Secondo loop: We initialize a edge->vertex map
00393 
00394     for(fi=m.face.begin();fi!=m.face.end();++fi) if(!(*fi).IsD())
00395   {
00396        if(cb && (++step%PercStep)==0)(*cb)(step/PercStep,"Refining...");
00397      for(j=0;j<3;j++)
00398          {
00399                 // skip unselected faces if necessary
00400                 if(RefineSelected && !(*fi).IsS()) continue;
00401                 for(j=0;j<3;j++)
00402                 {
00403                     PosType edgeCur(&*fi,j);
00404                     if(RefineSelected && ! edgeCur.FFlip()->IsS()) continue;
00405 
00406                     if( RD[edgeCur.F()].ep[edgeCur.E()] &&  RD[edgeCur.F()].vp[edgeCur.E()] ==0 )
00407                     {
00408                         RD[edgeCur.F()].vp[edgeCur.E()] = &*lastv;
00409                         mid(*lastv,edgeCur);
00410                         if(!edgeCur.IsBorder())
00411                         {
00412                             edgeCur.FlipF();
00413                             assert(RD[edgeCur.F()].ep[edgeCur.E()]);
00414                             RD[edgeCur.F()].vp[edgeCur.E()] = &*lastv;
00415                         }
00416                         ++lastv;
00417                     }
00418                 }
00419          }
00420   }
00421 
00422     assert(lastv==m.vert.end()); // critical assert: we MUST have used all the vertex that we forecasted we need
00423 
00424     FaceIterator lastf = tri::Allocator<MESH_TYPE>::AddFaces(m,NewFaceNum);
00425     FaceIterator oldendf = lastf;
00426 
00427 /*
00428  *               v0
00429  *
00430  *
00431  *               f0
00432  *
00433  *       mp01     f3     mp02
00434  *
00435  *
00436  *       f1               f2
00437  *
00438  *v1            mp12                v2
00439  *
00440 */
00441 
00442     VertexPointer vv[6];        // The six vertices that arise in the single triangle splitting
00443     //     0..2 Original triangle vertices
00444     //     3..5 mp01, mp12, mp20 midpoints of the three edges
00445     FacePointer nf[4];   // The (up to) four faces that are created.
00446 
00447     TexCoordType wtt[6];  // per ogni faccia sono al piu' tre i nuovi valori
00448     // di texture per wedge (uno per ogni edge)
00449 
00450     int fca=0,fcn =0;
00451     for(fi=m.face.begin();fi!=oldendf;++fi) if(!(*fi).IsD())
00452     {
00453       if(cb && (++step%PercStep)==0)(*cb)(step/PercStep,"Refining...");
00454       fcn++;
00455       vv[0]=(*fi).V(0);
00456       vv[1]=(*fi).V(1);
00457       vv[2]=(*fi).V(2);
00458       vv[3] = RD[fi].vp[0];
00459       vv[4] = RD[fi].vp[1];
00460       vv[5] = RD[fi].vp[2];
00461 
00462       int ind=((&*vv[3])?1:0)+((&*vv[4])?2:0)+((&*vv[5])?4:0);
00463 
00464       nf[0]=&*fi;
00465       int i;
00466       for(i=1;i<SplitTab[ind].TriNum;++i){
00467         nf[i]=&*lastf; ++lastf; fca++;
00468         if(RefineSelected || (*fi).IsS()) (*nf[i]).SetS();
00469         nf[i]->ImportData(*fi);
00470 //              if(tri::HasPerFaceColor(m))
00471 //              nf[i]->C()=(*fi).cC();
00472       }
00473 
00474 
00475       if(tri::HasPerWedgeTexCoord(m))
00476         for(i=0;i<3;++i)        {
00477           wtt[i]=(*fi).WT(i);
00478           wtt[3+i]=mid.WedgeInterp((*fi).WT(i),(*fi).WT((i+1)%3));
00479         }
00480 
00481       int orgflag=      (*fi).Flags();
00482       for(i=0;i<SplitTab[ind].TriNum;++i)
00483         for(j=0;j<3;++j){
00484           (*nf[i]).V(j)=&*vv[SplitTab[ind].TV[i][j]];
00485 
00486           if(tri::HasPerWedgeTexCoord(m)) //analogo ai vertici...
00487             (*nf[i]).WT(j)=wtt[SplitTab[ind].TV[i][j]];
00488 
00489           assert((*nf[i]).V(j)!=0);
00490           if(SplitTab[ind].TE[i][j]!=3){
00491             if(orgflag & (MESH_TYPE::FaceType::BORDER0<<(SplitTab[ind].TE[i][j])))
00492               (*nf[i]).SetB(j);
00493             else
00494               (*nf[i]).ClearB(j);
00495           }
00496           else (*nf[i]).ClearB(j);
00497         }
00498 
00499       if(SplitTab[ind].TriNum==3 &&
00500          SquaredDistance(vv[SplitTab[ind].swap[0][0]]->P(),vv[SplitTab[ind].swap[0][1]]->P()) <
00501          SquaredDistance(vv[SplitTab[ind].swap[1][0]]->P(),vv[SplitTab[ind].swap[1][1]]->P()) )
00502       { // swap the last two triangles
00503         (*nf[2]).V(1)=(*nf[1]).V(0);
00504         (*nf[1]).V(1)=(*nf[2]).V(0);
00505         if(tri::HasPerWedgeTexCoord(m)){ //swap also textures coordinates
00506           (*nf[2]).WT(1)=(*nf[1]).WT(0);
00507           (*nf[1]).WT(1)=(*nf[2]).WT(0);
00508         }
00509 
00510         if((*nf[1]).IsB(0)) (*nf[2]).SetB(1); else (*nf[2]).ClearB(1);
00511         if((*nf[2]).IsB(0)) (*nf[1]).SetB(1); else (*nf[1]).ClearB(1);
00512         (*nf[1]).ClearB(0);
00513         (*nf[2]).ClearB(0);
00514       }
00515     }
00516 
00517     assert(lastf==m.face.end());         // critical assert: we MUST have used all the faces that we forecasted we need and that we previously allocated.
00518     assert(!m.vert.empty());
00519     for(fi=m.face.begin();fi!=m.face.end();++fi) if(!(*fi).IsD()){
00520       assert((*fi).V(0)>=&*m.vert.begin() && (*fi).V(0)<=&m.vert.back() );
00521       assert((*fi).V(1)>=&*m.vert.begin() && (*fi).V(1)<=&m.vert.back() );
00522       assert((*fi).V(2)>=&*m.vert.begin() && (*fi).V(2)<=&m.vert.back() );
00523     }
00524     tri::UpdateTopology<MESH_TYPE>::FaceFace(m);
00525 
00526     tri::Allocator<MESH_TYPE> :: template DeletePerFaceAttribute<RefinedFaceData<VertexPointer> >  (m,RD);
00527 
00528     return true;
00529 }
00530 
00531 /*************************************************************************/
00532 // simple wrapper of the base refine for lazy coder that do not need a edge predicate
00533 
00534 template<class MESH_TYPE,class MIDPOINT>
00535 bool Refine(MESH_TYPE &m, MIDPOINT mid, typename MESH_TYPE::ScalarType thr=0,bool RefineSelected=false, CallBackPos *cb = 0)
00536 {
00537     EdgeLen <MESH_TYPE, typename MESH_TYPE::ScalarType> ep(thr);
00538   return RefineE(m,mid,ep,RefineSelected,cb);
00539 }
00540 /*************************************************************************/
00541 
00542 /*
00543 Modified Butterfly interpolation scheme,
00544 as presented in
00545 Zorin, Schroeder
00546 Subdivision for modeling and animation
00547 Siggraph 2000 Course Notes
00548 */
00549 
00550 /*
00551 
00552     vul-------vu--------vur
00553       \      /  \      /
00554        \    /    \    /
00555         \  /  fu  \  /
00556          vl--------vr
00557         /  \  fd  /  \
00558        /    \    /    \
00559       /      \  /      \
00560     vdl-------vd--------vdr
00561 
00562 */
00563 
00564 template<class MESH_TYPE>
00565 struct MidPointButterfly : public std::unary_function<face::Pos<typename MESH_TYPE::FaceType> , typename MESH_TYPE::CoordType>
00566 {
00567   MESH_TYPE &m;
00568   MidPointButterfly(MESH_TYPE &_m):m(_m){}
00569 
00570     void operator()(typename MESH_TYPE::VertexType &nv, face::Pos<typename MESH_TYPE::FaceType>  ep)
00571     {
00572         face::Pos<typename MESH_TYPE::FaceType> he(ep.f,ep.z,ep.f->V(ep.z));
00573         typename MESH_TYPE::CoordType *vl,*vr;
00574         typename MESH_TYPE::CoordType *vl0,*vr0;
00575         typename MESH_TYPE::CoordType *vu,*vd,*vul,*vur,*vdl,*vdr;
00576         vl=&he.v->P();
00577         he.FlipV();
00578         vr=&he.v->P();
00579 
00580         if( tri::HasPerVertexColor(m))
00581             nv.C().lerp(ep.f->V(ep.z)->C(),ep.f->V1(ep.z)->C(),.5f);
00582 
00583         if(he.IsBorder())
00584         {
00585             he.NextB();
00586             vr0=&he.v->P();
00587             he.FlipV();
00588             he.NextB();
00589             assert(&he.v->P()==vl);
00590             he.NextB();
00591             vl0=&he.v->P();
00592             nv.P()=((*vl)+(*vr))*(9.0/16.0)-((*vl0)+(*vr0))/16.0 ;
00593         }
00594         else
00595         {
00596             he.FlipE();he.FlipV();
00597             vu=&he.v->P();
00598             he.FlipF();he.FlipE();he.FlipV();
00599             vur=&he.v->P();
00600             he.FlipV();he.FlipE();he.FlipF(); assert(&he.v->P()==vu); // back to vu (on the right)
00601             he.FlipE();
00602             he.FlipF();he.FlipE();he.FlipV();
00603             vul=&he.v->P();
00604             he.FlipV();he.FlipE();he.FlipF(); assert(&he.v->P()==vu); // back to vu (on the left)
00605             he.FlipV();he.FlipE();he.FlipF(); assert(&he.v->P()==vl);// again on vl (but under the edge)
00606             he.FlipE();he.FlipV();
00607             vd=&he.v->P();
00608             he.FlipF();he.FlipE();he.FlipV();
00609             vdl=&he.v->P();
00610             he.FlipV();he.FlipE();he.FlipF(); assert(&he.v->P()==vd);// back to vd (on the right)
00611             he.FlipE();
00612             he.FlipF();he.FlipE();he.FlipV();
00613             vdr=&he.v->P();
00614 
00615             nv.P()=((*vl)+(*vr))/2.0+((*vu)+(*vd))/8.0 - ((*vul)+(*vur)+(*vdl)+(*vdr))/16.0;
00616             }
00617     }
00618 
00620     Color4<typename MESH_TYPE::ScalarType> WedgeInterp(Color4<typename MESH_TYPE::ScalarType> &c0, Color4<typename MESH_TYPE::ScalarType> &c1)
00621     {
00622         Color4<typename MESH_TYPE::ScalarType> cc;
00623         return cc.lerp(c0,c1,0.5f);
00624     }
00625 
00626     template<class FL_TYPE>
00627     TexCoord2<FL_TYPE,1> WedgeInterp(TexCoord2<FL_TYPE,1> &t0, TexCoord2<FL_TYPE,1> &t1)
00628     {
00629         TexCoord2<FL_TYPE,1> tmp;
00630         assert(t0.n()== t1.n());
00631         tmp.n()=t0.n();
00632         tmp.t()=(t0.t()+t1.t())/2.0;
00633         return tmp;
00634     }
00635 };
00636 
00637 
00638 #if 0
00639             int rule=0;
00640             if(vr==vul) rule+=1;
00641             if(vl==vur) rule+=2;
00642             if(vl==vdr) rule+=4;
00643             if(vr==vdl) rule+=8;
00644             switch(rule){
00645 /*      */
00646 /*      */                      case  0 :       return ((*vl)+(*vr))/2.0+((*vu)+(*vd))/8.0 - ((*vul)+(*vur)+(*vdl)+(*vdr))/16.0;
00647 /* ul   */              case  1 : return (*vl*6 + *vr*10 + *vu + *vd*3 - *vur - *vdl -*vdr*2 )/16.0;
00648 /* ur   */              case  2 : return (*vr*6 + *vl*10 + *vu + *vd*3 - *vul - *vdr -*vdl*2 )/16.0;
00649 /* dr   */              case  4 : return (*vr*6 + *vl*10 + *vd + *vu*3 - *vdl - *vur -*vul*2 )/16.0;
00650 /* dl   */              case  8 : return (*vl*6 + *vr*10 + *vd + *vu*3 - *vdr - *vul -*vur*2 )/16.0;
00651 /* ul,ur */             case  3 : return (*vl*4 + *vr*4 + *vd*2 + - *vdr - *vdl )/8.0;
00652 /* dl,dr */             case 12 : return (*vl*4 + *vr*4 + *vu*2 + - *vur - *vul )/8.0;
00653 
00654 /* ul,dr */             case  5 :
00655 /* ur,dl */             case 10 :
00656                                 default:
00657                                     return (*vl+ *vr)/2.0;
00658             }
00659 
00660 
00661 
00662 #endif
00663 /*
00664     vul-------vu--------vur
00665           \      /  \      /
00666              \    /    \    /
00667         \  /  fu  \  /
00668          vl--------vr
00669         /  \  fd  /  \
00670        /    \    /    \
00671       /      \  /      \
00672     vdl-------vd--------vdr
00673 
00674 */
00675 
00676 // Versione modificata per tenere di conto in meniara corretta dei vertici con valenza alta
00677 
00678 template<class MESH_TYPE>
00679 struct MidPointButterfly2 : public std::unary_function<face::Pos<typename MESH_TYPE::FaceType> , typename MESH_TYPE::CoordType>
00680 {
00681     typename MESH_TYPE::CoordType operator()(face::Pos<typename MESH_TYPE::FaceType>  ep)
00682     {
00683 double Rules[11][10] =
00684 {
00685     {.0}, // valenza 0
00686     {.0}, // valenza 1
00687     {.0}, // valenza 2
00688     {  .4166666667, -.08333333333 , -.08333333333  }, // valenza 3
00689     {  .375       ,  .0           ,  -0.125        ,  .0          }, // valenza 4
00690     {  .35        ,  .03090169945 ,  -.08090169945 , -.08090169945,  .03090169945       }, // valenza 5
00691     {  .5         ,  .125         ,  -0.0625       ,  .0          ,  -0.0625      , 0.125       }, // valenza 6
00692     {  .25        ,  .1088899050  , -.06042933822  , -.04846056675, -.04846056675, -.06042933822,  .1088899050  }, // valenza 7
00693     {  .21875     ,  .1196383476  , -.03125        , -.05713834763, -.03125      , -.05713834763, -.03125      ,.1196383476  }, // valenza 8
00694     {  .1944444444,  .1225409480  , -.00513312590  , -.05555555556, -.03407448880, -.03407448880, -.05555555556, -.00513312590, .1225409480  }, // valenza 9
00695     {  .175       ,  .1213525492  ,  .01545084973  , -.04635254918, -.04045084973, -.025        , -.04045084973, -.04635254918,  .01545084973,  .1213525492  } // valenza 10
00696 };
00697 
00698 face::Pos<typename MESH_TYPE::FaceType> he(ep.f,ep.z,ep.f->V(ep.z));
00699     typename MESH_TYPE::CoordType *vl,*vr;
00700     vl=&he.v->P();
00701     vr=&he.VFlip()->P();
00702     if(he.IsBorder())
00703         {he.FlipV();
00704         typename MESH_TYPE::CoordType *vl0,*vr0;
00705             he.NextB();
00706             vr0=&he.v->P();
00707             he.FlipV();
00708             he.NextB();
00709             assert(&he.v->P()==vl);
00710             he.NextB();
00711             vl0=&he.v->P();
00712             return ((*vl)+(*vr))*(9.0/16.0)-((*vl0)+(*vr0))/16.0 ;
00713         }
00714 
00715     int kl=0,kr=0; // valence of left and right vertices
00716     bool bl=false,br=false; // if left and right vertices are of border
00717   face::Pos<typename MESH_TYPE::FaceType> heStart=he;assert(he.v->P()==*vl);
00718     do { // compute valence of left vertex
00719         he.FlipE();he.FlipF();
00720         if(he.IsBorder()) bl=true;
00721         ++kl;
00722     }   while(he!=heStart);
00723 
00724     he.FlipV();heStart=he;assert(he.v->P()==*vr);
00725     do { // compute valence of right vertex
00726         he.FlipE();he.FlipF();
00727         if(he.IsBorder()) br=true;
00728         ++kr;
00729     }   while(he!=heStart);
00730   if(br||bl) return MidPointButterfly<MESH_TYPE>()( ep );
00731     if(kr==6 && kl==6) return MidPointButterfly<MESH_TYPE>()( ep );
00732     // TRACE("odd vertex among valences of %i %i\n",kl,kr);
00733     typename MESH_TYPE::CoordType newposl=*vl*.75, newposr=*vr*.75;
00734     he.FlipV();heStart=he; assert(he.v->P()==*vl);
00735     int i=0;
00736     if(kl!=6)
00737     do { // compute position  of left vertex
00738         newposl+= he.VFlip()->P() * Rules[kl][i];
00739         he.FlipE();he.FlipF();
00740         ++i;
00741     }   while(he!=heStart);
00742     i=0;he.FlipV();heStart=he;assert(he.v->P()==*vr);
00743     if(kr!=6)
00744     do { // compute position of right vertex
00745         newposr+=he.VFlip()->P()* Rules[kr][i];
00746         he.FlipE();he.FlipF();
00747         ++i;
00748     }   while(he!=heStart);
00749     if(kr==6) return newposl;
00750     if(kl==6) return newposr;
00751     return newposl+newposr;
00752     }
00753 };
00754 
00755 /* The two following classes are the functor and the predicate that you need for using the refine framework to cut a mesh along a linear interpolation of the quality.
00756    This can be used for example to slice a mesh with a plane. Just set the quality value as distance from plane and then functor and predicate
00757    initialized 0 and invoke the refine
00758 
00759   MyMesh A;
00760   tri::UpdateQuality:MyMesh>::VertexFromPlane(plane);
00761   QualityMidPointFunctor<MyMesh> slicingfunc(0.0);
00762   QualityEdgePredicate<MyMesh> slicingpred(0.0);
00763   tri::UpdateTopology<MyMesh>::FaceFace(A);
00764   RefineE<MyMesh, QualityMidPointFunctor<MyMesh>, QualityEdgePredicate<MyMesh> > (A, slicingfunc, slicingpred, false);
00765 
00766   Note that they store in the vertex quality the plane distance.
00767   */
00768 
00769 template<class MESH_TYPE>
00770 class QualityMidPointFunctor : public std::unary_function<face::Pos<typename MESH_TYPE::FaceType> , typename MESH_TYPE::CoordType>
00771 {
00772 public:
00773   typedef Point3<typename MESH_TYPE::ScalarType> Point3x;
00774   typedef typename MESH_TYPE::ScalarType ScalarType;
00775 
00776   ScalarType thr;
00777 
00778   QualityMidPointFunctor(ScalarType _thr):thr(_thr){}
00779 
00780 
00781   void operator()(typename MESH_TYPE::VertexType &nv, const face::Pos<typename MESH_TYPE::FaceType> &ep){
00782     Point3x p0=ep.f->V0(ep.z)->P();
00783     Point3x p1=ep.f->V1(ep.z)->P();
00784     ScalarType q0=ep.f->V0(ep.z)->Q()-thr;
00785     ScalarType q1=ep.f->V1(ep.z)->Q()-thr;
00786     double pp= q0/(q0-q1);
00787     nv.P()=p1*pp + p0*(1.0-pp);
00788     nv.Q()=thr;
00789     }
00790 
00791     Color4<typename MESH_TYPE::ScalarType> WedgeInterp(Color4<typename MESH_TYPE::ScalarType> &c0, Color4<typename MESH_TYPE::ScalarType> &c1)
00792     {
00793         Color4<typename MESH_TYPE::ScalarType> cc;
00794         return cc.lerp(c0,c1,0.5f);
00795     }
00796 
00797     template<class FL_TYPE>
00798     TexCoord2<FL_TYPE,1> WedgeInterp(TexCoord2<FL_TYPE,1> &t0, TexCoord2<FL_TYPE,1> &t1)
00799     {
00800         TexCoord2<FL_TYPE,1> tmp;
00801         assert(t0.n()== t1.n());
00802         tmp.n()=t0.n();
00803         tmp.t()=(t0.t()+t1.t())/2.0;
00804         return tmp;
00805     }
00806 };
00807 
00808 
00809 template <class MESH_TYPE>
00810 class QualityEdgePredicate
00811 {
00812   public:
00813   typedef Point3<typename MESH_TYPE::ScalarType> Point3x;
00814   typedef typename MESH_TYPE::ScalarType ScalarType;
00815   ScalarType thr;
00816   ScalarType tolerance;
00817   QualityEdgePredicate(const ScalarType &thr,ScalarType _tolerance=0.02):thr(thr) {tolerance=_tolerance;}
00818   bool operator()(face::Pos<typename MESH_TYPE::FaceType> ep)
00819     {
00820     ScalarType q0=ep.f->V0(ep.z)->Q()-thr;
00821     ScalarType q1=ep.f->V1(ep.z)->Q()-thr;
00822     if(q0>q1) std::swap(q0,q1);
00823     if ( q0*q1 >= 0) return false;
00824     // now a small check to be sure that we do not make too thin crossing.
00825     double pp= q0/(q0-q1);
00826     if ((fabs(pp)< tolerance)||(fabs(pp)> (1-tolerance))) return false;
00827     return true;
00828   }
00829 };
00830 
00831 
00832 template<class MESH_TYPE>
00833 struct MidPointSphere : public std::unary_function<face::Pos<typename MESH_TYPE::FaceType> , typename MESH_TYPE::CoordType>
00834 {
00835     Sphere3<typename MESH_TYPE::ScalarType> sph;
00836     typedef Point3<typename MESH_TYPE::ScalarType> Point3x;
00837 
00838     void operator()(typename MESH_TYPE::VertexType &nv, face::Pos<typename MESH_TYPE::FaceType>  ep){
00839         Point3x &p0=ep.f->V0(ep.z)->P();
00840         Point3x &p1=ep.f->V1(ep.z)->P();
00841     nv.P()= sph.c+((p0+p1)/2.0 - sph.c ).Normalize();
00842     }
00843 
00844     Color4<typename MESH_TYPE::ScalarType> WedgeInterp(Color4<typename MESH_TYPE::ScalarType> &c0, Color4<typename MESH_TYPE::ScalarType> &c1)
00845     {
00846         Color4<typename MESH_TYPE::ScalarType> cc;
00847         return cc.lerp(c0,c1,0.5f);
00848     }
00849 
00850     template<class FL_TYPE>
00851     TexCoord2<FL_TYPE,1> WedgeInterp(TexCoord2<FL_TYPE,1> &t0, TexCoord2<FL_TYPE,1> &t1)
00852     {
00853         TexCoord2<FL_TYPE,1> tmp;
00854         assert(t0.n()== t1.n());
00855         tmp.n()=t0.n();
00856         tmp.t()=(t0.t()+t1.t())/2.0;
00857         return tmp;
00858     }
00859 };
00860 
00861 
00862 template <class FLT>
00863 class EdgeSplSphere
00864 {
00865     public:
00866   Sphere3<FLT> sph;
00867     bool operator()(const Point3<FLT> &p0, const  Point3<FLT> &p1) const
00868     {
00869         if(Distance(sph,p0)>0) {
00870             if(Distance(sph,p1)>0) return false;
00871             else return true;
00872         }
00873         else if(Distance(sph,p1)<=0) return false;
00874         return true;
00875     }
00876 };
00877 
00878 template<class TRIMESH_TYPE>
00879 struct CenterPointBarycenter : public std::unary_function<typename TRIMESH_TYPE::FacePointer, typename TRIMESH_TYPE::CoordType>
00880 {
00881     typename TRIMESH_TYPE::CoordType operator()(typename TRIMESH_TYPE::FacePointer f){
00882         return vcg::Barycenter<typename TRIMESH_TYPE::FaceType>(*f);
00883     }
00884 };
00885 
00889 
00890 template<class TRIMESH_TYPE, class CenterPoint=CenterPointBarycenter <TRIMESH_TYPE> >
00891 class TriSplit
00892 {
00893 public:
00894   typedef typename TRIMESH_TYPE::FaceType FaceType;
00895   typedef typename TRIMESH_TYPE::VertexType VertexType;
00896 
00897   static void Apply(FaceType *f,
00898                     FaceType * f1,FaceType * f2,
00899                     VertexType * vB, CenterPoint        Center)
00900   {
00901     vB->P() = Center(f);
00902 
00903     //i tre vertici della faccia da dividere
00904     VertexType *V0,*V1,*V2;
00905     V0 = f->V(0);
00906     V1 = f->V(1);
00907     V2 = f->V(2);
00908 
00909     //risistemo la faccia di partenza
00910     (*f).V(2) = &(*vB);
00911     //Faccia nuova #1
00912     (*f1).V(0) = &(*vB);
00913     (*f1).V(1) = V1;
00914     (*f1).V(2) = V2;
00915     //Faccia nuova #2
00916     (*f2).V(0) = V0;
00917     (*f2).V(1) = &(*vB);
00918     (*f2).V(2) = V2;
00919 
00920     if(f->HasFFAdjacency())
00921     {
00922       //adiacenza delle facce adiacenti a quelle aggiunte
00923       f->FFp(1)->FFp(f->FFi(1)) = f1;
00924       f->FFp(2)->FFp(f->FFi(2)) = f2;
00925 
00926       //adiacenza ff
00927       FaceType *  FF0,*FF1,*FF2;
00928       FF0 = f->FFp(0);
00929       FF1 = f->FFp(1);
00930       FF2 = f->FFp(2);
00931 
00932       //Indici di adiacenza ff
00933       char FFi0,FFi1,FFi2;
00934       FFi0 = f->FFi(0);
00935       FFi1 = f->FFi(1);
00936       FFi2 = f->FFi(2);
00937 
00938       //adiacenza della faccia di partenza
00939       (*f).FFp(1) = &(*f1);
00940       (*f).FFi(1) = 0;
00941       (*f).FFp(2) = &(*f2);
00942       (*f).FFi(2) = 0;
00943 
00944       //adiacenza della faccia #1
00945       (*f1).FFp(0) = f;
00946       (*f1).FFi(0) = 1;
00947 
00948       (*f1).FFp(1) = FF1;
00949       (*f1).FFi(1) = FFi1;
00950 
00951       (*f1).FFp(2) = &(*f2);
00952       (*f1).FFi(2) = 1;
00953 
00954       //adiacenza della faccia #2
00955       (*f2).FFp(0) = f;
00956       (*f2).FFi(0) = 2;
00957 
00958       (*f2).FFp(1) = &(*f1);
00959       (*f2).FFi(1) = 2;
00960 
00961       (*f2).FFp(2) = FF2;
00962       (*f2).FFi(2) = FFi2;
00963     }
00964   }
00965 }; // end class TriSplit
00966 
00967 template <class MeshType>
00968 void TrivialMidPointRefine(MeshType & m)
00969 {
00970   typedef typename MeshType::VertexIterator VertexIterator;
00971   typedef typename MeshType::FaceIterator FaceIterator;
00972   typedef typename MeshType::VertexPointer VertexPointer;
00973   typedef typename MeshType::FacePointer FacePointer;
00974   
00975   Allocator<MeshType>::CompactEveryVector(m);
00976   int startFn = m.fn;
00977   FaceIterator lastf = tri::Allocator<MeshType>::AddFaces(m,m.fn*3);
00978   VertexIterator lastv = tri::Allocator<MeshType>::AddVertices(m,m.fn*3);
00979   
00980   /*
00981    *               v0
00982    *              /  \
00983    *            /  f0  \
00984    *          /          \
00985    *        mp01----------mp02
00986    *       /  \    f3    /   \
00987    *     / f1   \      /  f2   \
00988    *   /          \  /           \
00989    *v1 ---------- mp12------------v2
00990    *
00991   */
00992   
00993   for(int i=0;i<startFn;++i)
00994   {
00995     FacePointer f0= &m.face[i];
00996     FacePointer f1= &*lastf; ++lastf;
00997     FacePointer f2= &*lastf; ++lastf;
00998     FacePointer f3= &*lastf; ++lastf;    
00999     VertexPointer v0 =m.face[i].V(0); 
01000     VertexPointer v1 =m.face[i].V(1); 
01001     VertexPointer v2 =m.face[i].V(2); 
01002     VertexPointer mp01 = &*lastv; ++lastv; 
01003     VertexPointer mp12 = &*lastv; ++lastv; 
01004     VertexPointer mp02 = &*lastv; ++lastv; 
01005     
01006     f0->V(0) = v0;   f0->V(1) = mp01; f0->V(2) = mp02;
01007     f1->V(0) = v1;   f1->V(1) = mp12; f1->V(2) = mp01;
01008     f2->V(0) = v2;   f2->V(1) = mp02; f2->V(2) = mp12;
01009     f3->V(0) = mp12; f3->V(1) = mp02; f3->V(2) = mp01;
01010     mp01->P() = (v0>v1) ? (v0->P()+v1->P())/2.0 : (v1->P()+v0->P())/2.0;
01011     mp12->P() = (v1>v2) ? (v1->P()+v2->P())/2.0 : (v2->P()+v1->P())/2.0;
01012     mp02->P() = (v0>v2) ? (v0->P()+v2->P())/2.0 : (v2->P()+v0->P())/2.0;
01013   }
01014   
01015   int vd = tri::Clean<MeshType>::RemoveDuplicateVertex(m);
01016   printf("Vertex unification %i\n",vd);
01017   int vu = tri::Clean<MeshType>::RemoveUnreferencedVertex(m);
01018   printf("Vertex unref %i\n",vu);
01019   Allocator<MeshType>::CompactEveryVector(m);
01020 }
01021 
01022 } // namespace tri
01023 } // namespace vcg
01024 
01025 #endif


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