00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #ifndef __VCGLIB_TRIMESH_STAT
00025 #define __VCGLIB_TRIMESH_STAT
00026
00027
00028
00029
00030 #include <vcg/math/histogram.h>
00031 #include <vcg/simplex/face/pos.h>
00032 #include <vcg/simplex/face/topology.h>
00033 #include <vcg/complex/algorithms/closest.h>
00034 #include <vcg/space/index/grid_static_ptr.h>
00035 #include <vcg/complex/algorithms/update/topology.h>
00036 #include <vcg/complex/algorithms/inertia.h>
00037
00038
00039 namespace vcg {
00040 namespace tri{
00041 template <class StatMeshType>
00042 class Stat
00043 {
00044 public:
00045 typedef StatMeshType MeshType;
00046 typedef typename MeshType::VertexType VertexType;
00047 typedef typename MeshType::VertexPointer VertexPointer;
00048 typedef typename MeshType::VertexIterator VertexIterator;
00049 typedef typename MeshType::ScalarType ScalarType;
00050 typedef typename MeshType::FaceType FaceType;
00051 typedef typename MeshType::FacePointer FacePointer;
00052 typedef typename MeshType::FaceIterator FaceIterator;
00053 typedef typename MeshType::EdgeIterator EdgeIterator;
00054 typedef typename MeshType::FaceContainer FaceContainer;
00055 typedef typename vcg::Box3<ScalarType> Box3Type;
00056
00057 static void ComputePerVertexQualityMinMax( MeshType & m, float &minV, float &maxV)
00058 {
00059 std::pair<float,float> pp=ComputePerVertexQualityMinMax(m);
00060 minV=pp.first; maxV=pp.second;
00061 }
00062 static std::pair<float,float> ComputePerVertexQualityMinMax( MeshType & m)
00063 {
00064
00065 tri::RequirePerVertexQuality(m);
00066 typename MeshType::template PerMeshAttributeHandle < std::pair<float,float> > mmqH;
00067 mmqH = tri::Allocator<MeshType>::template GetPerMeshAttribute <std::pair<float,float> >(m,"minmaxQ");
00068
00069 std::pair<float,float> minmax = std::make_pair(std::numeric_limits<float>::max(),-std::numeric_limits<float>::max());
00070
00071 for(VertexIterator vi = m.vert.begin(); vi != m.vert.end(); ++vi)
00072 if(!(*vi).IsD())
00073 {
00074 if( (*vi).Q() < minmax.first) minmax.first=(*vi).Q();
00075 if( (*vi).Q() > minmax.second) minmax.second=(*vi).Q();
00076 }
00077
00078 mmqH() = minmax;
00079 return minmax;
00080 }
00081
00082 static void ComputePerFaceQualityMinMax( MeshType & m, float &minV, float &maxV)
00083 {
00084 std::pair<float,float> pp=ComputePerFaceQualityMinMax(m);
00085 minV=pp.first; maxV=pp.second;
00086 }
00087
00088 static std::pair<ScalarType,ScalarType> ComputePerFaceQualityMinMax( MeshType & m)
00089 {
00090 tri::RequirePerFaceQuality(m);
00091 std::pair<ScalarType,ScalarType> minmax = std::make_pair(std::numeric_limits<ScalarType>::max(),-std::numeric_limits<ScalarType>::max());
00092
00093 FaceIterator fi;
00094 for(fi = m.face.begin(); fi != m.face.end(); ++fi)
00095 if(!(*fi).IsD())
00096 {
00097 if( (*fi).Q() < minmax.first) minmax.first =(*fi).Q();
00098 if( (*fi).Q() > minmax.second) minmax.second=(*fi).Q();
00099 }
00100 return minmax;
00101 }
00102
00103 static std::pair<ScalarType,ScalarType> ComputePerEdgeQualityMinMax( MeshType & m)
00104 {
00105 tri::RequirePerEdgeQuality(m);
00106 std::pair<ScalarType,ScalarType> minmax = std::make_pair(std::numeric_limits<ScalarType>::max(),-std::numeric_limits<ScalarType>::max());
00107
00108 EdgeIterator ei;
00109 for(ei = m.edge.begin(); ei != m.edge.end(); ++ei)
00110 if(!(*ei).IsD())
00111 {
00112 if( (*ei).Q() < minmax.first) minmax.first =(*ei).Q();
00113 if( (*ei).Q() > minmax.second) minmax.second=(*ei).Q();
00114 }
00115 return minmax;
00116 }
00117
00122 static Point3<ScalarType> ComputeCloudBarycenter(MeshType & m, bool useQualityAsWeight=false)
00123 {
00124 if (useQualityAsWeight)
00125 tri::RequirePerVertexQuality(m);
00126
00127 Point3<ScalarType> barycenter(0, 0, 0);
00128 Point3d accumulator(0.0, 0.0, 0.0);
00129 double weightSum = 0;
00130 VertexIterator vi;
00131 for (vi = m.vert.begin(); vi != m.vert.end(); ++vi)
00132 if (!(*vi).IsD())
00133 {
00134 ScalarType weight = useQualityAsWeight ? (*vi).Q() : 1.0;
00135 accumulator[0] += (double)((*vi).P()[0] * weight);
00136 accumulator[1] += (double)((*vi).P()[1] * weight);
00137 accumulator[2] += (double)((*vi).P()[2] * weight);
00138 weightSum += weight;
00139 }
00140 barycenter[0] = (ScalarType)(accumulator[0] / weightSum);
00141 barycenter[1] = (ScalarType)(accumulator[1] / weightSum);
00142 barycenter[2] = (ScalarType)(accumulator[2] / weightSum);
00143 return barycenter;
00144 }
00145
00152 static Point3<ScalarType> ComputeShellBarycenter(MeshType & m)
00153 {
00154 Point3<ScalarType> barycenter(0,0,0);
00155 ScalarType areaSum=0;
00156 FaceIterator fi;
00157 for(fi = m.face.begin(); fi != m.face.end(); ++fi)
00158 if(!(*fi).IsD())
00159 {
00160 ScalarType area=DoubleArea(*fi);
00161 barycenter += Barycenter(*fi)*area;
00162 areaSum+=area;
00163 }
00164 return barycenter/areaSum;
00165 }
00166
00167 static ScalarType ComputeMeshVolume(MeshType & m)
00168 {
00169 Inertia<MeshType> I(m);
00170 return I.Mass();
00171 }
00172
00173 static ScalarType ComputeMeshArea(MeshType & m)
00174 {
00175 ScalarType area=0;
00176
00177 for(FaceIterator fi = m.face.begin(); fi != m.face.end(); ++fi)
00178 if(!(*fi).IsD())
00179 area += DoubleArea(*fi);
00180
00181 return area/ScalarType(2.0);
00182 }
00183
00184 static void ComputePerVertexQualityDistribution( MeshType & m, Distribution<float> &h, bool selectionOnly = false)
00185 {
00186 tri::RequirePerVertexQuality(m);
00187 for(VertexIterator vi = m.vert.begin(); vi != m.vert.end(); ++vi)
00188 if(!(*vi).IsD() && ((!selectionOnly) || (*vi).IsS()) )
00189 {
00190 assert(!math::IsNAN((*vi).Q()) && "You should never try to compute Histogram with Invalid Floating points numbers (NaN)");
00191 h.Add((*vi).Q());
00192 }
00193 }
00194
00195 static void ComputePerFaceQualityDistribution( MeshType & m, Distribution<typename MeshType::ScalarType> &h,
00196 bool selectionOnly = false)
00197 {
00198 tri::RequirePerFaceQuality(m);
00199 for(FaceIterator fi = m.face.begin(); fi != m.face.end(); ++fi)
00200 if(!(*fi).IsD() && ((!selectionOnly) || (*fi).IsS()) )
00201 {
00202 assert(!math::IsNAN((*fi).Q()) && "You should never try to compute Histogram with Invalid Floating points numbers (NaN)");
00203 h.Add((*fi).Q());
00204 }
00205 }
00206
00207 static void ComputePerFaceQualityHistogram( MeshType & m, Histogramf &h, bool selectionOnly=false,int HistSize=10000 )
00208 {
00209 tri::RequirePerFaceQuality(m);
00210 std::pair<float,float> minmax = tri::Stat<MeshType>::ComputePerFaceQualityMinMax(m);
00211 h.Clear();
00212 h.SetRange( minmax.first,minmax.second, HistSize );
00213 for(FaceIterator fi = m.face.begin(); fi != m.face.end(); ++fi)
00214 if(!(*fi).IsD() && ((!selectionOnly) || (*fi).IsS()) ){
00215 assert(!math::IsNAN((*fi).Q()) && "You should never try to compute Histogram with Invalid Floating points numbers (NaN)");
00216 h.Add((*fi).Q());
00217 }
00218 }
00219
00220 static void ComputePerVertexQualityHistogram( MeshType & m, Histogramf &h, bool selectionOnly = false, int HistSize=10000 )
00221 {
00222 tri::RequirePerVertexQuality(m);
00223 std::pair<float,float> minmax = ComputePerVertexQualityMinMax(m);
00224
00225 h.Clear();
00226 h.SetRange( minmax.first,minmax.second, HistSize);
00227 for(VertexIterator vi = m.vert.begin(); vi != m.vert.end(); ++vi)
00228 if(!(*vi).IsD() && ((!selectionOnly) || (*vi).IsS()) )
00229 {
00230 assert(!math::IsNAN((*vi).Q()) && "You should never try to compute Histogram with Invalid Floating points numbers (NaN)");
00231 h.Add((*vi).Q());
00232 }
00233
00234
00235
00236
00237
00238
00239 if(h.MaxCount() > HistSize/5)
00240 {
00241 std::vector<float> QV;
00242 QV.reserve(m.vn);
00243 for(VertexIterator vi = m.vert.begin(); vi != m.vert.end(); ++vi)
00244 if(!(*vi).IsD()) QV.push_back((*vi).Q());
00245
00246 std::nth_element(QV.begin(),QV.begin()+m.vn/100,QV.end());
00247 float newmin=*(QV.begin()+m.vn/100);
00248 std::nth_element(QV.begin(),QV.begin()+m.vn-m.vn/100,QV.end());
00249 float newmax=*(QV.begin()+m.vn-m.vn/100);
00250
00251 h.Clear();
00252 h.SetRange(newmin, newmax, HistSize*50);
00253 for(VertexIterator vi = m.vert.begin(); vi != m.vert.end(); ++vi)
00254 if(!(*vi).IsD() && ((!selectionOnly) || (*vi).IsS()) )
00255 h.Add((*vi).Q());
00256 }
00257 }
00258
00259 static void ComputeEdgeLengthHistogram( MeshType & m, Histogramf &h)
00260 {
00261 assert(m.edge.size()>0);
00262 h.Clear();
00263 h.SetRange( 0, m.bbox.Diag(), 10000);
00264 for(EdgeIterator ei = m.edge.begin(); ei != m.edge.end(); ++ei)
00265 {
00266 if(!(*ei).IsD())
00267 {
00268 h.Add(Distance<float>((*ei).V(0)->P(),(*ei).V(1)->P()));
00269 }
00270 }
00271 }
00272
00273 static ScalarType ComputeEdgeLengthAverage(MeshType & m)
00274 {
00275 Histogramf h;
00276 ComputeEdgeLengthHistogram(m,h);
00277 return h.Avg();
00278 }
00279
00280 static void ComputeFaceEdgeLengthDistribution( MeshType & m, Distribution<float> &h, bool includeFauxEdge=false)
00281 {
00282 std::vector< typename tri::UpdateTopology<MeshType>::PEdge > edgeVec;
00283 tri::UpdateTopology<MeshType>::FillUniqueEdgeVector(m,edgeVec,includeFauxEdge);
00284 h.Clear();
00285 tri::UpdateFlags<MeshType>::FaceBorderFromNone(m);
00286 for(size_t i=0;i<edgeVec.size();++i)
00287 h.Add(Distance(edgeVec[i].v[0]->P(),edgeVec[i].v[1]->P()));
00288 }
00289
00290 static ScalarType ComputeFaceEdgeLengthAverage(MeshType & m)
00291 {
00292 double sum=0;
00293 for(FaceIterator fi = m.face.begin(); fi != m.face.end(); ++fi)
00294 if(!(*fi).IsD())
00295 {
00296 for(int i=0;i<3;++i)
00297 sum+=double(Distance(fi->P0(i),fi->P1(i)));
00298 }
00299 return sum/(m.fn*3.0);
00300 }
00301
00302 };
00303
00304 }
00305 }
00306
00307 #endif
00308