00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011 #include "common/wave_ex.h"
00012 #include "kdtree/kdtree.h"
00013 #include "perf/perf.h"
00014
00015 #include <iostream>
00016
00017
00018
00019 static const float s_max = 5000.0;
00020
00021
00022
00023
00024
00025
00026
00027
00028 class Test : public kdtree::Entry {
00029 public:
00030 ~Test(void) throw() { }
00031 };
00032
00033
00034 static float
00035 getRandom
00036 (
00037 IN float q
00038 )
00039 {
00040 ASSERT(q > 0, "bad q: %f", q);
00041
00042 return (q * rand()) / RAND_MAX;
00043 }
00044
00045
00046
00047 static void
00048 getRandomRect
00049 (
00050 IN const rect3d_t& bounds,
00051 IN float size,
00052 OUT rect3d_t& r
00053 )
00054 {
00055 ASSERT(bounds.isValid(), "invalid");
00056
00057 r.x0 = bounds.x0 + getRandom(bounds.x1 - bounds.x0 - 1.01 * size);
00058 r.y0 = bounds.y0 + getRandom(bounds.y1 - bounds.y0 - 1.01 * size);
00059 r.z0 = bounds.z0 + getRandom(bounds.z1 - bounds.z0 - 1.01 * size);
00060
00061 r.x1 = r.x0 + size;
00062 r.y1 = r.y0 + size;
00063 r.z1 = r.z0 + size;
00064 }
00065
00066
00067
00068 static kdtree::eAction
00069 countCallback
00070 (
00071 IN void * context,
00072 IN kdtree::Entry * e,
00073 IN const rect3d_t& r
00074 )
00075 {
00076 long * pCount = (long *) context;
00077 ASSERT(pCount, "null context?");
00078
00079 *pCount = (*pCount) + 1;
00080
00081 return kdtree::eAction_Continue;
00082 }
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106 static kdtree::eAction
00107 findCallback
00108 (
00109 IN void * context,
00110 IN kdtree::Entry * e,
00111 IN const rect3d_t& r
00112 )
00113 {
00114 if (e == context) {
00115
00116 return kdtree::eAction_Halt;
00117 }
00118
00119
00120 return kdtree::eAction_Continue;
00121 }
00122
00123
00124
00125 static kdtree::eAction
00126 removeCallback
00127 (
00128 IN void * context,
00129 IN kdtree::Entry * e,
00130 IN const rect3d_t& r
00131 )
00132 {
00133 if (e == context) {
00134
00135 return (kdtree::eAction)
00136 (kdtree::eAction_Remove | kdtree::eAction_Halt);
00137 }
00138
00139
00140 return kdtree::eAction_Continue;
00141 }
00142
00143
00144
00145 static int
00146 popAllDynamicEntries
00147 (
00148 IN kdtree::Node * node
00149 )
00150 {
00151 int count = 0;
00152
00153
00154 while (smart_ptr<kdtree::Node::dynamic_entry_t> pde =
00155 node->popDynamicEntry()) {
00156 ++count;
00157 }
00158
00159 kdtree::Node * left = node->getLeftChild();
00160 kdtree::Node * right = node->getRightChild();
00161
00162 if (left) {
00163 count += popAllDynamicEntries(left);
00164 }
00165 if (right) {
00166 count += popAllDynamicEntries(right);
00167 }
00168
00169 return count;
00170 }
00171
00172
00173 static void
00174 doTest1
00175 (
00176 IN int nCount,
00177 IN int subdivide
00178 )
00179 {
00180 perf::Timer timer("doTest1");
00181 ASSERT(nCount > 0, "bad count: %d", nCount);
00182 ASSERT(subdivide > 0, "Bad subdivide: %d", subdivide);
00183
00184 rect3d_t bounds;
00185
00186 DPRINTF(
00187 "Running test with %d entries, subdivide at %d entries per node",
00188 nCount, subdivide);
00189
00190 bounds.x0 = -s_max;
00191 bounds.x1 = +s_max;
00192 bounds.y0 = -(s_max / 2.5);
00193 bounds.y1 = +(s_max / 2.5);
00194 bounds.z0 = -(s_max / 5);
00195 bounds.z1 = +(s_max / 5);
00196
00197
00198 smart_ptr<kdtree::Node> root = kdtree::Node::create(bounds);
00199 ASSERT(root, "failed to create root node");
00200
00201 for (int i = 0; i < nCount; ++i) {
00202 rect3d_t r;
00203 getRandomRect(bounds, getRandom(10), r);
00204
00205 smart_ptr<kdtree::Entry> e;
00206
00207 {
00208 perf::Timer timer("addEntry");
00209 root->addStaticEntry(e, r);
00210 }
00211 }
00212
00213 DPRINTF("Tree depth: %d", root->getTreeDepth());
00214 DPRINTF("Node count: %d", root->getNodeCount());
00215 DPRINTF("Entry count: %d", root->getStaticEntryCount());
00216 if (root->getStaticEntryCount() != nCount) {
00217 WAVE_EX(wex);
00218 wex << "Count of entries in tree does not match what was added";
00219 }
00220
00221
00222 DPRINTF("Subdividing...");
00223 {
00224 perf::Timer timer("subdivide");
00225 root->subdivide(kdtree::eStrategy_Naive, subdivide);
00226 }
00227 DPRINTF("Tree depth: %d", root->getTreeDepth());
00228 DPRINTF("Node count: %d", root->getNodeCount());
00229 DPRINTF("Entry count: %d", root->getStaticEntryCount());
00230
00231 long count = 0;
00232 {
00233 perf::Timer timer("full iteration");
00234 root->iterateStaticEntries(bounds, countCallback, (void *) &count);
00235 }
00236 if (count != nCount) {
00237 WAVE_EX(wex);
00238 wex << "Iteration should return all entities!";
00239 }
00240
00241 rect3d_t sub;
00242 getRandomRect(bounds, 1000, sub);
00243 sub.dump("Search rect");
00244 count = 0;
00245 {
00246
00247
00248 perf::Timer timer("sub iteration");
00249 root->iterateStaticEntries(sub, countCallback, (void *) &count);
00250 }
00251 DPRINTF("Found %ld entries in sub rect", count);
00252
00253
00254 DPRINTF("Adding %d dynamic objects", nCount);
00255 for (int i = 0; i < nCount; ++i) {
00256 smart_ptr<kdtree::Node::dynamic_entry_t> pde =
00257 new kdtree::Node::dynamic_entry_t;
00258 ASSERT(pde, "out of memory");
00259
00260 getRandomRect(bounds, 1.0 + getRandom(4.0), pde->rect);
00261
00262 root->addDynamicEntry(pde);
00263 }
00264
00265
00266 int popped = popAllDynamicEntries(root);
00267 DPRINTF("Popped %d dynamic entries", popped);
00268 ASSERT_THROW(popped == nCount, "should have popped as many as added");
00269
00270
00271 ASSERT_THROW(0 == popAllDynamicEntries(root),
00272 "Should not have found any dynamic entries remaining");
00273 }
00274
00275
00276
00277
00278
00279
00280
00281
00282
00283 int
00284 main
00285 (
00286 IN int argc,
00287 IN const char * argv[]
00288 )
00289 {
00290 int nCount = 50 * 1000;
00291 int nDivide = 32;
00292 if (argc > 1) {
00293 nCount = atoi(argv[1]);
00294 } else {
00295 DPRINTF("No count provided, so using count = %d", nCount);
00296 }
00297 if (argc > 2) {
00298 nDivide = atoi(argv[2]);
00299 } else {
00300 DPRINTF("No subdivide threshold specified, using %d", nDivide);
00301 }
00302 int retval = 0;
00303
00304 try {
00305 perf::Timer timer("Total test time");
00306
00307 doTest1(nCount, nDivide);
00308
00309 } catch (std::exception& e) {
00310 DPRINTF("Exception: %s", e.what());
00311 retval = 1;
00312 }
00313
00314 perf::dumpTimingSummary(std::cerr);
00315
00316 return retval;
00317 }
00318