VCG Library
Loading...
Searching...
No Matches
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
27namespace vcg {
28namespace tri {
30
32
34
43template <class UpdateMeshType>
45{
46public:
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
67static 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
76static 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
94static 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
105static 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
117static 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
128static 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
137static 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
144static void TetraConstant(MeshType & m, const TetraQualityType q)
145{
146 tri::RequirePerTetraQuality(m);
147 ForEachTetra(m, [&q] (TetraType & t) {
148 t.Q() = q;
149 });
150}
151static 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
159static 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
167static 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
193static 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
218template <class HandleScalar>
219static 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
227static 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
236template <class HandleScalar>
237static 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
244static 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
253static 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
266static 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
273static 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
281static 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}
288static 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}
295static 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
314static 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}
336static 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
366static 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 */
387static 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 */
402static 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
476static 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: color4.h:30