libatomprobe
Library for Atom Probe Tomography (APT) computation
KDTest.cpp
Go to the documentation of this file.
1 /* KDTest.cpp: Sample program for spatial searching (eg Nearest Neighbour)
2  * Copyright (C) 2014 Daniel Haley
3  *
4  * This program is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 3 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <http://www.gnu.org/licenses/>.
16  */
17 #include <iostream>
18 #include <cstdlib>
19 #include <sys/time.h>
20 
21 #include "atomprobe/atomprobe.h"
22 
23 using namespace std;
24 using namespace AtomProbe;
25 
26 const unsigned int NUM_IONS=1000;
27 const float SCALE=100;
28 const float SEARCH_RAD = 5;
29 
30 unsigned int progress=0;
31 
32 bool callback()
33 {
34  return true;
35 }
36 
38 {
39  //Generate a random cube
40  vector<IonHit> ions;
41 
42  //initialise random number generator using
43  // current system time
44 
45  ions.resize(NUM_IONS);
46  for(unsigned int ui=0;ui<NUM_IONS;ui++)
47  {
48 
49  float xyzm[4];
50  xyzm[0] = SCALE*((float)rand()/RAND_MAX-0.5);
51  xyzm[1] = SCALE*((float)rand()/RAND_MAX-0.5);
52  xyzm[2] = SCALE*((float)rand()/RAND_MAX-0.5);
53  xyzm[3] = SCALE*((float)rand()/RAND_MAX-0.5);
54  ions[ui].setHit(xyzm);
55  }
56 
57  K3DTreeExact kdExact;
58  kdExact.setCallback(callback);
59  kdExact.setProgressPointer(&progress);
60  kdExact.resetPts(ions);
61 
62  cerr << ".";
63  kdExact.build();
64 
65  BoundCube bc;
66  kdExact.getBoundCube(bc);
67 
68  for(unsigned int ui=1;ui<kdExact.size();ui++)
69  {
70  {
71  //Find the nearest using the repeated untagged method
72  vector<size_t> resultA, resultB;
73  kdExact.findUntaggedInRadius(kdExact.getPtRef(ui),bc,SEARCH_RAD,resultA);
74  kdExact.ptsInSphere(kdExact.getPtRef(ui),SEARCH_RAD,resultB);
75 
76  std::sort(resultA.begin(),resultA.end());
77  std::sort(resultB.begin(),resultB.end());
78 
79 
80  if(resultA.size() != resultB.size() ||
81  !(std::equal(resultA.begin(),resultA.end(),resultB.begin())))
82  {
83  cerr << "FAIL! Mismatched" << resultA.size () << " vs " << resultB.size() << "pts, sourcept : " << ui << endl;
84 
85  cerr << "A:" << endl;
86  for(unsigned int uj=0;uj<resultA.size();uj++)
87  cerr << "\t" << kdExact.getPtRef(resultA[uj]) << endl;
88  cerr << " :" << endl;
89  for(unsigned int uj=0;uj<resultB.size();uj++)
90  cerr << "\t" << kdExact.getPtRef(resultB[uj]) << endl;
91 
92  exit(1);
93  }
94  }
95  }
96 }
97 
99 {
100  //Tiny example where we should get the root node as the answer
101  vector<Point3D> pts;
102 
103  pts.push_back(Point3D(0,0,0));
104  pts.push_back(Point3D(0,0.5,0.5));
105  pts.push_back(Point3D(100,0,0));
106 
107  BoundCube bc(pts);
108 
109  K3DTreeApprox k3dTree;
110  k3dTree.build(pts);
111 
112  //0,0.5,0.5 (aka pts[1]) should be closest to 0,0,0
113  const Point3D *p;
114  p = k3dTree.findNearest(pts[0],bc,0.00001);
115 
116  if( p->sqrDist(pts[1]) > 0.01)
117  {
118  cerr << "K3DTreeApprox findNearest check failed" << endl;
119  return false;
120  }
121 
122  return true;
123 }
124 
125 int main()
126 {
127 
128  timeval timeNow;
129  gettimeofday(&timeNow,NULL);
130 
131  if(!testInexactKDTree())
132  {
133  cerr << "TEST FAILED" << endl;
134  return false;
135  }
136 
137 
138  cerr << "Comparing two NN search methods to ensure they give the same answers, over many queries" << endl;
139 
140  unsigned int randSeed=timeNow.tv_usec;
141  srand(randSeed);
142  cerr << "Random seed :" << randSeed << endl;
143  cerr << "SCALE :" << SCALE << " Num Ions per Build : " << NUM_IONS << endl;
144  cerr << "Search radius :" << SEARCH_RAD << endl;
145 
146  const unsigned int ITERATIONS=100;
147  cerr << "Attempting " << ITERATIONS << " random trees, finding ions in < search radius, using every ion as centre." << endl;
148  cerr << "Will repeat for :" << ITERATIONS << " passes" << endl;
149  for(unsigned int ui=1;ui<ITERATIONS; ui++)
150  {
151  kdExactFuzz();
152 
153  if( ui && !(ui%50))
154  cerr << " Pass" << ui<< endl;
155  }
156 
157  timeval timeEnd;
158  gettimeofday(&timeEnd,NULL);
159  float timeDelta;
160  timeDelta = (timeEnd.tv_sec - timeNow.tv_sec)*1e3 + (timeEnd.tv_usec - timeNow.tv_usec)/1000;
161  cerr << "Complete (" << timeDelta <<" msec), all searches gave the same results" << endl;
162 }
float sqrDist(const Point3D &pt) const
Returns the square of distance to another Point3D.
Definition: point3D.cpp:272
int main()
Definition: KDTest.cpp:125
void getBoundCube(BoundCube &b)
obtain the bounding rectangular prism volume for all elements in the KD tree
const unsigned int NUM_IONS
Definition: KDTest.cpp:26
void setProgressPointer(unsigned int *p)
bool testInexactKDTree()
Definition: KDTest.cpp:98
STL namespace.
3D specific KD tree
Definition: K3DTree-exact.h:54
unsigned int progress
Definition: KDTest.cpp:30
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.
Definition: point3D.h:39
void setCallback(bool(*cb)(void))
const float SCALE
Definition: KDTest.cpp:27
void kdExactFuzz()
Definition: KDTest.cpp:37
bool callback()
Definition: KDTest.cpp:32
const Point3D * findNearest(const Point3D &, const BoundCube &, float deadDistSqr) const
Find the nearest point to a given P that lies outsid some dead zone.
const float SEARCH_RAD
Definition: KDTest.cpp:28
Helper class to define a bounding cube.
Definition: boundcube.h:29
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.
3D specific KD tree
const Point3D & getPtRef(size_t index) const
void ptsInSphere(const Point3D &origin, float radius, std::vector< size_t > &pts) const
void build(const std::vector< Point3D > &pts)
Builds a balanced KD tree from a list of points.