ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/OpenMD/trunk/src/openbabel/vector3.cpp
Revision: 1081
Committed: Thu Oct 19 20:49:05 2006 UTC (18 years, 6 months ago) by gezelter
File size: 9733 byte(s)
Log Message:
updated OpenBabel to version 2.0.2

File Contents

# Content
1 /**********************************************************************
2 vector3.cpp - Handle 3D coordinates.
3
4 Copyright (C) 1998-2001 by OpenEye Scientific Software, Inc.
5 Some portions Copyright (C) 2001-2005 by Geoffrey R. Hutchison
6
7 This file is part of the Open Babel project.
8 For more information, see <http://openbabel.sourceforge.net/>
9
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation version 2 of the License.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18 ***********************************************************************/
19
20 #include <math.h>
21
22 #include "mol.hpp"
23 #include "vector3.hpp"
24
25 using namespace std;
26
27 namespace OpenBabel
28 {
29
30 /*! \class vector3
31 \brief Represents a vector in the 3-dimensional real space.
32
33 The vector3 class was designed to simplify operations with floating
34 point coordinates. To this end many of the common operations have been
35 overloaded for simplicity. Vector addition, subtraction, scalar
36 multiplication, dot product, cross product, magnitude and a number of
37 other utility functions are built in to the vector class. For a full
38 description of the class member functions please consult the header
39 file vector3.h. The following code demonstrates several of the
40 functions of the vector class:
41 \code
42 vector3 v1,v2,v3;
43 v1 = VX;
44 v2 = VY;
45 v3 = cross(v1,v2);
46 v3 *= 2.5;
47 v3.normalize();
48 \endcode
49 */
50
51 /*! This (slow) method allows to access the elements of the
52 vector as if it were an array of doubles. If the index is > 2,
53 then a warning is printed, and the program is terminated via
54 exit(-1). Otherwise, if i is 0, 1 or 2, then a reference to x,
55 y or z is returned, respectively.
56
57 \warning This method is primarily designed to facilitate the
58 integration ('Open Babelization') of code that uses arrays of
59 doubles rather than the vector class. Due to the error checks
60 the method is of course very slow and should therefore be
61 avoided in production code.
62 */
63 double& vector3::operator[] ( unsigned int i)
64 {
65 if (i > 2)
66 {
67 cerr << "ERROR in OpenBabel::vector3::operator[]" << endl
68 << "The method has been called with an illegal index i=" << i << "." << endl
69 << "Please contact the author of the offending program immediately." << endl;
70 exit(-1);
71 }
72 if (i == 0)
73 return _vx;
74 if (i == 1)
75 return _vy;
76 return _vz;
77 }
78
79 /*! replaces *this with a random unit vector, which is (supposed
80 to be) uniformly distributed over the unit sphere. Uses the
81 random number generator obRand, or uses the system number
82 generator with a time seed if obRand == NULL.
83
84 @param obRandP random number generator to use, or 0L, if the
85 system random number generator (with time seed) should be used
86 */
87 void vector3::randomUnitVector(OBRandom *obRandP)
88 {
89 OBRandom *ptr;
90 if (!obRandP)
91 {
92 ptr = new OBRandom(true);
93 ptr->TimeSeed();
94 }
95 else
96 ptr = obRandP;
97
98 // obtain a random vector with 0.001 <= length^2 <= 1.0, normalize
99 // the vector to obtain a random vector of length 1.0.
100 double l;
101 do
102 {
103 this->Set(ptr->NextFloat()-0.5, ptr->NextFloat()-0.5, ptr->NextFloat()-0.5);
104 l = length_2();
105 }
106 while ( (l > 1.0) || (l < 1e-4) );
107 this->normalize();
108
109 if (!obRandP)
110 delete ptr;
111 }
112
113 OBAPI ostream& operator<< ( ostream& co, const vector3& v )
114 {
115 co << "< " << v._vx << ", " << v._vy << ", " << v._vz << " >" ;
116 return co ;
117 }
118
119 OBAPI int operator== ( const vector3& v1, const vector3& v2 )
120 {
121 if ( ( v1._vx == v2._vx ) &&
122 ( v1._vy == v2._vy ) &&
123 ( v1._vz == v2._vz ) )
124 return ( true ) ;
125 else
126 return ( false ) ;
127 }
128
129 OBAPI int operator!= ( const vector3& v1, const vector3& v2 )
130 {
131 if ( ( v1._vx != v2._vx ) ||
132 ( v1._vy != v2._vy ) ||
133 ( v1._vz != v2._vz ) )
134 return ( true ) ;
135 else
136 return ( false ) ;
137 }
138
139 /*! This method checks if the current vector has length() ==
140 0.0. If so, *this remains unchanged. Otherwise, *this is
141 scaled by 1.0/length().
142
143 \warning If length() is very close to zero, but not == 0.0,
144 this method may behave in unexpected ways and return almost
145 random results; details may depend on your particular floating
146 point implementation. The use of this method is therefore
147 highly discouraged, unless you are certain that length() is in
148 a reasonable range, away from 0.0 (Stefan Kebekus)
149
150 \deprecated This method will probably replaced by a safer
151 algorithm in the future.
152
153 \todo Replace this method with a more fool-proof version.
154
155 @returns a reference to *this
156 */
157 vector3& vector3 :: normalize ()
158 {
159 double l = length ();
160
161 if (IsNearZero(l))
162 return(*this);
163
164 _vx = _vx / l ;
165 _vy = _vy / l ;
166 _vz = _vz / l ;
167
168 return(*this);
169 }
170
171 OBAPI double dot ( const vector3& v1, const vector3& v2 )
172 {
173 return v1._vx*v2._vx + v1._vy*v2._vy + v1._vz*v2._vz ;
174 }
175
176 OBAPI vector3 cross ( const vector3& v1, const vector3& v2 )
177 {
178 vector3 vv ;
179
180 vv._vx = v1._vy*v2._vz - v1._vz*v2._vy ;
181 vv._vy = - v1._vx*v2._vz + v1._vz*v2._vx ;
182 vv._vz = v1._vx*v2._vy - v1._vy*v2._vx ;
183
184 return ( vv ) ;
185 }
186
187
188 /*! This method calculates the angle between two vectors
189
190 \warning If length() of any of the two vectors is == 0.0,
191 this method will divide by zero. If the product of the
192 length() of the two vectors is very close to 0.0, but not ==
193 0.0, this method may behave in unexpected ways and return
194 almost random results; details may depend on your particular
195 floating point implementation. The use of this method is
196 therefore highly discouraged, unless you are certain that the
197 length()es are in a reasonable range, away from 0.0 (Stefan
198 Kebekus)
199
200 \deprecated This method will probably replaced by a safer
201 algorithm in the future.
202
203 \todo Replace this method with a more fool-proof version.
204
205 @returns the angle in degrees (0-360)
206 */
207 OBAPI double vectorAngle ( const vector3& v1, const vector3& v2 )
208 {
209 double mag;
210 double dp;
211
212 mag = v1.length() * v2.length();
213 dp = dot(v1,v2)/mag;
214
215 if (dp < -0.999999)
216 dp = -0.9999999;
217
218 if (dp > 0.9999999)
219 dp = 0.9999999;
220
221 if (dp > 1.0)
222 dp = 1.0;
223
224 return((RAD_TO_DEG * acos(dp)));
225 }
226
227 /*! This function calculates the torsion angle of three vectors, represented
228 by four points A--B--C--D, i.e. B and C are vertexes, but none of A--B,
229 B--C, and C--D are colinear. A "torsion angle" is the amount of "twist"
230 or torsion needed around the B--C axis to bring A--B into the same plane
231 as B--C--D. The torsion is measured by "looking down" the vector B--C so
232 that B is superimposed on C, then noting how far you'd have to rotate
233 A--B to superimpose A over D. Angles are + in the anticlockwise
234 direction. The operation is symmetrical in that if you reverse the image
235 (look from C to B and rotate D over A), you get the same answer.
236 */
237
238 OBAPI double CalcTorsionAngle(const vector3 &a, const vector3 &b,
239 const vector3 &c, const vector3 &d)
240 {
241 double torsion;
242 vector3 b1,b2,b3,c1,c2,c3;
243
244 b1 = a - b;
245 b2 = b - c;
246 b3 = c - d;
247
248 c1 = cross(b1,b2);
249 c2 = cross(b2,b3);
250 c3 = cross(c1,c2);
251
252 if (c1.length() * c2.length() < 0.001)
253 torsion = 0.0;
254 else
255 {
256 torsion = vectorAngle(c1,c2);
257 if (dot(b2,c3) > 0.0)
258 torsion *= -1.0;
259 }
260
261 return(torsion);
262 }
263
264 /*! This method checks if the current vector *this is zero
265 (i.e. if all entries == 0.0). If so, a warning message is
266 printed, and the whole program is aborted with exit(0).
267 Otherwise, a vector of length one is generated, which is
268 orthogonal to *this, and stored in v. The resulting vector is
269 not random.
270
271 \warning If the entries of the *this (in particular the
272 z-component) are very close to zero, but not == 0.0, this
273 method may behave in unexpected ways and return almost random
274 results; details may depend on your particular floating point
275 implementation. The use of this method is therefore highly
276 discouraged, unless you are certain that all components of
277 *this are in a reasonable range, away from 0.0 (Stefan
278 Kebekus)
279
280 \deprecated This method will probably replaced by a safer
281 algorithm in the future.
282
283 \todo Replace this method with a more fool-proof version that
284 does not call exit()
285
286 @param res a reference to a vector where the result will be
287 stored
288 */
289 void vector3::createOrthoVector(vector3 &res) const
290 {
291 vector3 cO;
292
293 if ( ( IsNearZero(this->x())) && (IsNearZero(this->y())) )
294 {
295 if ( IsNearZero(this->z()) )
296 {
297 cerr << "makeorthovec zero vector" << endl;
298 exit(0);
299 }
300 cO.SetX(1.0);
301 }
302 else
303 {
304 cO.SetZ(1.0);
305 }
306 res= cross(cO,*this);
307 res.normalize();
308 }
309
310 const vector3 VZero ( 0.0, 0.0, 0.0 ) ;
311 const vector3 VX ( 1.0, 0.0, 0.0 ) ;
312 const vector3 VY ( 0.0, 1.0, 0.0 ) ;
313 const vector3 VZ ( 0.0, 0.0, 1.0 ) ;
314
315 /* Calculate the distance of point a to the plane determined by b,c,d */
316 double Point2Plane(vector3 a, vector3 b, vector3 c, vector3 d)
317 {
318 double angle =0;
319 double dist_ab =0;
320 vector3 v_ba = a-b;
321 vector3 v_normal = cross(c-b, d-b).normalize();
322 angle = vectorAngle(v_normal, v_ba);
323 dist_ab = v_ba.length();
324 return fabs(dist_ab * cos(DEG_TO_RAD * angle));
325 }
326
327 } // namespace OpenBabel
328
329 //! \file vector3.cpp
330 //! \brief Handle 3D coordinates.