00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 
00021 
00022 
00023 
00024 
00025 
00026 
00027 
00028 
00029 
00030 
00031 
00032 
00033 
00034 
00035 
00036 #include <gtest/gtest.h>
00037 
00038 #include <vector>
00039 
00040 #include <stdio.h>
00041 
00042 using namespace std;
00043 
00044 #include <pcl/common/time.h>
00045 #include <pcl/point_cloud.h>
00046 #include <pcl/point_types.h>
00047 
00048 using namespace pcl;
00049 
00050 #include <pcl/octree/octree.h>
00051 #include <pcl/octree/octree_impl.h>
00052 #include <pcl/octree/octree_pointcloud_adjacency.h>
00053 
00054 using namespace octree;
00055 
00056 TEST (PCL, Octree_Test)
00057 {
00058 
00059   unsigned int i, j;
00060   int data[256];
00061 
00062   
00063   OctreeBase<int> octreeA;
00064   OctreeBase<int> octreeB;
00065 
00066   
00067   octreeA.setTreeDepth (8);
00068   octreeB.setTreeDepth (8);
00069 
00070   struct MyVoxel
00071   {
00072     unsigned int x;
00073     unsigned int y;
00074     unsigned int z;
00075   };
00076   MyVoxel voxels[256];
00077 
00078   srand (static_cast<unsigned int> (time (NULL)));
00079 
00080   
00081   for (i = 0; i < 256; i++)
00082   {
00083     data[i] = i;
00084 
00085     voxels[i].x = i;
00086     voxels[i].y = 255 - i;
00087     voxels[i].z = i;
00088 
00089     
00090     int* voxel_container = octreeA.createLeaf(voxels[i].x, voxels[i].y, voxels[i].z);
00091     *voxel_container = data[i];
00092   }
00093 
00094   for (i = 0; i < 128; i++)
00095   {
00096     
00097     int* voxel_container = octreeA.createLeaf(voxels[i].x, voxels[i].y, voxels[i].z);
00098     
00099     ASSERT_EQ(*voxel_container, data[i]);
00100   }
00101 
00102   for (i = 128; i < 256; i++)
00103   {
00104     
00105     ASSERT_EQ( octreeA.existLeaf(voxels[i].x,voxels[i].y,voxels[i].z), true);
00106 
00107     
00108     octreeA.removeLeaf (voxels[i].x, voxels[i].y, voxels[i].z);
00109 
00110     
00111     ASSERT_EQ( octreeA.existLeaf(voxels[i].x,voxels[i].y,voxels[i].z), false);
00112   }
00113 
00114   
00115 
00116   std::vector<char> treeBinaryA;
00117   std::vector<char> treeBinaryB;
00118 
00119   std::vector<int*> leafVectorA;
00120   std::vector<int*> leafVectorB;
00121 
00122   
00123   octreeA.serializeTree (treeBinaryA);
00124 
00125   
00126   octreeB.deserializeTree (treeBinaryA);
00127 
00128   for (i = 0; i < 128; i++)
00129   {
00130     
00131     ASSERT_EQ( octreeA.existLeaf(voxels[i].x,voxels[i].y,voxels[i].z), true);
00132     ASSERT_EQ( octreeB.existLeaf(voxels[i].x,voxels[i].y,voxels[i].z), true);
00133   }
00134 
00135   for (i = 128; i < 256; i++)
00136   {
00137     
00138     ASSERT_EQ( octreeB.existLeaf(voxels[i].x,voxels[i].y,voxels[i].z), false);
00139   }
00140 
00141   
00142   octreeB.deleteTree ();
00143 
00144   
00145   ASSERT_EQ (0u, octreeB.getLeafCount());
00146 
00147   
00148   for (i = 0; i < 128; i++)
00149   {
00150     ASSERT_EQ(octreeB.existLeaf(voxels[i].x,voxels[i].y,voxels[i].z), false);
00151   }
00152 
00153   
00154   octreeA.serializeTree (treeBinaryA, leafVectorA);
00155 
00156   
00157   ASSERT_EQ(leafVectorA.size(), octreeA.getLeafCount());
00158 
00159   
00160   bool bFound;
00161   for (i = 0; i < 128; i++)
00162   {
00163     int leafInt = *leafVectorA.back ();
00164     leafVectorA.pop_back ();
00165 
00166     bFound = false;
00167     for (j = 0; j < 256; j++)
00168       if (data[j] == leafInt)
00169       {
00170         bFound = true;
00171         break;
00172       }
00173 
00174     ASSERT_EQ(bFound, true);
00175   }
00176 
00177   
00178   octreeA.serializeLeafs (leafVectorA);
00179 
00180   for (i = 0; i < 128; i++)
00181   {
00182     int leafInt = *leafVectorA.back ();
00183     leafVectorA.pop_back ();
00184 
00185     bFound = false;
00186     for (j = 0; j < 256; j++)
00187       if (data[j] == leafInt)
00188       {
00189         bFound = true;
00190         break;
00191       }
00192 
00193     ASSERT_EQ(bFound, true);
00194   }
00195 
00196   
00197   octreeA.serializeTree (treeBinaryA, leafVectorA);
00198   octreeB.deserializeTree (treeBinaryA, leafVectorA);
00199 
00200   
00201   ASSERT_EQ(octreeA.getLeafCount(), octreeB.getLeafCount());
00202   ASSERT_EQ(128u, octreeB.getLeafCount());
00203 
00204   octreeB.serializeTree (treeBinaryB, leafVectorB);
00205 
00206   
00207   ASSERT_EQ(leafVectorB.size(), octreeB.getLeafCount());
00208   ASSERT_EQ(leafVectorA.size(), leafVectorB.size());
00209 
00210   for (i = 0; i < leafVectorB.size (); i++)
00211   {
00212     ASSERT_EQ( (*leafVectorA[i] == *leafVectorB[i]), true);
00213   }
00214 
00215   
00216 
00217   OctreeBase<int>::Iterator a_it;
00218   OctreeBase<int>::Iterator a_it_end = octreeA.end();
00219 
00220   unsigned int node_count = 0;
00221   unsigned int branch_count = 0;
00222   unsigned int leaf_count = 0;
00223 
00224   
00225   for (a_it=octreeA.begin(); a_it!=a_it_end; ++a_it)
00226   {
00227     
00228     unsigned int depth = a_it.getCurrentOctreeDepth ();
00229     ASSERT_LE(depth, octreeA.getTreeDepth());
00230 
00231     
00232     const OctreeNode* node = a_it.getCurrentOctreeNode ();
00233     if (node->getNodeType () == BRANCH_NODE)
00234     {
00235       branch_count++;
00236     }
00237     else if (node->getNodeType () == LEAF_NODE)
00238     {
00239       leaf_count++;
00240     }
00241     node_count++;
00242   }
00243 
00244   
00245   ASSERT_EQ(node_count, branch_count + leaf_count);
00246   ASSERT_EQ(leaf_count, octreeA.getLeafCount ());
00247 
00248 }
00249 
00250 TEST (PCL, Octree_Dynamic_Depth_Test)
00251 {
00252 
00253   size_t i;
00254   int test_runs = 100;
00255   int pointcount = 300;
00256 
00257   int test, point;
00258 
00259   float resolution = 0.01f;
00260 
00261   const static size_t leafAggSize = 5;
00262 
00263   OctreePointCloudPointVector<PointXYZ> octree (resolution);
00264 
00265   
00266   PointCloud<PointXYZ>::Ptr cloud (new PointCloud<PointXYZ> ());
00267 
00268   
00269   octree.setInputCloud (cloud);
00270 
00271   for (test = 0; test < test_runs; ++test)
00272   {
00273     
00274     cloud->points.clear ();
00275     octree.deleteTree ();
00276 
00277     PointXYZ newPoint (1.5, 2.5, 3.5);
00278     cloud->push_back (newPoint);
00279 
00280     for (point = 0; point < 15; point++)
00281     {
00282       
00283       PointXYZ newPoint (1.0, 2.0, 3.0);
00284 
00285       
00286       cloud->push_back (newPoint);
00287     }
00288 
00289     
00290     octree.defineBoundingBox ();
00291     octree.enableDynamicDepth (leafAggSize);
00292     octree.addPointsFromInputCloud ();
00293 
00294     unsigned int leaf_node_counter = 0;
00295     
00296     OctreePointCloudPointVector<PointXYZ>::LeafNodeIterator it2;
00297     const OctreePointCloudPointVector<PointXYZ>::LeafNodeIterator it2_end = octree.leaf_end();
00298     for (it2 = octree.leaf_begin(); it2 != it2_end; ++it2)
00299     {
00300       ++leaf_node_counter;
00301       unsigned int depth = it2.getCurrentOctreeDepth ();
00302       ASSERT_EQ((depth==1)||(depth==6), true);
00303     }
00304 
00305     
00306     cloud->points.clear ();
00307     octree.deleteTree ();
00308 
00309     for (point = 0; point < pointcount; point++)
00310     {
00311       
00312       PointXYZ newPoint (static_cast<float> (1024.0 * rand () / RAND_MAX),
00313           static_cast<float> (1024.0 * rand () / RAND_MAX),
00314           static_cast<float> (1024.0 * rand () / RAND_MAX));
00315 
00316       
00317       cloud->push_back (newPoint);
00318     }
00319 
00320 
00321     
00322     octree.defineBoundingBox ();
00323     octree.enableDynamicDepth (leafAggSize);
00324     octree.addPointsFromInputCloud ();
00325 
00326     
00327     OctreePointCloudPointVector<PointXYZ>::LeafNodeIterator it;
00328     const OctreePointCloudPointVector<PointXYZ>::LeafNodeIterator it_end = octree.leaf_end();
00329     unsigned int leaf_count = 0;
00330 
00331     std::vector<int> indexVector;
00332 
00333     
00334     for (it = octree.leaf_begin(); it != it_end; ++it)
00335     {
00336       OctreeNode* node = it.getCurrentOctreeNode ();
00337 
00338 
00339       ASSERT_EQ(node->getNodeType(), LEAF_NODE);
00340 
00341       OctreeContainerPointIndices& container = it.getLeafContainer();
00342       if (it.getCurrentOctreeDepth () < octree.getTreeDepth ())
00343         ASSERT_LE(container.getSize(), leafAggSize);
00344 
00345       
00346       container.getPointIndices (indexVector);
00347 
00348       
00349       std::vector<int> tmpVector;
00350       container.getPointIndices (tmpVector);
00351 
00352       Eigen::Vector3f min_pt, max_pt;
00353       octree.getVoxelBounds (it, min_pt, max_pt);
00354 
00355       for (i=0; i<tmpVector.size(); ++i)
00356       {
00357         ASSERT_GE(cloud->points[tmpVector[i]].x, min_pt(0));
00358         ASSERT_GE(cloud->points[tmpVector[i]].y, min_pt(1));
00359         ASSERT_GE(cloud->points[tmpVector[i]].z, min_pt(2));
00360         ASSERT_LE(cloud->points[tmpVector[i]].x, max_pt(0));
00361         ASSERT_LE(cloud->points[tmpVector[i]].y, max_pt(1));
00362         ASSERT_LE(cloud->points[tmpVector[i]].z, max_pt(2));
00363       }
00364 
00365       leaf_count++;
00366 
00367     }
00368     ASSERT_EQ(pointcount, indexVector.size());
00369 
00370     
00371     for (i = 0; i < indexVector.size (); ++i)
00372     {
00373 #if !defined(__APPLE__)
00374       bool indexFound = (std::find(indexVector.begin(), indexVector.end(), i) != indexVector.end());
00375       ASSERT_EQ(indexFound, true);
00376 #endif
00377     }
00378 
00379     
00380     ASSERT_EQ(leaf_count, octree.getLeafCount ());
00381 
00382   }
00383 }
00384 
00385 TEST (PCL, Octree2Buf_Test)
00386 {
00387 
00388   
00389   Octree2BufBase<int> octreeA;
00390   Octree2BufBase<int> octreeB;
00391 
00392   
00393   octreeA.setTreeDepth (8);
00394   octreeB.setTreeDepth (8);
00395 
00396   struct MyVoxel
00397   {
00398     unsigned int x;
00399     unsigned int y;
00400     unsigned int z;
00401   };
00402 
00403   unsigned int i, j;
00404   int data[256];
00405   MyVoxel voxels[256];
00406 
00407   srand (static_cast<unsigned int> (time (NULL)));
00408 
00409   
00410   for (i = 0; i < 256; i++)
00411   {
00412     data[i] = i;
00413 
00414     voxels[i].x = i;
00415     voxels[i].y = 255 - i;
00416     voxels[i].z = i;
00417 
00418     
00419     int* voxel_container = octreeA.createLeaf(voxels[i].x, voxels[i].y, voxels[i].z);
00420     data[i] = *voxel_container;
00421 
00422   }
00423 
00424   ASSERT_EQ(static_cast<unsigned int> (256), octreeA.getLeafCount());
00425 
00426   for (i = 0; i < 128; i++)
00427   {
00428     
00429     int* voxel_container = octreeA.findLeaf(voxels[i].x, voxels[i].y, voxels[i].z);
00430     ASSERT_EQ(*voxel_container, data[i]);
00431   }
00432 
00433   for (i = 128; i < 256; i++)
00434   {
00435     
00436     ASSERT_EQ( octreeA.existLeaf(voxels[i].x,voxels[i].y,voxels[i].z), true);
00437 
00438     
00439     octreeA.removeLeaf (voxels[i].x, voxels[i].y, voxels[i].z);
00440 
00441     
00442     ASSERT_EQ( octreeA.existLeaf(voxels[i].x,voxels[i].y,voxels[i].z), false);
00443   }
00444 
00446 
00447   
00448 
00449   std::vector<char> treeBinaryA;
00450   std::vector<char> treeBinaryB;
00451 
00452   std::vector<int*> leafVectorA;
00453   std::vector<int*> leafVectorB;
00454 
00455   
00456   octreeA.serializeTree (treeBinaryA);
00457 
00458   
00459   octreeB.deserializeTree (treeBinaryA);
00460 
00461   
00462   for (i = 0; i < 128; i++)
00463   {
00464     ASSERT_EQ( octreeB.existLeaf(voxels[i].x,voxels[i].y,voxels[i].z), true);
00465   }
00466 
00467   
00468   for (i = 128; i < 256; i++)
00469   {
00470     ASSERT_EQ( octreeB.existLeaf(voxels[i].x,voxels[i].y,voxels[i].z), false);
00471   }
00472 
00473   
00474   octreeB.deleteTree ();
00475   octreeB.setTreeDepth (8);
00476 
00477   
00478   ASSERT_EQ(static_cast<unsigned int> (0), octreeB.getLeafCount());
00479 
00480   for (i = 0; i < 128; i++)
00481   {
00482     ASSERT_EQ( octreeB.existLeaf(voxels[i].x,voxels[i].y,voxels[i].z), false);
00483   }
00484 
00485   
00486   octreeA.serializeTree (treeBinaryA, leafVectorA);
00487 
00488   
00489   ASSERT_EQ(leafVectorA.size(), octreeA.getLeafCount());
00490 
00491   
00492   bool bFound;
00493   for (i = 0; i < 128; i++)
00494   {
00495     int leafInt = *leafVectorA.back ();
00496     leafVectorA.pop_back ();
00497 
00498     bFound = false;
00499     for (j = 0; j < 256; j++)
00500       if (data[j] == leafInt)
00501       {
00502         bFound = true;
00503         break;
00504       }
00505 
00506     ASSERT_EQ(bFound, true);
00507   }
00508 
00509   
00510   octreeA.serializeLeafs (leafVectorA);
00511 
00512   for (i = 0; i < 128; i++)
00513   {
00514     int leafInt = *leafVectorA.back ();
00515     leafVectorA.pop_back ();
00516 
00517     bFound = false;
00518     for (j = 0; j < 256; j++)
00519       if (data[j] == leafInt)
00520       {
00521         bFound = true;
00522         break;
00523       }
00524 
00525     ASSERT_EQ(bFound, true);
00526   }
00527 
00528   
00529   octreeA.serializeTree (treeBinaryA, leafVectorA);
00530   octreeB.deserializeTree (treeBinaryA, leafVectorA);
00531 
00532   ASSERT_EQ(octreeA.getLeafCount(), octreeB.getLeafCount());
00533   ASSERT_EQ(static_cast<unsigned int> (128), octreeB.getLeafCount());
00534 
00535   octreeB.serializeTree (treeBinaryB, leafVectorB);
00536 
00537   
00538   ASSERT_EQ(leafVectorB.size(), octreeB.getLeafCount());
00539   ASSERT_EQ(leafVectorA.size(), leafVectorB.size());
00540 
00541   for (i = 0; i < leafVectorB.size (); i++)
00542   {
00543     ASSERT_EQ( (*leafVectorA[i] == *leafVectorB[i]), true);
00544   }
00545 
00546 }
00547 
00548 
00549 TEST (PCL, Octree2Buf_Base_Double_Buffering_Test)
00550 {
00551 
00552 #define TESTPOINTS 3000
00553 
00554   
00555   Octree2BufBase<int> octreeA;
00556   Octree2BufBase<int> octreeB;
00557 
00558   std::vector<char> treeBinaryA;
00559   std::vector<char> treeBinaryB;
00560 
00561   std::vector<int*> leafVectorA;
00562   std::vector<int*> leafVectorB;
00563 
00564   octreeA.setTreeDepth (5);
00565   octreeB.setTreeDepth (5);
00566 
00567   struct MyVoxel
00568   {
00569     unsigned int x;
00570     unsigned int y;
00571     unsigned int z;
00572   };
00573 
00574   unsigned int i, j, k, runs;
00575   int data[TESTPOINTS];
00576   MyVoxel voxels[TESTPOINTS];
00577 
00578   srand (static_cast<unsigned int> (time (NULL)));
00579 
00580   const unsigned int test_runs = 20;
00581 
00582   for (j = 0; j < test_runs; j++)
00583   {
00584     octreeA.deleteTree ();
00585     octreeB.deleteTree ();
00586     octreeA.setTreeDepth (5);
00587     octreeB.setTreeDepth (5);
00588 
00589     runs = rand () % 20 + 1;
00590     for (k = 0; k < runs; k++)
00591     {
00592       
00593       octreeA.switchBuffers ();
00594       octreeB.switchBuffers ();
00595 
00596       for (i = 0; i < TESTPOINTS; i++)
00597       {
00598         data[i] = rand ();
00599 
00600         voxels[i].x = rand () % 4096;
00601         voxels[i].y = rand () % 4096;
00602         voxels[i].z = rand () % 4096;
00603 
00604         
00605 
00606         int* container = octreeA.createLeaf(voxels[i].x, voxels[i].y, voxels[i].z);
00607         *container = data[i];
00608 
00609       }
00610 
00611       
00612       octreeA.serializeTree (treeBinaryA, leafVectorA, true);
00613       octreeB.deserializeTree (treeBinaryA, leafVectorA, true);
00614     }
00615 
00616     octreeB.serializeTree (treeBinaryB, leafVectorB, true);
00617 
00618     
00619     ASSERT_EQ(octreeA.getLeafCount(), octreeB.getLeafCount());
00620     ASSERT_EQ(leafVectorB.size(), octreeB.getLeafCount());
00621     ASSERT_EQ(leafVectorA.size(), leafVectorB.size());
00622 
00623     
00624     for (i = 0; i < leafVectorB.size (); i++)
00625     {
00626       ASSERT_EQ( (*leafVectorA[i] == *leafVectorB[i]), true);
00627     }
00628 
00629   }
00630 
00631 }
00632 
00633 TEST (PCL, Octree2Buf_Base_Double_Buffering_XOR_Test)
00634 {
00635 
00636 #define TESTPOINTS 3000
00637 
00638   
00639   Octree2BufBase<int> octreeA;
00640   Octree2BufBase<int> octreeB;
00641 
00642   std::vector<char> treeBinaryA;
00643   std::vector<char> treeBinaryB;
00644 
00645   std::vector<int*> leafVectorA;
00646   std::vector<int*> leafVectorB;
00647 
00648   octreeA.setTreeDepth (5);
00649   octreeB.setTreeDepth (5);
00650 
00651   struct MyVoxel
00652   {
00653     unsigned int x;
00654     unsigned int y;
00655     unsigned int z;
00656   };
00657 
00658   unsigned int i, j;
00659   int data[TESTPOINTS];
00660   MyVoxel voxels[TESTPOINTS];
00661 
00662   srand (static_cast<unsigned int> (time (NULL)));
00663 
00664   const unsigned int test_runs = 15;
00665 
00666   for (j = 0; j < test_runs; j++)
00667   {
00668     for (i = 0; i < TESTPOINTS; i++)
00669     {
00670       data[i] = rand ();
00671 
00672       voxels[i].x = rand () % 4096;
00673       voxels[i].y = rand () % 4096;
00674       voxels[i].z = rand () % 4096;
00675 
00676       
00677 
00678       int* container = octreeA.createLeaf(voxels[i].x, voxels[i].y, voxels[i].z);
00679       *container = data[i];
00680     }
00681 
00682     
00683     octreeA.serializeTree (treeBinaryA, leafVectorA, true);
00684     octreeB.deserializeTree (treeBinaryA, leafVectorA, true);
00685     octreeB.serializeTree (treeBinaryB, leafVectorB, true);
00686 
00687     
00688     ASSERT_EQ(octreeA.getLeafCount(), octreeB.getLeafCount());
00689     ASSERT_EQ(leafVectorB.size(), octreeB.getLeafCount());
00690     ASSERT_EQ(leafVectorA.size(), leafVectorB.size());
00691     ASSERT_EQ(treeBinaryA.size(), octreeB.getBranchCount());
00692     ASSERT_EQ(treeBinaryA.size(), treeBinaryB.size());
00693 
00694     
00695     for (i = 0; i < leafVectorB.size (); i++)
00696     {
00697       ASSERT_EQ( (*leafVectorA[i] == *leafVectorB[i]), true);
00698     }
00699 
00700     
00701     octreeA.switchBuffers ();
00702     octreeB.switchBuffers ();
00703 
00704   }
00705 
00706 }
00707 
00708 TEST (PCL, Octree_Pointcloud_Test)
00709 {
00710 
00711   size_t i;
00712   int test_runs = 100;
00713   int pointcount = 300;
00714 
00715   int test, point;
00716 
00717   float resolution = 0.01f;
00718 
00719   
00720   OctreePointCloudSinglePoint<PointXYZ> octreeA (resolution);
00721   OctreePointCloudSearch<PointXYZ> octreeB (resolution);
00722   OctreePointCloudPointVector<PointXYZ> octreeC (resolution);
00723 
00724   
00725   PointCloud<PointXYZ>::Ptr cloudA (new PointCloud<PointXYZ> ());
00726   PointCloud<PointXYZ>::Ptr cloudB (new PointCloud<PointXYZ> ());
00727 
00728   
00729   octreeA.setInputCloud (cloudA);
00730   octreeB.setInputCloud (cloudB);
00731   octreeC.setInputCloud (cloudB);
00732 
00733   for (test = 0; test < test_runs; ++test)
00734   {
00735 
00736     
00737     cloudA->points.clear ();
00738     octreeA.deleteTree ();
00739 
00740     cloudB->points.clear ();
00741     octreeB.deleteTree ();
00742 
00743     octreeC.deleteTree ();
00744 
00745     for (point = 0; point < pointcount; point++)
00746     {
00747       
00748       PointXYZ newPoint (static_cast<float> (1024.0 * rand () / RAND_MAX), 
00749                          static_cast<float> (1024.0 * rand () / RAND_MAX), 
00750                          static_cast<float> (1024.0 * rand () / RAND_MAX));
00751 
00752       if (!octreeA.isVoxelOccupiedAtPoint (newPoint))
00753       {
00754         
00755         octreeA.addPointToCloud (newPoint, cloudA);
00756       }
00757 
00758       
00759       cloudB->push_back (newPoint);
00760     }
00761 
00762     ASSERT_EQ(octreeA.getLeafCount(), cloudA->points.size());
00763 
00764     
00765     for (i = 0; i < cloudA->points.size (); i++)
00766     {
00767       ASSERT_EQ(octreeA.isVoxelOccupiedAtPoint(cloudA->points[i]), true);
00768       octreeA.deleteVoxelAtPoint (cloudA->points[i]);
00769       ASSERT_EQ(octreeA.isVoxelOccupiedAtPoint(cloudA->points[i]), false);
00770     }
00771 
00772     ASSERT_EQ(octreeA.getLeafCount(), static_cast<unsigned int> (0));
00773 
00774     
00775     octreeB.defineBoundingBox ();
00776     octreeB.addPointsFromInputCloud ();
00777 
00778     
00779     OctreePointCloudPointVector<PointXYZ>::Iterator b_it;
00780     OctreePointCloudPointVector<PointXYZ>::Iterator b_it_end = octreeB.end();
00781 
00782     
00783 
00784     unsigned int node_count = 0;
00785     unsigned int branch_count = 0;
00786     unsigned int leaf_count = 0;
00787 
00788     double minx, miny, minz, maxx, maxy, maxz;
00789     octreeB.getBoundingBox (minx, miny, minz, maxx, maxy, maxz);
00790 
00791     
00792     for (b_it = octreeB.begin(); b_it != b_it_end; ++b_it)
00793     {
00794       
00795       unsigned int depth = b_it.getCurrentOctreeDepth ();
00796       ASSERT_LE(depth, octreeB.getTreeDepth());
00797 
00798       Eigen::Vector3f voxel_min, voxel_max;
00799       octreeB.getVoxelBounds (b_it, voxel_min, voxel_max);
00800 
00801       ASSERT_GE(voxel_min.x (), minx - 1e-4);
00802       ASSERT_GE(voxel_min.y (), miny - 1e-4);
00803       ASSERT_GE(voxel_min.z (), minz - 1e-4);
00804 
00805       ASSERT_LE(voxel_max.x (), maxx + 1e-4);
00806       ASSERT_LE(voxel_max.y (), maxy + 1e-4);
00807       ASSERT_LE(voxel_max.z (), maxz + 1e-4);
00808 
00809       
00810       const OctreeNode* node = b_it.getCurrentOctreeNode ();
00811       if (node->getNodeType () == BRANCH_NODE)
00812       {
00813         branch_count++;
00814       }
00815       else if (node->getNodeType () == LEAF_NODE)
00816       {
00817         leaf_count++;
00818       }
00819       node_count++;
00820     }
00821 
00822     
00823     ASSERT_EQ(node_count, branch_count + leaf_count);
00824     ASSERT_EQ(leaf_count, octreeB.getLeafCount ());
00825 
00826     for (i = 0; i < cloudB->points.size (); i++)
00827     {
00828 
00829       std::vector<int> pointIdxVec;
00830       octreeB.voxelSearch (cloudB->points[i], pointIdxVec);
00831 
00832       bool bIdxFound = false;
00833       std::vector<int>::const_iterator current = pointIdxVec.begin ();
00834       while (current != pointIdxVec.end ())
00835       {
00836         if (*current == static_cast<int> (i))
00837         {
00838           bIdxFound = true;
00839           break;
00840         }
00841         ++current;
00842       }
00843 
00844       ASSERT_EQ(bIdxFound, true);
00845 
00846     }
00847 
00848   }
00849 
00850 }
00851 
00852 TEST (PCL, Octree_Pointcloud_Density_Test)
00853 {
00854 
00855   
00856 
00857   PointCloud<PointXYZ>::Ptr cloudIn (new PointCloud<PointXYZ> ());
00858 
00859   for (float z = 0.05f; z < 7.0f; z += 0.1f)
00860     for (float y = 0.05f; y < 7.0f; y += 0.1f)
00861       for (float x = 0.05f; x < 7.0f; x += 0.1f)
00862         cloudIn->push_back (PointXYZ (x, y, z));
00863 
00864   cloudIn->width = static_cast<uint32_t> (cloudIn->points.size ());
00865   cloudIn->height = 1;
00866 
00867   OctreePointCloudDensity<PointXYZ> octreeA (1.0f); 
00868   OctreePointCloudDensity<PointXYZ> octreeB (0.00001f); 
00869 
00870   octreeA.defineBoundingBox (7.0, 7.0, 7.0);
00871   octreeB.defineBoundingBox (7.0, 7.0, 7.0);
00872 
00873   
00874   octreeA.setInputCloud (cloudIn);
00875   octreeB.setInputCloud (cloudIn);
00876 
00877   octreeA.addPointsFromInputCloud ();
00878   octreeB.addPointsFromInputCloud ();
00879 
00880   
00881   for (float z = 1.5f; z < 3.5f; z += 1.0f)
00882     for (float y = 1.5f; y < 3.5f; y += 1.0f)
00883       for (float x = 1.5f; x < 3.5f; x += 1.0f)
00884         ASSERT_EQ(octreeA.getVoxelDensityAtPoint (PointXYZ(x, y, z)), 1000u);
00885 
00886   for (float z = 0.05f; z < 5.0f; z += 0.1f)
00887     for (float y = 0.05f; y < 5.0f; y += 0.1f)
00888       for (float x = 0.05f; x < 5.0f; x += 0.1f)
00889         ASSERT_EQ(octreeB.getVoxelDensityAtPoint (PointXYZ(x, y, z)), 1u);
00890 }
00891 
00892 TEST (PCL, Octree_Pointcloud_Iterator_Test)
00893 {
00894   
00895 
00896   PointCloud<PointXYZ>::Ptr cloudIn (new PointCloud<PointXYZ> ());
00897 
00898   for (float z = 0.05f; z < 7.0f; z += 0.1f)
00899     for (float y = 0.05f; y < 7.0f; y += 0.1f)
00900       for (float x = 0.05f; x < 7.0f; x += 0.1f)
00901         cloudIn->push_back (PointXYZ (x, y, z));
00902 
00903   cloudIn->width = static_cast<uint32_t> (cloudIn->points.size ());
00904   cloudIn->height = 1;
00905 
00906   OctreePointCloud<PointXYZ> octreeA (1.0f); 
00907 
00908   
00909   octreeA.setInputCloud (cloudIn);
00910   octreeA.addPointsFromInputCloud ();
00911 
00912   
00913   OctreePointCloud<PointXYZ>::LeafNodeIterator it1;
00914   OctreePointCloud<PointXYZ>::LeafNodeIterator it1_end = octreeA.leaf_end();
00915 
00916   std::vector<int> indexVector;
00917   unsigned int leafNodeCounter = 0;
00918 
00919   for (it1 = octreeA.leaf_begin(); it1 != it1_end; ++it1)
00920   {
00921     it1.getLeafContainer().getPointIndices(indexVector);
00922     leafNodeCounter++;
00923   }
00924 
00925   ASSERT_EQ(indexVector.size(), cloudIn->points.size ());
00926   ASSERT_EQ(leafNodeCounter, octreeA.getLeafCount());
00927 
00928   OctreePointCloud<PointXYZ>::Iterator it2;
00929   OctreePointCloud<PointXYZ>::Iterator it2_end = octreeA.end();
00930 
00931   unsigned int traversCounter = 0;
00932   for (it2 = octreeA.begin(); it2 != it2_end; ++it2)
00933   {
00934     traversCounter++;
00935   }
00936 
00937   ASSERT_EQ(octreeA.getLeafCount() + octreeA.getBranchCount(), traversCounter);
00938 
00939   
00940 
00941   unsigned int lastDepth = 0;
00942   unsigned int branchNodeCount = 0;
00943   unsigned int leafNodeCount = 0;
00944 
00945   bool leafNodeVisited = false;
00946 
00947   OctreePointCloud<PointXYZ>::BreadthFirstIterator bfIt;
00948   const OctreePointCloud<PointXYZ>::BreadthFirstIterator bfIt_end = octreeA.breadth_end();
00949 
00950   for (bfIt = octreeA.breadth_begin(); bfIt != bfIt_end; ++bfIt)
00951   {
00952     
00953     ASSERT_EQ( bfIt.getCurrentOctreeDepth()>=lastDepth, true);
00954     lastDepth = bfIt.getCurrentOctreeDepth ();
00955 
00956     if (bfIt.isBranchNode ())
00957     {
00958       branchNodeCount++;
00959       
00960       ASSERT_EQ( leafNodeVisited, false);
00961     }
00962 
00963     if (bfIt.isLeafNode ())
00964     {
00965       leafNodeCount++;
00966       leafNodeVisited = true;
00967     }
00968   }
00969 
00970   
00971   ASSERT_EQ( leafNodeCount, octreeA.getLeafCount());
00972   ASSERT_EQ( branchNodeCount, octreeA.getBranchCount());
00973 
00974 }
00975 
00976 TEST(PCL, Octree_Pointcloud_Occupancy_Test)
00977 {
00978   const unsigned int test_runs = 100;
00979   unsigned int test_id;
00980 
00981   
00982 
00983   PointCloud<PointXYZ>::Ptr cloudIn (new PointCloud<PointXYZ> ());
00984 
00985   OctreePointCloudOccupancy<PointXYZ> octree (0.00001f);
00986 
00987   size_t i;
00988 
00989   srand (static_cast<unsigned int> (time (NULL)));
00990 
00991   for (test_id = 0; test_id < test_runs; test_id++)
00992   {
00993 
00994     cloudIn->width = 1000;
00995     cloudIn->height = 1;
00996     cloudIn->points.resize (cloudIn->width * cloudIn->height);
00997 
00998     
00999     for (i = 0; i < 1000; i++)
01000     {
01001       cloudIn->points[i] = PointXYZ (static_cast<float> (5.0  * rand () / RAND_MAX),
01002                                      static_cast<float> (10.0 * rand () / RAND_MAX),
01003                                      static_cast<float> (10.0 * rand () / RAND_MAX));
01004     }
01005 
01006     
01007     octree.setInputCloud (cloudIn);
01008     octree.addPointsFromInputCloud ();
01009 
01010     
01011     for (i = 0; i < 1000; i++)
01012     {
01013       ASSERT_EQ(octree.isVoxelOccupiedAtPoint(cloudIn->points[i]), true);
01014       octree.deleteVoxelAtPoint (cloudIn->points[i]);
01015       ASSERT_EQ(octree.isVoxelOccupiedAtPoint(cloudIn->points[i]), false);
01016     }
01017 
01018   }
01019 
01020 }
01021 
01022 TEST (PCL, Octree_Pointcloud_Change_Detector_Test)
01023 {
01024   
01025 
01026   PointCloud<PointXYZ>::Ptr cloudIn (new PointCloud<PointXYZ> ());
01027 
01028   OctreePointCloudChangeDetector<PointXYZ> octree (0.01f);
01029 
01030   size_t i;
01031 
01032   srand (static_cast<unsigned int> (time (NULL)));
01033 
01034   cloudIn->width = 1000;
01035   cloudIn->height = 1;
01036   cloudIn->points.resize (cloudIn->width * cloudIn->height);
01037 
01038   
01039   for (i = 0; i < 1000; i++)
01040   {
01041     cloudIn->points[i] = PointXYZ (static_cast<float> (5.0  * rand () / RAND_MAX),
01042                                    static_cast<float> (10.0 * rand () / RAND_MAX),
01043                                    static_cast<float> (10.0 * rand () / RAND_MAX));
01044   }
01045 
01046   
01047   octree.setInputCloud (cloudIn);
01048 
01049   
01050   octree.addPointsFromInputCloud ();
01051 
01052   
01053   octree.switchBuffers ();
01054 
01055   
01056   octree.addPointsFromInputCloud ();
01057 
01058   
01059   for (i = 0; i < 1000; i++)
01060   {
01061     octree.addPointToCloud (
01062         PointXYZ (static_cast<float> (100.0 + 5.0  * rand () / RAND_MAX), 
01063                   static_cast<float> (100.0 + 10.0 * rand () / RAND_MAX),
01064                   static_cast<float> (100.0 + 10.0 * rand () / RAND_MAX)),
01065         cloudIn);
01066   }
01067 
01068   vector<int> newPointIdxVector;
01069 
01070   
01071   octree.getPointIndicesFromNewVoxels (newPointIdxVector);
01072 
01073   
01074   ASSERT_EQ( newPointIdxVector.size(), static_cast<std::size_t> (1000));
01075 
01076   
01077   for (i = 0; i < 1000; i++)
01078   {
01079     ASSERT_EQ( ( newPointIdxVector [i] >= 1000 ), true);
01080   }
01081 
01082 }
01083 
01084 TEST (PCL, Octree_Pointcloud_Voxel_Centroid_Test)
01085 {
01086 
01087   
01088 
01089   PointCloud<PointXYZ>::Ptr cloudIn (new PointCloud<PointXYZ> ());
01090 
01091   OctreePointCloudVoxelCentroid<PointXYZ> octree (1.0f);
01092   octree.defineBoundingBox (10.0, 10.0, 10.0);
01093 
01094   size_t i;
01095 
01096   srand (static_cast<unsigned int> (time (NULL)));
01097 
01098   cloudIn->width = 10 * 3;
01099   cloudIn->height = 1;
01100   cloudIn->points.resize (cloudIn->width * cloudIn->height);
01101 
01102   
01103   for (i = 0; i < 10; i++)
01104   {
01105     
01106     cloudIn->points[i * 3 + 0] = PointXYZ (static_cast<float> (i) + 0.2f, static_cast<float> (i) + 0.2f, static_cast<float> (i) + 0.2f);
01107     cloudIn->points[i * 3 + 1] = PointXYZ (static_cast<float> (i) + 0.4f, static_cast<float> (i) + 0.4f, static_cast<float> (i) + 0.4f);
01108     cloudIn->points[i * 3 + 2] = PointXYZ (static_cast<float> (i) + 0.6f, static_cast<float> (i) + 0.6f, static_cast<float> (i) + 0.6f);
01109   }
01110 
01111   
01112   octree.setInputCloud (cloudIn);
01113 
01114   
01115   octree.addPointsFromInputCloud ();
01116 
01117   pcl::PointCloud<PointXYZ>::VectorType voxelCentroids;
01118   octree.getVoxelCentroids (voxelCentroids);
01119 
01120   
01121   ASSERT_EQ (voxelCentroids.size(), static_cast<std::size_t> (10));
01122 
01123   
01124   for (i = 0; i < 10; i++)
01125   {
01126     EXPECT_NEAR(voxelCentroids[i].x, static_cast<float> (i)+0.4, 1e-4);
01127     EXPECT_NEAR(voxelCentroids[i].y, static_cast<float> (i)+0.4, 1e-4);
01128     EXPECT_NEAR(voxelCentroids[i].z, static_cast<float> (i)+0.4, 1e-4);
01129   }
01130 
01131   
01132 
01133   
01134   for (i = 0; i < 10; i++)
01135   {
01136     
01137     cloudIn->points[i * 3 + 0] = PointXYZ (static_cast<float> (i) + 0.1f, static_cast<float> (i) + 0.1f, static_cast<float> (i) + 0.1f);
01138     cloudIn->points[i * 3 + 1] = PointXYZ (static_cast<float> (i) + 0.4f, static_cast<float> (i) + 0.4f, static_cast<float> (i) + 0.4f);
01139     cloudIn->points[i * 3 + 2] = PointXYZ (static_cast<float> (i) + 0.7f, static_cast<float> (i) + 0.7f, static_cast<float> (i) + 0.7f);
01140   }
01141 
01142   
01143   octree.setInputCloud (cloudIn);
01144   octree.addPointsFromInputCloud ();
01145 
01146   voxelCentroids.clear();
01147   octree.getVoxelCentroids (voxelCentroids);
01148 
01149   
01150   for (i = 0; i < 10; i++)
01151   {
01152     EXPECT_NEAR(voxelCentroids[i].x, static_cast<float> (i)+0.4, 1e-4);
01153     EXPECT_NEAR(voxelCentroids[i].y, static_cast<float> (i)+0.4, 1e-4);
01154     EXPECT_NEAR(voxelCentroids[i].z, static_cast<float> (i)+0.4, 1e-4);
01155   }
01156 
01157 }
01158 
01159 
01160 class prioPointQueueEntry
01161 {
01162 public:
01163   prioPointQueueEntry () : point_ (), pointDistance_ (), pointIdx_ ()
01164   {
01165   }
01166   prioPointQueueEntry (PointXYZ& point_arg, double pointDistance_arg, int pointIdx_arg) :
01167     point_ (point_arg),
01168     pointDistance_ (pointDistance_arg),
01169     pointIdx_ (pointIdx_arg)
01170   {
01171   }
01172 
01173   bool
01174   operator< (const prioPointQueueEntry& rhs_arg) const
01175   {
01176     return (this->pointDistance_ < rhs_arg.pointDistance_);
01177   }
01178 
01179   PointXYZ point_;
01180   double pointDistance_;
01181   int pointIdx_;
01182 
01183 };
01184 
01185 TEST (PCL, Octree_Pointcloud_Nearest_K_Neighbour_Search)
01186 {
01187 
01188   const unsigned int test_runs = 10;
01189   unsigned int test_id;
01190 
01191   
01192   PointCloud<PointXYZ>::Ptr cloudIn (new PointCloud<PointXYZ> ());
01193 
01194   size_t i;
01195 
01196   srand (static_cast<unsigned int> (time (NULL)));
01197 
01198   unsigned int K;
01199 
01200   std::priority_queue<prioPointQueueEntry, pcl::PointCloud<prioPointQueueEntry>::VectorType> pointCandidates;
01201 
01202   
01203   OctreePointCloudSearch<PointXYZ> octree (0.1);
01204   octree.setInputCloud (cloudIn);
01205 
01206   std::vector<int> k_indices;
01207   std::vector<float> k_sqr_distances;
01208 
01209   std::vector<int> k_indices_bruteforce;
01210   std::vector<float> k_sqr_distances_bruteforce;
01211 
01212   for (test_id = 0; test_id < test_runs; test_id++)
01213   {
01214     
01215 
01216     PointXYZ searchPoint (static_cast<float> (10.0 * rand () / RAND_MAX), 
01217                           static_cast<float> (10.0 * rand () / RAND_MAX),
01218                           static_cast<float> (10.0 * rand () / RAND_MAX));
01219 
01220     K = 1 + rand () % 10;
01221 
01222     
01223     cloudIn->width = 1000;
01224     cloudIn->height = 1;
01225     cloudIn->points.resize (cloudIn->width * cloudIn->height);
01226     for (i = 0; i < 1000; i++)
01227     {
01228       cloudIn->points[i] = PointXYZ (static_cast<float> (5.0  * rand () / RAND_MAX),
01229                                      static_cast<float> (10.0 * rand () / RAND_MAX),
01230                                      static_cast<float> (10.0 * rand () / RAND_MAX));
01231     }
01232 
01233     double pointDist;
01234 
01235     k_indices.clear ();
01236     k_sqr_distances.clear ();
01237 
01238     k_indices_bruteforce.clear ();
01239     k_sqr_distances_bruteforce.clear ();
01240 
01241     
01242     for (i = 0; i < cloudIn->points.size (); i++)
01243     {
01244       pointDist = ((cloudIn->points[i].x - searchPoint.x) * (cloudIn->points[i].x - searchPoint.x)
01245           + (cloudIn->points[i].y - searchPoint.y) * (cloudIn->points[i].y - searchPoint.y)
01246           + (cloudIn->points[i].z - searchPoint.z) * (cloudIn->points[i].z - searchPoint.z));
01247 
01248       prioPointQueueEntry pointEntry (cloudIn->points[i], pointDist, static_cast<int> (i));
01249 
01250       pointCandidates.push (pointEntry);
01251     }
01252 
01253     
01254     while (pointCandidates.size () > K)
01255       pointCandidates.pop ();
01256 
01257     
01258     unsigned idx = static_cast<unsigned> (pointCandidates.size ());
01259     k_indices_bruteforce.resize (idx);
01260     k_sqr_distances_bruteforce.resize (idx);
01261     while (pointCandidates.size ())
01262     {
01263       --idx;
01264       k_indices_bruteforce [idx] = pointCandidates.top ().pointIdx_;
01265       k_sqr_distances_bruteforce [idx] = static_cast<float> (pointCandidates.top ().pointDistance_);
01266 
01267       pointCandidates.pop ();
01268     }
01269     
01270     
01271     octree.deleteTree ();
01272     octree.addPointsFromInputCloud ();
01273     octree.nearestKSearch (searchPoint, static_cast<int> (K), k_indices, k_sqr_distances);
01274 
01275     ASSERT_EQ( k_indices.size(), k_indices_bruteforce.size());
01276 
01277     
01278     i = 0;
01279     while (k_indices_bruteforce.size ())
01280     {
01281       ASSERT_EQ( k_indices.back(), k_indices_bruteforce.back());
01282       EXPECT_NEAR(k_sqr_distances.back(), k_sqr_distances_bruteforce.back(), 1e-4);
01283 
01284       k_indices_bruteforce.pop_back ();
01285       k_indices.pop_back ();
01286 
01287       k_sqr_distances_bruteforce.pop_back ();
01288       k_sqr_distances.pop_back ();
01289 
01290     }
01291 
01292   }
01293 
01294 }
01295 
01296 TEST (PCL, Octree_Pointcloud_Box_Search)
01297 {
01298 
01299   const unsigned int test_runs = 30;
01300   unsigned int test_id;
01301 
01302   
01303   PointCloud<PointXYZ>::Ptr cloudIn (new PointCloud<PointXYZ> ());
01304 
01305   size_t i;
01306 
01307   srand (static_cast<unsigned int> (time (NULL)));
01308 
01309   
01310   OctreePointCloudSearch<PointXYZ> octree (1);
01311   octree.setInputCloud (cloudIn);
01312 
01313   for (test_id = 0; test_id < test_runs; test_id++)
01314   {
01315     std::vector<int> k_indices;
01316 
01317     
01318     cloudIn->width = 300;
01319     cloudIn->height = 1;
01320     cloudIn->points.resize (cloudIn->width * cloudIn->height);
01321     for (i = 0; i < cloudIn->points.size(); i++)
01322     {
01323       cloudIn->points[i] = PointXYZ (static_cast<float> (10.0 * rand () / RAND_MAX),
01324                                      static_cast<float> (10.0 * rand () / RAND_MAX),
01325                                      static_cast<float> (10.0 * rand () / RAND_MAX));
01326     }
01327 
01328 
01329     
01330     octree.deleteTree ();
01331     octree.addPointsFromInputCloud ();
01332 
01333     
01334 
01335     Eigen::Vector3f lowerBoxCorner (static_cast<float> (4.0 * rand () / RAND_MAX),
01336                                     static_cast<float> (4.0 * rand () / RAND_MAX),
01337                                     static_cast<float> (4.0 * rand () / RAND_MAX));
01338     Eigen::Vector3f upperBoxCorner (static_cast<float> (5.0 + 4.0 * rand () / RAND_MAX),
01339                                     static_cast<float> (5.0 + 4.0 * rand () / RAND_MAX),
01340                                     static_cast<float> (5.0 + 4.0 * rand () / RAND_MAX));
01341 
01342     octree.boxSearch (lowerBoxCorner, upperBoxCorner, k_indices);
01343 
01344     
01345     for (i = 0; i < 300; i++)
01346     {
01347       std::size_t j;
01348       bool inBox;
01349       bool idxInResults;
01350       const PointXYZ& pt = cloudIn->points[i];
01351 
01352       inBox = (pt.x > lowerBoxCorner (0)) && (pt.x < upperBoxCorner (0)) &&
01353               (pt.y > lowerBoxCorner (1)) && (pt.y < upperBoxCorner (1)) &&
01354               (pt.z > lowerBoxCorner (2)) && (pt.z < upperBoxCorner (2));
01355 
01356       idxInResults = false;
01357       for (j = 0; (j < k_indices.size ()) && (!idxInResults); ++j)
01358       {
01359         if (i == static_cast<unsigned int> (k_indices[j]))
01360           idxInResults = true;
01361       }
01362 
01363       ASSERT_EQ(idxInResults, inBox);
01364 
01365     }
01366 
01367   }
01368 }
01369 
01370 TEST(PCL, Octree_Pointcloud_Approx_Nearest_Neighbour_Search)
01371 {
01372   const unsigned int test_runs = 100;
01373   unsigned int test_id;
01374 
01375   unsigned int bestMatchCount = 0;
01376 
01377   
01378   PointCloud<PointXYZ>::Ptr cloudIn (new PointCloud<PointXYZ> ());
01379 
01380   size_t i;
01381   srand (static_cast<unsigned int> (time (NULL)));
01382 
01383   double voxelResolution = 0.1;
01384 
01385   
01386   OctreePointCloudSearch<PointXYZ> octree (voxelResolution);
01387   octree.setInputCloud (cloudIn);
01388 
01389   for (test_id = 0; test_id < test_runs; test_id++)
01390   {
01391     
01392 
01393     PointXYZ searchPoint (static_cast<float> (10.0 * rand () / RAND_MAX), 
01394                           static_cast<float> (10.0 * rand () / RAND_MAX),
01395                           static_cast<float> (10.0 * rand () / RAND_MAX));
01396 
01397     
01398     cloudIn->width = 1000;
01399     cloudIn->height = 1;
01400     cloudIn->points.resize (cloudIn->width * cloudIn->height);
01401     for (i = 0; i < 1000; i++)
01402     {
01403       cloudIn->points[i] = PointXYZ (static_cast<float> (5.0  * rand () / RAND_MAX),
01404                                      static_cast<float> (10.0 * rand () / RAND_MAX),
01405                                      static_cast<float> (10.0 * rand () / RAND_MAX));
01406     }
01407 
01408     
01409     double pointDist;
01410     double BFdistance = numeric_limits<double>::max ();
01411     int BFindex = 0;
01412 
01413     for (i = 0; i < cloudIn->points.size (); i++)
01414     {
01415       pointDist = ((cloudIn->points[i].x - searchPoint.x) * (cloudIn->points[i].x - searchPoint.x)
01416           + (cloudIn->points[i].y - searchPoint.y) * (cloudIn->points[i].y - searchPoint.y)
01417           + (cloudIn->points[i].z - searchPoint.z) * (cloudIn->points[i].z - searchPoint.z));
01418 
01419       if (pointDist < BFdistance)
01420       {
01421         BFindex = static_cast<int> (i);
01422         BFdistance = pointDist;
01423       }
01424 
01425     }
01426 
01427     int ANNindex;
01428     float ANNdistance;
01429 
01430     
01431     octree.deleteTree ();
01432     octree.addPointsFromInputCloud ();
01433     octree.approxNearestSearch (searchPoint, ANNindex, ANNdistance);
01434 
01435     if (BFindex == ANNindex)
01436     {
01437       EXPECT_NEAR(ANNdistance, BFdistance, 1e-4);
01438       bestMatchCount++;
01439     }
01440 
01441   }
01442 
01443   
01444   ASSERT_EQ( (bestMatchCount > 0), true);
01445 
01446 }
01447 
01448 TEST (PCL, Octree_Pointcloud_Neighbours_Within_Radius_Search)
01449 {
01450 
01451   const unsigned int test_runs = 100;
01452   unsigned int test_id;
01453 
01454   
01455   PointCloud<PointXYZ>::Ptr cloudIn (new PointCloud<PointXYZ> ());
01456   PointCloud<PointXYZ>::Ptr cloudOut (new PointCloud<PointXYZ> ());
01457 
01458   size_t i;
01459 
01460   srand (static_cast<unsigned int> (time (NULL)));
01461 
01462   for (test_id = 0; test_id < test_runs; test_id++)
01463   {
01464     
01465     PointXYZ searchPoint (static_cast<float> (10.0 * rand () / RAND_MAX), 
01466                           static_cast<float> (10.0 * rand () / RAND_MAX),
01467                           static_cast<float> (10.0 * rand () / RAND_MAX));
01468 
01469     cloudIn->width = 1000;
01470     cloudIn->height = 1;
01471     cloudIn->points.resize (cloudIn->width * cloudIn->height);
01472 
01473     
01474     for (i = 0; i < 1000; i++)
01475     {
01476       cloudIn->points[i] = PointXYZ (static_cast<float> (10.0 * rand () / RAND_MAX),
01477                                      static_cast<float> (10.0 * rand () / RAND_MAX),
01478                                      static_cast<float> (5.0  * rand () / RAND_MAX));
01479     }
01480 
01481     OctreePointCloudSearch<PointXYZ> octree (0.001);
01482 
01483     
01484     octree.setInputCloud (cloudIn);
01485     octree.addPointsFromInputCloud ();
01486 
01487     double pointDist;
01488     double searchRadius = 5.0 * static_cast<float> (rand () / RAND_MAX);
01489 
01490     
01491     vector<int> cloudSearchBruteforce;
01492     for (i = 0; i < cloudIn->points.size (); i++)
01493     {
01494       pointDist = sqrt (
01495           (cloudIn->points[i].x - searchPoint.x) * (cloudIn->points[i].x - searchPoint.x)
01496               + (cloudIn->points[i].y - searchPoint.y) * (cloudIn->points[i].y - searchPoint.y)
01497               + (cloudIn->points[i].z - searchPoint.z) * (cloudIn->points[i].z - searchPoint.z));
01498 
01499       if (pointDist <= searchRadius)
01500       {
01501         
01502         cloudSearchBruteforce.push_back (static_cast<int> (i));
01503       }
01504     }
01505 
01506     vector<int> cloudNWRSearch;
01507     vector<float> cloudNWRRadius;
01508 
01509     
01510     octree.radiusSearch (searchPoint, searchRadius, cloudNWRSearch, cloudNWRRadius);
01511 
01512     ASSERT_EQ( cloudNWRRadius.size(), cloudSearchBruteforce.size());
01513 
01514     
01515     std::vector<int>::const_iterator current = cloudNWRSearch.begin ();
01516     while (current != cloudNWRSearch.end ())
01517     {
01518       pointDist = sqrt (
01519           (cloudIn->points[*current].x - searchPoint.x) * (cloudIn->points[*current].x - searchPoint.x)
01520               + (cloudIn->points[*current].y - searchPoint.y) * (cloudIn->points[*current].y - searchPoint.y)
01521               + (cloudIn->points[*current].z - searchPoint.z) * (cloudIn->points[*current].z - searchPoint.z));
01522 
01523       ASSERT_EQ( (pointDist<=searchRadius), true);
01524 
01525       ++current;
01526     }
01527 
01528     
01529     octree.radiusSearch (searchPoint, searchRadius, cloudNWRSearch, cloudNWRRadius, 5);
01530 
01531     ASSERT_EQ( cloudNWRRadius.size() <= 5, true);
01532 
01533   }
01534 
01535 }
01536 
01537 TEST (PCL, Octree_Pointcloud_Ray_Traversal)
01538 {
01539 
01540   const unsigned int test_runs = 100;
01541   unsigned int test_id;
01542 
01543   
01544   PointCloud<PointXYZ>::Ptr cloudIn (new PointCloud<PointXYZ> ());
01545 
01546   octree::OctreePointCloudSearch<PointXYZ> octree_search (0.02f);
01547 
01548   
01549   pcl::PointCloud<pcl::PointXYZ>::VectorType voxelsInRay, voxelsInRay2;
01550 
01551   
01552   std::vector<int> indicesInRay, indicesInRay2;
01553 
01554   srand (static_cast<unsigned int> (time (NULL)));
01555 
01556   for (test_id = 0; test_id < test_runs; test_id++)
01557   {
01558     
01559     octree_search.deleteTree ();
01560     
01561     octree_search.defineBoundingBox (0.0, 0.0, 0.0, 10.0, 10.0, 10.0);
01562 
01563     cloudIn->width = 4;
01564     cloudIn->height = 1;
01565     cloudIn->points.resize (cloudIn->width * cloudIn->height);
01566 
01567     Eigen::Vector3f p (static_cast<float> (10.0 * rand () / RAND_MAX), 
01568                        static_cast<float> (10.0 * rand () / RAND_MAX),
01569                        static_cast<float> (10.0 * rand () / RAND_MAX));
01570 
01571     
01572     Eigen::Vector3f o (static_cast<float> (12.0 * rand () / RAND_MAX), 
01573                        static_cast<float> (12.0 * rand () / RAND_MAX),
01574                        static_cast<float> (12.0 * rand () / RAND_MAX));
01575 
01576     cloudIn->points[0] = pcl::PointXYZ (p[0], p[1], p[2]);
01577 
01578     
01579     Eigen::Vector3f dir (p - o);
01580 
01581     float tmin = 1.0;
01582     for (unsigned int j = 1; j < 4; j++)
01583     {
01584       tmin = tmin - 0.25f;
01585       Eigen::Vector3f n_p = o + (tmin * dir);
01586       cloudIn->points[j] = pcl::PointXYZ (n_p[0], n_p[1], n_p[2]);
01587     }
01588 
01589     
01590     octree_search.setInputCloud (cloudIn);
01591     octree_search.addPointsFromInputCloud ();
01592 
01593     octree_search.getIntersectedVoxelCenters (o, dir, voxelsInRay);
01594     octree_search.getIntersectedVoxelIndices (o, dir, indicesInRay);
01595 
01596     
01597     ASSERT_EQ( voxelsInRay.size (), cloudIn->points.size ());
01598     
01599     ASSERT_EQ( indicesInRay.size (), cloudIn->points.size ());
01600 
01601     octree_search.getIntersectedVoxelCenters (o, dir, voxelsInRay2, 1);
01602     octree_search.getIntersectedVoxelIndices (o, dir, indicesInRay2, 1);
01603 
01604     
01605     ASSERT_EQ( voxelsInRay2.size (), 1u );
01606     ASSERT_EQ( indicesInRay2.size (), 1u );
01607 
01608     
01609     pcl::PointXYZ pt = cloudIn->points[ indicesInRay2[0] ];
01610     Eigen::Vector3f d = Eigen::Vector3f (pt.x, pt.y, pt.z) - o;
01611     float min_dist = d.norm ();
01612 
01613     for (unsigned int i = 0; i < cloudIn->width * cloudIn->height; i++) {
01614         pt = cloudIn->points[i];
01615         d = Eigen::Vector3f (pt.x, pt.y, pt.z) - o;
01616         ASSERT_GE( d.norm (), min_dist );
01617     }
01618 
01619   }
01620 
01621 }
01622 
01623 TEST (PCL, Octree_Pointcloud_Adjacency)
01624 {
01625 
01626   const unsigned int test_runs = 100;
01627   unsigned int test_id;
01628 
01629   
01630 
01631 
01632   srand (static_cast<unsigned int> (time (NULL)));
01633 
01634   for (test_id = 0; test_id < test_runs; test_id++)
01635   {
01636     
01637     PointCloud<PointXYZ>::Ptr cloudIn (new PointCloud<PointXYZ> ());
01638     
01639     float resolution = static_cast<float> (0.01 * rand () / RAND_MAX) + 0.00001f;
01640     
01641     PointXYZ point (static_cast<float> (0.5 * rand () / RAND_MAX), 
01642                     static_cast<float> (0.5 * rand () / RAND_MAX),
01643                     static_cast<float> (0.5 * rand () / RAND_MAX));
01644     
01645     PointXYZ p1 (10,10,10);
01646     PointXYZ p2 (-10,-10,-10);
01647     cloudIn->push_back(p1);
01648     cloudIn->push_back(p2);
01649     cloudIn->push_back (point);
01650 
01651     
01652     for (int dx = -1; dx <= 1; ++dx)
01653     {
01654       for (int dy = -1; dy <= 1; ++dy)
01655       {
01656         for (int dz = -1; dz <= 1; ++dz)
01657         {
01658           float factor = 1.0f;
01659           PointXYZ neighbor (point.x+dx*resolution*factor, point.y+dy*resolution*factor, point.z+dz*resolution*factor); 
01660           cloudIn->push_back (neighbor);
01661         }
01662       }
01663     }
01664     
01665     
01666     PointXYZ point2 (static_cast<float> (point.x + 10*resolution), 
01667                      static_cast<float> (point.y + 10*resolution),
01668                      static_cast<float> (point.z + 10*resolution));
01669     cloudIn->push_back (point2);
01670     
01671     for (int i = 0; i < 100; ++i)
01672     {
01673       PointXYZ not_neighbor_point (static_cast<float> (10.0 * rand () / RAND_MAX), 
01674                      static_cast<float> (10.0 * rand () / RAND_MAX),
01675                      static_cast<float> (10.0 * rand () / RAND_MAX));
01676       if ( (point2.getVector3fMap () - not_neighbor_point.getVector3fMap ()).norm () > 3*resolution )
01677       {
01678         cloudIn->push_back(not_neighbor_point);
01679       }
01680     }
01681     
01682       
01683 
01684     OctreePointCloudAdjacency<PointXYZ> octree (resolution);
01685     octree.setInputCloud (cloudIn);
01686     octree.addPointsFromInputCloud ();
01687       
01688     OctreePointCloudAdjacencyContainer<PointXYZ> *leaf_container;
01689     
01690     leaf_container = octree.getLeafContainerAtPoint (point);
01691     
01692     ASSERT_EQ( leaf_container->size() == 27, true);
01693 
01694     leaf_container = octree.getLeafContainerAtPoint (point2);
01695   
01696     
01697     ASSERT_EQ( leaf_container->size() == 1, true);
01698 
01699   }
01700 
01701 }
01702 
01703 int
01704 main (int argc, char** argv)
01705 {
01706   testing::InitGoogleTest (&argc, argv);
01707   return (RUN_ALL_TESTS ());
01708 }
01709