libatomprobe
Library for Atom Probe Tomography (APT) computation
boundcube.cpp
Go to the documentation of this file.
1 /* boundcube.cpp : bounding cube class
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  */
19 
21 
22 #include <limits>
23 
24 namespace AtomProbe{
25 
26 BoundCube::BoundCube(const Point3D &p1, const Point3D &p2)
27 {
28  for(unsigned int ui=0;ui<3;ui++)
29  {
30 #ifdef DEBUG
31  valid[ui][0] = valid[ui][1] = true;
32 #endif
33  bounds[ui][0] =std::min(p1[ui],p2[ui]);
34  bounds[ui][1] =std::max(p1[ui],p2[ui]);
35  }
36 }
37 
38 bool BoundCube::operator==(const BoundCube &other) const
39 {
40  for(unsigned int ui=0; ui<3; ui++)
41  {
42  if(bounds[ui][0]!=other.bounds[ui][0] ||
43  bounds[ui][1]!=other.bounds[ui][1])
44  return false;
45  }
46  return true;
47 }
48 
49 void BoundCube::setBounds(float xMin,float yMin,float zMin,
50  float xMax,float yMax,float zMax)
51 {
52  bounds[0][0]=xMin; bounds[1][0]=yMin; bounds[2][0]=zMin;
53  bounds[0][1]=xMax; bounds[1][1]=yMax; bounds[2][1]=zMax;
54 #ifdef DEBUG
55  valid[0][0]=true; valid[1][0]=true; valid[2][0]=true;
56  valid[0][1]=true; valid[1][1]=true; valid[2][1]=true;
57 #endif
58 }
59 
61 {
62  for(unsigned int ui=0;ui<3;ui++)
63  {
64  bounds[ui][0] = b.bounds[ui][0];
65  bounds[ui][1] = b.bounds[ui][1];
66 #ifdef DEBUG
67  valid[ui][0] = b.valid[ui][0];
68  valid[ui][1] = b.valid[ui][1];
69 #endif
70  }
71 }
72 
73 
74 
75 
76 void BoundCube::setBound(unsigned int bound, unsigned int minMax, float value)
77 {
78  ASSERT(bound <3 && minMax < 2);
79  bounds[bound][minMax]=value;
80 #ifdef DEBUG
81  valid[bound][minMax]=true;
82 #endif
83 }
84 
85 
86 float BoundCube::getBound(unsigned int bound, unsigned int minMax) const
87 {
88  ASSERT(bound <3 && minMax < 2);
89  ASSERT(valid[bound][minMax]==true);
90  return bounds[bound][minMax];
91 }
92 
93 
95 {
96  bounds[0][0] = std::numeric_limits<float>::max();
97  bounds[1][0] = std::numeric_limits<float>::max();
98  bounds[2][0] = std::numeric_limits<float>::max();
99 
100  bounds[0][1] = -std::numeric_limits<float>::max();
101  bounds[1][1] = -std::numeric_limits<float>::max();
102  bounds[2][1] = -std::numeric_limits<float>::max();
103 
104 #ifdef DEBUG
105  valid[0][0] =false;
106  valid[1][0] =false;
107  valid[2][0] =false;
108 
109  valid[0][1] =false;
110  valid[1][1] =false;
111  valid[2][1] =false;
112 #endif
113 }
114 
116 {
117  bounds[0][0] = -std::numeric_limits<float>::max();
118  bounds[1][0] = -std::numeric_limits<float>::max();
119  bounds[2][0] = -std::numeric_limits<float>::max();
120 
121  bounds[0][1] = std::numeric_limits<float>::max();
122  bounds[1][1] = std::numeric_limits<float>::max();
123  bounds[2][1] = std::numeric_limits<float>::max();
124 
125 
126 #ifdef DEBUG
127  valid[0][0] =false;
128  valid[1][0] =false;
129  valid[2][0] =false;
130 
131  valid[0][1] =false;
132  valid[1][1] =false;
133  valid[2][1] =false;
134 #endif
135 }
136 bool BoundCube::isFlat() const
137 {
138  //Test the limits being inverted or equated
139  for(unsigned int ui=0;ui<3; ui++)
140  {
141  if(fabs(bounds[ui][0] - bounds[ui][1]) < std::numeric_limits<float>::epsilon())
142  return true;
143  }
144 
145  return false;
146 }
147 
149 {
150  //Check both lower and upper limit.
151  //Moving to other cubes value as needed
152 
153 #ifdef DEBUG
154  if(!b.isValid())
155  return;
156 #endif
157  //If self not valid, ensure that it will be after this run
158  //if(!isValid())
159  // setInverseLimits();
160 
161  for(unsigned int ui=0; ui<3; ui++)
162  {
163  if(b.bounds[ui][0] < bounds[ui][0])
164  {
165  bounds[ui][0] = b.bounds[ui][0];
166 #ifdef DEBUG
167  valid[ui][0] = true;
168 #endif
169  }
170 
171  if(b.bounds[ui][1] > bounds[ui][1])
172  {
173  bounds[ui][1] = b.bounds[ui][1];
174  #ifdef DEBUG
175  valid[ui][1] = true;
176  #endif
177  }
178  }
179 }
180 
181 void BoundCube::expand(const Point3D &p)
182 {
183  //If self not valid, ensure that it will be after this run
184  //ASSERT(isValid())
185  for(unsigned int ui=0; ui<3; ui++)
186  {
187  //Check lower bound is lower to new pt
188  if(bounds[ui][0] > p[ui])
189  bounds[ui][0] = p[ui];
190 
191  //Check upper bound is upper to new pt
192  if(bounds[ui][1] < p[ui])
193  bounds[ui][1] = p[ui];
194  }
195 }
196 
197 void BoundCube::expand(float f)
198 {
199  //If self not valid, ensure that it will be after this run
200  for(unsigned int ui=0; ui<3; ui++)
201  {
202  //Check lower bound is lower to new pt
203  bounds[ui][0]-=f;
204 
205  //Check upper bound is upper to new pt
206  bounds[ui][1]+=f;
207  }
208 }
209 
210 void BoundCube::setBounds(const Point3D *p, unsigned int n)
211 {
212  bounds[0][0] = std::numeric_limits<float>::max();
213  bounds[1][0] = std::numeric_limits<float>::max();
214  bounds[2][0] = std::numeric_limits<float>::max();
215 
216  bounds[0][1] = -std::numeric_limits<float>::max();
217  bounds[1][1] = -std::numeric_limits<float>::max();
218  bounds[2][1] = -std::numeric_limits<float>::max();
219 
220  for(unsigned int ui=0;ui<n; ui++)
221  {
222  for(unsigned int uj=0;uj<3;uj++)
223  {
224  if(bounds[uj][0] > p[ui][uj])
225  {
226  bounds[uj][0] = p[ui][uj];
227 #ifdef DEBUG
228  valid[uj][0] = true;
229 #endif
230  }
231 
232 
233  if(bounds[uj][1] < p[ui][uj])
234  {
235  bounds[uj][1] = p[ui][uj];
236 #ifdef DEBUG
237  valid[uj][1] = true;
238 #endif
239  }
240  }
241  }
242 }
243 
244 void BoundCube::setBounds( const Point3D &p1, const Point3D &p2)
245 {
246  for(unsigned int ui=0; ui<3; ui++)
247  {
248  bounds[ui][0]=std::min(p1[ui],p2[ui]);
249  bounds[ui][1]=std::max(p1[ui],p2[ui]);
250 #ifdef DEBUG
251  valid[ui][0]= true;
252  valid[ui][1]= true;
253 #endif
254  }
255 
256 }
257 
258 
259 void BoundCube::setBounds(const Point3D &p1, float radius)
260 {
261  for(unsigned int ui=0;ui<3;ui++)
262  {
263  bounds[ui][0]=p1[ui]-radius;
264  bounds[ui][1]=p1[ui]+radius;
265 #ifdef DEBUG
266  valid[ui][0]=true;
267  valid[ui][1]=true;
268 #endif
269  }
270 }
271 
273 void BoundCube::setBounds(const std::vector<Point3D> &ptArray)
274 {
275  setBounds(&(ptArray[0]),ptArray.size());
276 }
277 
279 void BoundCube::setBounds(const std::vector<IonHit> &ptArray)
280 {
282 #pragma omp parallel for
283  for(size_t ui=0;ui<ptArray.size();ui++)
284  {
285  for(unsigned int uj=0;uj<3;uj++)
286  {
287  bounds[uj][0]=std::min(bounds[uj][0],ptArray[ui].getPosRef()[uj]);
288  bounds[uj][1]=std::max(bounds[uj][1],ptArray[ui].getPosRef()[uj]);
289  }
290  }
291 
292 #ifdef DEBUG
293  for(unsigned int ui=0;ui<3;ui++)
294  {
295  if(bounds[ui][0] < bounds[ui][1])
296  valid[ui][0]=valid[ui][1]=true;
297  }
298 #endif
299 }
300 
301 
302 void BoundCube::getBounds(Point3D &low, Point3D &high) const
303 {
304  for(unsigned int ui=0; ui<3; ui++)
305  {
306  ASSERT(valid[ui][0] && valid[ui][1]);
307  low.setValue(ui,bounds[ui][0]);
308  high.setValue(ui,bounds[ui][1]);
309  }
310 }
311 
313 {
314  Point3D minPt;
315  for(unsigned int ui=0; ui<3; ui++)
316  {
317  ASSERT(valid[ui][0]);
318  minPt.setValue(ui,bounds[ui][0]);
319  }
320 
321  return minPt;
322 }
323 
325 {
326  Point3D maxPt;
327  for(unsigned int ui=0; ui<3; ui++)
328  {
329  ASSERT(valid[ui][1]);
330  maxPt.setValue(ui,bounds[ui][1]);
331  }
332 
333  return maxPt;
334 }
336 {
337  float f;
338  f=getSize(0);
339  f=std::max(getSize(1),f);
340  return std::max(getSize(2),f);
341 }
342 
343 float BoundCube::getSize(unsigned int dim) const
344 {
345  ASSERT(dim < 3);
346 #ifdef DEBUG
347  for(unsigned int ui=0;ui<3; ui++)
348  {
349  ASSERT(valid[0][1] && valid [0][0]);
350  }
351 #endif
352  return fabs(bounds[dim][1] - bounds[dim][0]);
353 }
354 
355 float BoundCube::getVolume() const
356 {
357  return getSize(2)*getSize(1)*getSize(0);
358 }
359 
360 bool BoundCube::contains(const BoundCube &b) const
361 {
362  Point3D low,high;
363  b.getBounds(low,high);
364  return containsPt(low) && containsPt(high);
365 }
366 
367 bool BoundCube::containsPt(const Point3D &p) const
368 {
369  for(unsigned int ui=0; ui<3; ui++)
370  {
371  ASSERT(valid[ui][0] && valid[ui][1]);
372  if( p[ui] < bounds[ui][0] || p[ui] > bounds[ui][1])
373  return false;
374  }
375 
376  return true;
377 }
378 
379 bool BoundCube::containedInSphere(const Point3D &origin, float radius) const
380 {
381  float sqrRad= radius*radius;
382  //Check each coordinate for the box, (hi, low)*(x,y,z)
383  for(size_t ui=0;ui<8;ui++)
384  {
385  Point3D p;
386  p[0] = bounds[0][ui&1];
387  p[1] = bounds[1][(ui&2) >> 1];
388  p[2] = bounds[2][(ui&4)>> 2];
389 
390  if(p.sqrDist(origin) >=sqrRad)
391  return false;
392  }
393 
394 
395 
396  return true;
397 }
398 
400 {
401  BoundCube res;
402  for(unsigned int dim=0;dim<3;dim++)
403  {
404  float a,b;
405  //Expand the lower bound down
406  a=bounds[dim][0]; b=bC.bounds[dim][0];
407  res.setBound(dim,0,std::min(a,b));
408  //Expand the upper bound up
409  a=bounds[dim][1]; b=bC.bounds[dim][1];
410  res.setBound(dim,1,std::max(a,b));
411  }
412 
413  return res;
414 }
415 
417 {
418  BoundCube res;
419  for(unsigned int dim=0;dim<3;dim++)
420  {
421  float a,b;
422  //Expand the lower bound down
423  a=bounds[dim][0]; b=bC.bounds[dim][0];
424  res.setBound(dim,0,std::max(a,b));
425  //Expand the upper bound up
426  a=bounds[dim][1]; b=bC.bounds[dim][1];
427  res.setBound(dim,1,std::min(a,b));
428  }
429 
430  return res;
431 }
432 
433 //checks intersection with sphere [centre,centre+radius)
434 bool BoundCube::intersects(const Point3D &pt, float sqrRad) const
435 {
436  Point3D nearPt;
437 
438  //Find the closest point on the cube to the sphere
439  unsigned int ui=2;
440  const float *val=pt.getValueArr()+ui;
441  do
442  {
443  if(*val <= bounds[ui][0])
444  {
445  nearPt.setValue(ui,bounds[ui][0]);
446  --val;
447  continue;
448  }
449 
450  if(*val >=bounds[ui][1])
451  {
452  nearPt.setValue(ui,bounds[ui][1]);
453  --val;
454  continue;
455  }
456 
457  nearPt.setValue(ui,*val);
458  --val;
459  }while(ui--);
460 
461  //now test the distance from nrPt to pt
462  return (nearPt.sqrDist(pt) < sqrRad);
463 }
464 
465 bool BoundCube::intersects(const BoundCube &b) const
466 {
467  Point3D p1,p2;
468 
469  //Check to see if the other cube contains either of our bounds
470  // If this is the case, we intersect
471  getBounds(p1,p2);
472  if(b.containsPt(p1) || b.containsPt(p2))
473  return true;
474 
475  //Check to see if the other cube's bounds are contined in this one
476  // this also implies intersection
477  b.getBounds(p1,p2);
478  if(containsPt(p1) || containsPt(p2))
479  return true;
480 
481  //No containment.
482  return false;
483 }
484 
485 
487 {
488 #ifdef DEBUG
489  for(unsigned int ui=0;ui<3; ui++)
490  {
491  ASSERT(valid[ui][1] && valid [ui][0]);
492  }
493 #endif
494  return Point3D(bounds[0][1] + bounds[0][0],
495  bounds[1][1] + bounds[1][0],
496  bounds[2][1] + bounds[2][0])/2.0f;
497 }
498 
499 float BoundCube::getMaxDistanceToBox(const Point3D &queryPt) const
500 {
501 #ifdef DEBUG
502  for(unsigned int ui=0;ui<3; ui++)
503  {
504  ASSERT(valid[ui][1] && valid [ui][0]);
505  }
506 #endif
507 
508  float maxDistSqr=0.0f;
509 
510  //Could probably be a bit more compact.
511 
512 
513  //Set lower and upper corners on the bounding rectangle
514  Point3D p[2];
515  p[0] = Point3D(bounds[0][0],bounds[1][0],bounds[2][0]);
516  p[1] = Point3D(bounds[0][1],bounds[1][1],bounds[2][1]);
517 
518  //Count binary-wise selecting upper and lower limits, to enumerate all 8 verticies.
519  for(unsigned int ui=0;ui<8; ui++)
520  {
521  maxDistSqr=std::max(maxDistSqr,
522  queryPt.sqrDist(Point3D(p[ui&1][0],p[(ui&2) >> 1][1],p[(ui&4) >> 2][2])));
523  }
524 
525  return sqrtf(maxDistSqr);
526 }
527 
528 
529 unsigned int BoundCube::segmentTriple(unsigned int dim, float slice) const
530 {
531  ASSERT(isValid(dim));
532  ASSERT(dim < 3);
533 
534  //check lower
535  if( slice < bounds[dim][0])
536  return 0;
537 
538  //check upper
539  if( slice >=bounds[dim][1])
540  return 2;
541 
542  return 1;
543 
544 }
545 
547 {
548  for(unsigned int ui=0;ui<3; ui++)
549  {
550  for(unsigned int uj=0;uj<2; uj++)
551  {
552 #ifdef DEBUG
553  valid[ui][uj] = b.valid[ui][uj];
554 #endif
555  bounds[ui][uj] = b.bounds[ui][uj];
556 
557  }
558  }
559 
560  return *this;
561 }
562 
563 std::ostream &operator<<(std::ostream &stream, const BoundCube& b)
564 {
565  stream << "Bounds :Low (";
566  stream << b.bounds[0][0] << ",";
567  stream << b.bounds[1][0] << ",";
568  stream << b.bounds[2][0] << ") , High (";
569 
570  stream << b.bounds[0][1] << ",";
571  stream << b.bounds[1][1] << ",";
572  stream << b.bounds[2][1] << ")" << std::endl;
573 
574 #ifdef DEBUG
575 
576  stream << "Bounds Valid: Low (";
577  stream << b.valid[0][0] << ",";
578  stream << b.valid[1][0] << ",";
579  stream << b.valid[2][0] << ") , High (";
580 
581  stream << b.valid[0][1] << ",";
582  stream << b.valid[1][1] << ",";
583  stream << b.valid[2][1] << ")" << std::endl;
584 #endif
585  return stream;
586 }
587 
588 #ifdef DEBUG
589 bool BoundCube::isValid() const
590 {
591  for(unsigned int ui=0;ui<3; ui++)
592  {
593  if(!valid[ui][0] || !valid[ui][1])
594  return false;
595  }
596 
597  return true;
598 }
599 
600 bool BoundCube::isValid(unsigned int dim) const
601 {
602  return (valid[dim][0] && valid[dim][1]);
603 }
604 
605 void BoundCube::setInvalid()
606 {
607  valid[0][0]=false; valid[1][0]=false; valid[2][0]=false;
608  valid[0][1]=false; valid[1][1]=false; valid[2][1]=false;
609 }
610 #endif
611 }
float sqrDist(const Point3D &pt) const
Returns the square of distance to another Point3D.
Definition: point3D.cpp:272
bool containsPt(const Point3D &pt) const
Check to see if the point is contained in, or part of the walls of the cube.
Definition: boundcube.cpp:367
void setInverseLimits()
Set the cube to be "inside out" at the limits of numeric results;.
Definition: boundcube.cpp:94
const float * getValueArr() const
Obtain a pointer to internal array (3 floats)
Definition: point3D.h:101
void setLimits()
Set min-max bounds to fp min/max.
Definition: boundcube.cpp:115
bool intersects(const Point3D &pt, float sqrRad) const
Checks if a point intersects a sphere of centre Pt, radius^2 sqrRad.
Definition: boundcube.cpp:434
void getBounds(Point3D &low, Point3D &high) const
Get the bounds of the cube as two points, the lower left (minimum bound) and upper right corner (max ...
Definition: boundcube.cpp:302
float getMaxDistanceToBox(const Point3D &pt) const
Returns maximum distance to box corners (which is an upper bound on max box distance).
Definition: boundcube.cpp:499
float getSize(unsigned int dim) const
Return the size of the side parallel to the given dimension.
Definition: boundcube.cpp:343
float getVolume() const
Obtain the volume of the cube.
Definition: boundcube.cpp:355
friend std::ostream & operator<<(std::ostream &stream, const BoundCube &b)
Definition: boundcube.cpp:563
Point3D max() const
Definition: boundcube.cpp:324
A 3D point data class storage.
Definition: point3D.h:39
unsigned int segmentTriple(unsigned int dim, float slice) const
Return a triplet to indicate a spatial partition value lies in.
Definition: boundcube.cpp:529
BoundCube makeUnion(const BoundCube &b) const
Create the box containing a union of two bounding cubes.
Definition: boundcube.cpp:399
float getLargestDim() const
Get the largest dimension of the bound cube.
Definition: boundcube.cpp:335
void setBound(unsigned int bound, unsigned int minMax, float value)
Set an individual bound.
Definition: boundcube.cpp:76
float getBound(unsigned int bound, unsigned int minMax) const
Return the bound on the given dimension.
Definition: boundcube.cpp:86
void setValue(unsigned int ui, float val)
Set value val of the ui-th dimension, ui in (0,1,2)
Definition: point3D.h:57
BoundCube makeIntersection(const BoundCube &b) const
Create the box which is the intersection of two bounding cubes this is either null, or a box.
Definition: boundcube.cpp:416
bool operator==(const BoundCube &other) const
Definition: boundcube.cpp:38
Helper class to define a bounding cube.
Definition: boundcube.h:29
bool containedInSphere(const Point3D &origin, float radius) const
Returns true if this box is contained by the sphere, represented by the origin+radius.
Definition: boundcube.cpp:379
bool isFlat() const
Returns true if any bound is of null thickness.
Definition: boundcube.cpp:136
#define ASSERT(f)
Point3D min() const
Definition: boundcube.cpp:312
Point3D getCentroid() const
Return the centroid.
Definition: boundcube.cpp:486
BoundCube operator=(const BoundCube &)
Definition: boundcube.cpp:546
bool contains(const BoundCube &b) const
Does this bounding box entirely contain another.
Definition: boundcube.cpp:360
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.
Definition: boundcube.cpp:49
void expand(const BoundCube &b)
Expand (as needed) volume such that the argument bounding cube is enclosed by this one...
Definition: boundcube.cpp:148