From 2b7e5ba20b1d4957de9bc23d77ecf2a4c2d71588 Mon Sep 17 00:00:00 2001 From: "T.Alderighi" Date: Wed, 9 May 2018 17:52:50 +0200 Subject: [PATCH] added some useful functions on tetras --- vcg/complex/algorithms/stat.h | 131 +++++++++++++++++++----- vcg/complex/algorithms/update/color.h | 121 +++++++++++++++++----- vcg/complex/algorithms/update/quality.h | 4 +- 3 files changed, 206 insertions(+), 50 deletions(-) diff --git a/vcg/complex/algorithms/stat.h b/vcg/complex/algorithms/stat.h index ca1f3de5..f7bda0e5 100644 --- a/vcg/complex/algorithms/stat.h +++ b/vcg/complex/algorithms/stat.h @@ -51,37 +51,45 @@ public: typedef typename MeshType::FacePointer FacePointer; typedef typename MeshType::FaceIterator FaceIterator; typedef typename MeshType::FaceContainer FaceContainer; + typedef typename MeshType::TetraType TetraType; + typedef typename MeshType::TetraPointer TetraPointer; + typedef typename MeshType::TetraIterator TetraIterator; + typedef typename MeshType::TetraContainer TetraContainer; typedef typename vcg::Box3 Box3Type; - static void ComputePerVertexQualityMinMax( MeshType & m, float &minV, float &maxV) + static void ComputePerVertexQualityMinMax(MeshType & m, ScalarType &minV, ScalarType &maxV) { - std::pair pp=ComputePerVertexQualityMinMax(m); - minV=pp.first; maxV=pp.second; + std::pair pp = ComputePerVertexQualityMinMax(m); + + minV=pp.first; + maxV=pp.second; } - static std::pair ComputePerVertexQualityMinMax( MeshType & m) + static std::pair ComputePerVertexQualityMinMax(MeshType & m) { // assert(0); tri::RequirePerVertexQuality(m); - typename MeshType::template PerMeshAttributeHandle < std::pair > mmqH; - mmqH = tri::Allocator::template GetPerMeshAttribute >(m,"minmaxQ"); + typename MeshType::template PerMeshAttributeHandle < std::pair > mmqH; + mmqH = tri::Allocator::template GetPerMeshAttribute >(m,"minmaxQ"); - std::pair minmax = std::make_pair(std::numeric_limits::max(),-std::numeric_limits::max()); + std::pair minmax = std::make_pair(std::numeric_limits::max(), -std::numeric_limits::max()); for(VertexIterator vi = m.vert.begin(); vi != m.vert.end(); ++vi) if(!(*vi).IsD()) { - if( (*vi).Q() < minmax.first) minmax.first=(*vi).Q(); - if( (*vi).Q() > minmax.second) minmax.second=(*vi).Q(); + if( (*vi).Q() < minmax.first) minmax.first = (*vi).Q(); + if( (*vi).Q() > minmax.second) minmax.second = (*vi).Q(); } mmqH() = minmax; return minmax; } - static void ComputePerFaceQualityMinMax( MeshType & m, float &minV, float &maxV) + + static void ComputePerFaceQualityMinMax(MeshType & m, ScalarType &minV, ScalarType &maxV) { - std::pair pp=ComputePerFaceQualityMinMax(m); - minV=pp.first; maxV=pp.second; + std::pair pp = ComputePerFaceQualityMinMax(m); + minV=pp.first; + maxV=pp.second; } static std::pair ComputePerFaceQualityMinMax( MeshType & m) @@ -93,13 +101,46 @@ public: for(fi = m.face.begin(); fi != m.face.end(); ++fi) if(!(*fi).IsD()) { - if( (*fi).Q() < minmax.first) minmax.first =(*fi).Q(); - if( (*fi).Q() > minmax.second) minmax.second=(*fi).Q(); + if( (*fi).Q() < minmax.first) minmax.first = (*fi).Q(); + if( (*fi).Q() > minmax.second) minmax.second = (*fi).Q(); } return minmax; } - static ScalarType ComputePerFaceQualityAvg( MeshType & m) + static void ComputerPerTetraQualityMinMax(MeshType & m, ScalarType & minQ, ScalarType & maxQ) + { + std::pair minmax = ComputerPerTetraQualityMinMax(m); + + minQ = minmax.first; + maxQ = minmax.second; + } + + static std::pair ComputerPerTetraQualityMinMax(MeshType & m) + { + tri::RequirePerTetraQuality(m); + std::pair minmax = std::make_pair(std::numeric_limits::max(), -std::numeric_limits::max()); + + ForEachTetra(m, [&minmax] (TetraType & t) { + if (t.Q() < minmax.first) minmax.first = t.Q(); + if (t.Q() > minmax.second) minmax.second = t.Q(); + }); + + return minmax; + } + + static ScalarType ComputePerTetraQualityAvg(MeshType & m) + { + tri::RequirePerTetraQuality(m); + ScalarType avgQ = 0; + + ForEachTetra(m, [&avgQ] (TetraType & t) { + avgQ += t.Q(); + }); + + return avgQ /= (ScalarType) m.TN(); + } + + static ScalarType ComputePerFaceQualityAvg(MeshType & m) { tri::RequirePerFaceQuality(m); ScalarType AvgQ = 0; @@ -195,6 +236,17 @@ public: return barycenter/areaSum; } + static ScalarType ComputeTetraMeshVolume(MeshType & m) + { + ScalarType V = 0; + + ForEachTetra(m, [&V] (TetraType & t) { + V += Tetra::ComputeVolume(t); + }); + + return V; + } + static ScalarType ComputeMeshVolume(MeshType & m) { Inertia I(m); @@ -227,7 +279,7 @@ public: return sum; } - static void ComputePerVertexQualityDistribution( MeshType & m, Distribution &h, bool selectionOnly = false) // V1.0 + static void ComputePerVertexQualityDistribution(MeshType & m, Distribution & h, bool selectionOnly = false) // V1.0 { tri::RequirePerVertexQuality(m); for(VertexIterator vi = m.vert.begin(); vi != m.vert.end(); ++vi) @@ -250,10 +302,39 @@ public: } } - static void ComputePerFaceQualityHistogram( MeshType & m, Histogramf &h, bool selectionOnly=false,int HistSize=10000 ) + static void ComputePerTetraQualityDistribution(MeshType & m, Distribution & h, bool selectionOnly = false) + { + tri::RequirePerTetraQuality(m); + ForEachTetra(m, [&] (TetraType & t) { + if (!selectionOnly || t.IsS()) + { + assert(!math::IsNAN(t.Q()) && "You should never try to compute Histogram with Invalid Floating points numbers (NaN)"); + h.Add(t.Q()); + } + }) + } + + static void ComputePerTetraQualityHistogram(MeshType & m, Histogram & h, bool selectionOnly = false, int HistSize = 10000) + { + tri::RequirePerTetraQuality(m); + std::pair minmax = tri::Stat::ComputePerFaceQualityMinMax(m); + + h.Clear(); + h.SetRange(minmax.first, minmax.second, HistSize); + + ForEachTetra(m, [&] (TetraType & t) { + if (!selectionOnly || t.IsS()) + { + assert(!math::IsNAN(t.Q()) && "You should never try to compute Histogram with Invalid Floating points numbers (NaN)"); + h.Add(t.Q()); + } + }); + } + + static void ComputePerFaceQualityHistogram( MeshType & m, Histogram &h, bool selectionOnly=false,int HistSize=10000 ) { tri::RequirePerFaceQuality(m); - std::pair minmax = tri::Stat::ComputePerFaceQualityMinMax(m); + std::pair minmax = tri::Stat::ComputePerFaceQualityMinMax(m); h.Clear(); h.SetRange( minmax.first,minmax.second, HistSize ); for(FaceIterator fi = m.face.begin(); fi != m.face.end(); ++fi) @@ -263,10 +344,10 @@ public: } } - static void ComputePerVertexQualityHistogram( MeshType & m, Histogramf &h, bool selectionOnly = false, int HistSize=10000 ) // V1.0 + static void ComputePerVertexQualityHistogram( MeshType & m, Histogram &h, bool selectionOnly = false, int HistSize=10000 ) // V1.0 { tri::RequirePerVertexQuality(m); - std::pair minmax = ComputePerVertexQualityMinMax(m); + std::pair minmax = ComputePerVertexQualityMinMax(m); h.Clear(); h.SetRange( minmax.first,minmax.second, HistSize); @@ -284,15 +365,15 @@ public: if(h.MaxCount() > HistSize/5) { - std::vector QV; + std::vector QV; QV.reserve(m.vn); for(VertexIterator vi = m.vert.begin(); vi != m.vert.end(); ++vi) if(!(*vi).IsD()) QV.push_back((*vi).Q()); std::nth_element(QV.begin(),QV.begin()+m.vn/100,QV.end()); - float newmin=*(QV.begin()+m.vn/100); + ScalarType newmin=*(QV.begin()+m.vn/100); std::nth_element(QV.begin(),QV.begin()+m.vn-m.vn/100,QV.end()); - float newmax=*(QV.begin()+m.vn-m.vn/100); + ScalarType newmax=*(QV.begin()+m.vn-m.vn/100); h.Clear(); h.SetRange(newmin, newmax, HistSize*50); @@ -302,7 +383,7 @@ public: } } - static void ComputeEdgeLengthHistogram( MeshType & m, Histogramf &h) + static void ComputeEdgeLengthHistogram(MeshType & m, Histogram & h) { assert(m.edge.size()>0); h.Clear(); @@ -331,7 +412,7 @@ public: }); return sum; } - static void ComputeFaceEdgeLengthDistribution( MeshType & m, Distribution &h, bool includeFauxEdge=false) + static void ComputeFaceEdgeLengthDistribution( MeshType & m, Distribution & h, bool includeFauxEdge=false) { std::vector< typename tri::UpdateTopology::PEdge > edgeVec; tri::UpdateTopology::FillUniqueEdgeVector(m,edgeVec,includeFauxEdge); diff --git a/vcg/complex/algorithms/update/color.h b/vcg/complex/algorithms/update/color.h index dc5fbe81..578652ca 100644 --- a/vcg/complex/algorithms/update/color.h +++ b/vcg/complex/algorithms/update/color.h @@ -59,6 +59,10 @@ public: typedef typename MeshType::FacePointer FacePointer; typedef typename MeshType::FaceIterator FaceIterator; typedef typename MeshType::EdgeIterator EdgeIterator; + typedef typename MeshType::TetraType TetraType; + typedef typename MeshType::TetraPointer TetraPointer; + typedef typename MeshType::TetraIterator TetraIterator; + typedef typename MeshType::ScalarType ScalarType; typedef typename MeshType::CoordType CoordType; @@ -73,7 +77,7 @@ public: int cnt; }; - /*! \brief This function colores all (or the selected) the vertices of a mesh. + /*! \brief This function colors all (or the selected) the vertices of a mesh. */ static int PerVertexConstant(MeshType &m, Color4b vs=Color4b::White,bool selected=false) { @@ -91,7 +95,7 @@ public: return cnt; } - /*! \brief This function colores all (or the selected) faces of a mesh. + /*! \brief This function colors all (or the selected) faces of a mesh. */ static int PerFaceConstant(MeshType &m, Color4b vs=Color4b::White,bool selected=false) { @@ -108,6 +112,55 @@ public: return cnt; } + /*! \brief This function colors all (or the selected) tetras of a mesh. + */ + static int PerTetraConstant(MeshType & m, Color4b vs = Color4b::White, bool selected = false) + { + RequirePerTetraColor(m); + int cnt = 0; + ForEachTetra(m, [&] (TetraType & t) { + if (!selected || t.IsS()) + { + t.C() = vs; + ++cnt; + } + }); + return cnt; + } + + /** \brief Transfer tetra color onto vertex color + + Plain average of the color of the tetras incident on a given vertex. + No adjacency required. + */ + static void PerVertexFromTetra(MeshType & m) + { + RequirePerTetraColor(m); + RequirePerVertexColor(m); + + ColorAvgInfo csi; + csi.r = csi.g = csi.b = csi.cnt = 0; + SimpleTempData TD(m.vert, csi); + + ForEachTetra(m, [&] (TetraType & t) { + for (int i = 0; i < 4; ++i) + { + TD[t.V(i)].r += t.C()[0]; + TD[t.V(i)].g += t.C()[1]; + TD[t.V(i)].b += t.C()[2]; + TD[t.V(i)].a += t.C()[3]; + TD[t.V(i)].cnt += 1; + } + }); + + ForEachVertex(m, [&] (VertexType & v) { + v.C()[0] = TD[v].r / TD[v].cnt; + v.C()[1] = TD[v].g / TD[v].cnt; + v.C()[2] = TD[v].b / TD[v].cnt; + v.C()[3] = TD[v].a / TD[v].cnt; + }); + } + /** \brief Transfer face color onto vertex color Plain average of the color of the faces incident on a given vertex. @@ -167,14 +220,14 @@ public: If no range of quality is passed it is automatically computed. */ - static void PerVertexQualityRamp(MeshType &m, float minq=0, float maxq=0) + static void PerVertexQualityRamp(MeshType &m, ScalarType minq = 0., ScalarType maxq = 0.) { RequirePerVertexQuality(m); RequirePerVertexColor(m); - if(minq==maxq) + if(minq == maxq) { - std::pair minmax = Stat::ComputePerVertexQualityMinMax(m); + std::pair minmax = Stat::ComputePerVertexQualityMinMax(m); minq=minmax.first; maxq=minmax.second; } @@ -188,54 +241,76 @@ public: If no range of quality is passed it is automatically computed. */ - static void PerVertexQualityRampParula(MeshType &m, float minq=0, float maxq=0) + static void PerVertexQualityRampParula(MeshType &m, ScalarType minq = 0., ScalarType maxq = 0.) { RequirePerVertexQuality(m); RequirePerVertexColor(m); - if(minq==maxq) + if(minq == maxq) { - std::pair minmax = Stat::ComputePerVertexQualityMinMax(m); + std::pair minmax = Stat::ComputePerVertexQualityMinMax(m); minq=minmax.first; maxq=minmax.second; } - for(VertexIterator vi=m.vert.begin();vi!=m.vert.end();++vi) + for(VertexIterator vi = m.vert.begin(); vi != m.vert.end(); ++vi) if(!(*vi).IsD()) - (*vi).C().SetColorRampParula(minq,maxq,(*vi).Q()); + (*vi).C().SetColorRampParula(minq, maxq, (*vi).Q()); } + /*! \brief This function colores all the faces of a mesh with a hue color shade dependent on the quality. + + If no range of quality is passed it is automatically computed. + */ + static void PerTetraQualityRamp(MeshType &m, ScalarType minq = 0., ScalarType maxq = 0., bool selected = false) + { + RequirePerTetraColor(m); + RequirePerTetraQuality(m); + + if(minq == maxq) + { + std::pair minmax = Stat::ComputerPerTetraQualityMinMax(m); + minq=minmax.first; + maxq=minmax.second; + } + + ForEachTetra(m, [&] (TetraType & t){ + if (!selected || t.IsS()) + t.C().SetColorRamp(minq, maxq, t.Q()); + }); + } /*! \brief This function colores all the faces of a mesh with a hue color shade dependent on the quality. If no range of quality is passed it is automatically computed. */ - static void PerFaceQualityRamp(MeshType &m, float minq=0, float maxq=0, bool selected=false) + static void PerFaceQualityRamp(MeshType &m, ScalarType minq = 0, ScalarType maxq = 0, bool selected = false) { RequirePerFaceColor(m); RequirePerFaceQuality(m); - if(minq==maxq) + if(minq == maxq) { - std::pair minmax = Stat::ComputePerFaceQualityMinMax(m); + std::pair minmax = Stat::ComputePerFaceQualityMinMax(m); minq=minmax.first; maxq=minmax.second; } - for(FaceIterator fi=m.face.begin();fi!=m.face.end();++fi) if(!(*fi).IsD()) - if(!selected || (*fi).IsS()) - (*fi).C().SetColorRamp(minq,maxq,(*fi).Q()); + for(FaceIterator fi = m.face.begin();fi != m.face.end(); ++fi) + if(!(*fi).IsD()) + if(!selected || (*fi).IsS()) + (*fi).C().SetColorRamp(minq, maxq, (*fi).Q()); } /*! \brief This function colores all the edges of a mesh with a hue color shade dependent on the quality. If no range of quality is passed it is automatically computed. */ - static void PerEdgeQualityRamp(MeshType &m, float minq=0, float maxq=0, bool selected=false) + static void PerEdgeQualityRamp(MeshType &m, ScalarType minq = 0, ScalarType maxq = 0, bool selected = false) { RequirePerEdgeColor(m); RequirePerEdgeQuality(m); - if(minq==maxq) + if(minq == maxq) { - std::pair minmax = Stat::ComputePerEdgeQualityMinMax(m); + std::pair minmax = Stat::ComputePerEdgeQualityMinMax(m); minq=minmax.first; maxq=minmax.second; } @@ -248,13 +323,13 @@ public: If no range of quality is passed it is automatically computed. */ - static void PerVertexQualityGray(MeshType &m, float minq, float maxq) + static void PerVertexQualityGray(MeshType &m, ScalarType minq = 0, ScalarType maxq = 0) { RequirePerVertexColor(m); RequirePerVertexQuality(m); if(minq==maxq) { - std::pair minmax = Stat::ComputePerVertexQualityMinMax(m); + std::pair minmax = Stat::ComputePerVertexQualityMinMax(m); minq=minmax.first; maxq=minmax.second; } @@ -267,14 +342,14 @@ public: If no range of quality is passed it is automatically computed. */ - static void PerFaceQualityGray(MeshType &m, float minq=0, float maxq=0) + static void PerFaceQualityGray(MeshType &m, ScalarType minq = 0, ScalarType maxq = 0) { RequirePerFaceColor(m); RequirePerFaceQuality(m); if(minq==maxq) { - std::pair minmax = Stat::ComputePerFaceQualityMinMax(m); + std::pair minmax = Stat::ComputePerFaceQualityMinMax(m); minq=minmax.first; maxq=minmax.second; } diff --git a/vcg/complex/algorithms/update/quality.h b/vcg/complex/algorithms/update/quality.h index 7b8b6d2b..c8572aa0 100644 --- a/vcg/complex/algorithms/update/quality.h +++ b/vcg/complex/algorithms/update/quality.h @@ -148,11 +148,11 @@ static void TetraConstant(MeshType & m, const TetraQualityType q) t.Q() = q; }); } -static void TetraVolume(MeshType & m) +static void TetraFromVolume(MeshType & m) { tri::RequirePerTetraQuality(m); ForEachTetra(m, [] (MeshType::TetraType & t) { - t.Q() = TetraQualityType(vcg::Tetra::ComputeVolume(t)); + t.Q() = TetraQualityType(vcg::Tetra::ComputeVolume(t)); }); }