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.