test_octree.cpp
Go to the documentation of this file.
00001 /*
00002  * Software License Agreement (BSD License)
00003  *
00004  *  Copyright (c) 2010, Willow Garage, Inc.
00005  *  All rights reserved.
00006  *
00007  *  Redistribution and use in source and binary forms, with or without
00008  *  modification, are permitted provided that the following conditions
00009  *  are met:
00010  *
00011  *   * Redistributions of source code must retain the above copyright
00012  *     notice, this list of conditions and the following disclaimer.
00013  *   * Redistributions in binary form must reproduce the above
00014  *     copyright notice, this list of conditions and the following
00015  *     disclaimer in the documentation and/or other materials provided
00016  *     with the distribution.
00017  *   * Neither the name of the copyright holder(s) nor the names of its
00018  *     contributors may be used to endorse or promote products derived
00019  *     from this software without specific prior written permission.
00020  *
00021  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00022  *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00023  *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00024  *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
00025  *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00026  *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00027  *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00028  *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
00029  *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00030  *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
00031  *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00032  *  POSSIBILITY OF SUCH DAMAGE.
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   // create octree instance
00063   OctreeBase<int> octreeA;
00064   OctreeBase<int> octreeB;
00065 
00066   // set octree depth
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   // generate some voxel indices
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     // add data to leaf node voxel
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     // retrieve data from leaf node voxel
00097     int* voxel_container = octreeA.createLeaf(voxels[i].x, voxels[i].y, voxels[i].z);
00098     // check if retrieved data is identical to data[]
00099     ASSERT_EQ(*voxel_container, data[i]);
00100   }
00101 
00102   for (i = 128; i < 256; i++)
00103   {
00104     // check if leaf node exists in tree
00105     ASSERT_EQ( octreeA.existLeaf(voxels[i].x,voxels[i].y,voxels[i].z), true);
00106 
00107     // remove leaf node
00108     octreeA.removeLeaf (voxels[i].x, voxels[i].y, voxels[i].z);
00109 
00110     //  leaf node shouldn't exist in tree anymore
00111     ASSERT_EQ( octreeA.existLeaf(voxels[i].x,voxels[i].y,voxels[i].z), false);
00112   }
00113 
00114   // test serialization
00115 
00116   std::vector<char> treeBinaryA;
00117   std::vector<char> treeBinaryB;
00118 
00119   std::vector<int*> leafVectorA;
00120   std::vector<int*> leafVectorB;
00121 
00122   // serialize tree - generate binary octree description
00123   octreeA.serializeTree (treeBinaryA);
00124 
00125   // deserialize tree - rebuild octree based on binary octree description
00126   octreeB.deserializeTree (treeBinaryA);
00127 
00128   for (i = 0; i < 128; i++)
00129   {
00130     // check if leafs exist in both octrees
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     // these leafs were not copies and should not exist
00138     ASSERT_EQ( octreeB.existLeaf(voxels[i].x,voxels[i].y,voxels[i].z), false);
00139   }
00140 
00141   // testing deleteTree();
00142   octreeB.deleteTree ();
00143 
00144   // octreeB.getLeafCount() should be zero now;
00145   ASSERT_EQ (0u, octreeB.getLeafCount());
00146 
00147   // .. and previous leafs deleted..
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   // test tree serialization
00154   octreeA.serializeTree (treeBinaryA, leafVectorA);
00155 
00156   // make sure, we retrieved all data objects
00157   ASSERT_EQ(leafVectorA.size(), octreeA.getLeafCount());
00158 
00159   // check if leaf data is found in octree input data
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   // test tree serialization
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   // test tree serialization with leaf data vectors
00197   octreeA.serializeTree (treeBinaryA, leafVectorA);
00198   octreeB.deserializeTree (treeBinaryA, leafVectorA);
00199 
00200   // test size and leaf count of reconstructed octree
00201   ASSERT_EQ(octreeA.getLeafCount(), octreeB.getLeafCount());
00202   ASSERT_EQ(128u, octreeB.getLeafCount());
00203 
00204   octreeB.serializeTree (treeBinaryB, leafVectorB);
00205 
00206   // compare octree data content of octree A and octree B
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   //  test iterator
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   // iterate over tree
00225   for (a_it=octreeA.begin(); a_it!=a_it_end; ++a_it)
00226   {
00227     // depth should always be less than tree depth
00228     unsigned int depth = a_it.getCurrentOctreeDepth ();
00229     ASSERT_LE(depth, octreeA.getTreeDepth());
00230 
00231     // store node, branch and leaf count
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   // compare node, branch and leaf count against actual tree values
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   // create shared pointcloud instances
00266   PointCloud<PointXYZ>::Ptr cloud (new PointCloud<PointXYZ> ());
00267 
00268   // assign input point clouds to octree
00269   octree.setInputCloud (cloud);
00270 
00271   for (test = 0; test < test_runs; ++test)
00272   {
00273     // clean up
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       // gereate a random point
00283       PointXYZ newPoint (1.0, 2.0, 3.0);
00284 
00285       // OctreePointCloudPointVector can store all points..
00286       cloud->push_back (newPoint);
00287     }
00288 
00289     // check if all points from leaf data can be found in input pointcloud data sets
00290     octree.defineBoundingBox ();
00291     octree.enableDynamicDepth (leafAggSize);
00292     octree.addPointsFromInputCloud ();
00293 
00294     unsigned int leaf_node_counter = 0;
00295     // iterate over tree
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     // clean up
00306     cloud->points.clear ();
00307     octree.deleteTree ();
00308 
00309     for (point = 0; point < pointcount; point++)
00310     {
00311       // gereate a random point
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       // OctreePointCloudPointVector can store all points..
00317       cloud->push_back (newPoint);
00318     }
00319 
00320 
00321     // check if all points from leaf data can be found in input pointcloud data sets
00322     octree.defineBoundingBox ();
00323     octree.enableDynamicDepth (leafAggSize);
00324     octree.addPointsFromInputCloud ();
00325 
00326     //  test iterator
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     // iterate over tree
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       // add points from leaf node to indexVector
00346       container.getPointIndices (indexVector);
00347 
00348       // test points against bounding box of leaf node
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     // make sure all indices are within indexVector
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     // compare node, branch and leaf count against actual tree values
00380     ASSERT_EQ(leaf_count, octree.getLeafCount ());
00381 
00382   }
00383 }
00384 
00385 TEST (PCL, Octree2Buf_Test)
00386 {
00387 
00388   // create octree instances
00389   Octree2BufBase<int> octreeA;
00390   Octree2BufBase<int> octreeB;
00391 
00392   // set octree depth
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   // generate some voxel indices
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     // add data to leaf node voxel
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     // retrieve and check data from leaf voxel
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     // check if leaf node exists in tree
00436     ASSERT_EQ( octreeA.existLeaf(voxels[i].x,voxels[i].y,voxels[i].z), true);
00437 
00438     // remove leaf node
00439     octreeA.removeLeaf (voxels[i].x, voxels[i].y, voxels[i].z);
00440 
00441     //  leaf node shouldn't exist in tree anymore
00442     ASSERT_EQ( octreeA.existLeaf(voxels[i].x,voxels[i].y,voxels[i].z), false);
00443   }
00444 
00446 
00447   // test serialization
00448 
00449   std::vector<char> treeBinaryA;
00450   std::vector<char> treeBinaryB;
00451 
00452   std::vector<int*> leafVectorA;
00453   std::vector<int*> leafVectorB;
00454 
00455   // serialize tree - generate binary octree description
00456   octreeA.serializeTree (treeBinaryA);
00457 
00458   // deserialize tree - rebuild octree based on binary octree description
00459   octreeB.deserializeTree (treeBinaryA);
00460 
00461   // check if leafs exist in octrees
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   // these leafs should not exist..
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   // checking deleteTree();
00474   octreeB.deleteTree ();
00475   octreeB.setTreeDepth (8);
00476 
00477   // octreeB.getLeafCount() should be zero now;
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   // test tree serialization
00486   octreeA.serializeTree (treeBinaryA, leafVectorA);
00487 
00488   // make sure, we retrieved all data objects
00489   ASSERT_EQ(leafVectorA.size(), octreeA.getLeafCount());
00490 
00491   // check if leaf data is found in octree input data
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   // test tree serialization
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   // test tree serialization with leaf data vectors
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   // test size and leaf count of reconstructed octree
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   // create octree instances
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       // switch buffers
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         // add data to octree
00605 
00606         int* container = octreeA.createLeaf(voxels[i].x, voxels[i].y, voxels[i].z);
00607         *container = data[i];
00608 
00609       }
00610 
00611       // test serialization
00612       octreeA.serializeTree (treeBinaryA, leafVectorA, true);
00613       octreeB.deserializeTree (treeBinaryA, leafVectorA, true);
00614     }
00615 
00616     octreeB.serializeTree (treeBinaryB, leafVectorB, true);
00617 
00618     // check leaf count of rebuilt octree
00619     ASSERT_EQ(octreeA.getLeafCount(), octreeB.getLeafCount());
00620     ASSERT_EQ(leafVectorB.size(), octreeB.getLeafCount());
00621     ASSERT_EQ(leafVectorA.size(), leafVectorB.size());
00622 
00623     // check if octree octree structure is consistent.
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   // create octree instances
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       // add data to octree
00677 
00678       int* container = octreeA.createLeaf(voxels[i].x, voxels[i].y, voxels[i].z);
00679       *container = data[i];
00680     }
00681 
00682     // test serialization - XOR tree binary data
00683     octreeA.serializeTree (treeBinaryA, leafVectorA, true);
00684     octreeB.deserializeTree (treeBinaryA, leafVectorA, true);
00685     octreeB.serializeTree (treeBinaryB, leafVectorB, true);
00686 
00687     // check leaf count of rebuilt octree
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     // check if octree octree structure is consistent.
00695     for (i = 0; i < leafVectorB.size (); i++)
00696     {
00697       ASSERT_EQ( (*leafVectorA[i] == *leafVectorB[i]), true);
00698     }
00699 
00700     // switch buffers
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   // instantiate OctreePointCloudSinglePoint and OctreePointCloudPointVector classes
00720   OctreePointCloudSinglePoint<PointXYZ> octreeA (resolution);
00721   OctreePointCloudSearch<PointXYZ> octreeB (resolution);
00722   OctreePointCloudPointVector<PointXYZ> octreeC (resolution);
00723 
00724   // create shared pointcloud instances
00725   PointCloud<PointXYZ>::Ptr cloudA (new PointCloud<PointXYZ> ());
00726   PointCloud<PointXYZ>::Ptr cloudB (new PointCloud<PointXYZ> ());
00727 
00728   // assign input point clouds to octree
00729   octreeA.setInputCloud (cloudA);
00730   octreeB.setInputCloud (cloudB);
00731   octreeC.setInputCloud (cloudB);
00732 
00733   for (test = 0; test < test_runs; ++test)
00734   {
00735 
00736     // clean up
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       // gereate a random point
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         // add point only to OctreePointCloudSinglePoint if voxel at point location doesn't exist
00755         octreeA.addPointToCloud (newPoint, cloudA);
00756       }
00757 
00758       // OctreePointCloudPointVector can store all points..
00759       cloudB->push_back (newPoint);
00760     }
00761 
00762     ASSERT_EQ(octreeA.getLeafCount(), cloudA->points.size());
00763 
00764     // checks for getVoxelDataAtPoint() and isVoxelOccupiedAtPoint() functionality
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     // check if all points from leaf data can be found in input pointcloud data sets
00775     octreeB.defineBoundingBox ();
00776     octreeB.addPointsFromInputCloud ();
00777 
00778     //  test iterator
00779     OctreePointCloudPointVector<PointXYZ>::Iterator b_it;
00780     OctreePointCloudPointVector<PointXYZ>::Iterator b_it_end = octreeB.end();
00781 
00782     // iterate over tree
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     // iterate over tree
00792     for (b_it = octreeB.begin(); b_it != b_it_end; ++b_it)
00793     {
00794       // depth should always be less than tree depth
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       // store node, branch and leaf count
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     // compare node, branch and leaf count against actual tree values
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   // instantiate point cloud and fill it with point data
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); // low resolution
00868   OctreePointCloudDensity<PointXYZ> octreeB (0.00001f); // high resolution
00869 
00870   octreeA.defineBoundingBox (7.0, 7.0, 7.0);
00871   octreeB.defineBoundingBox (7.0, 7.0, 7.0);
00872 
00873   // add point data to octree
00874   octreeA.setInputCloud (cloudIn);
00875   octreeB.setInputCloud (cloudIn);
00876 
00877   octreeA.addPointsFromInputCloud ();
00878   octreeB.addPointsFromInputCloud ();
00879 
00880   // check density information
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   // instantiate point cloud and fill it with point data
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); // low resolution
00907 
00908   // add point data to octree
00909   octreeA.setInputCloud (cloudIn);
00910   octreeA.addPointsFromInputCloud ();
00911 
00912   // instantiate iterator for octreeA
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   // breadth-first iterator test
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     // tree depth of visited nodes must grow
00953     ASSERT_EQ( bfIt.getCurrentOctreeDepth()>=lastDepth, true);
00954     lastDepth = bfIt.getCurrentOctreeDepth ();
00955 
00956     if (bfIt.isBranchNode ())
00957     {
00958       branchNodeCount++;
00959       // leaf nodes are traversed in the end
00960       ASSERT_EQ( leafNodeVisited, false);
00961     }
00962 
00963     if (bfIt.isLeafNode ())
00964     {
00965       leafNodeCount++;
00966       leafNodeVisited = true;
00967     }
00968   }
00969 
00970   // check if every branch node and every leaf node has been visited
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   // instantiate point cloud
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     // generate point data for point cloud
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     // create octree
01007     octree.setInputCloud (cloudIn);
01008     octree.addPointsFromInputCloud ();
01009 
01010     // check occupancy of voxels
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   // instantiate point cloud
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   // generate point data for point cloud
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   // assign point cloud to octree
01047   octree.setInputCloud (cloudIn);
01048 
01049   // add points from cloud to octree
01050   octree.addPointsFromInputCloud ();
01051 
01052   // switch buffers - reset tree
01053   octree.switchBuffers ();
01054 
01055   // add points from cloud to new octree buffer
01056   octree.addPointsFromInputCloud ();
01057 
01058   // add 1000 additional points
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   // get a vector of new points, which did not exist in previous buffer
01071   octree.getPointIndicesFromNewVoxels (newPointIdxVector);
01072 
01073   // should be 1000
01074   ASSERT_EQ( newPointIdxVector.size(), static_cast<std::size_t> (1000));
01075 
01076   // all point indices found should have an index of >= 1000
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   // instantiate point cloud
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   // generate point data for point cloud
01103   for (i = 0; i < 10; i++)
01104   {
01105     // these three points should always be assigned to the same voxel in the octree
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   // assign point cloud to octree
01112   octree.setInputCloud (cloudIn);
01113 
01114   // add points from cloud to octree
01115   octree.addPointsFromInputCloud ();
01116 
01117   pcl::PointCloud<PointXYZ>::VectorType voxelCentroids;
01118   octree.getVoxelCentroids (voxelCentroids);
01119 
01120   // we expect 10 voxel centroids
01121   ASSERT_EQ (voxelCentroids.size(), static_cast<std::size_t> (10));
01122 
01123   // check centroid calculation
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   // ADDING AN ADDITIONAL POINT CLOUD TO OctreePointCloudVoxelCentroid
01132 
01133   // generate new point data
01134   for (i = 0; i < 10; i++)
01135   {
01136     // these three points should always be assigned to the same voxel in the octree
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   // add points from new cloud to octree
01143   octree.setInputCloud (cloudIn);
01144   octree.addPointsFromInputCloud ();
01145 
01146   voxelCentroids.clear();
01147   octree.getVoxelCentroids (voxelCentroids);
01148 
01149   // check centroid calculation
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 // helper class for priority queue
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   // instantiate point cloud
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   // create octree
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     // define a random search point
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     // generate point cloud
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     // push all points and their distance to the search point into a priority queue - bruteforce approach.
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     // pop priority queue until we have the nearest K elements
01254     while (pointCandidates.size () > K)
01255       pointCandidates.pop ();
01256 
01257     // copy results into vectors
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     // octree nearest neighbor search
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     // compare nearest neighbor results of octree with bruteforce search
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   // instantiate point cloud
01303   PointCloud<PointXYZ>::Ptr cloudIn (new PointCloud<PointXYZ> ());
01304 
01305   size_t i;
01306 
01307   srand (static_cast<unsigned int> (time (NULL)));
01308 
01309   // create octree
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     // generate point cloud
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     // octree points to octree
01330     octree.deleteTree ();
01331     octree.addPointsFromInputCloud ();
01332 
01333     // define a random search area
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     // test every point in point cloud
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   // instantiate point cloud
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   // create octree
01386   OctreePointCloudSearch<PointXYZ> octree (voxelResolution);
01387   octree.setInputCloud (cloudIn);
01388 
01389   for (test_id = 0; test_id < test_runs; test_id++)
01390   {
01391     // define a random search point
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     // generate point cloud
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     // brute force search
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     // octree approx. nearest neighbor search
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   // we should have found the absolute nearest neighbor at least once
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   // instantiate point clouds
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     // define a random search point
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     // generate point cloud data
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     // build octree
01484     octree.setInputCloud (cloudIn);
01485     octree.addPointsFromInputCloud ();
01486 
01487     double pointDist;
01488     double searchRadius = 5.0 * static_cast<float> (rand () / RAND_MAX);
01489 
01490     // bruteforce radius search
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         // add point candidates to vector list
01502         cloudSearchBruteforce.push_back (static_cast<int> (i));
01503       }
01504     }
01505 
01506     vector<int> cloudNWRSearch;
01507     vector<float> cloudNWRRadius;
01508 
01509     // execute octree radius search
01510     octree.radiusSearch (searchPoint, searchRadius, cloudNWRSearch, cloudNWRRadius);
01511 
01512     ASSERT_EQ( cloudNWRRadius.size(), cloudSearchBruteforce.size());
01513 
01514     // check if result from octree radius search can be also found in bruteforce search
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     // check if result limitation works
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   // instantiate point clouds
01544   PointCloud<PointXYZ>::Ptr cloudIn (new PointCloud<PointXYZ> ());
01545 
01546   octree::OctreePointCloudSearch<PointXYZ> octree_search (0.02f);
01547 
01548   // Voxels in ray
01549   pcl::PointCloud<pcl::PointXYZ>::VectorType voxelsInRay, voxelsInRay2;
01550 
01551   // Indices in ray
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     // delete octree
01559     octree_search.deleteTree ();
01560     // define octree bounding box 10x10x10
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     // origin
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     // direction vector
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     // insert cloud point into octree
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     // check if all voxels in the cloud are penetraded by the ray
01597     ASSERT_EQ( voxelsInRay.size (), cloudIn->points.size ());
01598     // check if all indices of penetrated voxels are in cloud
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     // check if only the point from a single voxel has been returned
01605     ASSERT_EQ( voxelsInRay2.size (), 1u );
01606     ASSERT_EQ( indicesInRay2.size (), 1u );
01607 
01608     // check if this point is the closest point to the origin
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     // instantiate point cloud
01637     PointCloud<PointXYZ>::Ptr cloudIn (new PointCloud<PointXYZ> ());
01638     
01639     float resolution = static_cast<float> (0.01 * rand () / RAND_MAX) + 0.00001f;
01640     //Define a random point
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     //This is done to define the grid
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     // generate neighbors
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;//*std::sqrt (dx*dx + dy*dy + dz*dz);          
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     //Add another point that isn't touching previous or neighbors
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     // Add points which are not neighbors
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     //Point should have 26 neighbors, plus itself
01692     ASSERT_EQ( leaf_container->size() == 27, true);
01693 
01694     leaf_container = octree.getLeafContainerAtPoint (point2);
01695   
01696     //Other point should only have itself for neighbor
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 /* ]--- */


pcl
Author(s): Open Perception
autogenerated on Wed Aug 26 2015 15:35:17