00001 #include <gtest/gtest.h>
00002 #include <cmath>
00003
00004 #include <megatree/megatree.h>
00005 #include <megatree/allocator.h>
00006 #include <megatree/storage_factory.h>
00007 #include <megatree/node_file.h>
00008 #include <megatree/tree_functions.h>
00009
00010 using namespace megatree;
00011
00012 static const double point_precision = 0.001;
00013
00014 #define EXPECT_V3_NEAR(a, b, c, v, tolerance) \
00015 if (v.size() != 3) ADD_FAILURE() << "Vector did not have 3 elements"; \
00016 else { \
00017 EXPECT_NEAR(a, v[0], tolerance); \
00018 EXPECT_NEAR(b, v[1], tolerance); \
00019 EXPECT_NEAR(c, v[2], tolerance); \
00020 }
00021
00022 #define EXPECT_F3_NEAR(a, b, c, v, tolerance) \
00023 EXPECT_NEAR(a, v[0], tolerance); \
00024 EXPECT_NEAR(b, v[1], tolerance); \
00025 EXPECT_NEAR(c, v[2], tolerance);
00026
00027
00028
00029 TEST(MegaTreeBasics, NodeGeometry)
00030 {
00031 double center[] = {0,0,0};
00032 NodeGeometry p(center, 10.0);
00033
00034 NodeGeometry c = p.getChild(3);
00035 EXPECT_NEAR(5.0, c.getSize(), 1e-3);
00036 EXPECT_NEAR(-2.5, c.getCenter(0), 1e-6);
00037 EXPECT_NEAR( 2.5, c.getCenter(1), 1e-6);
00038 EXPECT_NEAR( 2.5, c.getCenter(2), 1e-6);
00039
00040 p = NodeGeometry(center, 6386850.000000);
00041 c = p.getChild(3);
00042 EXPECT_NEAR(3193425.0, c.getSize(), 1e-3);
00043 EXPECT_NEAR(-1596712.5, c.getCenter(0), 1e-6);
00044 EXPECT_NEAR(1596712.5, c.getCenter(1), 1e-6);
00045 EXPECT_NEAR(1596712.5, c.getCenter(2), 1e-6);
00046
00047 double new_center[] = {-1596712.500000, 1596712.500000, 1596712.500000};
00048 p = NodeGeometry(new_center, 3193425.000000);
00049 c = p.getChild(3);
00050 EXPECT_NEAR(1596712.5, c.getSize(), 1e-3);
00051 EXPECT_NEAR(-2395068.75, c.getCenter(0), 1e-6);
00052 EXPECT_NEAR(2395068.75, c.getCenter(1), 1e-6);
00053 EXPECT_NEAR(2395068.75, c.getCenter(2), 1e-6);
00054 }
00055
00056
00057 TEST(MegaTreeBasics, NodeGeometryInPlace)
00058 {
00059 double center[] = {0,0,0};
00060 NodeGeometry p(center, 10.0);
00061
00062 NodeGeometry c = p;
00063 c = c.getChild(3);
00064 EXPECT_NEAR(5.0, c.getSize(), 1e-3);
00065 EXPECT_NEAR(-2.5, c.getCenter(0), 1e-6);
00066 EXPECT_NEAR(2.5, c.getCenter(1), 1e-6);
00067 EXPECT_NEAR(2.5, c.getCenter(2), 1e-6);
00068 }
00069
00070
00071 TEST(MegaTreeBasics, NodeGeometryPrecision_EdgesShouldAlign)
00072 {
00073
00074
00075
00076 double r_lo[] = {-5863017.3200000003, -2192262.1200000001, -6386851.2000000002};
00077 double r_hi[] = {6910682.6799999997, 10581437.879999999, 6386848.7999999998};
00078 NodeGeometry r(1, r_lo, r_hi);
00079
00080 NodeGeometry child = r.getChild(7);
00081 for (size_t i = 0; i < 26; ++i)
00082 {
00083 double child_left_edge = child.getLo(0);
00084
00085
00086
00087
00088
00089
00090 ASSERT_NEAR(r.getCenter(0), child_left_edge, 0.0) << "Descended " << (i + 1) << " times";
00091
00092 child = child.getChild(0);
00093 }
00094 }
00095
00096
00097
00098 TEST(MegaTreeBasics, Node)
00099 {
00100 std::vector<double> tree_center(3,0);
00101 Node n;
00102
00103 for (uint8_t i=0; i<8; i++)
00104 EXPECT_FALSE(n.hasChild(i));
00105
00106 n.setChild(0);
00107 EXPECT_TRUE(n.hasChild(0));
00108 for(uint8_t i = 1; i < 8; ++i)
00109 EXPECT_FALSE(n.hasChild(i));
00110
00111 n.setChild(7);
00112 EXPECT_TRUE(n.hasChild(0));
00113 EXPECT_TRUE(n.hasChild(7));
00114 for(uint8_t i = 1; i < 7; ++i)
00115 EXPECT_FALSE(n.hasChild(i));
00116 }
00117
00118
00119 TEST(MegaTreeBasics, OctreeLevel)
00120 {
00121 EXPECT_EQ(1, IdType(1).level());
00122 EXPECT_EQ(2, IdType(010).level());
00123 EXPECT_EQ(3, IdType(0177).level());
00124 EXPECT_EQ(8, IdType(014637720).level());
00125
00126 EXPECT_EQ(IdType(01), IdType(017).getParent());
00127 EXPECT_EQ(IdType(012747241), IdType(0127472410).getParent());
00128
00129 EXPECT_EQ(IdType(0), IdType(1).getParent());
00130 }
00131
00132
00133 TEST(MegaTreeBasics, NodePoint)
00134 {
00135 double point[3], color[3];
00136 point[0] = point[1] = point[2] = color[0] = color[1] = color[2] = 0;
00137 point[0] = 0.02;
00138 color[0] = 230;
00139
00140 double center[] = {0, 0, 0};
00141 double tree_size = 1.0;
00142 NodeGeometry ng(center, tree_size);
00143 Node n;
00144 n.setPoint(ng, point, color);
00145
00146 double point_get[3], color_get[3];
00147 n.getPoint(ng, point_get);
00148 n.getColor(color_get);
00149
00150 EXPECT_NEAR(point[0], point_get[0], 2.*ng.getSize()/256.);
00151 EXPECT_NEAR(point[1], point_get[1], 2.*ng.getSize()/256.);
00152 EXPECT_NEAR(point[2], point_get[2], 2.*ng.getSize()/256.);
00153
00154 EXPECT_NEAR(color[0], color_get[0], 2.*ng.getSize()/256.);
00155 EXPECT_NEAR(color[1], color_get[1], 2.*ng.getSize()/256.);
00156 EXPECT_NEAR(color[2], color_get[2], 2.*ng.getSize()/256.);
00157 }
00158
00159
00160
00161
00162 TEST(MegaTreeBasics, SinglePointRangeQuery)
00163 {
00164 std::vector<double> tree_center(3, 0);
00165 double tree_size = 10;
00166 boost::shared_ptr<TempDir> tree_path = createTempDir("rangequery", true);
00167 boost::shared_ptr<Storage> storage(openStorage(tree_path->getPath()));
00168 MegaTree tree(storage, tree_center, tree_size, 3, 1);
00169
00170
00171 std::vector<double> pt(3, 0);
00172 addPoint(tree, pt);
00173
00174
00175 std::vector<double> range_lo(3, -1.0f), range_hi(3, 1.0f);
00176 std::vector<double> result, colors;
00177 queryRange(tree, range_lo, range_hi, point_precision, result, colors);
00178 EXPECT_V3_NEAR(0, 0, 0, result, 2.*point_precision);
00179
00180
00181 range_lo[0] = 1.0f;
00182 range_lo[1] = 1.0f;
00183 range_lo[2] = 1.0f;
00184 range_hi[0] = 4.0f;
00185 range_hi[1] = 4.0f;
00186 range_hi[2] = 4.0f;
00187 result.clear();
00188 colors.clear();
00189 queryRange(tree, range_lo, range_hi, point_precision, result, colors);
00190 EXPECT_EQ(0, result.size());
00191 }
00192
00193
00194 void gridTest(bool clear)
00195 {
00196 std::vector<double> tree_center(3, 10);
00197 double tree_size = 30.0;
00198 NodeGeometry ng(tree_center, tree_size);
00199
00200 boost::shared_ptr<TempDir> tree_path(createTempDir("rangequery", true));
00201 boost::shared_ptr<Storage> storage(openStorage(tree_path->getPath()));
00202 MegaTree tree(storage, tree_center, tree_size, 4, 1);
00203
00204
00205 const double STEP = 1;
00206 const size_t WIDTH = 20;
00207 std::vector<double> pt(3, 0.0f);
00208 for (size_t i = 0; i < WIDTH; ++i)
00209 {
00210 for (size_t j = 0; j < WIDTH; ++j)
00211 {
00212 for (size_t k = 0; k < WIDTH; ++k)
00213 {
00214 pt[0] = STEP * i;
00215 pt[1] = STEP * j;
00216 pt[2] = STEP * k;
00217 addPoint(tree, pt);
00218 }
00219 }
00220 }
00221
00222 if (clear)
00223 tree.flushCache();
00224
00225
00226 NodeHandle root;
00227 tree.getRoot(root);
00228 ASSERT_TRUE(root.getCount() > 1);
00229 EXPECT_EQ(pow(WIDTH, 3), root.getCount());
00230
00231
00232 double mean = double(WIDTH - 1) / 2 * STEP;
00233 double point[3];
00234 root.getPoint(point);
00235 EXPECT_NEAR(mean, point[0], 2. * tree_size / 256.);
00236 EXPECT_NEAR(mean, point[1], 2. * tree_size / 256.);
00237 EXPECT_NEAR(mean, point[2], 2. * tree_size / 256.);
00238 tree.releaseNode(root);
00239
00240
00241 std::vector<double> range_lo(3, -1), range_hi(3, WIDTH * STEP + 1);
00242 std::vector<double> result, colors;
00243 queryRange(tree, range_lo, range_hi, point_precision, result, colors);
00244 EXPECT_EQ(pow(WIDTH, 3), result.size() / 3);
00245
00246
00247 range_hi[0] = WIDTH * STEP;
00248 range_hi[1] = WIDTH * STEP;
00249 range_hi[2] = (WIDTH * STEP) / 2;
00250 result.clear();
00251 colors.clear();
00252 queryRange(tree, range_lo, range_hi, point_precision, result, colors);
00253 EXPECT_EQ(pow(WIDTH, 3) / 2, result.size() / 3);
00254
00255
00256 range_lo[0] = 2 * STEP - 0.00001;
00257 range_lo[1] = 2 * STEP - 0.00001;
00258 range_lo[2] = 2 * STEP - 0.00001;
00259 range_hi[0] = 4 * STEP - 0.00001;
00260 range_hi[1] = 4 * STEP - 0.00001;
00261 range_hi[2] = 4 * STEP - 0.00001;
00262 result.clear();
00263 colors.clear();
00264 queryRange(tree, range_lo, range_hi, point_precision, result, colors);
00265 EXPECT_EQ(8, result.size() / 3);
00266
00267
00268 range_lo[0] = -1000; range_hi[0] = 1000;
00269 range_lo[1] = 5.9 * STEP; range_hi[1] = 6.1 * STEP;
00270 range_lo[2] = 5.9 * STEP; range_hi[2] = 6.1 * STEP;
00271 result.clear();
00272 colors.clear();
00273 queryRange(tree, range_lo, range_hi, point_precision, result, colors);
00274 EXPECT_EQ(WIDTH, result.size() / 3);
00275 }
00276
00277
00278 TEST(MegaTreeBasics, GridRangeQuery)
00279 {
00280 gridTest(false);
00281 gridTest(true);
00282 }
00283
00284 TEST(MegaTreeBasics, TestDiskAccess)
00285 {
00286 std::vector<double> tree_center(3, 0);
00287 double tree_size = 1000000;
00288
00289 boost::shared_ptr<TempDir> tree1_path(createTempDir("tree1", true));
00290 boost::shared_ptr<Storage> storage1(openStorage(tree1_path->getPath()));
00291 MegaTree tree1(storage1, tree_center, tree_size, 3, 1);
00292
00293 boost::shared_ptr<TempDir> tree2_path(createTempDir("tree2", true));
00294 boost::shared_ptr<Storage> storage2(openStorage(tree2_path->getPath()));
00295 MegaTree tree2(storage2, tree_center, tree_size, 2, 1);
00296
00297
00298 const double STEP = 1;
00299 const size_t WIDTH = 2;
00300 std::vector<double> pt(3, 0.0f);
00301 for (size_t i = 0; i < WIDTH; ++i)
00302 {
00303 for (size_t j = 0; j < WIDTH; ++j)
00304 {
00305 for (size_t k = 0; k < WIDTH; ++k)
00306 {
00307 pt[0] = STEP * i;
00308 pt[1] = STEP * j;
00309 pt[2] = STEP * k;
00310 addPoint(tree1, pt);
00311 addPoint(tree2, pt);
00312 }
00313 }
00314 }
00315
00316 tree1.flushCache();
00317 EXPECT_TRUE(tree1 == tree2);
00318
00319
00320 boost::shared_ptr<Storage> storage3(openStorage(tree1_path->getPath()));
00321 MegaTree tree3(storage3, 10000, true);
00322
00323 EXPECT_TRUE(tree1 == tree3);
00324 EXPECT_TRUE(tree2 == tree3);
00325
00326 }
00327
00328 TEST(MegaTreeBasics, ColorSanityCheck)
00329 {
00330 std::vector<double> tree_center(3, 0);
00331 double tree_size = 1000000;
00332
00333 boost::shared_ptr<TempDir> tree_path(createTempDir("test_color_tree", true));
00334 boost::shared_ptr<Storage> storage(openStorage(tree_path->getPath()));
00335 MegaTree tree(storage, tree_center, tree_size, 3, 1);
00336
00337
00338 std::vector<double> pt(3, 0);
00339 std::vector<double> color(3, 0);
00340 color[0] = 1.0f;
00341 color[1] = 255.0f;
00342 addPoint(tree, pt, color);
00343
00344 NodeHandle root;
00345 tree.getRoot(root);
00346 double col[3];
00347 root.getColor(col);
00348 EXPECT_NEAR(1.0, col[0], 1e-5);
00349 EXPECT_NEAR(255.0, col[1], 1e-5);
00350 tree.releaseNode(root);
00351
00352
00353 tree.flushCache();
00354 boost::shared_ptr<Storage> storage2(openStorage(tree_path->getPath()));
00355 MegaTree tree2(storage2, 10000, true);
00356 NodeHandle root2;
00357 tree2.getRoot(root2);
00358 root2.getColor(col);
00359 EXPECT_NEAR(1.0, col[0], 1e-5);
00360 EXPECT_NEAR(255.0, col[1], 1e-5);
00361 tree2.releaseNode(root2);
00362 }
00363
00364 TEST(MegaTreeBasics, ColorsAggregateProperly)
00365 {
00366 std::vector<double> tree_center(3, 0);
00367 double tree_size = 100;
00368
00369 boost::shared_ptr<TempDir> tree_path(createTempDir("test_color_tree", true));
00370 boost::shared_ptr<Storage> storage(openStorage(tree_path->getPath()));
00371 MegaTree tree(storage, tree_center, tree_size, 2, 1);
00372
00373
00374 std::vector<double> pt(3, 0);
00375 std::vector<double> color(3, 0);
00376 color[0] = 254.0;
00377 color[1] = 254.0;
00378 color[2] = 0.0;
00379 addPoint(tree, pt, color);
00380 pt[0] = 0.1;
00381 color[0] = 0.0;
00382 color[1] = 254.0;
00383 color[2] = 254.0;
00384 addPoint(tree, pt, color);
00385
00386 NodeHandle root;
00387 tree.getRoot(root);
00388 double col[3];
00389 root.getColor(col);
00390 EXPECT_NEAR(127.0, col[0], 1e-5);
00391 EXPECT_NEAR(254.0, col[1], 1e-5);
00392 EXPECT_NEAR(127.0, col[2], 1e-5);
00393 tree.releaseNode(root);
00394 }
00395
00396
00397
00398 int main(int argc, char **argv){
00399 testing::InitGoogleTest(&argc, argv);
00400 return RUN_ALL_TESTS();
00401 }