libatomprobe
Library for Atom Probe Tomography (APT) computation
point3D.cpp
Go to the documentation of this file.
1 /* point3D.cpp : 3D point primitive for libatomprobe
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 
22 
23 #include <limits>
24 #include <cstdlib>
25 #include <iostream>
26 #include <algorithm>
27 
28 #ifdef _OPENMP
29 #include <omp.h>
30 #endif
31 
32 
33 //FIXME: This is not the right place for this
34 #include <gsl/gsl_linalg.h>
35 #include <gsl/gsl_blas.h>
36 
37 namespace AtomProbe{
38 
39 bool Point3D::parse(const std::string &str)
40 {
41  using std::string;
42  using std::vector;
43 
44  //Needs to be at minimum #,#,#
45  if(str.size()< 5)
46  return false;
47 
48  string tmpStr;
49  tmpStr=stripWhite(str);
50 
51  //are we using polar notation? This is indicated by < ... >
52  bool polarNotation = (tmpStr[0] == '<' && tmpStr[tmpStr.size()-1] == '>');
53 
54  //Two strings must be in sync
55  std::string allowableStartChars, allowableEndChars;
56  allowableStartChars="([{<'";
57  allowableEndChars=")]}>'";
58 
59  //Find the start/end chars
60  size_t startPos,endPos;
61  startPos=allowableStartChars.find(tmpStr[0]);
62  endPos=allowableEndChars.find(tmpStr[tmpStr.size()-1]);
63 
64 
65  //Strip the start/end chars
66  if(startPos !=std::string::npos && endPos != std::string::npos)
67  tmpStr=tmpStr.substr(1,tmpStr.size()-1);
68  else if (startPos !=endPos)
69  return false; //we had one start bracket, but not the other...
70 
71  //First try splitting with non-whitespace separators,
72  // there should be exactly 3 components
73  vector<string> components;
74  const char *NONWHITE_SEPARATOR=",;|_";
75  splitStrsRef(tmpStr.c_str(),NONWHITE_SEPARATOR,
76  components);
77  if(components.size()!=3)
78  return false;
79  components.clear();
80 
81  //Now try splitting with whitespace components, dropping empty
82  // strings. As we have already checked the non-whitespace components
83  // additional components must be whitespace only, which is fine.
84 
85  const char *ALLOWABLE_SEPARATORS=",; \t|_";
86 
87  splitStrsRef(tmpStr.c_str(),ALLOWABLE_SEPARATORS,
88  components);
89  for(size_t ui=0;ui<components.size();ui++)
90  components[ui]=stripWhite(components[ui]);
91 
92  //Drop the blank bits from the field
93  vector<string>::iterator rmIt;
94  rmIt=std::remove(components.begin(),components.end(),string(""));
95  components.erase(rmIt,components.end());
96 
97  if(components.size()!=3)
98  return false;
99 
100  float p[3];
101  for(size_t ui=0;ui<3;ui++)
102  {
103  if(stream_cast(p[ui],components[ui]))
104  return false;
105  }
106 
107  if(!polarNotation)
108  setValueArr(p);
109  else
110  {
111  //r,theta,phi, as users should input
112  // <r,theta,phi>
113  //Convert from degrees to radiians
114  p[1]*=M_PI/180;
115  p[2]*=M_PI/180;
116 
117  //set spherical co-ordinates
118  setISOSpherical(p[0],p[1],p[2]);
119  }
120 
121 
122 
123  return true;
124 }
125 
126 
127 float Point3D::operator[](unsigned int ui) const
128 {
129  ASSERT(ui < 3);
130  return value[ui];
131 }
132 
133 float &Point3D::operator[](unsigned int ui)
134 {
135  ASSERT(ui < 3);
136  return value[ui];
137 }
138 
139 void Point3D::copyValueArr(float *valArr) const
140 {
141  ASSERT(valArr);
142  //compiler should unroll this automatically
143  for(unsigned int ui=0; ui<3; ui++)
144  {
145  *(valArr+ui) = *(value+ui);
146  }
147 }
148 
150 {
151  for(unsigned int ui=0;ui<3; ui++)
152  value[ui]-= pt.value[ui];
153 
154  return *this;
155 }
156 
157 bool Point3D::operator==(const Point3D &pt) const
158 {
159  return (value[0] == pt.value[0] && value[1] == pt.value[1] && value[2] == pt.value[2]);
160 }
161 
163 {
164  value [0] = pt.value[0];
165  value [1] = pt.value[1];
166  value [2] = pt.value[2];
167  return *this;
168 }
169 
171 {
172  for(unsigned int ui=0;ui<3; ui++)
173  value[ui]+= pt.value[ui];
174 
175  return *this;
176 }
177 
178 const Point3D Point3D::operator+(const Point3D &pt) const
179 {
180  Point3D ptTmp;
181 
182  for(unsigned int ui=0;ui<3; ui++)
183  ptTmp.value[ui] = value[ui] + pt.value[ui];
184 
185  return ptTmp;
186 }
187 
188 const Point3D Point3D::operator+(float f) const
189 {
190  Point3D tmp;
191  for(unsigned int ui=0;ui<3; ui++)
192  tmp.value[ui] = value[ui] + f;
193 
194  return tmp;
195 }
196 
197 const Point3D Point3D::operator-(const Point3D &pt) const
198 {
199  Point3D ptTmp;
200 
201  for(unsigned int ui=0;ui<3; ui++)
202  ptTmp.value[ui] = value[ui] - pt.value[ui];
203 
204  return ptTmp;
205 }
206 
208 {
209  Point3D ptTmp;
210 
211  for(unsigned int ui=0;ui<3; ui++)
212  ptTmp.value[ui] = -value[ui];
213 
214  return ptTmp;
215 }
216 
217 Point3D Point3D::operator*=(const float scale)
218 {
219  value[0] = value[0]*scale;
220  value[1] = value[1]*scale;
221  value[2] = value[2]*scale;
222 
223  return *this;
224 }
225 
226 const Point3D Point3D::operator*(float scale) const
227 {
228  Point3D tmpPt;
229 
230  tmpPt.value[0] = value[0]*scale;
231  tmpPt.value[1] = value[1]*scale;
232  tmpPt.value[2] = value[2]*scale;
233 
234  return tmpPt;
235 }
236 
237 const Point3D Point3D::operator*(const Point3D &pt) const
238 {
239  Point3D tmpPt;
240 
241  tmpPt.value[0] = value[0]*pt[0];
242  tmpPt.value[1] = value[1]*pt[1];
243  tmpPt.value[2] = value[2]*pt[2];
244 
245  return tmpPt;
246 }
247 
248 const Point3D Point3D::operator/(float scale) const
249 {
250  Point3D tmpPt;
251 
252  scale = 1.0f/scale;
253  tmpPt.value[0] = value[0]*scale;
254  tmpPt.value[1] = value[1]*scale;
255  tmpPt.value[2] = value[2]*scale;
256 
257  return tmpPt;
258 }
259 
260 const Point3D Point3D::operator/(const Point3D &pt) const
261 {
262  Point3D tmpPt;
263 
264  tmpPt.value[0] = value[0]/pt[0];
265  tmpPt.value[1] = value[1]/pt[1];
266  tmpPt.value[2] = value[2]/pt[2];
267 
268  return tmpPt;
269 }
270 
271 
272 float Point3D::sqrDist(const Point3D &pt) const
273 {
274  return (pt.value[0]-value[0])*(pt.value[0]-value[0])+
275  (pt.value[1]-value[1])*(pt.value[1]-value[1])+
276  (pt.value[2]-value[2])*(pt.value[2]-value[2]);
277 }
278 
279 float Point3D::dotProd(const Point3D &pt) const
280 {
281  //Return the inner product
282  return value[0]*pt.value[0] + value[1]*pt.value[1] + value[2]*pt.value[2];
283 }
284 
286 {
287  Point3D cross;
288 
289  cross.value[0] = (pt.value[2]*value[1] - pt.value[1]*value[2]);
290  cross.value[1] = (value[2]*pt.value[0] - pt.value[2]*value[0]);
291  cross.value[2] = (value[0]*pt.value[1] - value[1]*pt.value[0]);
292 
293 
294 
295  return cross;
296 }
297 
298 void Point3D::extend(float distance)
299 {
300  ASSERT(sqrMag() > 0.0f);
301 
302  Point3D p;
303  p=*this;
304  p.normalise();
305  *this+=p*distance;
306 }
307 
308 bool Point3D::insideBox(const Point3D &farPoint) const
309 {
310 
311  return (value[0] < farPoint.value[0] && value[0] >=0) &&
312  (value[1] < farPoint.value[1] && value[1] >=0) &&
313  (value[2] < farPoint.value[2] && value[2] >=0);
314 }
315 
316 bool Point3D::insideBox(const Point3D &lowPt,const Point3D &highPt) const
317 {
318 
319  return (value[0] < highPt.value[0] && value[0] >=lowPt.value[0]) &&
320  (value[1] < highPt.value[1] && value[1] >=lowPt.value[1]) &&
321  (value[2] < highPt.value[2] && value[2] >=lowPt.value[2]);
322 }
323 
324 //This is different to +=, because it generates no return value
325 void Point3D::add(const Point3D &obj)
326 {
327  value[0] = obj.value[0] + value[0];
328  value[1] = obj.value[1] + value[1];
329  value[2] = obj.value[2] + value[2];
330 }
331 
332 float Point3D::sqrMag() const
333 {
334  return value[0]*value[0] + value[1]*value[1] + value[2]*value[2];
335 }
336 
338 {
339  float mag = sqrtf(sqrMag());
340 
341  value[0]/=mag;
342  value[1]/=mag;
343  value[2]/=mag;
344 
345 }
346 
348 {
349  Point3D ret;
350  float mag = sqrtf(sqrMag());
351 
352  ret[0]=value[0]/mag;
353  ret[1]=value[1]/mag;
354  ret[2]=value[2]/mag;
355 
356  return ret;
357 }
359 {
360  value[0] = -value[0];
361  value[1] = -value[1];
362  value[2] = -value[2];
363 }
364 
366 {
367  value[0] = 1.0/value[0];
368  value[1] = 1.0/value[1];
369  value[2] = 1.0/value[2];
370 }
371 
373 {
374  Point3D crossp;
375  crossp=this->crossProd(pt);
376 
377  //They are co-linear, or near-enough to be not resolvable.
378  if(crossp.sqrMag() < sqrt(std::numeric_limits<float>::epsilon()))
379  return false;
380  crossp.normalise();
381 
382  crossp=crossp.crossProd(pt);
383  *this=crossp.normal()*sqrt(this->sqrMag());
384 
385  return true;
386 }
387 
388 float Point3D::angle(const Point3D &pt) const
389 {
390  return acos(dotProd(pt)/(sqrtf(sqrMag()*pt.sqrMag())));
391 }
392 
393 void Point3D::getCentroid(const std::vector<Point3D> &points,Point3D &centroid)
394 {
395  centroid=Point3D(0,0,0);
396  size_t nPoints=points.size();
397 #ifdef _OPENMP
398 
399  //Parallel version
400  //--
401  std::vector<Point3D> centroids(omp_get_max_threads(),Point3D(0,0,0));
402 #pragma omp parallel for
403  for(size_t ui=0;ui<nPoints;ui++)
404  centroids[omp_get_thread_num()]+=points[ui];
405 
406  for(size_t ui=0;ui<centroids.size();ui++)
407  centroid+=centroids[ui];
408  //--
409 
410 #else
411  for(unsigned int ui=0;ui<nPoints;ui++)
412  centroid+=points[ui];
413 #endif
414 
415  centroid*=1.0f/(float)nPoints;
416 }
417 std::ostream& operator<<(std::ostream &stream, const Point3D &pt)
418 {
419  stream << "(" << pt.value[0] << "," << pt.value[1]
420  << "," << pt.value[2] << ")";
421  return stream;
422 }
423 
424 
425 void Point3D::setISOSpherical(float r,float theta, float phi)
426 {
427  value[0] = r*sin(theta)*cos(phi);
428  value[1] = r*sin(theta)*sin(phi);
429  value[2] = r*cos(theta);
430 }
431 
432 
433 void Point3D::getISOSpherical(float &r,float &theta, float &phi) const
434 {
435  r=sqrt(sqrMag());
436  if(r < std::numeric_limits<float>::epsilon())
437  {
438  theta=phi=0;
439  return;
440  }
441  theta =acos(value[2]/r);
442  phi =atan2(value[1],value[0]);
443 }
444 
445 void Point3D::transform3x3(const gsl_matrix* matrix)
446 {
447  float newValue[3];
448  for(unsigned int row=0;row<3;row++)
449  {
450  newValue[row]=0;
451 
452  for(unsigned int col=0;col<3;col++)
453  {
454 
455  newValue[row]+= gsl_matrix_get(matrix,row,col)*value[col];
456  }
457  }
458 
459  value[0]=newValue[0];
460  value[1]=newValue[1];
461  value[2]=newValue[2];
462 }
463 
464 #ifdef __LITTLE_ENDIAN__
465 void Point3D::switchEndian()
466 {
467  floatSwapBytes(&value[0]);
468  floatSwapBytes(&value[1]);
469  floatSwapBytes(&value[2]);
470 }
471 #endif
472 #ifdef DEBUG
473 
474 #include "helper/helpFuncs.h"
475 
476 bool testPoint3D()
477 {
478 
479  Point3D p1;
480  p1.parse("(1,0,0)");
481  Point3D p2;
482  p2.parse("<1,0,0>");
483 
484  TEST(p1 == Point3D(1,0,0),"Parse check");
485  TEST(p2 == Point3D(0,0,1),"parse check (spherical)");
486 
487  TEST(p2.mag() == 1.0,"mag check");
488 
489  p1=Point3D(1,1,1);
490 
491  TEST(TOL_EQ(p1.dotProd(p1),(3.0)),"Dot product");
492 
493  p1=Point3D(1,0,0);
494  p2=Point3D(0,1,0);
495 
496  TEST(TOL_EQ(
497  (p1.crossProd(p2) - Point3D(0,0,1)).sqrMag(),0),"cross prod");
498 
499  return true;
500 }
501 
502 #endif
503 }
float sqrDist(const Point3D &pt) const
Returns the square of distance to another Point3D.
Definition: point3D.cpp:272
void reciprocal()
Makes each value its reciprocal (1/X, 1/Y, 1/Z)
Definition: point3D.cpp:365
void negate()
Makes each value negative of old value (-X, -Y, -Z)
Definition: point3D.cpp:358
float operator[](unsigned int ui) const
Array indexing operator, Point3D[1] returns the value of the ui-th dim.
Definition: point3D.cpp:127
const Point3D operator*(float scale) const
Scalar multiplication (X*f, Y*f, Z*f)
Definition: point3D.cpp:226
Point3D crossProd(const Point3D &pt) const
Calculate the cross product of this and another point.
Definition: point3D.cpp:285
std::string stripWhite(const std::string &str)
Strip whitespace, (eg tab,space) from either side of a string.
const Point3D & operator+=(const Point3D &pt)
+= operator
Definition: point3D.cpp:170
Point3D()
Constructor with no initialisation.
Definition: point3D.h:46
#define TEST(f, g)
Definition: aptAssert.h:49
void copyValueArr(float *value) const
Copy data from internal into target array of length 3 : Pointer MUST be allocated.
Definition: point3D.cpp:139
bool orthogonalise(const Point3D &p)
Perform a cross-product based orthogonalisation with the specified vector.
Definition: point3D.cpp:372
void getISOSpherical(float &radius, float &theta, float &phi) const
Get the Point3D value as spherical coordinates (ISO 30-11)
Definition: point3D.cpp:433
const Point3D operator+(const Point3D &pt) const
Addition of Point3D objects (X1+X2, Y1+Y2, Z1+Z2)
Definition: point3D.cpp:178
float sqrMag() const
Returns magnitude^2, taking this as a position vector.
Definition: point3D.cpp:332
void splitStrsRef(const char *cpStr, const char delim, std::vector< std::string > &v)
Split string references using a single delimiter.
A 3D point data class storage.
Definition: point3D.h:39
void setISOSpherical(float radius, float theta, float phi)
Assign the vector using spherical coordinates.
Definition: point3D.cpp:425
bool parse(const std::string &s)
Set from string representation.
Definition: point3D.cpp:39
float angle(const Point3D &pt) const
Calculate the angle between two position vectors in radians.
Definition: point3D.cpp:388
#define M_PI
Definition: kd-example.cpp:34
float mag() const
Magnitude of position vector.
Definition: point3D.h:197
Point3D normal() const
Return point unit magnitude, maintianing direction.
Definition: point3D.cpp:347
const Point3D & operator-=(const Point3D &pt)
-= operator
Definition: point3D.cpp:149
friend std::ostream & operator<<(std::ostream &stream, const Point3D &)
Output streaming operator. Streams values in the text format (x,y,z)
Definition: point3D.cpp:417
void setValueArr(const float *val)
Set value by pointer (X, Y, Z from array of len 3)
Definition: point3D.h:90
void transform3x3(const gsl_matrix *matrix)
Perform a 3x3 matrix transformation using a GSL matrix.
Definition: point3D.cpp:445
void floatSwapBytes(float *inFloat)
Definition: endianTest.h:58
void normalise()
Make point unit magnitude, maintaining direction.
Definition: point3D.cpp:337
Point3D operator*=(const float scale)
*= operator, multiplies the whole Point3D by a scalar
Definition: point3D.cpp:217
#define ASSERT(f)
bool operator==(const Point3D &pt) const
Equality operator.
Definition: point3D.cpp:157
const Point3D operator-() const
Negation, Returns a Point3D object with the negative of the previous value.
Definition: point3D.cpp:207
void add(const Point3D &obj)
Add a point to this, without generating a return value.
Definition: point3D.cpp:325
const Point3D & operator=(const Point3D &pt)
Assignment operator.
Definition: point3D.cpp:162
bool stream_cast(T1 &result, const T2 &obj)
Template function to cast and object to another by the stringstream.
Definition: stringFuncs.h:32
const Point3D operator/(float scale) const
Scalar division of Point3D by scale (X/scale, Y/scale, Z/scale)
Definition: point3D.cpp:248
bool insideBox(const Point3D &farPoint) const
Is this point inside a box bounded by orign and farPoint?
Definition: point3D.cpp:308
float dotProd(const Point3D &pt) const
Calculate the dot product of this and another point.
Definition: point3D.cpp:279
void extend(float distance)
Extend the vector by the specified distance.
Definition: point3D.cpp:298
static void getCentroid(const std::vector< Point3D > &pts, Point3D &p)
find the centroid of a set of points
Definition: point3D.cpp:393