ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/group/trunk/OOPSE-2.0/src/openbabel/matrix3x3.cpp
Revision: 2518
Committed: Fri Dec 16 21:52:50 2005 UTC (18 years, 6 months ago) by tim
File size: 20576 byte(s)
Log Message:
changed __FUNCTION__ to __func__ to match C99 standard, and then added
an autoconf test to check for __func__ usability.  Changed some default
compile flags for the Sun architecture

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)
181 {
182 if (col > 2)
183 {
184 obErrorLog.ThrowError(__func__,
185 "The method was called with col > 2.", obError);
186 }
187
188 ele[0][col] = v.x();
189 ele[1][col] = v.y();
190 ele[2][col] = v.z();
191 }
192
193 void matrix3x3::SetRow(int row, const vector3 &v)
194 {
195 if (row > 2)
196 {
197 obErrorLog.ThrowError(__func__,
198 "The method was called with row > 2.", obError);
199 }
200
201 ele[row][0] = v.x();
202 ele[row][1] = v.y();
203 ele[row][2] = v.z();
204 }
205
206 vector3 matrix3x3::GetColumn(unsigned int col)
207 {
208 if (col > 2)
209 {
210 obErrorLog.ThrowError(__func__,
211 "The method was called with col > 2.", obError);
212 }
213
214 return vector3(ele[0][col], ele[1][col], ele[2][col]);
215 }
216
217 vector3 matrix3x3::GetRow(unsigned int row)
218 {
219 if (row > 2)
220 {
221 obErrorLog.ThrowError(__func__,
222 "The method was called with row > 2.", obError);
223 }
224
225 return vector3(ele[row][0], ele[row][1], ele[row][2]);
226 }
227
228 /*! calculates the product m*v of the matrix m and the column
229 vector represented by v
230 */
231 vector3 operator *(const matrix3x3 &m,const vector3 &v)
232 {
233 vector3 vv;
234
235 vv._vx = v._vx*m.ele[0][0] + v._vy*m.ele[0][1] + v._vz*m.ele[0][2];
236 vv._vy = v._vx*m.ele[1][0] + v._vy*m.ele[1][1] + v._vz*m.ele[1][2];
237 vv._vz = v._vx*m.ele[2][0] + v._vy*m.ele[2][1] + v._vz*m.ele[2][2];
238
239 return(vv);
240 }
241
242 matrix3x3 operator *(const matrix3x3 &A,const matrix3x3 &B)
243 {
244 matrix3x3 result;
245
246 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];
247 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];
248 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];
249
250 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];
251 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];
252 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];
253
254 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];
255 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];
256 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];
257
258 return(result);
259 }
260
261 /*! calculates the product m*(*this) of the matrix m and the
262 column vector represented by *this
263 */
264 vector3 &vector3::operator *= (const matrix3x3 &m)
265 {
266 vector3 vv;
267
268 vv.SetX(_vx*m.Get(0,0) + _vy*m.Get(0,1) + _vz*m.Get(0,2));
269 vv.SetY(_vx*m.Get(1,0) + _vy*m.Get(1,1) + _vz*m.Get(1,2));
270 vv.SetZ(_vx*m.Get(2,0) + _vy*m.Get(2,1) + _vz*m.Get(2,2));
271 _vx = vv.x();
272 _vy = vv.y();
273 _vz = vv.z();
274
275 return(*this);
276 }
277
278 /*! This method checks if the absolute value of the determinant is smaller than 1e-6. If
279 so, nothing is done and an exception is thrown. Otherwise, the
280 inverse matrix is calculated and returned. *this is not changed.
281
282 \warning If the determinant is close to zero, but not == 0.0,
283 this method may behave in unexpected ways and return almost
284 random results; details may depend on your particular doubleing
285 point implementation. The use of this method is therefore highly
286 discouraged, unless you are certain that the determinant is in a
287 reasonable range, away from 0.0 (Stefan Kebekus)
288 */
289 matrix3x3 matrix3x3::inverse(void)
290 {
291 double det = determinant();
292 if (fabs(det) <= 1e-6)
293 {
294 obErrorLog.ThrowError(__func__,
295 "The method was called on a matrix with |determinant| <= 1e-6.", obError);
296 }
297
298 matrix3x3 inverse;
299 inverse.ele[0][0] = ele[1][1]*ele[2][2] - ele[1][2]*ele[2][1];
300 inverse.ele[1][0] = ele[1][2]*ele[2][0] - ele[1][0]*ele[2][2];
301 inverse.ele[2][0] = ele[1][0]*ele[2][1] - ele[1][1]*ele[2][0];
302 inverse.ele[0][1] = ele[2][1]*ele[0][2] - ele[2][2]*ele[0][1];
303 inverse.ele[1][1] = ele[2][2]*ele[0][0] - ele[2][0]*ele[0][2];
304 inverse.ele[2][1] = ele[2][0]*ele[0][1] - ele[2][1]*ele[0][0];
305 inverse.ele[0][2] = ele[0][1]*ele[1][2] - ele[0][2]*ele[1][1];
306 inverse.ele[1][2] = ele[0][2]*ele[1][0] - ele[0][0]*ele[1][2];
307 inverse.ele[2][2] = ele[0][0]*ele[1][1] - ele[0][1]*ele[1][0];
308
309 inverse /= det;
310
311 return(inverse);
312 }
313
314 /* This method returns the transpose of a matrix. The original
315 matrix remains unchanged. */
316 matrix3x3 matrix3x3::transpose(void) const
317 {
318 matrix3x3 transpose;
319
320 for(unsigned int i=0; i<3; i++)
321 for(unsigned int j=0; j<3; j++)
322 transpose.ele[i][j] = ele[j][i];
323
324 return(transpose);
325 }
326
327 double matrix3x3::determinant(void) const
328 {
329 double x,y,z;
330
331 x = ele[0][0] * (ele[1][1] * ele[2][2] - ele[1][2] * ele[2][1]);
332 y = ele[0][1] * (ele[1][2] * ele[2][0] - ele[1][0] * ele[2][2]);
333 z = ele[0][2] * (ele[1][0] * ele[2][1] - ele[1][1] * ele[2][0]);
334
335 return(x + y + z);
336 }
337
338 /*! This method returns false if there are indices i,j such that
339 fabs(*this[i][j]-*this[j][i]) > 1e-6. Otherwise, it returns
340 true. */
341 bool matrix3x3::isSymmetric(void) const
342 {
343 if (fabs(ele[0][1] - ele[1][0]) > 1e-6)
344 return false;
345 if (fabs(ele[0][2] - ele[2][0]) > 1e-6)
346 return false;
347 if (fabs(ele[1][2] - ele[2][1]) > 1e-6)
348 return false;
349 return true;
350 }
351
352 /*! This method returns false if there are indices i != j such
353 that fabs(*this[i][j]) > 1e-6. Otherwise, it returns true. */
354 bool matrix3x3::isDiagonal(void) const
355 {
356 if (fabs(ele[0][1]) > 1e-6)
357 return false;
358 if (fabs(ele[0][2]) > 1e-6)
359 return false;
360 if (fabs(ele[1][2]) > 1e-6)
361 return false;
362
363 if (fabs(ele[1][0]) > 1e-6)
364 return false;
365 if (fabs(ele[2][0]) > 1e-6)
366 return false;
367 if (fabs(ele[2][1]) > 1e-6)
368 return false;
369
370 return true;
371 }
372
373 /*! This method returns false if there are indices i != j such
374 that fabs(*this[i][j]) > 1e-6, or if there is an index i such
375 that fabs(*this[i][j]-1) > 1e-6. Otherwise, it returns
376 true. */
377 bool matrix3x3::isUnitMatrix(void) const
378 {
379 if (!isDiagonal())
380 return false;
381
382 if (fabs(ele[0][0]-1) > 1e-6)
383 return false;
384 if (fabs(ele[1][1]-1) > 1e-6)
385 return false;
386 if (fabs(ele[2][2]-1) > 1e-6)
387 return false;
388
389 return true;
390 }
391
392 /*! This method employs the static method matrix3x3::jacobi(...)
393 to find the eigenvalues and eigenvectors of a symmetric
394 matrix. On entry it is checked if the matrix really is
395 symmetric: if isSymmetric() returns 'false', an OBError is
396 thrown.
397
398 \note The jacobi algorithm is should work great for all
399 symmetric 3x3 matrices. If you need to find the eigenvectors
400 of a non-symmetric matrix, you might want to resort to the
401 sophisticated routines of LAPACK.
402
403 @param eigenvals a reference to a vector3 where the
404 eigenvalues will be stored. The eigenvalues are ordered so
405 that eigenvals[0] <= eigenvals[1] <= eigenvals[2].
406
407 @return an orthogonal matrix whose ith column is an
408 eigenvector for the eigenvalue eigenvals[i]. Here 'orthogonal'
409 means that all eigenvectors have length one and are mutually
410 orthogonal. The ith eigenvector can thus be conveniently
411 accessed by the GetColumn() method, as in the following
412 example.
413 \code
414 // Calculate eigenvectors and -values
415 vector3 eigenvals;
416 matrix3x3 eigenmatrix = somematrix.findEigenvectorsIfSymmetric(eigenvals);
417
418 // Print the 2nd eigenvector
419 cout << eigenmatrix.GetColumn(1) << endl;
420 \endcode
421 With these conventions, a matrix is diagonalized in the following way:
422 \code
423 // Diagonalize the matrix
424 matrix3x3 diagonalMatrix = eigenmatrix.inverse() * somematrix * eigenmatrix;
425 \endcode
426
427 */
428 matrix3x3 matrix3x3::findEigenvectorsIfSymmetric(vector3 &eigenvals)
429 {
430 matrix3x3 result;
431
432 if (!isSymmetric())
433 {
434 obErrorLog.ThrowError(__func__,
435 "The method was called on a matrix that was not symmetric, i.e. where isSymetric() == false.", obError);
436 }
437
438 double d[3];
439 matrix3x3 copyOfThis = *this;
440
441 jacobi(3, copyOfThis.ele[0], d, result.ele[0]);
442 eigenvals.Set(d);
443
444 return result;
445 }
446
447 matrix3x3 &matrix3x3::operator/=(const double &c)
448 {
449 for (int row = 0;row < 3; row++)
450 for (int col = 0;col < 3; col++)
451 ele[row][col] /= c;
452
453 return(*this);
454 }
455
456 #ifndef SQUARE
457 #define SQUARE(x) ((x)*(x))
458 #endif
459
460 void matrix3x3::FillOrth(double Alpha,double Beta, double Gamma,
461 double A, double B, double C)
462 {
463 double V;
464
465 Alpha *= DEG_TO_RAD;
466 Beta *= DEG_TO_RAD;
467 Gamma *= DEG_TO_RAD;
468
469 // from the PDB specification:
470 // http://www.rcsb.org/pdb/docs/format/pdbguide2.2/part_75.html
471
472
473 // since we'll ultimately divide by (a * b), we've factored those out here
474 V = C * sqrt(1 - SQUARE(cos(Alpha)) - SQUARE(cos(Beta)) - SQUARE(cos(Gamma))
475 + 2 * cos(Alpha) * cos(Beta) * cos(Gamma));
476
477 ele[0][0] = A;
478 ele[0][1] = B*cos(Gamma);
479 ele[0][2] = C*cos(Beta);
480
481 ele[1][0] = 0.0;
482 ele[1][1] = B*sin(Gamma);
483 ele[1][2] = C*(cos(Alpha)-cos(Beta)*cos(Gamma))/sin(Gamma);
484
485 ele[2][0] = 0.0;
486 ele[2][1] = 0.0;
487 ele[2][2] = V / (sin(Gamma)); // again, we factored out A * B when defining V
488 }
489
490 ostream& operator<< ( ostream& co, const matrix3x3& m )
491
492 {
493 co << "[ "
494 << m.ele[0][0]
495 << ", "
496 << m.ele[0][1]
497 << ", "
498 << m.ele[0][2]
499 << " ]" << endl;
500
501 co << "[ "
502 << m.ele[1][0]
503 << ", "
504 << m.ele[1][1]
505 << ", "
506 << m.ele[1][2]
507 << " ]" << endl;
508
509 co << "[ "
510 << m.ele[2][0]
511 << ", "
512 << m.ele[2][1]
513 << ", "
514 << m.ele[2][2]
515 << " ]" << endl;
516
517 return co ;
518 }
519
520 /*! This static function computes the eigenvalues and
521 eigenvectors of a SYMMETRIC nxn matrix. This method is used
522 internally by OpenBabel, but may be useful as a general
523 eigenvalue finder.
524
525 The algorithm uses Jacobi transformations. It is described
526 e.g. in Wilkinson, Reinsch "Handbook for automatic computation,
527 Volume II: Linear Algebra", part II, contribution II/1. The
528 implementation is also similar to the implementation in this
529 book. This method is adequate to solve the eigenproblem for
530 small matrices, of size perhaps up to 10x10. For bigger
531 problems, you might want to resort to the sophisticated routines
532 of LAPACK.
533
534 \note If you plan to find the eigenvalues of a symmetric 3x3
535 matrix, you will probably prefer to use the more convenient
536 method findEigenvectorsIfSymmetric()
537
538 @param n the size of the matrix that should be diagonalized
539
540 @param a array of size n^2 which holds the symmetric matrix
541 whose eigenvectors are to be computed. The convention is that
542 the entry in row r and column c is addressed as a[n*r+c] where,
543 of course, 0 <= r < n and 0 <= c < n. There is no check that the
544 matrix is actually symmetric. If it is not, the behaviour of
545 this function is undefined. On return, the matrix is
546 overwritten with junk.
547
548 @param d pointer to a field of at least n doubles which will be
549 overwritten. On return of this function, the entries d[0]..d[n-1]
550 will contain the eigenvalues of the matrix.
551
552 @param v an array of size n^2 where the eigenvectors will be
553 stored. On return, the columns of this matrix will contain the
554 eigenvectors. The eigenvectors are normalized and mutually
555 orthogonal.
556 */
557 void matrix3x3::jacobi(unsigned int n, double *a, double *d, double *v)
558 {
559 double onorm, dnorm;
560 double b, dma, q, t, c, s;
561 double atemp, vtemp, dtemp;
562 register int i, j, k, l;
563 int nrot;
564
565 int MAX_SWEEPS=50;
566
567 // Set v to the identity matrix, set the vector d to contain the
568 // diagonal elements of the matrix a
569 for (j = 0; j < static_cast<int>(n); j++)
570 {
571 for (i = 0; i < static_cast<int>(n); i++)
572 v[n*i+j] = 0.0;
573 v[n*j+j] = 1.0;
574 d[j] = a[n*j+j];
575 }
576
577 nrot = MAX_SWEEPS;
578 for (l = 1; l <= nrot; l++)
579 {
580 // Set dnorm to be the maximum norm of the diagonal elements, set
581 // onorm to the maximum norm of the off-diagonal elements
582 dnorm = 0.0;
583 onorm = 0.0;
584 for (j = 0; j < static_cast<int>(n); j++)
585 {
586 dnorm += (double)fabs(d[j]);
587 for (i = 0; i < j; i++)
588 onorm += (double)fabs(a[n*i+j]);
589 }
590 // Normal end point of this algorithm.
591 if((onorm/dnorm) <= 1.0e-12)
592 goto Exit_now;
593
594 for (j = 1; j < static_cast<int>(n); j++)
595 {
596 for (i = 0; i <= j - 1; i++)
597 {
598
599 b = a[n*i+j];
600 if(fabs(b) > 0.0)
601 {
602 dma = d[j] - d[i];
603 if((fabs(dma) + fabs(b)) <= fabs(dma))
604 t = b / dma;
605 else
606 {
607 q = 0.5 * dma / b;
608 t = 1.0/((double)fabs(q) + (double)sqrt(1.0+q*q));
609 if (q < 0.0)
610 t = -t;
611 }
612
613 c = 1.0/(double)sqrt(t*t + 1.0);
614 s = t * c;
615 a[n*i+j] = 0.0;
616
617 for (k = 0; k <= i-1; k++)
618 {
619 atemp = c * a[n*k+i] - s * a[n*k+j];
620 a[n*k+j] = s * a[n*k+i] + c * a[n*k+j];
621 a[n*k+i] = atemp;
622 }
623
624 for (k = i+1; k <= j-1; k++)
625 {
626 atemp = c * a[n*i+k] - s * a[n*k+j];
627 a[n*k+j] = s * a[n*i+k] + c * a[n*k+j];
628 a[n*i+k] = atemp;
629 }
630
631 for (k = j+1; k < static_cast<int>(n); k++)
632 {
633 atemp = c * a[n*i+k] - s * a[n*j+k];
634 a[n*j+k] = s * a[n*i+k] + c * a[n*j+k];
635 a[n*i+k] = atemp;
636 }
637
638 for (k = 0; k < static_cast<int>(n); k++)
639 {
640 vtemp = c * v[n*k+i] - s * v[n*k+j];
641 v[n*k+j] = s * v[n*k+i] + c * v[n*k+j];
642 v[n*k+i] = vtemp;
643 }
644
645 dtemp = c*c*d[i] + s*s*d[j] - 2.0*c*s*b;
646 d[j] = s*s*d[i] + c*c*d[j] + 2.0*c*s*b;
647 d[i] = dtemp;
648 } /* end if */
649 } /* end for i */
650 } /* end for j */
651 } /* end for l */
652
653 Exit_now:
654
655 // Now sort the eigenvalues (and the eigenvectors) so that the
656 // smallest eigenvalues come first.
657 nrot = l;
658
659 for (j = 0; j < static_cast<int>(n)-1; j++)
660 {
661 k = j;
662 dtemp = d[k];
663 for (i = j+1; i < static_cast<int>(n); i++)
664 if(d[i] < dtemp)
665 {
666 k = i;
667 dtemp = d[k];
668 }
669
670 if(k > j)
671 {
672 d[k] = d[j];
673 d[j] = dtemp;
674 for (i = 0; i < static_cast<int>(n); i++)
675 {
676 dtemp = v[n*i+k];
677 v[n*i+k] = v[n*i+j];
678 v[n*i+j] = dtemp;
679 }
680 }
681 }
682 }
683
684 } // end namespace OpenBabel
685
686 //! \file matrix3x3.cpp
687 //! \brief Handle 3D rotation matrix.
688