00001 #include <iostream>
00002 #include <QTime>
00003 #include <omp.h>
00004
00005 #include "nanoflann.hpp"
00006
00007 #include <vcg/complex/complex.h>
00008
00009 #include <wrap/io_trimesh/import.h>
00010 #include <wrap/io_trimesh/export.h>
00011
00012
00013 #include <vcg/space/index/kdtree/kdtree.h>
00014 #include <vcg/space/index/grid_static_ptr.h>
00015 #include <vcg/space/index/perfect_spatial_hashing.h>
00016 #include <vcg/space/index/spatial_hashing.h>
00017 #include <vcg/space/index/octree.h>
00018
00019 int num_test = 1000;
00020 int kNearest = 256;
00021 float queryDist = 0.0037;
00022 float ratio = 1000.0f;
00023
00024
00025 class CVertex;
00026 class CFace;
00027 class CEdge;
00028
00029 class CUsedTypes : public vcg::UsedTypes < vcg::Use< CVertex >::AsVertexType, vcg::Use< CFace >::AsFaceType>{};
00030 class CVertex : public vcg::Vertex < CUsedTypes, vcg::vertex::Coord3f, vcg::vertex::Normal3f, vcg::vertex::Radiusf, vcg::vertex::BitFlags, vcg::vertex::Qualityf, vcg::vertex::Color4b>{};
00031 class CFace : public vcg::Face < CUsedTypes, vcg::face::VertexRef>{};
00032
00033 class CMesh : public vcg::tri::TriMesh < std::vector< CVertex >, std::vector< CFace > > {};
00034
00035
00036 template <typename T>
00037 struct PointCloud
00038 {
00039 struct Point
00040 {
00041 T x,y,z;
00042 };
00043
00044 std::vector<Point> pts;
00045
00046 inline size_t kdtree_get_point_count() const { return pts.size(); }
00047
00048 inline T kdtree_distance(const T *p1, const size_t idx_p2,size_t size) const
00049 {
00050 const T d0=p1[0]-pts[idx_p2].x;
00051 const T d1=p1[1]-pts[idx_p2].y;
00052 const T d2=p1[2]-pts[idx_p2].z;
00053 return d0*d0+d1*d1+d2*d2;
00054 }
00055
00056 inline T kdtree_get_pt(const size_t idx, int dim) const
00057 {
00058 if (dim==0) return pts[idx].x;
00059 else if (dim==1) return pts[idx].y;
00060 else return pts[idx].z;
00061 }
00062
00063 template <class BBOX>
00064 bool kdtree_get_bbox(BBOX &bb) const { return false; }
00065
00066 };
00067
00068
00069 void testKDTree(CMesh& mesh, std::vector<unsigned int>& test_indeces, std::vector<vcg::Point3f>& randomSamples)
00070 {
00071 std::cout << "==================================================="<< std::endl;
00072 std::cout << "KDTree" << std::endl;
00073 QTime time;
00074 time.start();
00075
00076
00077 vcg::ConstDataWrapper<CMesh::VertexType::CoordType> wrapperVcg(&mesh.vert[0].P(), mesh.vert.size(), size_t(mesh.vert[1].P().V()) - size_t(mesh.vert[0].P().V()));
00078 vcg::KdTree<CMesh::ScalarType> kdTreeVcg(wrapperVcg);
00079 std::cout << "Build: " << time.elapsed() << " ms" << std::endl;
00080
00081
00082 float mAveragePointSpacing = 0;
00083 time.restart();
00084 #pragma omp parallel for reduction(+: mAveragePointSpacing) schedule(dynamic, 10)
00085 for (int i = 0; i < mesh.vert.size(); i++)
00086 {
00087 vcg::KdTree<CMesh::ScalarType>::PriorityQueue queue;
00088 kdTreeVcg.doQueryK(mesh.vert[i].cP(), 16, queue);
00089 float newRadius = 2.0f * sqrt(queue.getWeight(0)/ queue.getNofElements());
00090 mesh.vert[i].R() -= newRadius;
00091 mAveragePointSpacing += newRadius;
00092 }
00093 mAveragePointSpacing /= mesh.vert.size();
00094 std::cout << "Average point radius (OpenMP) " << mAveragePointSpacing << std::endl;
00095 std::cout << "Time (OpenMP): " << time.elapsed() << " ms" << std::endl;
00096
00097 queryDist = mAveragePointSpacing * 150;
00098
00099
00100 std::cout << "Radius search (" << num_test << " tests)"<< std::endl;
00101 float avgTime = 0.0f;
00102 for (int ii = 0; ii < num_test; ii++)
00103 {
00104 time.restart();
00105 std::vector<unsigned int> indeces;
00106 std::vector<float> dists;
00107 kdTreeVcg.doQueryDist(mesh.vert[test_indeces[ii]].cP(), queryDist, indeces, dists);
00108 avgTime += time.elapsed();
00109 }
00110 std::cout << "Time (radius = " << queryDist << "): " << avgTime << " ms (mean " << avgTime / num_test << "ms)" << std::endl;
00111
00112
00113 std::cout << "k-Nearest search (" << num_test*10 << " tests)"<< std::endl;
00114 avgTime = 0.0f;
00115 for (int ii = 0; ii < num_test * 10; ii++)
00116 {
00117 time.restart();
00118 vcg::KdTree<CMesh::ScalarType>::PriorityQueue queue;
00119 kdTreeVcg.doQueryK(mesh.vert[test_indeces[ii]].cP(), kNearest, queue);
00120 avgTime += time.elapsed();
00121 }
00122 std::cout << "Time (k = " << kNearest << "): " << avgTime << " ms (mean " << avgTime / (num_test * 10) << "ms)" << std::endl;
00123
00124
00125 std::cout << "Closest search (" << num_test*10 << " tests)"<< std::endl;
00126 avgTime = 0.0f;
00127 for (int ii = 0; ii < num_test * 10; ii++)
00128 {
00129 time.restart();
00130 unsigned int index;
00131 float minDist;
00132 kdTreeVcg.doQueryClosest(randomSamples[ii], index, minDist);
00133 avgTime += time.elapsed();
00134 }
00135 std::cout << "Time : " << avgTime << " ms (mean " << avgTime / (num_test * 10) << "ms)" << std::endl << std::endl;
00136 }
00137
00138
00139 void testNanoFLANN(CMesh& mesh, std::vector<unsigned int>& test_indeces, std::vector<vcg::Point3f> randomSamples)
00140 {
00141 std::cout << "==================================================="<< std::endl;
00142 std::cout << "nanoFLANN" << std::endl;
00143
00144 PointCloud<float> cloud;
00145 cloud.pts.resize(mesh.vert.size());
00146 for (size_t i=0; i < mesh.vert.size(); i++)
00147 {
00148 cloud.pts[i].x = mesh.vert[i].P().X();
00149 cloud.pts[i].y = mesh.vert[i].P().Y();
00150 cloud.pts[i].z = mesh.vert[i].P().Z();
00151 }
00152
00153 typedef nanoflann::KDTreeSingleIndexAdaptor<
00154 nanoflann::L2_Simple_Adaptor<float, PointCloud<float> > ,
00155 PointCloud<float>,
00156 3
00157 > my_kd_tree_t;
00158
00159
00160 QTime time;
00161 time.start();
00162 my_kd_tree_t index(3, cloud, nanoflann::KDTreeSingleIndexAdaptorParams(16) );
00163 index.buildIndex();
00164 std::cout << "Build nanoFlann: " << time.elapsed() << " ms" << std::endl;
00165
00166
00167 std::cout << "Radius search (" << num_test << " tests)"<< std::endl;
00168 float avgTime = 0.0f;
00169 std::vector<std::pair<size_t,float> > ret_matches;
00170 nanoflann::SearchParams params;
00171 for (int ii = 0; ii < num_test; ii++)
00172 {
00173 time.restart();
00174 const size_t nMatches = index.radiusSearch(mesh.vert[test_indeces[ii]].P().V(), queryDist, ret_matches, params);
00175 avgTime += time.elapsed();
00176 }
00177 std::cout << "Time (radius = " << queryDist << "): " << avgTime << " ms (mean " << avgTime / num_test << "ms)" << std::endl;
00178
00179
00180 std::cout << "k-Nearest search (" << num_test*10 << " tests)"<< std::endl;
00181 avgTime = 0.0f;
00182 std::vector<size_t> ret_index(kNearest);
00183 std::vector<float> out_dist_sqr(kNearest);
00184 for (int ii = 0; ii < num_test * 10; ii++)
00185 {
00186 time.restart();
00187 index.knnSearch(mesh.vert[test_indeces[ii]].P().V(), kNearest, &ret_index[0], &out_dist_sqr[0]);
00188 avgTime += time.elapsed();
00189 }
00190 std::cout << "Time (k = " << kNearest << "): " << avgTime << " ms (mean " << avgTime / (num_test * 10) << "ms)" << std::endl;
00191
00192
00193 std::cout << "Closest search (" << num_test*10 << " tests)"<< std::endl;
00194 avgTime = 0.0f;
00195 std::vector<size_t> ret_index_clos(1);
00196 std::vector<float> out_dist_sqr_clos(1);
00197 for (int ii = 0; ii < num_test * 10; ii++)
00198 {
00199 time.restart();
00200 index.knnSearch(randomSamples[ii].V(), 1, &ret_index_clos[0], &out_dist_sqr_clos[0]);
00201 avgTime += time.elapsed();
00202 }
00203 std::cout << "Time : " << avgTime << " ms (mean " << avgTime / (num_test * 10) << "ms)" << std::endl << std::endl;
00204 }
00205
00206
00207 void testUniformGrid(CMesh& mesh, std::vector<unsigned int>& test_indeces, std::vector<vcg::Point3f>& randomSamples)
00208 {
00209 std::cout << "==================================================="<< std::endl;
00210 std::cout << "Uniform Grid" << std::endl;
00211 QTime time;
00212 time.start();
00213
00214
00215 typedef vcg::GridStaticPtr<CMesh::VertexType, CMesh::VertexType::ScalarType> MeshGrid;
00216 MeshGrid uniformGrid;
00217 uniformGrid.Set(mesh.vert.begin(), mesh.vert.end());
00218 std::cout << "Build: " << time.elapsed() << " ms" << std::endl;
00219
00220
00221 std::cout << "Radius search (" << num_test << " tests)"<< std::endl;
00222 float avgTime = 0.0f;
00223 for (int ii = 0; ii < num_test; ii++)
00224 {
00225 time.restart();
00226 std::vector<CMesh::VertexPointer> vertexPtr;
00227 std::vector<CMesh::VertexType::CoordType> points;
00228 std::vector<float> dists;
00229 vcg::tri::GetInSphereVertex(mesh, uniformGrid, mesh.vert[test_indeces[ii]].cP(), queryDist, vertexPtr, dists, points);
00230 avgTime += time.elapsed();
00231 }
00232 std::cout << "Time (radius = " << queryDist << "): " << avgTime << " ms (mean " << avgTime / num_test << "ms)" << std::endl;
00233
00234
00235 std::cout << "k-Nearest search (" << num_test*10 << " tests)"<< std::endl;
00236 avgTime = 0.0f;
00237 for (int ii = 0; ii < num_test * 10; ii++)
00238 {
00239 time.restart();
00240 std::vector<CMesh::VertexPointer> vertexPtr;
00241 std::vector<CMesh::VertexType::CoordType> points;
00242 std::vector<float> dists;
00243 vcg::tri::GetKClosestVertex(mesh, uniformGrid, kNearest, mesh.vert[test_indeces[ii]].cP(), mesh.bbox.Diag(), vertexPtr, dists, points);
00244 avgTime += time.elapsed();
00245 }
00246 std::cout << "Time (k = " << kNearest << "): " << avgTime << " ms (mean " << avgTime / (num_test * 10) << "ms)" << std::endl;
00247
00248
00249 std::cout << "Closest search (" << num_test*10 << " tests)"<< std::endl;
00250 avgTime = 0.0f;
00251 for (int ii = 0; ii < num_test * 10; ii++)
00252 {
00253 time.restart();
00254 float minDist;
00255 vcg::tri::GetClosestVertex(mesh, uniformGrid, randomSamples[ii], mesh.bbox.Diag(), minDist);
00256 avgTime += time.elapsed();
00257 }
00258 std::cout << "Time : " << avgTime << " ms (mean " << avgTime / (num_test * 10) << "ms)" << std::endl << std::endl;
00259 }
00260
00261
00262
00263 void testSpatialHashing(CMesh& mesh, std::vector<unsigned int>& test_indeces, std::vector<vcg::Point3f>& randomSamples)
00264 {
00265 std::cout << "==================================================="<< std::endl;
00266 std::cout << "Spatial Hashing" << std::endl;
00267 QTime time;
00268 time.start();
00269
00270
00271 typedef vcg::SpatialHashTable<CMesh::VertexType, CMesh::VertexType::ScalarType> MeshGrid;
00272 MeshGrid uniformGrid;
00273 uniformGrid.Set(mesh.vert.begin(), mesh.vert.end());
00274 std::cout << "Build: " << time.elapsed() << " ms" << std::endl;
00275
00276
00277 std::cout << "Radius search (" << num_test << " tests)"<< std::endl;
00278 float avgTime = 0.0f;
00279 for (int ii = 0; ii < num_test; ii++)
00280 {
00281 time.restart();
00282 std::vector<CMesh::VertexPointer> vertexPtr;
00283 std::vector<CMesh::VertexType::CoordType> points;
00284 std::vector<float> dists;
00285 vcg::tri::GetInSphereVertex(mesh, uniformGrid, mesh.vert[test_indeces[ii]].cP(), queryDist, vertexPtr, dists, points);
00286 avgTime += time.elapsed();
00287 }
00288 std::cout << "Time (radius = " << queryDist << "): " << avgTime << " ms (mean " << avgTime / num_test << "ms)" << std::endl;
00289
00290
00291 std::cout << "k-Nearest search (" << num_test*10 << " tests)"<< std::endl;
00292 avgTime = 0.0f;
00293 for (int ii = 0; ii < num_test * 10; ii++)
00294 {
00295 time.restart();
00296 std::vector<CMesh::VertexPointer> vertexPtr;
00297 std::vector<CMesh::VertexType::CoordType> points;
00298 std::vector<float> dists;
00299 vcg::tri::GetKClosestVertex(mesh, uniformGrid, kNearest, mesh.vert[test_indeces[ii]].cP(), mesh.bbox.Diag(), vertexPtr, dists, points);
00300 avgTime += time.elapsed();
00301 }
00302 std::cout << "Time (k = " << kNearest << "): " << avgTime << " ms (mean " << avgTime / (num_test * 10) << "ms)" << std::endl;
00303
00304
00305 std::cout << "Closest search (" << num_test*10 << " tests)"<< std::endl;
00306 avgTime = 0.0f;
00307 for (int ii = 0; ii < num_test * 10; ii++)
00308 {
00309 time.restart();
00310 float minDist;
00311 vcg::tri::GetClosestVertex(mesh, uniformGrid, randomSamples[ii], mesh.bbox.Diag(), minDist);
00312 avgTime += time.elapsed();
00313 }
00314 std::cout << "Time : " << avgTime << " ms (mean " << avgTime / (num_test * 10) << "ms)" << std::endl << std::endl;
00315 }
00316
00317
00318
00319 void testPerfectSpatialHashing(CMesh& mesh, std::vector<unsigned int>& test_indeces)
00320 {
00321 std::cout << "==================================================="<< std::endl;
00322 std::cout << "Perfect Spatial Hashing" << std::endl;
00323 QTime time;
00324 time.start();
00325
00326
00327 typedef vcg::SpatialHashTable<CMesh::VertexType, CMesh::VertexType::ScalarType> MeshGrid;
00328 MeshGrid uniformGrid;
00329 uniformGrid.Set(mesh.vert.begin(), mesh.vert.end());
00330 std::cout << "Build: " << time.elapsed() << " ms" << std::endl;
00331
00332
00333 std::cout << "Radius search (" << num_test << " tests)"<< std::endl;
00334 float avgTime = 0.0f;
00335 for (int ii = 0; ii < num_test; ii++)
00336 {
00337 time.restart();
00338 std::vector<CMesh::VertexPointer> vertexPtr;
00339 std::vector<CMesh::VertexType::CoordType> points;
00340 std::vector<float> dists;
00341 vcg::tri::GetInSphereVertex(mesh, uniformGrid, mesh.vert[test_indeces[ii]].cP(), queryDist, vertexPtr, dists, points);
00342 avgTime += time.elapsed();
00343 }
00344 std::cout << "Time (radius = " << queryDist << "): " << avgTime << " ms (mean " << avgTime / num_test << "ms)" << std::endl << std::endl;
00345 }
00346
00347
00348 void testOctree(CMesh& mesh, std::vector<unsigned int>& test_indeces, std::vector<vcg::Point3f>& randomSamples)
00349 {
00350 std::cout << "==================================================="<< std::endl;
00351 std::cout << "Octree" << std::endl;
00352 QTime time;
00353 time.start();
00354
00355
00356 typedef vcg::Octree<CMesh::VertexType, CMesh::VertexType::ScalarType> MeshGrid;
00357 MeshGrid uniformGrid;
00358 uniformGrid.Set(mesh.vert.begin(), mesh.vert.end());
00359 std::cout << "Build: " << time.elapsed() << " ms" << std::endl;
00360
00361
00362 std::cout << "Radius search (" << num_test << " tests)"<< std::endl;
00363 float avgTime = 0.0f;
00364 for (int ii = 0; ii < num_test; ii++)
00365 {
00366 time.restart();
00367 std::vector<CMesh::VertexPointer> vertexPtr;
00368 std::vector<CMesh::VertexType::CoordType> points;
00369 std::vector<float> dists;
00370 vcg::tri::GetInSphereVertex(mesh, uniformGrid, mesh.vert[test_indeces[ii]].cP(), queryDist, vertexPtr, dists, points);
00371 avgTime += time.elapsed();
00372 }
00373 std::cout << "Time (radius = " << queryDist << "): " << avgTime << " ms (mean " << avgTime / num_test << "ms)" << std::endl;
00374
00375
00376 std::cout << "k-Nearest search (" << num_test*10 << " tests)"<< std::endl;
00377 avgTime = 0.0f;
00378 for (int ii = 0; ii < num_test * 10; ii++)
00379 {
00380 time.restart();
00381 std::vector<CMesh::VertexPointer> vertexPtr;
00382 std::vector<CMesh::VertexType::CoordType> points;
00383 std::vector<float> dists;
00384 vcg::tri::GetKClosestVertex(mesh, uniformGrid, kNearest, mesh.vert[test_indeces[ii]].cP(), mesh.bbox.Diag(), vertexPtr, dists, points);
00385 avgTime += time.elapsed();
00386 }
00387 std::cout << "Time (k = " << kNearest << "): " << avgTime << " ms (mean " << avgTime / (num_test * 10) << "ms)" << std::endl;
00388
00389
00390 std::cout << "Closest search (" << num_test*10 << " tests)"<< std::endl;
00391 avgTime = 0.0f;
00392 for (int ii = 0; ii < num_test * 10; ii++)
00393 {
00394 time.restart();
00395 float minDist;
00396 vcg::tri::GetClosestVertex(mesh, uniformGrid, randomSamples[ii], mesh.bbox.Diag(), minDist);
00397 avgTime += time.elapsed();
00398 }
00399 std::cout << "Time : " << avgTime << " ms (mean " << avgTime / (num_test * 10) << "ms)" << std::endl << std::endl;
00400 }
00401
00402
00403
00404 int main( int argc, char * argv[] )
00405 {
00406 if (argc < 2)
00407 std::cout << "Invalid arguments" << std::endl;
00408
00409 CMesh mesh;
00410 if (vcg::tri::io::Importer<CMesh>::Open(mesh, argv[1]) != 0)
00411 std::cout << "Invalid filename" << std::endl;
00412
00413 std::cout << "Mesh BBox diagonal: " << mesh.bbox.Diag() << std::endl;
00414 std::cout << "Max point random offset: " << mesh.bbox.Diag() / 1000.0f << std::endl << std::endl;
00415
00416 vcg::math::MarsenneTwisterRNG randGen;
00417 randGen.initialize(0);
00418 std::vector<vcg::Point3f> randomSamples;
00419 for (int i = 0; i < num_test * 10; i++)
00420 randomSamples.push_back(vcg::math::GeneratePointOnUnitSphereUniform<float>(randGen) * randGen.generate01() * mesh.bbox.Diag() / ratio);
00421
00422 std::vector<unsigned int> test_indeces;
00423 for (int i = 0; i < num_test * 10; i++)
00424 {
00425 int index = randGen.generate01() * (mesh.vert.size() - 1);
00426 test_indeces.push_back(index);
00427 randomSamples[i] += mesh.vert[i].P();
00428 }
00429
00430 testKDTree(mesh, test_indeces, randomSamples);
00431 testNanoFLANN(mesh, test_indeces, randomSamples);
00432 testUniformGrid(mesh, test_indeces, randomSamples);
00433 testSpatialHashing(mesh, test_indeces, randomSamples);
00434 testPerfectSpatialHashing(mesh, test_indeces);
00435 testOctree(mesh, test_indeces, randomSamples);
00436 }