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

File Contents

# Content
1 /**********************************************************************
2 matrix3x3.cpp - Handle 3D rotation matrix.
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 "matrix3x3.hpp"
24
25 #ifndef true
26 #define true 1
27 #endif
28
29 #ifndef false
30 #define false 0
31 #endif
32
33 using namespace std;
34
35 namespace OpenBabel
36 {
37
38 /** \class matrix3x3
39 \brief Represents a real 3x3 matrix.
40
41 Rotating points in space can be performed by a vector-matrix
42 multiplication. The matrix3x3 class is designed as a helper to the
43 vector3 class for rotating points in space. The rotation matrix may be
44 initialised by passing in the array of doubleing point values, by
45 passing euler angles, or a rotation vector and angle of rotation about
46 that vector. Once set, the matrix3x3 class can be used to rotate
47 vectors by the overloaded multiplication operator. The following
48 demonstrates the usage of the matrix3x3 class:
49
50 \code
51 matrix3x3 mat;
52 mat.SetupRotMat(0.0,180.0,0.0); //rotate theta by 180 degrees
53 vector3 v = VX;
54 v *= mat; //apply the rotation
55 \endcode
56
57 */
58
59 /*! the axis of the rotation will be uniformly distributed on
60 the unit sphere, the angle will be uniformly distributed in
61 the interval 0..360 degrees. */
62 void matrix3x3::randomRotation(OBRandom &rnd)
63 {
64 double rotAngle;
65 vector3 v1;
66
67 v1.randomUnitVector(&rnd);
68 rotAngle = 360.0 * rnd.NextFloat();
69 this->RotAboutAxisByAngle(v1,rotAngle);
70 }
71
72 void matrix3x3::SetupRotMat(double phi,double theta,double psi)
73 {
74 double p = phi * DEG_TO_RAD;
75 double h = theta * DEG_TO_RAD;
76 double b = psi * DEG_TO_RAD;
77
78 double cx = cos(p);
79 double sx = sin(p);
80 double cy = cos(h);
81 double sy = sin(h);
82 double cz = cos(b);
83 double sz = sin(b);
84
85 ele[0][0] = cy*cz;
86 ele[0][1] = cy*sz;
87 ele[0][2] = -sy;
88
89 ele[1][0] = sx*sy*cz-cx*sz;
90 ele[1][1] = sx*sy*sz+cx*cz;
91 ele[1][2] = sx*cy;
92
93 ele[2][0] = cx*sy*cz+sx*sz;
94 ele[2][1] = cx*sy*sz-sx*cz;
95 ele[2][2] = cx*cy;
96 }
97
98 /*! Replaces *this with a matrix that represents reflection on
99 the plane through 0 which is given by the normal vector norm.
100
101 \warning If the vector norm has length zero, this method will
102 generate the 0-matrix. If the length of the axis is close to
103 zero, but not == 0.0, this method may behave in unexpected
104 ways and return almost random results; details may depend on
105 your particular doubleing point implementation. The use of this
106 method is therefore highly discouraged, unless you are certain
107 that the length is in a reasonable range, away from 0.0
108 (Stefan Kebekus)
109
110 \deprecated This method will probably replaced by a safer
111 algorithm in the future.
112
113 \todo Replace this method with a more fool-proof version.
114
115 @param norm specifies the normal to the plane
116 */
117 void matrix3x3::PlaneReflection(const vector3 &norm)
118 {
119 //@@@ add a safety net
120
121 vector3 normtmp = norm;
122 normtmp.normalize();
123
124 SetColumn(0, vector3(1,0,0) - 2*normtmp.x()*normtmp);
125 SetColumn(1, vector3(0,1,0) - 2*normtmp.y()*normtmp);
126 SetColumn(2, vector3(0,0,1) - 2*normtmp.z()*normtmp);
127 }
128
129 #define x vtmp.x()
130 #define y vtmp.y()
131 #define z vtmp.z()
132
133 /*! Replaces *this with a matrix that represents rotation about the
134 axis by a an angle.
135
136 \warning If the vector axis has length zero, this method will
137 generate the 0-matrix. If the length of the axis is close to
138 zero, but not == 0.0, this method may behave in unexpected ways
139 and return almost random results; details may depend on your
140 particular doubleing point implementation. The use of this method
141 is therefore highly discouraged, unless you are certain that the
142 length is in a reasonable range, away from 0.0 (Stefan
143 Kebekus)
144
145 \deprecated This method will probably replaced by a safer
146 algorithm in the future.
147
148 \todo Replace this method with a more fool-proof version.
149
150 @param v specifies the axis of the rotation
151 @param angle angle in degrees (0..360)
152 */
153 void matrix3x3::RotAboutAxisByAngle(const vector3 &v,const double angle)
154 {
155 double theta = angle*DEG_TO_RAD;
156 double s = sin(theta);
157 double c = cos(theta);
158 double t = 1 - c;
159
160 vector3 vtmp = v;
161 vtmp.normalize();
162
163 ele[0][0] = t*x*x + c;
164 ele[0][1] = t*x*y + s*z;
165 ele[0][2] = t*x*z - s*y;
166
167 ele[1][0] = t*x*y - s*z;
168 ele[1][1] = t*y*y + c;
169 ele[1][2] = t*y*z + s*x;
170
171 ele[2][0] = t*x*z + s*y;
172 ele[2][1] = t*y*z - s*x;
173 ele[2][2] = t*z*z + c;
174 }
175
176 #undef x
177 #undef y
178 #undef z
179
180 void matrix3x3::SetColumn(int col, const vector3 &v) throw(OBError)
181 {
182 if (col > 2)
183 {
184 OBError er("matrix3x3::SetColumn(int col, const vector3 &v)",
185 "The method was called with col > 2.",
186 "This is a programming error in your application.");
187 throw er;
188 }
189
190 ele[0][col] = v.x();
191 ele[1][col] = v.y();
192 ele[2][col] = v.z();
193 }
194
195 void matrix3x3::SetRow(int row, const vector3 &v) throw(OBError)
196 {
197 if (row > 2)
198 {
199 OBError er("matrix3x3::SetRow(int row, const vector3 &v)",
200 "The method was called with row > 2.",
201 "This is a programming error in your application.");
202 throw er;
203 }
204
205 ele[row][0] = v.x();
206 ele[row][1] = v.y();
207 ele[row][2] = v.z();
208 }
209
210 vector3 matrix3x3::GetColumn(unsigned int col) const throw(OBError)
211 {
212 if (col > 2)
213 {
214 OBError er("matrix3x3::GetColumn(unsigned int col) const",
215 "The method was called with col > 2.",
216 "This is a programming error in your application.");
217 throw er;
218 }
219
220 return vector3(ele[0][col], ele[1][col], ele[2][col]);
221 }
222
223 vector3 matrix3x3::GetRow(unsigned int row) const throw(OBError)
224 {
225 if (row > 2)
226 {
227 OBError er("matrix3x3::GetRow(unsigned int row) const",
228 "The method was called with row > 2.",
229 "This is a programming error in your application.");
230 throw er;
231 }
232
233 return vector3(ele[row][0], ele[row][1], ele[row][2]);
234 }
235
236 /*! calculates the product m*v of the matrix m and the column
237 vector represented by v
238 */
239 vector3 operator *(const matrix3x3 &m,const vector3 &v)
240 {
241 vector3 vv;
242
243 vv._vx = v._vx*m.ele[0][0] + v._vy*m.ele[0][1] + v._vz*m.ele[0][2];
244 vv._vy = v._vx*m.ele[1][0] + v._vy*m.ele[1][1] + v._vz*m.ele[1][2];
245 vv._vz = v._vx*m.ele[2][0] + v._vy*m.ele[2][1] + v._vz*m.ele[2][2];
246
247 return(vv);
248 }
249
250 matrix3x3 operator *(const matrix3x3 &A,const matrix3x3 &B)
251 {
252 matrix3x3 result;
253
254 result.ele[0][0] = A.ele[0][0]*B.ele[0][0] + A.ele[0][1]*B.ele[1][0] + A.ele[0][2]*B.ele[2][0];
255 result.ele[0][1] = A.ele[0][0]*B.ele[0][1] + A.ele[0][1]*B.ele[1][1] + A.ele[0][2]*B.ele[2][1];
256 result.ele[0][2] = A.ele[0][0]*B.ele[0][2] + A.ele[0][1]*B.ele[1][2] + A.ele[0][2]*B.ele[2][2];
257
258 result.ele[1][0] = A.ele[1][0]*B.ele[0][0] + A.ele[1][1]*B.ele[1][0] + A.ele[1][2]*B.ele[2][0];
259 result.ele[1][1] = A.ele[1][0]*B.ele[0][1] + A.ele[1][1]*B.ele[1][1] + A.ele[1][2]*B.ele[2][1];
260 result.ele[1][2] = A.ele[1][0]*B.ele[0][2] + A.ele[1][1]*B.ele[1][2] + A.ele[1][2]*B.ele[2][2];
261
262 result.ele[2][0] = A.ele[2][0]*B.ele[0][0] + A.ele[2][1]*B.ele[1][0] + A.ele[2][2]*B.ele[2][0];
263 result.ele[2][1] = A.ele[2][0]*B.ele[0][1] + A.ele[2][1]*B.ele[1][1] + A.ele[2][2]*B.ele[2][1];
264 result.ele[2][2] = A.ele[2][0]*B.ele[0][2] + A.ele[2][1]*B.ele[1][2] + A.ele[2][2]*B.ele[2][2];
265
266 return(result);
267 }
268
269 /*! calculates the product m*(*this) of the matrix m and the
270 column vector represented by *this
271 */
272 vector3 &vector3::operator *= (const matrix3x3 &m)
273 {
274 vector3 vv;
275
276 vv.SetX(_vx*m.Get(0,0) + _vy*m.Get(0,1) + _vz*m.Get(0,2));
277 vv.SetY(_vx*m.Get(1,0) + _vy*m.Get(1,1) + _vz*m.Get(1,2));
278 vv.SetZ(_vx*m.Get(2,0) + _vy*m.Get(2,1) + _vz*m.Get(2,2));
279 _vx = vv.x();
280 _vy = vv.y();
281 _vz = vv.z();
282
283 return(*this);
284 }
285
286 /*! This method checks if the absolute value of the determinant is smaller than 1e-6. If
287 so, nothing is done and an exception is thrown. Otherwise, the
288 inverse matrix is calculated and returned. *this is not changed.
289
290 \warning If the determinant is close to zero, but not == 0.0,
291 this method may behave in unexpected ways and return almost
292 random results; details may depend on your particular doubleing
293 point implementation. The use of this method is therefore highly
294 discouraged, unless you are certain that the determinant is in a
295 reasonable range, away from 0.0 (Stefan Kebekus)
296 */
297 matrix3x3 matrix3x3::inverse(void) const throw(OBError)
298 {
299 double det = determinant();
300 if (fabs(det) <= 1e-6)
301 {
302 OBError er("matrix3x3::invert(void)",
303 "The method was called on a matrix with |determinant| <= 1e-6.",
304 "This is a runtime or a programming error in your application.");
305 throw er;
306 }
307
308 matrix3x3 inverse;
309 inverse.ele[0][0] = ele[1][1]*ele[2][2] - ele[1][2]*ele[2][1];
310 inverse.ele[1][0] = ele[1][2]*ele[2][0] - ele[1][0]*ele[2][2];
311 inverse.ele[2][0] = ele[1][0]*ele[2][1] - ele[1][1]*ele[2][0];
312 inverse.ele[0][1] = ele[2][1]*ele[0][2] - ele[2][2]*ele[0][1];
313 inverse.ele[1][1] = ele[2][2]*ele[0][0] - ele[2][0]*ele[0][2];
314 inverse.ele[2][1] = ele[2][0]*ele[0][1] - ele[2][1]*ele[0][0];
315 inverse.ele[0][2] = ele[0][1]*ele[1][2] - ele[0][2]*ele[1][1];
316 inverse.ele[1][2] = ele[0][2]*ele[1][0] - ele[0][0]*ele[1][2];
317 inverse.ele[2][2] = ele[0][0]*ele[1][1] - ele[0][1]*ele[1][0];
318
319 inverse /= det;
320
321 return(inverse);
322 }
323
324 /* This method returns the transpose of a matrix. The original
325 matrix remains unchanged. */
326 matrix3x3 matrix3x3::transpose(void) const
327 {
328 matrix3x3 transpose;
329
330 for(unsigned int i=0; i<3; i++)
331 for(unsigned int j=0; j<3; j++)
332 transpose.ele[i][j] = ele[j][i];
333
334 return(transpose);
335 }
336
337 double matrix3x3::determinant(void) const
338 {
339 double x,y,z;
340
341 x = ele[0][0] * (ele[1][1] * ele[2][2] - ele[1][2] * ele[2][1]);
342 y = ele[0][1] * (ele[1][2] * ele[2][0] - ele[1][0] * ele[2][2]);
343 z = ele[0][2] * (ele[1][0] * ele[2][1] - ele[1][1] * ele[2][0]);
344
345 return(x + y + z);
346 }
347
348 /*! This method returns false if there are indices i,j such that
349 fabs(*this[i][j]-*this[j][i]) > 1e-6. Otherwise, it returns
350 true. */
351 bool matrix3x3::isSymmetric(void) const
352 {
353 if (fabs(ele[0][1] - ele[1][0]) > 1e-6)
354 return false;
355 if (fabs(ele[0][2] - ele[2][0]) > 1e-6)
356 return false;
357 if (fabs(ele[1][2] - ele[2][1]) > 1e-6)
358 return false;
359 return true;
360 }
361
362 /*! This method returns false if there are indices i != j such
363 that fabs(*this[i][j]) > 1e-6. Otherwise, it returns true. */
364 bool matrix3x3::isDiagonal(void) const
365 {
366 if (fabs(ele[0][1]) > 1e-6)
367 return false;
368 if (fabs(ele[0][2]) > 1e-6)
369 return false;
370 if (fabs(ele[1][2]) > 1e-6)
371 return false;
372
373 if (fabs(ele[1][0]) > 1e-6)
374 return false;
375 if (fabs(ele[2][0]) > 1e-6)
376 return false;
377 if (fabs(ele[2][1]) > 1e-6)
378 return false;
379
380 return true;
381 }
382
383 /*! This method returns false if there are indices i != j such
384 that fabs(*this[i][j]) > 1e-6, or if there is an index i such
385 that fabs(*this[i][j]-1) > 1e-6. Otherwise, it returns
386 true. */
387 bool matrix3x3::isUnitMatrix(void) const
388 {
389 if (!isDiagonal())
390 return false;
391
392 if (fabs(ele[0][0]-1) > 1e-6)
393 return false;
394 if (fabs(ele[1][1]-1) > 1e-6)
395 return false;
396 if (fabs(ele[2][2]-1) > 1e-6)
397 return false;
398
399 return true;
400 }
401
402 /*! This method employs the static method matrix3x3::jacobi(...)
403 to find the eigenvalues and eigenvectors of a symmetric
404 matrix. On entry it is checked if the matrix really is
405 symmetric: if isSymmetric() returns 'false', an OBError is
406 thrown.
407
408 \note The jacobi algorithm is should work great for all
409 symmetric 3x3 matrices. If you need to find the eigenvectors
410 of a non-symmetric matrix, you might want to resort to the
411 sophisticated routines of LAPACK.
412
413 @param eigenvals a reference to a vector3 where the
414 eigenvalues will be stored. The eigenvalues are ordered so
415 that eigenvals[0] <= eigenvals[1] <= eigenvals[2].
416
417 @return an orthogonal matrix whose ith column is an
418 eigenvector for the eigenvalue eigenvals[i]. Here 'orthogonal'
419 means that all eigenvectors have length one and are mutually
420 orthogonal. The ith eigenvector can thus be conveniently
421 accessed by the GetColumn() method, as in the following
422 example.
423 \code
424 // Calculate eigenvectors and -values
425 vector3 eigenvals;
426 matrix3x3 eigenmatrix = somematrix.findEigenvectorsIfSymmetric(eigenvals);
427
428 // Print the 2nd eigenvector
429 cout << eigenmatrix.GetColumn(1) << endl;
430 \endcode
431 With these conventions, a matrix is diagonalized in the following way:
432 \code
433 // Diagonalize the matrix
434 matrix3x3 diagonalMatrix = eigenmatrix.inverse() * somematrix * eigenmatrix;
435 \endcode
436
437 */
438 matrix3x3 matrix3x3::findEigenvectorsIfSymmetric(vector3 &eigenvals) const throw(OBError)
439 {
440 matrix3x3 result;
441
442 if (!isSymmetric())
443 {
444 OBError er("matrix3x3::findEigenvectorsIfSymmetric(vector3 &eigenvals) const throw(OBError)",
445 "The method was called on a matrix that was not symmetric, i.e. where isSymetric() == false.",
446 "This is a runtime or a programming error in your application.");
447 throw er;
448 }
449
450 double d[3];
451 matrix3x3 copyOfThis = *this;
452
453 jacobi(3, copyOfThis.ele[0], d, result.ele[0]);
454 eigenvals.Set(d);
455
456 return result;
457 }
458
459 matrix3x3 &matrix3x3::operator/=(const double &c)
460 {
461 for (int row = 0;row < 3; row++)
462 for (int col = 0;col < 3; col++)
463 ele[row][col] /= c;
464
465 return(*this);
466 }
467
468 #ifndef SQUARE
469 #define SQUARE(x) ((x)*(x))
470 #endif
471
472 void matrix3x3::FillOrth(double Alpha,double Beta, double Gamma,
473 double A, double B, double C)
474 {
475 double V;
476
477 Alpha *= DEG_TO_RAD;
478 Beta *= DEG_TO_RAD;
479 Gamma *= DEG_TO_RAD;
480
481 // from the PDB specification:
482 // http://www.rcsb.org/pdb/docs/format/pdbguide2.2/part_75.html
483
484
485 // since we'll ultimately divide by (a * b), we've factored those out here
486 V = C * sqrt(1 - SQUARE(cos(Alpha)) - SQUARE(cos(Beta)) - SQUARE(cos(Gamma))
487 + 2 * cos(Alpha) * cos(Beta) * cos(Gamma));
488
489 ele[0][0] = A;
490 ele[0][1] = B*cos(Gamma);
491 ele[0][2] = C*cos(Beta);
492
493 ele[1][0] = 0.0;
494 ele[1][1] = B*sin(Gamma);
495 ele[1][2] = C*(cos(Alpha)-cos(Beta)*cos(Gamma))/sin(Gamma);
496
497 ele[2][0] = 0.0;
498 ele[2][1] = 0.0;
499 ele[2][2] = V / (sin(Gamma)); // again, we factored out A * B when defining V
500 }
501
502 ostream& operator<< ( ostream& co, const matrix3x3& m )
503
504 {
505 co << "[ "
506 << m.ele[0][0]
507 << ", "
508 << m.ele[0][1]
509 << ", "
510 << m.ele[0][2]
511 << " ]" << endl;
512
513 co << "[ "
514 << m.ele[1][0]
515 << ", "
516 << m.ele[1][1]
517 << ", "
518 << m.ele[1][2]
519 << " ]" << endl;
520
521 co << "[ "
522 << m.ele[2][0]
523 << ", "
524 << m.ele[2][1]
525 << ", "
526 << m.ele[2][2]
527 << " ]" << endl;
528
529 return co ;
530 }
531
532 /*! This static function computes the eigenvalues and
533 eigenvectors of a SYMMETRIC nxn matrix. This method is used
534 internally by OpenBabel, but may be useful as a general
535 eigenvalue finder.
536
537 The algorithm uses Jacobi transformations. It is described
538 e.g. in Wilkinson, Reinsch "Handbook for automatic computation,
539 Volume II: Linear Algebra", part II, contribution II/1. The
540 implementation is also similar to the implementation in this
541 book. This method is adequate to solve the eigenproblem for
542 small matrices, of size perhaps up to 10x10. For bigger
543 problems, you might want to resort to the sophisticated routines
544 of LAPACK.
545
546 \note If you plan to find the eigenvalues of a symmetric 3x3
547 matrix, you will probably prefer to use the more convenient
548 method findEigenvectorsIfSymmetric()
549
550 @param n the size of the matrix that should be diagonalized
551
552 @param a array of size n^2 which holds the symmetric matrix
553 whose eigenvectors are to be computed. The convention is that
554 the entry in row r and column c is addressed as a[n*r+c] where,
555 of course, 0 <= r < n and 0 <= c < n. There is no check that the
556 matrix is actually symmetric. If it is not, the behaviour of
557 this function is undefined. On return, the matrix is
558 overwritten with junk.
559
560 @param d pointer to a field of at least n doubles which will be
561 overwritten. On return of this function, the entries d[0]..d[n-1]
562 will contain the eigenvalues of the matrix.
563
564 @param v an array of size n^2 where the eigenvectors will be
565 stored. On return, the columns of this matrix will contain the
566 eigenvectors. The eigenvectors are normalized and mutually
567 orthogonal.
568 */
569 void matrix3x3::jacobi(unsigned int n, double *a, double *d, double *v)
570 {
571 double onorm, dnorm;
572 double b, dma, q, t, c, s;
573 double atemp, vtemp, dtemp;
574 register int i, j, k, l;
575 int nrot;
576
577 int MAX_SWEEPS=50;
578
579 // Set v to the identity matrix, set the vector d to contain the
580 // diagonal elements of the matrix a
581 for (j = 0; j < static_cast<int>(n); j++)
582 {
583 for (i = 0; i < static_cast<int>(n); i++)
584 v[n*i+j] = 0.0;
585 v[n*j+j] = 1.0;
586 d[j] = a[n*j+j];
587 }
588
589 nrot = MAX_SWEEPS;
590 for (l = 1; l <= nrot; l++)
591 {
592 // Set dnorm to be the maximum norm of the diagonal elements, set
593 // onorm to the maximum norm of the off-diagonal elements
594 dnorm = 0.0;
595 onorm = 0.0;
596 for (j = 0; j < static_cast<int>(n); j++)
597 {
598 dnorm += (double)fabs(d[j]);
599 for (i = 0; i < j; i++)
600 onorm += (double)fabs(a[n*i+j]);
601 }
602 // Normal end point of this algorithm.
603 if((onorm/dnorm) <= 1.0e-12)
604 goto Exit_now;
605
606 for (j = 1; j < static_cast<int>(n); j++)
607 {
608 for (i = 0; i <= j - 1; i++)
609 {
610
611 b = a[n*i+j];
612 if(fabs(b) > 0.0)
613 {
614 dma = d[j] - d[i];
615 if((fabs(dma) + fabs(b)) <= fabs(dma))
616 t = b / dma;
617 else
618 {
619 q = 0.5 * dma / b;
620 t = 1.0/((double)fabs(q) + (double)sqrt(1.0+q*q));
621 if (q < 0.0)
622 t = -t;
623 }
624
625 c = 1.0/(double)sqrt(t*t + 1.0);
626 s = t * c;
627 a[n*i+j] = 0.0;
628
629 for (k = 0; k <= i-1; k++)
630 {
631 atemp = c * a[n*k+i] - s * a[n*k+j];
632 a[n*k+j] = s * a[n*k+i] + c * a[n*k+j];
633 a[n*k+i] = atemp;
634 }
635
636 for (k = i+1; k <= j-1; k++)
637 {
638 atemp = c * a[n*i+k] - s * a[n*k+j];
639 a[n*k+j] = s * a[n*i+k] + c * a[n*k+j];
640 a[n*i+k] = atemp;
641 }
642
643 for (k = j+1; k < static_cast<int>(n); k++)
644 {
645 atemp = c * a[n*i+k] - s * a[n*j+k];
646 a[n*j+k] = s * a[n*i+k] + c * a[n*j+k];
647 a[n*i+k] = atemp;
648 }
649
650 for (k = 0; k < static_cast<int>(n); k++)
651 {
652 vtemp = c * v[n*k+i] - s * v[n*k+j];
653 v[n*k+j] = s * v[n*k+i] + c * v[n*k+j];
654 v[n*k+i] = vtemp;
655 }
656
657 dtemp = c*c*d[i] + s*s*d[j] - 2.0*c*s*b;
658 d[j] = s*s*d[i] + c*c*d[j] + 2.0*c*s*b;
659 d[i] = dtemp;
660 } /* end if */
661 } /* end for i */
662 } /* end for j */
663 } /* end for l */
664
665 Exit_now:
666
667 // Now sort the eigenvalues (and the eigenvectors) so that the
668 // smallest eigenvalues come first.
669 nrot = l;
670
671 for (j = 0; j < static_cast<int>(n)-1; j++)
672 {
673 k = j;
674 dtemp = d[k];
675 for (i = j+1; i < static_cast<int>(n); i++)
676 if(d[i] < dtemp)
677 {
678 k = i;
679 dtemp = d[k];
680 }
681
682 if(k > j)
683 {
684 d[k] = d[j];
685 d[j] = dtemp;
686 for (i = 0; i < static_cast<int>(n); i++)
687 {
688 dtemp = v[n*i+k];
689 v[n*i+k] = v[n*i+j];
690 v[n*i+j] = dtemp;
691 }
692 }
693 }
694 }
695
696 } // end namespace OpenBabel
697
698 //! \file matrix3x3.cpp
699 //! \brief Handle 3D rotation matrix.
700