ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/group/trunk/OOPSE-4/src/openbabel/vector3.cpp
Revision: 2440
Committed: Wed Nov 16 19:42:11 2005 UTC (18 years, 8 months ago) by tim
File size: 9072 byte(s)
Log Message:
adding openbabel

File Contents

# User Rev Content
1 tim 2440 /**********************************************************************
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 doubleing
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 doubleing
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     doubleing 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     OBAPI double CalcTorsionAngle(const vector3 &a, const vector3 &b,
228     const vector3 &c, const vector3 &d)
229     {
230     double torsion;
231     vector3 b1,b2,b3,c1,c2,c3;
232    
233     b1 = a - b;
234     b2 = b - c;
235     b3 = c - d;
236    
237     c1 = cross(b1,b2);
238     c2 = cross(b2,b3);
239     c3 = cross(c1,c2);
240    
241     if (c1.length() * c2.length() < 0.001)
242     torsion = 0.0;
243     else
244     {
245     torsion = vectorAngle(c1,c2);
246     if (dot(b2,c3) > 0.0)
247     torsion *= -1.0;
248     }
249    
250     return(torsion);
251     }
252    
253     /*! This method checks if the current vector *this is zero
254     (i.e. if all entries == 0.0). If so, a warning message is
255     printed, and the whole program is aborted with exit(0).
256     Otherwise, a vector of length one is generated, which is
257     orthogonal to *this, and stored in v. The resulting vector is
258     not random.
259    
260     \warning If the entries of the *this (in particular the
261     z-component) are very close to zero, but not == 0.0, this
262     method may behave in unexpected ways and return almost random
263     results; details may depend on your particular floating point
264     implementation. The use of this method is therefore highly
265     discouraged, unless you are certain that all components of
266     *this are in a reasonable range, away from 0.0 (Stefan
267     Kebekus)
268    
269     \deprecated This method will probably replaced by a safer
270     algorithm in the future.
271    
272     \todo Replace this method with a more fool-proof version that
273     does not call exit()
274    
275     @param res a reference to a vector where the result will be
276     stored
277     */
278     void vector3::createOrthoVector(vector3 &res) const
279     {
280     vector3 cO;
281    
282     if ( ( IsNearZero(this->x())) && (IsNearZero(this->y())) )
283     {
284     if ( IsNearZero(this->z()) )
285     {
286     cerr << "makeorthovec zero vector" << endl;
287     exit(0);
288     }
289     cO.SetX(1.0);
290     }
291     else
292     {
293     cO.SetZ(1.0);
294     }
295     res= cross(cO,*this);
296     res.normalize();
297     }
298    
299     const vector3 VZero ( 0.0, 0.0, 0.0 ) ;
300     const vector3 VX ( 1.0, 0.0, 0.0 ) ;
301     const vector3 VY ( 0.0, 1.0, 0.0 ) ;
302     const vector3 VZ ( 0.0, 0.0, 1.0 ) ;
303    
304     /* Calculate the distance of point a to the plane determined by b,c,d */
305     double Point2Plane(vector3 a, vector3 b, vector3 c, vector3 d)
306     {
307     double angle =0;
308     double dist_ab =0;
309     vector3 v_ba = a-b;
310     vector3 v_normal = cross(c-b, d-b).normalize();
311     angle = vectorAngle(v_normal, v_ba);
312     dist_ab = v_ba.length();
313     return fabs(dist_ab * cos(DEG_TO_RAD * angle));
314     }
315    
316     } // namespace OpenBabel
317    
318     //! \file vector3.cpp
319     //! \brief Handle 3D coordinates.