$darkmode
VCG Library
quality.h
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 #ifndef __VCG_TRI_UPDATE_QUALITY
24 #define __VCG_TRI_UPDATE_QUALITY
25 #include <vcg/complex/algorithms/stat.h>
26 
27 namespace vcg {
28 namespace tri {
30 
32 
34 
43 template <class UpdateMeshType>
45 {
46 public:
47  typedef UpdateMeshType MeshType;
48  typedef typename MeshType::ScalarType ScalarType;
49  typedef typename MeshType::CoordType CoordType;
50  typedef typename MeshType::VertexType VertexType;
51  typedef typename MeshType::VertexPointer VertexPointer;
52  typedef typename MeshType::VertexIterator VertexIterator;
53  typedef typename MeshType::FaceType FaceType;
54  typedef typename MeshType::FacePointer FacePointer;
55  typedef typename MeshType::FaceIterator FaceIterator;
56  typedef typename MeshType::VertexType::QualityType VertexQualityType;
57  typedef typename MeshType::FaceType::QualityType FaceQualityType;
58  typedef typename MeshType::TetraType TetraType;
59  typedef typename MeshType::TetraPointer TetraPointer;
60  typedef typename MeshType::TetraIterator TetraIterator;
61  typedef typename MeshType::TetraType::QualityType TetraQualityType;
62 
63 
64 
67 static void VertexConstant(MeshType &m, VertexQualityType q)
68 {
69  tri::RequirePerVertexQuality(m);
70  for(VertexIterator vi=m.vert.begin();vi!=m.vert.end();++vi) if(!(*vi).IsD())
71  (*vi).Q()=q;
72 }
73 
76 static void VertexValence(UpdateMeshType &m)
77 {
78  tri::RequirePerVertexQuality(m);
79  VertexConstant(m,0);
80  for (size_t i=0;i<m.face.size();i++)
81  {
82  if (m.face[i].IsD())continue;
83 
84  for (int j=0;j<m.face[i].VN();j++)
85  {
86  VertexType *v=m.face[i].V(j);
87  v->Q()+=1;
88  }
89  }
90 }
91 
94 static void VertexClamp(MeshType &m,
95  VertexQualityType qmin,
96  VertexQualityType qmax)
97 {
98  tri::RequirePerVertexQuality(m);
99  for(VertexIterator vi=m.vert.begin();vi!=m.vert.end();++vi) if(!(*vi).IsD())
100  (*vi).Q()=std::min(qmax, std::max(qmin,(*vi).Q()));
101 }
102 
105 static void VertexNormalize(MeshType &m, VertexQualityType qmin=0.0, VertexQualityType qmax=1.0)
106 {
107  tri::RequirePerVertexQuality(m);
108  ScalarType deltaRange = qmax-qmin;
109  std::pair<ScalarType,ScalarType> minmax = tri::Stat<MeshType>::ComputePerVertexQualityMinMax(m);
110  VertexIterator vi;
111  for(vi = m.vert.begin(); vi != m.vert.end(); ++vi)
112  (*vi).Q() = qmin+deltaRange*((*vi).Q() - minmax.first)/(minmax.second - minmax.first);
113 }
114 
117 static void FaceNormalize(MeshType &m, FaceQualityType qmin=0.0, FaceQualityType qmax=1.0)
118 {
119  tri::RequirePerFaceQuality(m);
120  FaceQualityType deltaRange = qmax-qmin;
121  std::pair<FaceQualityType,FaceQualityType> minmax = tri::Stat<MeshType>::ComputePerFaceQualityMinMax(m);
122  for(FaceIterator fi = m.face.begin(); fi != m.face.end(); ++fi)
123  (*fi).Q() = qmin+deltaRange*((*fi).Q() - minmax.first)/(minmax.second - minmax.first);
124 }
125 
128 static void FaceConstant(MeshType &m, FaceQualityType q)
129 {
130  tri::RequirePerFaceQuality(m);
131  for(FaceIterator fi=m.face.begin();fi!=m.face.end();++fi)
132  (*fi).Q()=q;
133 }
134 
137 static void FaceArea(MeshType &m)
138 {
139  tri::RequirePerFaceQuality(m);
140  for(FaceIterator fi=m.face.begin();fi!=m.face.end();++fi)
141  (*fi).Q()=FaceQualityType(vcg::DoubleArea(*fi)/ScalarType(2.0));
142 }
143 
144 static void TetraConstant(MeshType & m, const TetraQualityType q)
145 {
146  tri::RequirePerTetraQuality(m);
147  ForEachTetra(m, [&q] (TetraType & t) {
148  t.Q() = q;
149  });
150 }
151 static void TetraFromVolume(MeshType & m)
152 {
153  tri::RequirePerTetraQuality(m);
154  ForEachTetra(m, [] (TetraType & t) {
155  t.Q() = TetraQualityType(vcg::Tetra::ComputeVolume(t));
156  });
157 }
158 
159 static void TetraFromAspectRatio(MeshType & m)
160 {
161  tri::RequirePerTetraQuality(m);
162  ForEachTetra(m, [] (TetraType & t) {
163  t.Q() = TetraQualityType(vcg::Tetra::AspectRatio(t));
164  });
165 }
166 
167 static void VertexFromFace( MeshType &m, bool areaWeighted=true)
168 {
169  tri::RequirePerFaceQuality(m);
170  tri::RequirePerVertexQuality(m);
171  SimpleTempData<typename MeshType::VertContainer, ScalarType> TQ(m.vert,0);
172  SimpleTempData<typename MeshType::VertContainer, ScalarType> TCnt(m.vert,0);
173 
174  for(FaceIterator fi=m.face.begin();fi!=m.face.end();++fi)
175  if(!(*fi).IsD())
176  {
177  VertexQualityType weight=1.0;
178  if(areaWeighted) weight = vcg::DoubleArea(*fi);
179  for(int j=0;j<3;++j)
180  {
181  TQ[(*fi).V(j)]+=(*fi).Q()*weight;
182  TCnt[(*fi).V(j)]+=weight;
183  }
184  }
185 
186  for(VertexIterator vi=m.vert.begin();vi!=m.vert.end();++vi)
187  if(!(*vi).IsD() && TCnt[*vi]>0 )
188  {
189  (*vi).Q() = TQ[*vi] / TCnt[*vi];
190  }
191 }
192 
193 static void VertexFromTetra(MeshType & m, bool volumeWeighted = true)
194 {
195  tri::RequirePerTetraQuality(m);
196  tri::RequirePerVertexQuality(m);
197 
198  SimpleTempData<typename MeshType::VertContainer, ScalarType> TQ(m.vert, 0);
199  SimpleTempData<typename MeshType::VertContainer, ScalarType> TCnt(m.vert, 0);
200 
201  ForEachTetra(m, [&] (TetraType & t) {
202  TetraQualityType w = 1.;
203  if (volumeWeighted)
204  w = vcg::Tetra::ComputeVolume(t);
205 
206  for (int i = 0; i < 4; ++i)
207  {
208  TQ[t.V(i)] += t.Q() * w;
209  TCnt[t.V(i)] += w;
210  }
211  });
212 
213  ForEachVertex(m, [&] (VertexType & v) {
214  v.Q() = TQ[v] / TCnt[v];
215  });
216 }
217 
218 template <class HandleScalar>
219 static void VertexFromAttributeHandle(MeshType &m, typename MeshType::template PerVertexAttributeHandle<HandleScalar> &h)
220 {
221  tri::RequirePerVertexQuality(m);
222  for(VertexIterator vi=m.vert.begin();vi!=m.vert.end();++vi)
223  if(!(*vi).IsD())
224  (*vi).Q()=VertexQualityType(h[vi]);
225 }
226 
227 static void VertexFromAttributeName(MeshType &m, const std::string &AttrName)
228 {
229  tri::RequirePerVertexQuality(m);
230  auto KH = tri::Allocator<MeshType>:: template FindPerVertexAttribute<ScalarType> (m, AttrName);
231  if(!tri::Allocator<MeshType>::template IsValidHandle<ScalarType>(m, KH)) throw vcg::MissingPreconditionException("Required Attribute is non existent");
232  for(VertexIterator vi=m.vert.begin();vi!=m.vert.end();++vi) if(!(*vi).IsD())
233  (*vi).Q() = KH[vi];
234 }
235 
236 template <class HandleScalar>
237 static void FaceFromAttributeHandle(MeshType &m, typename MeshType::template PerFaceAttributeHandle<HandleScalar> &h)
238 {
239  tri::RequirePerFaceQuality(m);
240  for(FaceIterator fi=m.face.begin();fi!=m.face.end();++fi) if(!(*fi).IsD())
241  (*fi).Q() =FaceQualityType(h[fi]);
242 }
243 
244 static void FaceFromAttributeName(MeshType &m, const std::string &AttrName)
245 {
246  tri::RequirePerFaceQuality(m);
247  auto KH = tri::Allocator<MeshType>:: template FindPerFaceAttribute<ScalarType> (m, AttrName);
248  if(!tri::Allocator<MeshType>::template IsValidHandle<ScalarType>(m, KH)) throw vcg::MissingPreconditionException("Required Attribute is non existent");
249  for(FaceIterator fi=m.face.begin();fi!=m.face.end();++fi) if(!(*fi).IsD())
250  (*fi).Q() =FaceQualityType(KH[fi]);
251 }
252 
253 static void FaceFromVertex( MeshType &m)
254 {
255  tri::RequirePerFaceQuality(m);
256  tri::RequirePerVertexQuality(m);
257  for(FaceIterator fi=m.face.begin();fi!=m.face.end();++fi) if(!(*fi).IsD())
258  {
259  (*fi).Q() =0;
260  for (int i=0;i<(*fi).VN();i++)
261  (*fi).Q() += (*fi).V(i)->Q();
262  (*fi).Q()/=(FaceQualityType)(*fi).VN();
263  }
264 }
265 
266 static void VertexFromPlane(MeshType &m, const Plane3<ScalarType> &pl)
267 {
268  tri::RequirePerVertexQuality(m);
269  for(VertexIterator vi=m.vert.begin();vi!=m.vert.end();++vi) if(!(*vi).IsD())
270  (*vi).Q() =SignedDistancePlanePoint(pl,(*vi).cP());
271 }
272 
273 static void VertexGaussianFromCurvatureDir(MeshType &m)
274 {
275  tri::RequirePerVertexQuality(m);
276  tri::RequirePerVertexCurvatureDir(m);
277  for(VertexIterator vi=m.vert.begin();vi!=m.vert.end();++vi) if(!(*vi).IsD())
278  (*vi).Q() = (*vi).K1()*(*vi).K2();
279 }
280 
281 static void VertexMeanFromCurvatureDir(MeshType &m)
282 {
283  tri::RequirePerVertexQuality(m);
284  tri::RequirePerVertexCurvatureDir(m);
285  for(VertexIterator vi=m.vert.begin();vi!=m.vert.end();++vi) if(!(*vi).IsD())
286  (*vi).Q() = ((*vi).K1()+(*vi).K2())/2.0f;
287 }
288 static void VertexMinCurvFromCurvatureDir(MeshType &m)
289 {
290  tri::RequirePerVertexQuality(m);
291  tri::RequirePerVertexCurvatureDir(m);
292  for(VertexIterator vi=m.vert.begin();vi!=m.vert.end();++vi) if(!(*vi).IsD())
293  (*vi).Q() = (*vi).K1();
294 }
295 static void VertexMaxCurvFromCurvatureDir(MeshType &m)
296 {
297  tri::RequirePerVertexQuality(m);
298  tri::RequirePerVertexCurvatureDir(m);
299  for(VertexIterator vi=m.vert.begin();vi!=m.vert.end();++vi) if(!(*vi).IsD())
300  (*vi).Q() = (*vi).K2();
301 }
302 
314 static void VertexShapeIndexFromCurvatureDir(MeshType &m)
315 {
316  tri::RequirePerVertexQuality(m);
317  tri::RequirePerVertexCurvatureDir(m);
318  for(VertexIterator vi=m.vert.begin();vi!=m.vert.end();++vi) if(!(*vi).IsD())
319  {
320  ScalarType k1=(*vi).K1();
321  ScalarType k2=(*vi).K2();
322  if(k1<k2) std::swap(k1,k2);
323  (*vi).Q() = (2.0/M_PI)*atan2(k1+k2,k1-k2);
324  }
325 }
336 static void VertexCurvednessFromCurvatureDir(MeshType &m)
337 {
338  tri::RequirePerVertexQuality(m);
339  tri::RequirePerVertexCurvatureDir(m);
340  for(VertexIterator vi=m.vert.begin();vi!=m.vert.end();++vi) if(!(*vi).IsD())
341  {
342  const ScalarType k1=(*vi).K1();
343  const ScalarType k2=(*vi).K2();
344 
345  (*vi).Q() = math::Sqrt((k1*k1+k2*k2)/2.0);
346  }
347 }
348 
349 
350 /*
351  * Absolute Curvature
352  *
353  * 2|H| if K >= 0
354  * |k1| + |k2| = <
355  * 2 * sqrt(|H|^2-K) otherwise
356  *
357  * defs and formulas taken from
358  *
359  * Improved curvature estimation for watershed segmentation of 3-dimensional meshes
360  * S Pulla, A Razdan, G Farin - Arizona State University, Tech. Rep, 2001
361  * and from
362  * Optimizing 3D triangulations using discrete curvature analysis
363  * N Dyn, K Hormann, SJ Kim, D Levin - Mathematical Methods for Curves and Surfaces: Oslo, 2000
364  */
365 
366 static void VertexAbsoluteCurvatureFromHGAttribute(MeshType &m)
367 {
368  tri::RequirePerVertexQuality(m);
369  auto KH = vcg::tri::Allocator<MeshType>:: template GetPerVertexAttribute<ScalarType> (m, std::string("KH"));
370  auto KG = vcg::tri::Allocator<MeshType>:: template GetPerVertexAttribute<ScalarType> (m, std::string("KG"));
371  for(auto vi=m.vert.begin();vi!=m.vert.end();++vi) if(!(*vi).IsD())
372  {
373  if(KG[vi] >= 0)
374  (*vi).Q() = math::Abs( 2.0*KH[vi] );
375  else
376  (*vi).Q() = 2*math::Sqrt(math::Abs( KH[vi]*KH[vi] - KG[vi]));
377  }
378 }
379 
380 /*
381  * RMS Curvature = sqrt(4H^2-2K)
382  * def and formula taken from
383  *
384  * Improved curvature estimation for watershed segmentation of 3-dimensional meshes
385  * S Pulla, A Razdan, G Farin - Arizona State University, Tech. Rep, 2001
386  */
387 static void VertexRMSCurvatureFromHGAttribute(MeshType &m)
388 {
389  tri::RequirePerVertexQuality(m);
390  auto KH = vcg::tri::Allocator<MeshType>:: template GetPerVertexAttribute<ScalarType> (m, std::string("KH"));
391  auto KG = vcg::tri::Allocator<MeshType>:: template GetPerVertexAttribute<ScalarType> (m, std::string("KG"));
392  for(auto vi=m.vert.begin();vi!=m.vert.end();++vi) if(!(*vi).IsD())
393  (*vi).Q() = math::Sqrt(math::Abs( 4*KH[vi]*KH[vi] - 2*KG[vi]));
394 }
395 
396 /*
397  Saturate the Face quality so that for each vertex the gradient of the quality is lower than the given threshold value (in absolute value)
398  The saturation is done in a conservative way (quality is always decreased and never increased)
399 
400  Note: requires FF adjacency.
401  */
402 static void FaceSaturate(MeshType &m, FaceQualityType gradientThr=1.0)
403 {
404  tri::RequirePerFaceQuality(m);
405  tri::RequireFFAdjacency(m);
406  UpdateFlags<MeshType>::FaceClearV(m);
407  std::stack<FacePointer> st;
408 
409  st.push(&*m.face.begin());
410 
411  while(!st.empty())
412  {
413  FacePointer fc = st.top(); // the center
414  //printf("Stack size %i\n",st.size());
415  //printf("Pop elem %i %f\n",st.top() - &*m.vert.begin(), st.top()->Q());
416  st.pop();
417  fc->SetV();
418  std::vector<FacePointer> star;
419  typename std::vector<FacePointer>::iterator ffi;
420  for (int i=0;i<3;i++)
421  {
422  FacePointer fnext=fc->FFp(i);
423  if (fnext!=fc)star.push_back(fnext);
424  }
425  CoordType bary0=(fc->P(0)+fc->P(1)+fc->P(2))/3;
426  for(ffi=star.begin();ffi!=star.end();++ffi )
427  {
428  assert(fc!=(*ffi));
429  FaceQualityType &qi = (*ffi)->Q();
430  CoordType bary1=((*ffi)->P(0)+(*ffi)->P(1)+(*ffi)->P(2))/3;
431  FaceQualityType distGeom = Distance(bary0,bary1) / gradientThr;
432  // Main test if the quality varies more than the geometric displacement we have to lower something.
433  if( distGeom < fabs(qi - fc->Q()))
434  {
435  // center = 0 other=10 -> other =
436  // center = 10 other=0
437  if(fc->Q() > qi) // first case: the center of the star has to be lowered (and re-inserted in the queue).
438  {
439  //printf("Reinserting center %i \n",vc - &*m.vert.begin());
440  fc->Q() = qi+distGeom-(ScalarType)0.00001;
441  assert( distGeom > fabs(qi - fc->Q()));
442  st.push(fc);
443  break;
444  }
445  else
446  {
447  // second case: you have to lower qi, the vertex under examination.
448  assert( distGeom < fabs(qi - fc->Q()));
449  assert(fc->Q() < qi);
450  FaceQualityType newQi = fc->Q() + distGeom -(FaceQualityType)0.00001;
451  assert(newQi <= qi);
452  assert(fc->Q() < newQi);
453  assert( distGeom > fabs(newQi - fc->Q()) );
454 // printf("distGeom %f, qi %f, vc->Q() %f, fabs(qi - vc->Q()) %f\n",distGeom,qi,vc->Q(),fabs(qi - vc->Q()));
455  qi = newQi;
456  (*ffi)->ClearV();
457  }
458  }
459  if(!(*ffi)->IsV())
460  {
461  st.push( *ffi);
462 // printf("Reinserting side %i \n",*vvi - &*m.vert.begin());
463  (*ffi)->SetV();
464  }
465  }
466  }
467  }
468 
476 static void VertexSaturate(MeshType &m, ScalarType gradientThr=1.0)
477 {
478  tri::RequirePerVertexQuality(m);
479  tri::RequireVFAdjacency(m);
480 
482  std::stack<VertexPointer> st;
483 
484  st.push(&*m.vert.begin());
485 
486  while(!st.empty())
487  {
488  VertexPointer vc = st.top(); // the center
489  //printf("Stack size %i\n",st.size());
490  //printf("Pop elem %i %f\n",st.top() - &*m.vert.begin(), st.top()->Q());
491  st.pop();
492  vc->SetV();
493  std::vector<VertexPointer> star;
494  face::VVStarVF<FaceType>(vc,star);
495  for(auto vvi=star.begin();vvi!=star.end();++vvi )
496  {
497  ScalarType qi = (*vvi)->Q();
498  ScalarType distGeom = Distance((*vvi)->cP(),vc->cP()) / gradientThr;
499  // Main test if the quality varies more than the geometric displacement we have to lower something.
500  if( distGeom < fabs(qi - vc->Q()))
501  {
502  // center = 0 other=10 -> other =
503  // center = 10 other=0
504  if(vc->Q() > qi) // first case: the center of the star has to be lowered (and re-inserted in the queue).
505  {
506  //printf("Reinserting center %i \n",vc - &*m.vert.begin());
507  VertexQualityType delta=std::min(ScalarType(0.00001),ScalarType(distGeom/2.0));
508  vc->Q() = VertexQualityType(qi+distGeom-delta);
509  assert( distGeom > fabs(qi - vc->Q()));
510  st.push(vc);
511  break;
512  }
513  else
514  {
515  // second case: you have to lower qi, the vertex under examination.
516  assert( distGeom < fabs(qi - vc->Q()));
517  assert(vc->Q() < qi);
518  VertexQualityType delta=std::min(VertexQualityType(0.00001),VertexQualityType(distGeom/2.0));
519  VertexQualityType newQi = vc->Q() + distGeom -delta;
520  assert(newQi <= qi);
521  assert(vc->Q() < newQi);
522  assert( distGeom > fabs(newQi - vc->Q()) );
523 // printf("distGeom %f, qi %f, vc->Q() %f, fabs(qi - vc->Q()) %f\n",distGeom,qi,vc->Q(),fabs(qi - vc->Q()));
524  qi = newQi;
525  (*vvi)->ClearV();
526  }
527  }
528  if(!(*vvi)->IsV())
529  {
530  st.push( *vvi);
531 // printf("Reinserting side %i \n",*vvi - &*m.vert.begin());
532  (*vvi)->SetV();
533  }
534  }
535  }
536  }
537 
538 
539 }; //end class
540 } // end namespace
541 } // end namespace
542 #endif
Class to safely add and delete elements in a mesh.
Definition: allocate.h:97
Management, updating and computation of per-vertex and per-face flags (like border flags).
Definition: flag.h:44
Generation of per-vertex and per-face qualities.
Definition: quality.h:45
static void VertexClamp(MeshType &m, VertexQualityType qmin, VertexQualityType qmax)
Definition: quality.h:94
static void FaceArea(MeshType &m)
Definition: quality.h:137
static void VertexShapeIndexFromCurvatureDir(MeshType &m)
VertexShapeIndexFromCurvatureDir Compute from the current Curvature Direction the Shape Index S as de...
Definition: quality.h:314
static void VertexValence(UpdateMeshType &m)
Definition: quality.h:76
static void VertexCurvednessFromCurvatureDir(MeshType &m)
VertexCurvednessFromCurvatureDir Compute from the current Curvature Direction the Curvedness as defin...
Definition: quality.h:336
static void VertexConstant(MeshType &m, VertexQualityType q)
Definition: quality.h:67
static void FaceConstant(MeshType &m, FaceQualityType q)
Definition: quality.h:128
static void VertexSaturate(MeshType &m, ScalarType gradientThr=1.0)
Saturate Vertex Quality Saturate the vertex quality so that for each vertex the gradient of the quali...
Definition: quality.h:476
static void VertexNormalize(MeshType &m, VertexQualityType qmin=0.0, VertexQualityType qmax=1.0)
Definition: quality.h:105
static void FaceNormalize(MeshType &m, FaceQualityType qmin=0.0, FaceQualityType qmax=1.0)
Definition: quality.h:117
void ForEachTetra(const MeshType &m, Callable action)
Definition: foreach.h:270
void ForEachVertex(const MeshType &m, Callable action)
Definition: foreach.h:126
Definition: namespaces.dox:6