libatomprobe
Library for Atom Probe Tomography (APT) computation
quat.cpp
Go to the documentation of this file.
1 /*
2  * quat.cpp - quaternion functions
3  * Copyright (C) 2018, D Haley
4 
5  * This program is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation, either version 3 of the License, or
8  * (at your option) any later version.
9 
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14 
15  * You should have received a copy of the GNU General Public License
16  * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18 
19 #include <gsl/gsl_blas.h>
20 
23 
24 using std::string;
25 using std::vector;
26 
27 namespace AtomProbe
28 {
29 //needed for sincos
30 #ifdef __LINUX__
31 #ifdef __GNUC__
32 #ifndef _GNU_SOURCE
33 #define _GNU_SOURCE
34 #endif
35 #endif
36 #endif
37 
38 //quaternion multiplication, assuming q2 has no "a" component
39 void quat_mult_no_second_a(Quaternion *result, const Quaternion *q1, const Quaternion *q2)
40 {
41  result->a = (-q1->b*q2->b-q1->c*q2->c -q1->d*q2->d);
42  result->b = (q1->a*q2->b +q1->c*q2->d -q1->d*q2->c);
43  result->c = (q1->a*q2->c -q1->b*q2->d +q1->d*q2->b);
44  result->d = (q1->a*q2->d +q1->b*q2->c -q1->c*q2->b );
45 }
46 
47 //this is a little optimisation that doesn't calculate the "a" component for
48 //the returned quaternion, and implicitly performs conjugation.
49 //Note that the result is specific to quaternion rotation
50 void quat_pointmult(Point3f *result, const Quaternion *q1, const Quaternion *q2)
51 {
52  result->fx = (-q1->a*q2->b +q1->b*q2->a -q1->c*q2->d +q1->d*q2->c);
53  result->fy = (-q1->a*q2->c +q1->b*q2->d +q1->c*q2->a -q1->d*q2->b);
54  result->fz = (-q1->a*q2->d -q1->b*q2->c +q1->c*q2->b +q1->d*q2->a);
55 
56 }
57 
58 //Inefficient Point3D version
59 void quat_rot(Point3D &p, const Point3D &r, float angle)
60 {
61  Point3f pP,rR;
62 
63  pP.fx =p[0]; pP.fy =p[1]; pP.fz =p[2];
64  rR.fx =r[0]; rR.fy =r[1]; rR.fz =r[2];
65 
66  quat_rot(&pP,&rR,angle);
67 
68  p[0] = pP.fx; p[1] =pP.fy; p[2] = pP.fz;
69 }
70 
71 
72 //Uses quaternion mathematics to perform a rotation around your favourite axis
73 //IMPORTANT: Rotvec must be normalised before passing to this function
74 //failure to do so will have weird results.
75 //For better performance on multiple rotations, use other function
76 //Note result is stored in returned point
77 void quat_rot(Point3f *point, const Point3f *rotVec, float angle)
78 {
79  ASSERT(rotVec->fx*rotVec->fx + rotVec->fy*rotVec->fy + rotVec->fz*rotVec->fz - 1.0f <
80  5.0f*sqrtf(std::numeric_limits<float>::epsilon()));
81 
82  double sinCoeff;
83  Quaternion rotQuat;
84  Quaternion pointQuat;
85  Quaternion temp;
86 
87  //remember this value so we don't recompute it
88 #ifdef _GNU_SOURCE
89  double cosCoeff;
90  //GNU provides sincos which is about twice the speed of sin/cos separately
91  sincos(angle*0.5f,&sinCoeff,&cosCoeff);
92  rotQuat.a=cosCoeff;
93 #else
94  angle*=0.5f;
95  sinCoeff=sin(angle);
96 
97  rotQuat.a = cos(angle);
98 #endif
99  rotQuat.b=sinCoeff*rotVec->fx;
100  rotQuat.c=sinCoeff*rotVec->fy;
101  rotQuat.d=sinCoeff*rotVec->fz;
102 
103 // pointQuat.a =0.0f; This is implied in the pointQuat multiplication function
104  pointQuat.b = point->fx;
105  pointQuat.c = point->fy;
106  pointQuat.d = point->fz;
107 
108 
109  //perform rotation
110  quat_mult_no_second_a(&temp,&rotQuat,&pointQuat);
111  quat_pointmult(point, &temp,&rotQuat);
112 
113 }
114 
115 void quat_rot_array(Point3D *pointArr, unsigned int n,
116  const Point3f *rotVec, float angle)
117 {
118  Point3f *fArr;
119  fArr = new Point3f[n];
120 
121  for(size_t ui=0;ui<n;ui++)
122  {
123  fArr[ui].fx = pointArr[ui][0];
124  fArr[ui].fy = pointArr[ui][1];
125  fArr[ui].fz = pointArr[ui][2];
126  }
127 
128  quat_rot_array(fArr,n,rotVec,angle);
129 
130  for(size_t ui=0;ui<n;ui++)
131  {
132  pointArr[ui][0]=fArr[ui].fx;
133  pointArr[ui][1]=fArr[ui].fy;
134  pointArr[ui][2]=fArr[ui].fz;
135  }
136 
137  delete[] fArr;
138 }
139 void quat_rot_array(Point3f *pointArr, unsigned int n,
140  const Point3f *rotVec, float angle)
141 {
142  Quaternion rotQuat;
143  Quaternion pointQuat;
144  Quaternion temp;
145  {
146  ASSERT(rotVec->fx*rotVec->fx + rotVec->fy*rotVec->fy + rotVec->fz*rotVec->fz - 1.0f <
147  5.0f*sqrtf(std::numeric_limits<float>::epsilon()));
148 
149  double sinCoeff;
150 
151  //remember this value so we don't recompute it
152  #ifdef _GNU_SOURCE
153  double cosCoeff;
154  //GNU provides sincos which is about twice the speed of sin/cos separately
155  sincos(angle*0.5f,&sinCoeff,&cosCoeff);
156  rotQuat.a=cosCoeff;
157  #else
158  angle*=0.5f;
159  sinCoeff=sin(angle);
160 
161  rotQuat.a = cos(angle);
162  #endif
163  rotQuat.b=sinCoeff*rotVec->fx;
164  rotQuat.c=sinCoeff*rotVec->fy;
165  rotQuat.d=sinCoeff*rotVec->fz;
166 
167  for(unsigned int ui=0;ui<n; ui++)
168  {
169  // pointQuat.a =0.0f; This is implied in the pointQuat multiplication function
170  pointQuat.b = pointArr[ui].fx;
171  pointQuat.c = pointArr[ui].fy;
172  pointQuat.d = pointArr[ui].fz;
173 
174 
175  //perform rotation
176  quat_mult_no_second_a(&temp,&rotQuat,&pointQuat);
177  quat_pointmult(pointArr+ui, &temp,&rotQuat);
178 
179  }
180  }
181 }
182 
183 //Retrieve the quaternion for repeated rotation. Pass to the quat_rot_apply_quats
184 void quat_get_rot_quat(const Point3f *rotVec, float angle,Quaternion *rotQuat)
185 {
186  ASSERT(rotVec->fx*rotVec->fx + rotVec->fy*rotVec->fy + rotVec->fz*rotVec->fz - 1.0f <
187  5.0f*sqrtf(std::numeric_limits<float>::epsilon()));
188  double sinCoeff;
189 #ifdef _GNU_SOURCE
190  double cosCoeff;
191  //GNU provides sincos which is about twice the speed of sin/cos separately
192  sincos(angle*0.5f,&sinCoeff,&cosCoeff);
193  rotQuat->a=cosCoeff;
194 #else
195  angle*=0.5f;
196  sinCoeff=sin(angle);
197  rotQuat->a = cos(angle);
198 #endif
199 
200  rotQuat->b=sinCoeff*rotVec->fx;
201  rotQuat->c=sinCoeff*rotVec->fy;
202  rotQuat->d=sinCoeff*rotVec->fz;
203 }
204 
205 //Use previously generated quats from quat_get_rot_quats to rotate a point
206 void quat_rot_apply_quat(Point3f *point, const Quaternion *rotQuat)
207 {
208  Quaternion pointQuat,temp;
209 // pointQuat.a =0.0f; No need to set this, as we do not use it in the multiplication function
210  pointQuat.b = point->fx;
211  pointQuat.c = point->fy;
212  pointQuat.d = point->fz;
213  //perform rotation
214  quat_mult_no_second_a(&temp,rotQuat,&pointQuat);
215  quat_pointmult(point, &temp,rotQuat);
216 }
217 
218 //Invert the given quaternion (this for example, can generate the inverse rotation)
220 {
221  quat->b=-quat->b;
222  quat->c=-quat->c;
223  quat->d=-quat->d;
224 }
225 }
226 
void quat_mult_no_second_a(Quaternion *result, const Quaternion *q1, const Quaternion *q2)
Definition: quat.cpp:39
void quat_get_rot_quat(const Point3f *rotVec, float angle, Quaternion *rotQuat)
Compute the quaternion for specified rotation.
Definition: quat.cpp:184
void quat_rot_apply_quat(Point3f *point, const Quaternion *rotQuat)
Use previously generated quats from quat_get_rot_quats to rotate a point.
Definition: quat.cpp:206
void quat_pointmult(Point3f *result, const Quaternion *q1, const Quaternion *q2)
Definition: quat.cpp:50
A 3D point data class storage.
Definition: point3D.h:39
Data storage structure for points.
Definition: quat.h:45
Data storage structure for quaternions.
Definition: quat.h:35
#define ASSERT(f)
void quat_rot(Point3D &p, const Point3D &r, float angle)
Rotate a point around a given rotation axis by a specified angle.
Definition: quat.cpp:59
void quat_rot_array(Point3f *point, unsigned int n, const Point3f *rotVec, float angle)
Rotate each point in array of size n around a given vector, with specified angle. ...
Definition: quat.cpp:139
void quat_invert(Quaternion *quat)
Definition: quat.cpp:219