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