1 /****************************************************************************
2 * VCGLib                                                            o o     *
3 * Visual and Computer Graphics Library                            o     o   *
4 *                                                                _   O  _   *
5 * Copyright(C) 2004-2016                                           \/)\/    *
6 * Visual Computing Lab                                            /\/|      *
7 * ISTI - Italian National Research Council                           |      *
8 *                                                                    \      *
9 * All rights reserved.                                                      *
10 *                                                                           *
11 * This program is free software; you can redistribute it and/or modify      *
12 * it under the terms of the GNU General Public License as published by      *
13 * the Free Software Foundation; either version 2 of the License, or         *
14 * (at your option) any later version.                                       *
15 *                                                                           *
16 * This program is distributed in the hope that it will be useful,           *
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of            *
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             *
19 * GNU General Public License (http://www.gnu.org/licenses/gpl.txt)          *
20 * for more details.                                                         *
21 *                                                                           *
22 ****************************************************************************/
23 
24 
25 
26 
27 #ifndef __VCG_TRIMESHCOLLAPSE_QUADRIC_TEX_
28 #define __VCG_TRIMESHCOLLAPSE_QUADRIC_TEX_
29 
30 #include <vcg/complex/algorithms/local_optimization.h>
31 #include <vcg/complex/algorithms/local_optimization/tri_edge_collapse_quadric.h>
32 #include <vcg/container/simple_temporary_data.h>
33 #include <vcg/math/quadric5.h>
34 namespace vcg
35 {
36 namespace tri
37 {
38 
39 
40 class TriEdgeCollapseQuadricTexParameter : public BaseParameterClass
41 {
42 public:
43   double  BoundaryWeight;
44   double  CosineThr;
45   float   ExtraTCoordWeight;
46   bool    NormalCheck;
47   double	  NormalThrRad;
48   bool    OptimalPlacement;
49   bool		  PreserveBoundary;
50   bool		  PreserveTopology;
51   double	  QuadricEpsilon;
52   double	  QualityThr;
53   bool	    QualityQuadric;
54   bool    SafeHeapUpdate;
55   double	  ScaleFactor;
56   bool	    ScaleIndependent;
57   bool	    UseArea;
58   bool	    UseVertexWeight;
59 
TriEdgeCollapseQuadricTexParameter()60   TriEdgeCollapseQuadricTexParameter()
61   {
62     SetDefaultParams();
63   }
64 
SetDefaultParams()65   void SetDefaultParams()
66   {
67     this->BoundaryWeight=.5;
68     this->CosineThr = cos(M_PI/2);
69     this->ExtraTCoordWeight=0.0;
70     this->NormalCheck=false;
71     this->NormalThrRad=M_PI/2;
72     this->OptimalPlacement=true;
73     this->PreserveBoundary = false;
74     this->PreserveTopology = false;
75     this->QuadricEpsilon =1e-15;
76     this->QualityThr=.1;
77     this->QualityQuadric = false;
78     this->SafeHeapUpdate=false;
79     this->ScaleFactor=1.0;
80     this->ScaleIndependent=true;
81     this->UseArea=true;
82     this->UseVertexWeight=false;
83   }
84 };
85 
86 
87 // This is a static class that contains the references for the simple temporary data for the current mesh.
88 // for each vertex we keep a classic Quadric3D  and a vector of pairs texcoord+Quadric5D
89 
90 template <class MeshType>
91 class QuadricTexHelper
92     {
93     public:
94   typedef typename MeshType::VertexType VertexType;
95 
96   typedef	SimpleTempData<typename MeshType::VertContainer, std::vector<std::pair<vcg::TexCoord2f ,Quadric5<double> > > > Quadric5Temp;
97   typedef	SimpleTempData<typename MeshType::VertContainer, math::Quadric<double> > QuadricTemp;
98 
QuadricTexHelper()99       QuadricTexHelper(){}
100 
101 
Init()102         static void Init(){}
103 
104     // it allocs the std::pair for the vertex relativly to the texture coord parameter
Alloc(VertexType * v,vcg::TexCoord2f & coord)105     static void Alloc(VertexType *v,vcg::TexCoord2f &coord)
106     {
107        std::vector<std::pair<vcg::TexCoord2f ,Quadric5<double> > > &qv = Vd(v);
108        Quadric5<double> newq5;
109        newq5.Zero();
110        vcg::TexCoord2f newcoord;
111        newcoord.u() = coord.u();
112        newcoord.v() = coord.v();
113 
114        newq5.Sum3(Qd3(v),coord.u(),coord.v());
115 
116        qv.push_back(std::pair<vcg::TexCoord2f ,Quadric5<double> >(newcoord,newq5));
117     }
118 
SumAll(VertexType * v,vcg::TexCoord2f & coord,Quadric5<double> & q)119     static void SumAll(VertexType *v,vcg::TexCoord2f &coord, Quadric5<double>& q)
120     {
121        std::vector<std::pair<vcg::TexCoord2f ,Quadric5<double> > > &qv = Vd(v);
122 
123        for(size_t i = 0; i < qv.size(); i++)
124        {
125          vcg::TexCoord2f &f = qv[i].first;
126          if((f.u() == coord.u()) && (f.v() == coord.v()))
127            qv[i].second += q;
128          else
129            qv[i].second.Sum3(Qd3(v),f.u(),f.v());
130        }
131     }
132 
Contains(VertexType * v,vcg::TexCoord2f & coord)133     static bool Contains(VertexType *v,vcg::TexCoord2f &coord)
134     {
135        std::vector<std::pair<vcg::TexCoord2f ,Quadric5<double> > > &qv = Vd(v);
136 
137        for(size_t i = 0; i < qv.size(); i++)
138        {
139          vcg::TexCoord2f &f = qv[i].first;
140          if((f.u() == coord.u()) && (f.v() == coord.v()))
141            return true;
142        }
143 
144        return false;
145     }
146 
Qd(VertexType * v,const vcg::TexCoord2f & coord)147     static Quadric5<double> &Qd(VertexType *v,const vcg::TexCoord2f &coord)
148     {
149        std::vector<std::pair<vcg::TexCoord2f ,Quadric5<double> > > &qv = Vd(v);
150        //assert(coord.N()>=0);
151        for(size_t i = 0; i < qv.size(); i++)
152        {
153          vcg::TexCoord2f &f = qv[i].first;
154          if((f.u() == coord.u()) && (f.v() == coord.v()))
155            return qv[i].second;
156        }
157 
158        assert(0);
159        return qv[0].second;
160     }
Qd3(VertexType * v)161       static math::Quadric<double> &Qd3(VertexType *v) {return TD3()[*v];}
Qd3(VertexType & v)162     static math::Quadric<double> &Qd3(VertexType &v) {return TD3()[v];}
163 
Vd(VertexType * v)164     static std::vector<std::pair<vcg::TexCoord2f ,Quadric5<double> > > &Vd(VertexType *v){return (TD()[*v]);}
W(VertexType *)165       static typename VertexType::ScalarType W(VertexType * /*v*/) {return 1.0;}
W(VertexType &)166       static typename VertexType::ScalarType W(VertexType & /*v*/) {return 1.0;}
Merge(VertexType &,VertexType const &)167       static void Merge(VertexType & /*v_dest*/, VertexType const & /*v_del*/){}
TDp()168       static  Quadric5Temp* &TDp() {static  Quadric5Temp *td; return td;}
TD()169       static  Quadric5Temp &TD() {return *TDp();}
TDp3()170       static  QuadricTemp* &TDp3() {static  QuadricTemp *td3; return td3;}
TD3()171       static  QuadricTemp &TD3() {return *TDp3();}
172     };
173 
174 
175 
176 
177 
178 
179 
180 template<class TriMeshType, class VertexPair, class MYTYPE, class HelperType = tri::QInfoStandard<typename TriMeshType::VertexType>  >
181 class TriEdgeCollapseQuadricTex: public vcg::tri::TriEdgeCollapse< TriMeshType, VertexPair, MYTYPE>
182 {
183   typedef HelperType QH;
184   typedef typename tri::TriEdgeCollapse<TriMeshType, VertexPair, MYTYPE>::HeapType HeapType;
185   typedef typename tri::TriEdgeCollapse<TriMeshType, VertexPair, MYTYPE>::HeapElem HeapElem;
186   typedef typename TriMeshType::FaceType FaceType;
187   typedef typename TriMeshType::VertexType VertexType;
188   typedef typename TriMeshType::CoordType CoordType;
189   typedef typename TriMeshType::CoordType::ScalarType ScalarType;
190   typedef typename TriMeshType::VertexPointer VertexPointer;
191 
192 
193   public:
194 
TriEdgeCollapseQuadricTex(const VertexPair & p,int mark,BaseParameterClass * _pp)195   inline TriEdgeCollapseQuadricTex(const VertexPair &p, int mark, BaseParameterClass *_pp)
196   {
197       TriEdgeCollapseQuadricTexParameter *pp = (TriEdgeCollapseQuadricTexParameter *)_pp;
198       this->localMark = mark;
199       this->pos=p;
200       this->_priority = ComputePriority(pp);
201   }
202 
203 // puntatori ai vertici che sono stati messi non-w per preservare il boundary
WV()204   static std::vector<VertexPointer>  & WV(){
205       static std::vector<VertexPointer> _WV; return _WV;
206     };
207 
208 
209 
Params()210   static TriEdgeCollapseQuadricTexParameter & Params(){static TriEdgeCollapseQuadricTexParameter p; return p;}
211 
212       // Final Clean up after the end of the simplification process
Finalize(TriMeshType & m,HeapType &,BaseParameterClass * _pp)213     static void Finalize(TriMeshType &m,HeapType & /*h_ret*/, BaseParameterClass *_pp)
214     {
215       TriEdgeCollapseQuadricTexParameter *pp = (TriEdgeCollapseQuadricTexParameter *)_pp;
216       vcg::tri::UpdateFlags<TriMeshType>::FaceBorderFromVF(m);
217 
218       // If we had the boundary preservation we should clean up the writable flags
219       if(pp->PreserveBoundary)
220       {
221         typename 	std::vector<VertexPointer>::iterator wvi;
222         for(wvi=WV().begin();wvi!=WV().end();++wvi)
223           if(!(*wvi)->IsD()) (*wvi)->SetW();
224       }
225     }
226 
227 
228 
229 
matchVertexID(FaceType * f,VertexType * v)230   inline static int matchVertexID(FaceType *f,VertexType *v)
231   {
232     if(f->V(0)==v) return 0;
233     if(f->V(1)==v) return 1;
234     if(f->V(2)==v) return 2;
235 
236     assert(0); return -1;
237   }
238 
GetTexCoords(vcg::TexCoord2f & tcoord0_1,vcg::TexCoord2f & tcoord1_1,vcg::TexCoord2f & tcoord0_2,vcg::TexCoord2f & tcoord1_2)239   inline int GetTexCoords(vcg::TexCoord2f &tcoord0_1, vcg::TexCoord2f &tcoord1_1,vcg::TexCoord2f &tcoord0_2,vcg::TexCoord2f &tcoord1_2)
240   {
241     int ncoords = 0;
242     tcoord0_1.P()=Point2f(0.5f,0.5f);
243     tcoord1_1.P()=Point2f(0.5f,0.5f);
244     tcoord0_2.P()=Point2f(0.5f,0.5f);
245     tcoord1_2.P()=Point2f(0.5f,0.5f);
246 
247     vcg::face::VFIterator<FaceType> vfi(this->pos.V(0));
248 
249     for(vfi.F() = this->pos.V(0)->VFp(), vfi.I() = this->pos.V(0)->VFi(); vfi.F()!=0; ++vfi )	// for all faces in v0
250       if(vfi.F()->V(0)==this->pos.V(1) || vfi.F()->V(1)==this->pos.V(1) || vfi.F()->V(2)==this->pos.V(1) ) // and v1
251       {
252         if(ncoords == 0)
253         {
254           tcoord0_1 = vfi.F()->WT(matchVertexID(vfi.F(),this->pos.V(0)));
255           tcoord1_1 = vfi.F()->WT(matchVertexID(vfi.F(),this->pos.V(1)));
256         }
257         else
258         {
259           tcoord0_2 = vfi.F()->WT(matchVertexID(vfi.F(),this->pos.V(0)));
260           tcoord1_2 = vfi.F()->WT(matchVertexID(vfi.F(),this->pos.V(1)));
261 
262           if(
263             (tcoord0_1.u() == tcoord0_2.u()) &&
264             (tcoord0_1.v() == tcoord0_2.v()) &&
265             (tcoord1_1.u() == tcoord1_2.u()) &&
266             (tcoord1_1.v() == tcoord1_2.v())
267             )
268             return 1;
269           else
270             return 2;
271         }
272         ncoords++;
273       }
274 
275     return ncoords;
276   }
277 
278 
ComputePriority(BaseParameterClass * _pp)279     ScalarType ComputePriority(BaseParameterClass *_pp)
280     {
281       TriEdgeCollapseQuadricTexParameter *pp = (TriEdgeCollapseQuadricTexParameter *)_pp;
282       Quadric5<double> qsum1;
283       Quadric5<double> qsum2;
284       double min1[5];
285       double min2[5];
286       vcg::TexCoord2f tcoord0_1;
287       vcg::TexCoord2f tcoord1_1;
288       vcg::TexCoord2f tcoord0_2;
289       vcg::TexCoord2f tcoord1_2;
290       int ncoords;
291 
292       ncoords = GetTexCoords(tcoord0_1,tcoord1_1,tcoord0_2,tcoord1_2);
293 
294       return (ScalarType)ComputeMinimalsAndPriority(min1,min2,qsum1,qsum2,tcoord0_1,tcoord1_1,tcoord0_2,tcoord1_2,ncoords,pp);
295     }
296 
297 
298     /*
299     * the very important function that says how good is a collapse.
300     Originally is should be just the quadric error (e.g. you should choose the collapse that make the minimal quadric error)
301     but important correcting factors has to be applyed
302     - quality of the involved triangles
303     - normal checking
304     */
ComputeTexPriority(const double vv[5],Quadric5<double> & qsum,BaseParameterClass * _pp)305     ScalarType ComputeTexPriority(const double vv[5],Quadric5<double> &qsum, BaseParameterClass *_pp)
306     {
307       TriEdgeCollapseQuadricTexParameter *pp = (TriEdgeCollapseQuadricTexParameter *)_pp;
308       VertexType * v[2];
309       v[0] = this->pos.V(0);
310       v[1] = this->pos.V(1);
311 
312       assert(!math::IsNAN(vv[0]));
313       assert(!math::IsNAN(vv[1]));
314       assert(!math::IsNAN(vv[2]));
315       assert(!math::IsNAN(vv[3]));
316       assert(!math::IsNAN(vv[4]));
317 
318       //// Move the two vertexe  into new position (storing the old ones)
319       CoordType OldPos0=v[0]->P();
320       CoordType OldPos1=v[1]->P();
321 
322       v[0]->P() = CoordType(vv[0],vv[1],vv[2]);
323       //v[0]->P() = (v[0]->P()+v[1]->P())/2.0;
324       v[1]->P()=v[0]->P();
325 
326       double QuadErr = qsum.Apply(vv);
327 
328       //// Rescan faces and compute quality and difference between normals
329       int i;
330 
331       double qt,   MinQual = 1e100;
332       vcg::face::VFIterator<FaceType> x(this->pos.V(0));
333 
334       double ndiff,MinCos  = 1e100; // minimo coseno di variazione di una normale della faccia
335                                   // (e.g. max angle) Mincos varia da 1 (normali coincidenti) a
336                                   // -1 (normali opposte);
337 
338       for(x.F() = v[0]->VFp(), x.I() = v[0]->VFi(),i=0; x.F()!=0; ++x )	// for all faces in v0
339         if(x.F()->V(0)!=v[1] && x.F()->V(1)!=v[1] && x.F()->V(2)!=v[1] )		// skip faces with v1
340         {
341           qt= QualityFace(*x.F());
342           if(qt<MinQual) MinQual=qt;
343           if(pp->NormalCheck){
344               CoordType nn=TriangleNormal(*x.F()).Normalize();
345               ndiff=nn.dot(x.F()->N()) / x.F()->N().Norm();
346               if(ndiff<MinCos) MinCos=ndiff;
347               assert(!math::IsNAN(ndiff));
348               }
349         }
350       for(x.F() = v[1]->VFp(), x.I() = v[1]->VFi(),i=0; x.F()!=0; ++x )		// for all faces in v1
351         if(x.F()->V(0)!=v[0] && x.F()->V(1)!=v[0] && x.F()->V(2)!=v[0] )			// skip faces with v0
352         {
353           qt= QualityFace(*x.F());
354           if(qt<MinQual) MinQual=qt;
355           if(pp->NormalCheck){
356               CoordType nn=TriangleNormal(*x.F()).Normalize();
357               ndiff=nn.dot(x.F()->N() / x.F()->N().Norm());
358               if(ndiff<MinCos) MinCos=ndiff;
359               assert(!math::IsNAN(ndiff));
360           }
361 
362         }
363 
364 
365       // All collapses involving triangles with quality larger than <QualityThr> have no penalty;
366       if(MinQual>pp->QualityThr) MinQual=pp->QualityThr;
367       if(QuadErr<1e-15) QuadErr=1e-15; // Do not use zero quality penalties
368 
369       this->_priority = (ScalarType)(QuadErr / MinQual);  // the priority of collapses that create low quality triangles has a penalty (it is increased)
370 
371 
372       if(pp->NormalCheck){
373           if(MinCos<pp->CosineThr) this->_priority *=1000;  // gross penalty to collapses that move too much the original normals.
374       }
375 
376 
377 
378       //Restore old position of v0 and v1
379       v[0]->P()=OldPos0;
380       v[1]->P()=OldPos1;
381       return this->_priority;
382     }
383 
ComputeMinimalsAndPriority(double dest_1[5],double dest_2[5],Quadric5<double> & qsum_1,Quadric5<double> & qsum_2,const vcg::TexCoord2f & tcoord0_1,const vcg::TexCoord2f & tcoord1_1,const vcg::TexCoord2f & tcoord0_2,const vcg::TexCoord2f & tcoord1_2,int ncoords,BaseParameterClass * _pp)384     inline ScalarType ComputeMinimalsAndPriority(double dest_1[5],
385                   double dest_2[5],
386                   Quadric5<double> &qsum_1,
387                   Quadric5<double> &qsum_2,
388                   const vcg::TexCoord2f &tcoord0_1,
389                   const vcg::TexCoord2f &tcoord1_1,
390                   const vcg::TexCoord2f &tcoord0_2,
391                   const vcg::TexCoord2f &tcoord1_2,
392                    int ncoords,
393                    BaseParameterClass *_pp)
394     {
395       TriEdgeCollapseQuadricTexParameter *pp = (TriEdgeCollapseQuadricTexParameter *)_pp;
396       double tmp1[5];
397       double tmp2[5];
398       ScalarType priority1;
399       ScalarType priority2;
400 
401       assert(!math::IsNAN(tcoord0_1.u()));
402       assert(!math::IsNAN(tcoord0_1.v()));
403       assert(!math::IsNAN(tcoord1_1.u()));
404       assert(!math::IsNAN(tcoord1_1.v()));
405       assert(!math::IsNAN(tcoord0_2.u()));
406       assert(!math::IsNAN(tcoord0_2.v()));
407       assert(!math::IsNAN(tcoord1_2.u()));
408       assert(!math::IsNAN(tcoord1_2.v()));
409 
410 
411       tmp1[0] = this->pos.V(0)->P().X();
412       tmp1[1] = this->pos.V(0)->P().Y();
413       tmp1[2] = this->pos.V(0)->P().Z();
414       tmp1[3] = tcoord0_1.u();
415       tmp1[4] = tcoord0_1.v();
416 
417       tmp2[0] = this->pos.V(1)->P().X();
418       tmp2[1] = this->pos.V(1)->P().Y();
419       tmp2[2] = this->pos.V(1)->P().Z();
420       tmp2[3] = tcoord1_1.u();
421       tmp2[4] = tcoord1_1.v();
422 
423       assert(QH::Qd(this->pos.V(0),tcoord0_1).IsValid());
424       assert(QH::Qd(this->pos.V(1),tcoord1_1).IsValid());
425 
426       qsum_1 = QH::Qd(this->pos.V(0),tcoord0_1);
427       qsum_1 += QH::Qd(this->pos.V(1),tcoord1_1);
428 
429       ComputeMinimal(dest_1,tmp1,tmp2,qsum_1,pp);
430       priority1 = ComputeTexPriority(dest_1,qsum_1,pp);
431 
432       if(ncoords < 2)
433         return priority1*(1 + (pp->ExtraTCoordWeight)*(QH::Vd(this->pos.V(0)).size()+ QH::Vd(this->pos.V(1)).size() - 2));
434 
435 
436       tmp1[3] = tcoord0_2.u();
437       tmp1[4] = tcoord0_2.v();
438 
439       tmp2[3] = tcoord1_2.u();
440       tmp2[4] = tcoord1_2.v();
441 
442       assert(QH::Qd(this->pos.V(0),tcoord0_2).IsValid());
443       assert(QH::Qd(this->pos.V(1),tcoord1_2).IsValid());
444 
445       qsum_2 = QH::Qd(this->pos.V(0),tcoord0_2);
446       qsum_2 += QH::Qd(this->pos.V(1),tcoord1_2);
447 
448       ComputeMinimal(dest_2,tmp1,tmp2,qsum_2,pp);
449       priority2 = ComputeTexPriority(dest_2,qsum_2,pp);
450 
451       if(priority1 > priority2)
452       {
453         ComputeMinimalWithGeoContraints(dest_2,tmp1,tmp2,qsum_2,dest_1,pp);
454         priority2 = ComputeTexPriority(dest_2,qsum_2,pp);
455       }
456       else
457       {
458         ComputeMinimalWithGeoContraints(dest_1,tmp1,tmp2,qsum_1,dest_2,pp);
459         priority1 = ComputeTexPriority(dest_1,qsum_1,pp);
460       }
461 
462 
463       this->_priority = std::max(priority1, priority2)*(1 + (pp->ExtraTCoordWeight)*(QH::Vd(this->pos.V(0)).size()+QH::Vd(this->pos.V(1)).size() - 2));
464 
465       return this->_priority;
466     }
467 
ComputeMinimal(double vv[5],const double v0[5],const double v1[5],const Quadric5<double> qsum,BaseParameterClass * _pp)468     inline void ComputeMinimal(double vv[5],const double v0[5],const double v1[5], const Quadric5<double> qsum,BaseParameterClass *_pp)
469     {
470       tri::TriEdgeCollapseQuadricTexParameter *pp =(tri::TriEdgeCollapseQuadricTexParameter *)_pp;
471       bool rt=qsum.Minimum(vv);
472       // if the computation of the minimum fails we choose between the two edge points and the middle one.
473       // Switch to this branch also in the case of not using the optimal placement.
474         if(!rt || !pp->OptimalPlacement )
475         {
476           vv[0] = (v0[0] + v1[0])/2;
477           vv[1] = (v0[1] + v1[1])/2;
478           vv[2] = (v0[2] + v1[2])/2;
479           vv[3] = (v0[3] + v1[3])/2;
480           vv[4] = (v0[4] + v1[4])/2;
481 
482           // In the case of not using the optimal placement we have to be sure that the middle value is discarded.
483           double qvx= std::numeric_limits<float>::max();
484           if(pp->OptimalPlacement)
485             qvx = qsum.Apply(vv);
486 
487 
488           double qv0=qsum.Apply(v0);
489           double qv1=qsum.Apply(v1);
490 
491 
492           if(qv0<qvx)
493           {
494             vv[0] = v0[0];
495             vv[1] = v0[1];
496             vv[2] = v0[2];
497             vv[3] = v0[3];
498             vv[4] = v0[4];
499           }
500 
501           if(qv1<qvx && qv1<qv0)
502           {
503             vv[0] = v1[0];
504             vv[1] = v1[1];
505             vv[2] = v1[2];
506             vv[3] = v1[3];
507             vv[4] = v1[4];
508           }
509         }
510 
511         assert(!math::IsNAN(vv[0]));
512         assert(!math::IsNAN(vv[1]));
513         assert(!math::IsNAN(vv[2]));
514         assert(!math::IsNAN(vv[3]));
515         assert(!math::IsNAN(vv[4]));
516     }
517 
ComputeMinimalWithGeoContraints(double vv[5],const double v0[5],const double v1[5],const Quadric5<double> qsum,const double geo[5],BaseParameterClass * _pp)518     inline void ComputeMinimalWithGeoContraints(double vv[5],const double v0[5],const double v1[5], const Quadric5<double> qsum, const double geo[5],BaseParameterClass *_pp)
519     {
520     tri::TriEdgeCollapseQuadricTexParameter *pp =(tri::TriEdgeCollapseQuadricTexParameter *)_pp;
521       bool rt=qsum.MinimumWithGeoContraints(vv,geo);
522       // if the computation of the minimum fails we choose between the two edge points and the middle one.
523       // Switch to this branch also in the case of not using the optimal placement.
524       if(!rt || !pp->OptimalPlacement) {
525           double qvx = std::numeric_limits<float>::max();
526           vv[0] = geo[0];
527           vv[1] = geo[1];
528           vv[2] = geo[2];
529           if(pp->OptimalPlacement)
530             {
531               vv[3] = (v0[3] + v1[3])/2;
532               vv[4] = (v0[4] + v1[4])/2;
533               qvx=qsum.Apply(vv);
534             }
535           vv[3] = v0[3];
536           vv[4] = v0[4];
537 
538           double qv0=qsum.Apply(vv);
539 
540           vv[3] = v1[3];
541           vv[4] = v1[4];
542 
543           double qv1=qsum.Apply(v1);
544 
545           vv[3] = (v0[3] + v1[3])/2;
546           vv[4] = (v0[4] + v1[4])/2;
547 
548           if(qv0<qvx)
549           {
550             vv[3] = v0[3];
551             vv[4] = v0[4];
552           }
553 
554           if(qv1<qvx && qv1<qv0)
555           {
556             vv[3] = v1[3];
557             vv[4] = v1[4];
558           }
559         }
560 
561     }
562 
InitQuadric(TriMeshType & m,BaseParameterClass * _pp)563   static void InitQuadric(TriMeshType &m,BaseParameterClass *_pp)
564   {
565   tri::TriEdgeCollapseQuadricTexParameter *pp =(tri::TriEdgeCollapseQuadricTexParameter *)_pp;
566     typename TriMeshType::FaceIterator pf;
567     HelperType::Init();
568 
569     for(pf=m.face.begin();pf!=m.face.end();++pf)
570       if( !(*pf).IsD() && (*pf).IsR() )
571         if((*pf).V(0)->IsR() &&(*pf).V(1)->IsR() &&(*pf).V(2)->IsR())
572             {
573               Quadric5<double> q;
574               q.byFace(*pf, QH::Qd3((*pf).V(0)), QH::Qd3((*pf).V(1)), QH::Qd3((*pf).V(2)),pp->QualityQuadric,pp->BoundaryWeight);
575 
576               for(int j=0;j<3;++j)
577                 if( (*pf).V(j)->IsW())
578                 {
579                   if(!HelperType::Contains((*pf).V(j),(*pf).WT(j)))
580                   {
581                   HelperType::Alloc((*pf).V(j),(*pf).WT(j));
582                   }
583                   assert(!math::IsNAN((*pf).WT(j).u()));
584                   assert(!math::IsNAN((*pf).WT(j).v()));
585                   HelperType::SumAll((*pf).V(j),(*pf).WT(j),q);
586                 }
587 
588             }
589 
590   }
591 
Init(TriMeshType & m,HeapType & h_ret,BaseParameterClass * _pp)592     static void Init(TriMeshType &m,HeapType&h_ret,BaseParameterClass *_pp)
593     {
594     tri::TriEdgeCollapseQuadricTexParameter *pp =(tri::TriEdgeCollapseQuadricTexParameter *)_pp;
595     typename 	TriMeshType::VertexIterator  vi;
596     typename 	TriMeshType::FaceIterator  pf;
597 
598       vcg::tri::UpdateTopology<TriMeshType>::VertexFace(m);
599       vcg::tri::UpdateFlags<TriMeshType>::FaceBorderFromVF(m);
600 
601     if(pp->PreserveBoundary )
602     {
603       WV().clear();
604       for(pf=m.face.begin();pf!=m.face.end();++pf)
605         if( !(*pf).IsD() && (*pf).IsW() )
606           for(int j=0;j<3;++j)
607             if((*pf).IsB(j))
608             {
609               if((*pf).V(j)->IsW())  {(*pf).V(j)->ClearW(); WV().push_back((*pf).V(j));}
610               if((*pf).V1(j)->IsW()) {(*pf).V1(j)->ClearW();WV().push_back((*pf).V1(j));}
611             }
612     }
613 
614       InitQuadric(m,pp);
615 
616     // Initialize the heap with all the possible collapses
617         for(vi=m.vert.begin();vi!=m.vert.end();++vi)
618           if((*vi).IsRW())
619               {
620                   vcg::face::VFIterator<FaceType> x;
621                   for( x.F() = (*vi).VFp(), x.I() = (*vi).VFi(); x.F()!=0; ++ x){
622                     x.V1()->ClearV();
623                     x.V2()->ClearV();
624                   }
625                   for( x.F() = (*vi).VFp(), x.I() = (*vi).VFi(); x.F()!=0; ++x )
626           {
627                     assert(x.F()->V(x.I())==&(*vi));
628                     if((x.V0()<x.V1()) && x.V1()->IsRW() && !x.V1()->IsV()){
629                           x.V1()->SetV();
630                           h_ret.push_back(HeapElem(new MYTYPE(VertexPair(x.V0(),x.V1()),TriEdgeCollapse< TriMeshType,VertexPair,MYTYPE>::GlobalMark(),pp )));
631                           }
632                     if((x.V0()<x.V2()) && x.V2()->IsRW()&& !x.V2()->IsV()){
633                           x.V2()->SetV();
634                           h_ret.push_back(HeapElem(new MYTYPE(VertexPair(x.V0(),x.V2()),TriEdgeCollapse< TriMeshType,VertexPair,MYTYPE>::GlobalMark(),pp )));
635                         }
636                   }
637           }
638     make_heap(h_ret.begin(),h_ret.end());
639   }
640 
UpdateHeap(HeapType & h_ret,BaseParameterClass * _pp)641   inline  void UpdateHeap(HeapType & h_ret,BaseParameterClass *_pp)
642   {
643     tri::TriEdgeCollapseQuadricTexParameter *pp =(tri::TriEdgeCollapseQuadricTexParameter *)_pp;
644     this->GlobalMark()++;
645     VertexType *v[2];
646     v[0]= this->pos.V(0);
647         v[1]= this->pos.V(1);
648     v[1]->IMark() = this->GlobalMark();
649 
650     // First loop around the remaining vertex to unmark visited flags
651     vcg::face::VFIterator<FaceType> vfi(v[1]);
652 
653     while (!vfi.End()){
654       vfi.V1()->ClearV();
655       vfi.V2()->ClearV();
656       ++vfi;
657     }
658 
659     // Second Loop
660     vfi = face::VFIterator<FaceType>(v[1]);
661     while (!vfi.End())
662     {
663     assert(!vfi.F()->IsD());
664         for (int j=0;j<3;j++)
665         {
666 
667           if( !(vfi.V1()->IsV()) && vfi.V1()->IsRW())
668           {
669             vfi.V1()->SetV();
670 
671             h_ret.push_back(HeapElem(new MYTYPE(VertexPair(vfi.V0(),vfi.V1()), this->GlobalMark(),pp)));
672             std::push_heap(h_ret.begin(),h_ret.end());
673           }
674 
675           if(  !(vfi.V2()->IsV()) && vfi.V2()->IsRW())
676           {
677             vfi.V2()->SetV();
678 
679             h_ret.push_back(HeapElem(new MYTYPE(VertexPair(vfi.V0(),vfi.V2()),this->GlobalMark(),pp)));
680             std::push_heap(h_ret.begin(),h_ret.end());
681           }
682         }
683         ++vfi;
684     }
685   }
686 
Execute(TriMeshType & m,BaseParameterClass * _pp)687   void Execute(TriMeshType &m, BaseParameterClass *_pp)
688   {
689   tri::TriEdgeCollapseQuadricTexParameter *pp =(tri::TriEdgeCollapseQuadricTexParameter *)_pp;
690   Quadric5<double> qsum1;
691   Quadric5<double> qsum2;
692   double min1[5];
693   double min2[5];
694   vcg::TexCoord2f tcoord0_1;
695   vcg::TexCoord2f tcoord1_1;
696   vcg::TexCoord2f tcoord0_2;
697   vcg::TexCoord2f tcoord1_2;
698   vcg::TexCoord2f newtcoord1;
699   vcg::TexCoord2f newtcoord2;
700   std::vector<std::pair<vcg::TexCoord2f ,Quadric5<double> > > qv;
701   int ncoords;
702   VertexType * v[2];
703   v[0] = this->pos.V(0);
704   v[1] = this->pos.V(1);
705 
706   math::Quadric<double> qsum3 = QH::Qd3(v[0]);
707   qsum3 += QH::Qd3(v[1]);
708 
709   ncoords = GetTexCoords(tcoord0_1,tcoord1_1,tcoord0_2,tcoord1_2);
710 
711   ComputeMinimalsAndPriority(min1,min2,qsum1,qsum2,tcoord0_1,tcoord1_1,tcoord0_2,tcoord1_2,ncoords,pp);
712 
713    CoordType newPos(min1[0],min1[1],min1[2]); /* it's the same as min2[0],min2[1],min2[2] since the geometrical
714                         constraint has been imposed during the re-computation of the other minimal */
715 
716 
717   EdgeCollapser<TriMeshType,VertexPair>::Do(m, this->pos, newPos);
718   //DoCollapse(m, this->pos, newPos ); // v0 is deleted and v1 take the new position
719 
720   vcg::TexCoord2f newtcoord;
721   Quadric5<double> newq;
722 
723 
724 
725   newtcoord.u() = (float)min1[3];
726   newtcoord.v() = (float)min1[4];
727   assert(!math::IsNAN(newtcoord.u()));
728   assert(!math::IsNAN(newtcoord.v()));
729   newtcoord1 = newtcoord;
730   newq = qsum1;
731 
732   qv.push_back(std::pair<vcg::TexCoord2f ,Quadric5<double> >(newtcoord,newq));
733 
734   if(ncoords > 1)
735   {
736     newtcoord.u() = min2[3];
737     newtcoord.v() = min2[4];
738     newtcoord2 = newtcoord;
739     newq = qsum2;
740 
741     qv.push_back(std::pair<vcg::TexCoord2f ,Quadric5<double> >(newtcoord2,newq));
742   }
743 
744 
745   vcg::face::VFIterator<FaceType> vfi(v[1]);
746   while (!vfi.End())
747   {
748     vcg::TexCoord2f & tcoords = vfi.F()->WT(matchVertexID(vfi.F(),v[1]));
749 
750     if(
751       ((tcoords.u() == tcoord0_1.u()) && (tcoords.v() == tcoord0_1.v())) ||
752       ((tcoords.u() == tcoord1_1.u()) && (tcoords.v() == tcoord1_1.v()))
753       )
754     {
755       tcoords.u() = newtcoord1.u();
756       tcoords.v() = newtcoord1.v();
757     }
758     else if(
759       (ncoords > 1) &&
760       (
761       ((tcoords.u() == tcoord0_2.u()) && (tcoords.v() == tcoord0_2.v())) ||
762       ((tcoords.u() == tcoord1_2.u()) && (tcoords.v() == tcoord1_2.v()))
763       )
764       )
765     {
766       tcoords.u()= newtcoord2.u();
767       tcoords.v()= newtcoord2.v();
768     }
769     else
770     {
771       newtcoord = tcoords;
772 
773       if(QH::Contains(v[0],tcoords))
774       {
775         newq = QH::Qd(v[0],tcoords);
776         newq.Sum3(QH::Qd3(v[1]),tcoords.u(),tcoords.v());
777       }
778       else if(QH::Contains(v[1],tcoords))
779       {
780         newq = QH::Qd(v[1],tcoords);
781         newq.Sum3(QH::Qd3(v[0]),tcoords.u(),tcoords.v());
782       }
783       else
784         assert(0);
785 
786       qv.push_back(std::pair<vcg::TexCoord2f ,Quadric5<double> >(newtcoord,newq));
787     }
788 
789     ++vfi;
790   }
791   QH::Qd3(v[1]) = qsum3;
792   QH::Vd(v[1]) = qv;
793 
794   }
795 
796 };
797 
798 
799 
800   } // namespace tri
801     } // namespace vcg
802 #endif
803