50         void setAxis(
unsigned int Axis){axis=Axis;};
    51         inline bool operator()(
const std::pair<Point3D,size_t> &p1,
const std::pair<Point3D,size_t> &p2)
 const    52         {
return p1.first[axis]<p2.first[axis];};
    62             index(idx), cube(bc), depth(dpth) {};
    71     ASSERT(treeBounds.isValid());
    77     ASSERT(index < indexedPoints.size());
    78     return &(indexedPoints[index].first);
    83     ASSERT(index < indexedPoints.size());
    84     return (indexedPoints[index].first);
    89     ASSERT(treeIndex <indexedPoints.size());
    90     return indexedPoints[treeIndex].second;
    95     ASSERT(treeIndex < nodes.size());
    96     return nodes[treeIndex].tagged;
   101     ASSERT(treeIndex < nodes.size());
   102     nodes[treeIndex].tagged=tagVal;
   107 for(
unsigned int ui=0;ui<treeIndicies.size();ui++)
   109     ASSERT(treeIndicies[ui] < nodes.size());
   110     nodes[treeIndicies[ui]].tagged=tagVal;
   115     ASSERT(nodes.size() == indexedPoints.size());
   116     return indexedPoints.size();
   123     indexedPoints.resize(p.size());
   125     #pragma omp parallel for   126     for(
size_t ui=0;ui<indexedPoints.size();ui++)
   128         indexedPoints[ui].first=p[ui];
   129         indexedPoints[ui].second=ui;
   135     nodes.resize(indexedPoints.size());
   140     indexedPoints.resize(p.size());
   141     nodes.resize(p.size());
   150     #pragma omp parallel for   151     for(
size_t ui=0;ui<indexedPoints.size();ui++)
   153         indexedPoints[ui].first=p[ui].getPosRef();
   154         indexedPoints[ui].second=ui;
   165     using std::make_pair;
   182     if(indexedPoints.empty())
   186     ASSERT(treeBounds.isValid());
   189     stack<pair<size_t,size_t> > limits;
   190     stack<char> buildStatus;
   191     stack<size_t> splitStack;
   194     limits.push(make_pair(0,indexedPoints.size()-1));
   195     buildStatus.push(BUILT_NONE);
   196     splitStack.push((
size_t)-1);
   208     for(
size_t ui=0;ui<nodes.size();ui++)
   210         nodes[ui].childLeft=nodes[ui].childRight=(size_t)-2;
   218         switch(buildStatus.top())
   223                 int curAxis=(limits.size()-1)%3;
   230                 std::sort(indexedPoints.begin()+limits.top().first,
   231                         indexedPoints.begin() + limits.top().second+1,axisCmp);
   234                 splitIndex=(limits.top().second+limits.top().first)/2;
   239                 while(splitIndex != limits.top().second
   240                     && indexedPoints[splitIndex].first.getValue(curAxis) ==
   241                         indexedPoints[splitIndex+1].first.getValue(curAxis))
   247                 if(limits.size() ==1)
   253                     *childPtr=splitIndex;
   256                 if(splitIndex >limits.top().first)
   259                     limits.push(make_pair(
   260                         limits.top().first,splitIndex-1));
   262                     buildStatus.push(BUILT_NONE);
   265                     childPtr=&nodes[splitIndex].childLeft;
   270                     nodes[splitIndex].childLeft=(size_t)-1;
   272                 splitStack.push(splitIndex);
   282                 splitIndex=splitStack.top();
   284                 if(splitIndex <limits.top().second)
   287                     limits.push(make_pair(
   288                         splitIndex+1,limits.top().second));
   289                     buildStatus.push(BUILT_NONE);
   293                     childPtr=&nodes[splitIndex].childRight;
   298                     nodes[splitIndex].childRight=(size_t)-1;
   305                 ASSERT(nodes[splitStack.top()].childLeft != (size_t)-2
   306                     && nodes[splitStack.top()].childRight!= (size_t)-2 );
   307                 maxDepth=std::max(maxDepth,limits.size());
   312                     ASSERT(limits.size() == buildStatus.size());
   322                 *progress= (
unsigned int)((
float)numSeen/(float)nodes.size()*100.0f);
   328         }
while(!limits.empty());
   335     if(offset==(
size_t)-1)
   337         for(
unsigned int ui=0;ui<indexedPoints.size();ui++)
   339             strm << ui << 
" "<< indexedPoints[ui].first << std::endl;
   342         strm << 
"----------------" << std::endl;
   346     for(
size_t ui=0;ui<depth; ui++)
   349     strm << offset << 
" : (" << indexedPoints[offset].first[0] 
   350         << 
"," << indexedPoints[offset].first[1] << 
"," << indexedPoints[offset].first[2]
   355     for(
size_t ui=0;ui<depth; ui++)
   357     strm << 
"<l>" <<std::endl;
   359     if(nodes[offset].childLeft!=(
size_t)-1)
   361         dump(strm,depth+1,nodes[offset].childLeft);
   363     for(
size_t ui=0;ui<depth; ui++)
   365     strm << 
"</l>" <<std::endl;
   367     for(
size_t ui=0;ui<depth; ui++)
   369     strm << 
"<r>" <<std::endl;
   371     if(nodes[offset].childRight!=(
size_t)-1)
   372         dump(strm,depth+1,nodes[offset].childRight);
   374     for(
size_t ui=0;ui<depth; ui++)
   376     strm << 
"</r>" <<std::endl;
   380         vector<size_t> &pts)
 const   390     const float sqrRadius=radius*radius;
   392     std::queue<size_t> idxQueue;
   394     std::queue<NodeWalk> nodeQueue;
   395     nodeQueue.push(
NodeWalk(treeRoot,treeBounds,0));
   397     while(!nodeQueue.empty())
   401         unsigned int depth,axis;
   403         nodeIdx = nodeQueue.front().index;
   404         curCube=nodeQueue.front().cube;
   405         depth = nodeQueue.front().depth;
   415         if(nodes[nodeIdx].childLeft != (
size_t) -1)
   418             leftCube.bounds[axis][1]=indexedPoints[nodeIdx].first[axis];
   423                     ASSERT(indexedPoints[nodeIdx].first.sqrDist(origin) < radius*radius);
   424                     idxQueue.push(nodes[nodeIdx].childLeft);
   427                     nodeQueue.push(
NodeWalk(nodes[nodeIdx].childLeft,leftCube,depth+1));
   431         if(nodes[nodeIdx].childRight != (
size_t) -1)
   434             rightCube.bounds[axis][0]=indexedPoints[nodeIdx].first[axis];
   440                     ASSERT(indexedPoints[nodeIdx].first.sqrDist(origin) < sqrRadius);
   441                     idxQueue.push(nodes[nodeIdx].childRight);
   444                     nodeQueue.push(
NodeWalk(nodes[nodeIdx].childRight,rightCube,depth+1));
   448         if(indexedPoints[nodeIdx].first.sqrDist(origin) < sqrRadius)
   449             pts.push_back(nodeIdx);
   454     pts.reserve(idxQueue.size());
   456     while(!idxQueue.empty())
   459         curIdx=idxQueue.front();
   460         ASSERT(indexedPoints[curIdx].first.sqrDist(origin) < sqrRadius);
   461         if(nodes[curIdx].childLeft != (
size_t)-1)
   462             idxQueue.push(nodes[curIdx].childLeft);
   464         if(nodes[curIdx].childRight !=(
size_t) -1)
   465             idxQueue.push(nodes[curIdx].childRight);
   468         ASSERT(curIdx < nodes.size());
   469         pts.push_back(curIdx);
   476                 const BoundCube &domainCube, 
bool shouldTag)
   478     enum { NODE_FIRST_VISIT, 
   483     ASSERT(treeRoot!=(
size_t)-1);
   487     size_t nodeStack[maxDepth+1];
   488     float domainStack[maxDepth+1][2];
   489     unsigned int visitStack[maxDepth+1];
   496     unsigned int stackTop;
   497     unsigned int curAxis;
   505     bestPoint=(size_t)-1; 
   506     bestDistSqr =std::numeric_limits<float>::max();
   507     curDomain=domainCube;
   508     visit=NODE_FIRST_VISIT;
   517     if(!nodes[curNode].tagged)
   520         tmpDistSqr = indexedPoints[curNode].first.sqrDist(searchPt); 
   521         if(tmpDistSqr < bestDistSqr)
   523             bestDistSqr  = tmpDistSqr;
   533             case NODE_FIRST_VISIT:
   535                 if(searchPt[curAxis] < indexedPoints[curNode].first[curAxis])
   537                     if(nodes[curNode].childLeft!=(
size_t)-1)
   541                         tmpEdge= curDomain.bounds[curAxis][1];
   542                         curDomain.bounds[curAxis][1] = indexedPoints[curNode].first[curAxis];
   543                         if(!curDomain.
intersects(searchPt,bestDistSqr))
   545                             curDomain.bounds[curAxis][1] = tmpEdge; 
   550                         nodeStack[stackTop]=curNode;
   551                         visitStack[stackTop] = NODE_SECOND_VISIT; 
   552                         domainStack[stackTop][1] = tmpEdge;
   553                         domainStack[stackTop][0]= curDomain.bounds[curAxis][0];
   557                         curNode=nodes[curNode].childLeft;
   558                         visit=NODE_FIRST_VISIT;
   566                     if(nodes[curNode].childRight!=(
size_t)-1)
   570                         tmpEdge= curDomain.bounds[curAxis][0];
   571                         curDomain.bounds[curAxis][0] = indexedPoints[curNode].first[curAxis];
   573                         if(!curDomain.
intersects(searchPt,bestDistSqr))
   575                             curDomain.bounds[curAxis][0] =tmpEdge; 
   581                         nodeStack[stackTop]=curNode;
   582                         visitStack[stackTop] = NODE_SECOND_VISIT; 
   583                         domainStack[stackTop][0] = tmpEdge;
   584                         domainStack[stackTop][1]= curDomain.bounds[curAxis][1];
   588                         curNode=nodes[curNode].childRight;
   589                         visit=NODE_FIRST_VISIT;
   599             case NODE_SECOND_VISIT:
   601                 if(searchPt[curAxis]< indexedPoints[curNode].first[curAxis])
   603                     if(nodes[curNode].childRight!=(
size_t)-1)
   607                         tmpEdge= curDomain.bounds[curAxis][0];
   608                         curDomain.bounds[curAxis][0] = indexedPoints[curNode].first[curAxis];
   610                         if(!curDomain.
intersects(searchPt,bestDistSqr))
   612                             curDomain.bounds[curAxis][0] = tmpEdge; 
   617                         nodeStack[stackTop]=curNode;
   618                         visitStack[stackTop] = NODE_THIRD_VISIT; 
   619                         domainStack[stackTop][0] = tmpEdge;
   620                         domainStack[stackTop][1]= curDomain.bounds[curAxis][1];
   624                         curNode=nodes[curNode].childRight;
   625                         visit=NODE_FIRST_VISIT;
   634                     if(nodes[curNode].childLeft!=(
size_t)-1)
   638                         tmpEdge= curDomain.bounds[curAxis][1];
   639                         curDomain.bounds[curAxis][1] = indexedPoints[curNode].first[curAxis];
   641                         if(!curDomain.
intersects(searchPt,bestDistSqr))
   643                             curDomain.bounds[curAxis][1] = tmpEdge; 
   648                         nodeStack[stackTop]=curNode;
   649                         visitStack[stackTop] = NODE_THIRD_VISIT; 
   650                         domainStack[stackTop][1] = tmpEdge;
   651                         domainStack[stackTop][0]= curDomain.bounds[curAxis][0];
   655                         curNode=nodes[curNode].childLeft;
   656                         visit=NODE_FIRST_VISIT;
   666             case NODE_THIRD_VISIT:
   672                 if(!nodes[curNode].tagged)
   675                     tmpDistSqr = indexedPoints[curNode].first.sqrDist(searchPt); 
   676                     if(tmpDistSqr < bestDistSqr)
   678                         bestDistSqr  = tmpDistSqr;
   684                 ASSERT(stackTop%3 == curAxis)
   693                 ASSERT(stackTop < maxDepth+1);  
   697                     visit=visitStack[stackTop];
   698                     curNode=nodeStack[stackTop];
   699                     curDomain.bounds[curAxis][0]=domainStack[stackTop][0];
   700                     curDomain.bounds[curAxis][1]=domainStack[stackTop][1];
   701                     ASSERT((stackTop)%3 == curAxis);
   714     }
while(!(curNode== treeRoot &&  visit== NODE_THIRD_VISIT));
   716     if(bestPoint != (
size_t) -1)
   717         nodes[bestPoint].tagged|=shouldTag;
   725                 const BoundCube &domainCube, 
float radius, vector<size_t> &result)
   734     float sqrRad=radius*radius;
   743         if(resIdx == (
size_t)-1)
   753         result.push_back(resIdx);
   758     for(
size_t ui=0;ui<result.size();ui++)
   760         tag(result[ui],
false);
   769     #pragma omp parallel for reduction(+:count)   770     for(
size_t ui=0;ui<nodes.size();ui++)
   782 #pragma omp parallel for   783     for(
size_t ui=0;ui<tagsToClear.size();ui++)
   784         nodes[tagsToClear[ui]].tagged=
false;
   789 #pragma omp parallel for   790     for(
size_t ui=0;ui<nodes.size();ui++)
   791         nodes[ui].tagged=
false;
   807     const float CENTRE_POS=0.5f;
   809     const unsigned int NPTS=20;
   811     centre = 
Point3D(CENTRE_POS,CENTRE_POS,CENTRE_POS);
   813     vector<Point3D> spherePts;
   814     vector<Point3D> allPts;
   816     allPts.reserve(NPTS*NPTS*NPTS);
   817     spherePts.reserve(allPts.size()*CENTRE_POS);
   820     for(
size_t ui=0;ui<NPTS;ui++)
   822         for(
size_t uj=0;uj<NPTS;uj++)
   824             for(
size_t uk=0;uk<NPTS;uk++)
   826                 p= 
Point3D((
float)ui,(
float)uj,(
float)uk);
   829                 if(p.
sqrDist(centre) < CENTRE_POS*CENTRE_POS)
   830                     spherePts.push_back(p);
   837     unsigned int dummyProg=0;
   845     vector<size_t> spherePtIdx;
   848     TEST(spherePts.size() == spherePtIdx.size(), 
"Check brute force and KD methods match in size");
   852     for(
size_t ui=0;ui<spherePtIdx.size();ui++)
   855         pt=tree.
getPt(spherePtIdx[ui]);
   864 bool K3DTreeExact::runUnitTests() 
   867     TEST(inSphereTest(),
"In-sphere test");
 float sqrDist(const Point3D &pt) const
Returns the square of distance to another Point3D. 
void clearTags(std::vector< size_t > &tagsToClear)
bool getTag(size_t treeIndex) const
void getBoundCube(BoundCube &b)
obtain the bounding rectangular prism volume for all elements in the KD tree 
void setProgressPointer(unsigned int *p)
void setAxis(unsigned int Axis)
bool intersects(const Point3D &pt, float sqrRad) const
Checks if a point intersects a sphere of centre Pt, radius^2 sqrRad. 
size_t getOrigIndex(size_t treeIndex) const
void findUntaggedInRadius(const Point3D &queryPt, const BoundCube &b, float radius, std::vector< size_t > &result)
Find untagged points within a given radius. 
A 3D point data class storage. 
void setCallback(bool(*cb)(void))
const Point3D * getPt(size_t index) const
Functor allowing for sorting of points in 3D. 
static BoundCube getIonDataLimits(const std::vector< IonHit > &points)
NodeWalk(unsigned int idx, const BoundCube &bc, unsigned int dpth)
const size_t PROGRESS_REDUCE
bool operator()(const std::pair< Point3D, size_t > &p1, const std::pair< Point3D, size_t > &p2) const
void dump(std::ostream &, size_t depth=0, size_t offset=-1) const
Textual output of tree. Tabs are used to separate different levels of the tree. 
K3DTreeExact()
KD Tree constructor. Tree is uninitialised at start. 
Helper class to define a bounding cube. 
bool containedInSphere(const Point3D &origin, float radius) const
Returns true if this box is contained by the sphere, represented by the origin+radius. 
void resetPts(std::vector< Point3D > &pts, bool clear=true)
Supply points to KD tree. Ouput vector will be erased if clear=true. 
bool build()
Build the KD tree using the previously supplied points. 
void tag(size_t treeIndex, bool tagVal=true)
size_t findNearestUntagged(const Point3D &queryPt, const BoundCube &b, bool tag=true)
Find the nearest "untagged" point's internal index. 
const Point3D & getPtRef(size_t index) const
void ptsInSphere(const Point3D &origin, float radius, std::vector< size_t > &pts) const
void setBounds(float xMin, float yMin, float zMin, float xMax, float yMax, float zMax)
Set the bounds by passing in minima and maxima of each dimension.