source: molecuilder/src/vector.cpp@ 1f591b

Last change on this file since 1f591b was 1f591b, checked in by Tillmann Crueger <crueger@…>, 16 years ago

Prepared interface of Vector Class for transition to VectorComposites

  • Property mode set to 100644
File size: 24.9 KB
Line 
1/** \file vector.cpp
2 *
3 * Function implementations for the class vector.
4 *
5 */
6
7
8#include "defs.hpp"
9#include "gslmatrix.hpp"
10#include "leastsquaremin.hpp"
11#include "memoryallocator.hpp"
12#include "vector.hpp"
13#include "Helpers/fast_functions.hpp"
14#include "Helpers/Assert.hpp"
15#include "Plane.hpp"
16#include "Exceptions/LinearDependenceException.hpp"
17
18#include <gsl/gsl_linalg.h>
19#include <gsl/gsl_matrix.h>
20#include <gsl/gsl_permutation.h>
21#include <gsl/gsl_vector.h>
22
23/************************************ Functions for class vector ************************************/
24
25/** Constructor of class vector.
26 */
27Vector::Vector()
28{
29 x[0] = x[1] = x[2] = 0.;
30};
31
32/** Constructor of class vector.
33 */
34Vector::Vector(const double x1, const double x2, const double x3)
35{
36 x[0] = x1;
37 x[1] = x2;
38 x[2] = x3;
39};
40
41/**
42 * Copy constructor
43 */
44Vector::Vector(const Vector& src)
45{
46 x[0] = src[0];
47 x[1] = src[1];
48 x[2] = src[2];
49}
50
51/**
52 * Assignment operator
53 */
54Vector& Vector::operator=(const Vector& src){
55 // check for self assignment
56 if(&src!=this){
57 x[0] = src[0];
58 x[1] = src[1];
59 x[2] = src[2];
60 }
61 return *this;
62}
63
64/** Desctructor of class vector.
65 */
66Vector::~Vector() {};
67
68/** Calculates square of distance between this and another vector.
69 * \param *y array to second vector
70 * \return \f$| x - y |^2\f$
71 */
72double Vector::DistanceSquared(const Vector &y) const
73{
74 double res = 0.;
75 for (int i=NDIM;i--;)
76 res += (x[i]-y[i])*(x[i]-y[i]);
77 return (res);
78};
79
80/** Calculates distance between this and another vector.
81 * \param *y array to second vector
82 * \return \f$| x - y |\f$
83 */
84double Vector::Distance(const Vector &y) const
85{
86 return (sqrt(DistanceSquared(y)));
87};
88
89/** Calculates distance between this and another vector in a periodic cell.
90 * \param *y array to second vector
91 * \param *cell_size 6-dimensional array with (xx, xy, yy, xz, yz, zz) entries specifying the periodic cell
92 * \return \f$| x - y |\f$
93 */
94double Vector::PeriodicDistance(const Vector &y, const double * const cell_size) const
95{
96 double res = Distance(y), tmp, matrix[NDIM*NDIM];
97 Vector Shiftedy, TranslationVector;
98 int N[NDIM];
99 matrix[0] = cell_size[0];
100 matrix[1] = cell_size[1];
101 matrix[2] = cell_size[3];
102 matrix[3] = cell_size[1];
103 matrix[4] = cell_size[2];
104 matrix[5] = cell_size[4];
105 matrix[6] = cell_size[3];
106 matrix[7] = cell_size[4];
107 matrix[8] = cell_size[5];
108 // in order to check the periodic distance, translate one of the vectors into each of the 27 neighbouring cells
109 for (N[0]=-1;N[0]<=1;N[0]++)
110 for (N[1]=-1;N[1]<=1;N[1]++)
111 for (N[2]=-1;N[2]<=1;N[2]++) {
112 // create the translation vector
113 TranslationVector.Zero();
114 for (int i=NDIM;i--;)
115 TranslationVector.x[i] = (double)N[i];
116 TranslationVector.MatrixMultiplication(matrix);
117 // add onto the original vector to compare with
118 Shiftedy = y + TranslationVector;
119 // get distance and compare with minimum so far
120 tmp = Distance(Shiftedy);
121 if (tmp < res) res = tmp;
122 }
123 return (res);
124};
125
126/** Calculates distance between this and another vector in a periodic cell.
127 * \param *y array to second vector
128 * \param *cell_size 6-dimensional array with (xx, xy, yy, xz, yz, zz) entries specifying the periodic cell
129 * \return \f$| x - y |^2\f$
130 */
131double Vector::PeriodicDistanceSquared(const Vector &y, const double * const cell_size) const
132{
133 double res = DistanceSquared(y), tmp, matrix[NDIM*NDIM];
134 Vector Shiftedy, TranslationVector;
135 int N[NDIM];
136 matrix[0] = cell_size[0];
137 matrix[1] = cell_size[1];
138 matrix[2] = cell_size[3];
139 matrix[3] = cell_size[1];
140 matrix[4] = cell_size[2];
141 matrix[5] = cell_size[4];
142 matrix[6] = cell_size[3];
143 matrix[7] = cell_size[4];
144 matrix[8] = cell_size[5];
145 // in order to check the periodic distance, translate one of the vectors into each of the 27 neighbouring cells
146 for (N[0]=-1;N[0]<=1;N[0]++)
147 for (N[1]=-1;N[1]<=1;N[1]++)
148 for (N[2]=-1;N[2]<=1;N[2]++) {
149 // create the translation vector
150 TranslationVector.Zero();
151 for (int i=NDIM;i--;)
152 TranslationVector.x[i] = (double)N[i];
153 TranslationVector.MatrixMultiplication(matrix);
154 // add onto the original vector to compare with
155 Shiftedy = y + TranslationVector;
156 // get distance and compare with minimum so far
157 tmp = DistanceSquared(Shiftedy);
158 if (tmp < res) res = tmp;
159 }
160 return (res);
161};
162
163/** Keeps the vector in a periodic cell, defined by the symmetric \a *matrix.
164 * \param *out ofstream for debugging messages
165 * Tries to translate a vector into each adjacent neighbouring cell.
166 */
167void Vector::KeepPeriodic(const double * const matrix)
168{
169// int N[NDIM];
170// bool flag = false;
171 //vector Shifted, TranslationVector;
172 Vector TestVector;
173// Log() << Verbose(1) << "Begin of KeepPeriodic." << endl;
174// Log() << Verbose(2) << "Vector is: ";
175// Output(out);
176// Log() << Verbose(0) << endl;
177 TestVector = (*this);
178 TestVector.InverseMatrixMultiplication(matrix);
179 for(int i=NDIM;i--;) { // correct periodically
180 if (TestVector.x[i] < 0) { // get every coefficient into the interval [0,1)
181 TestVector.x[i] += ceil(TestVector.x[i]);
182 } else {
183 TestVector.x[i] -= floor(TestVector.x[i]);
184 }
185 }
186 TestVector.MatrixMultiplication(matrix);
187 (*this) = TestVector;
188// Log() << Verbose(2) << "New corrected vector is: ";
189// Output(out);
190// Log() << Verbose(0) << endl;
191// Log() << Verbose(1) << "End of KeepPeriodic." << endl;
192};
193
194/** Calculates scalar product between this and another vector.
195 * \param *y array to second vector
196 * \return \f$\langle x, y \rangle\f$
197 */
198double Vector::ScalarProduct(const Vector &y) const
199{
200 double res = 0.;
201 for (int i=NDIM;i--;)
202 res += x[i]*y[i];
203 return (res);
204};
205
206
207/** Calculates VectorProduct between this and another vector.
208 * -# returns the Product in place of vector from which it was initiated
209 * -# ATTENTION: Only three dim.
210 * \param *y array to vector with which to calculate crossproduct
211 * \return \f$ x \times y \f&
212 */
213void Vector::VectorProduct(const Vector &y)
214{
215 Vector tmp;
216 tmp[0] = x[1]* (y[2]) - x[2]* (y[1]);
217 tmp[1] = x[2]* (y[0]) - x[0]* (y[2]);
218 tmp[2] = x[0]* (y[1]) - x[1]* (y[0]);
219 (*this) = tmp;
220};
221
222
223/** projects this vector onto plane defined by \a *y.
224 * \param *y normal vector of plane
225 * \return \f$\langle x, y \rangle\f$
226 */
227void Vector::ProjectOntoPlane(const Vector &y)
228{
229 Vector tmp = y;
230 tmp.Normalize();
231 tmp *= ScalarProduct(tmp);
232 (*this) -= tmp;
233};
234
235/** Calculates the minimum distance of this vector to the plane.
236 * \param *out output stream for debugging
237 * \param *PlaneNormal normal of plane
238 * \param *PlaneOffset offset of plane
239 * \return distance to plane
240 */
241double Vector::DistanceToPlane(const Vector &PlaneNormal, const Vector &PlaneOffset) const
242{
243 // first create part that is orthonormal to PlaneNormal with withdraw
244 Vector temp = (*this) - PlaneOffset;
245 temp.MakeNormalTo(PlaneNormal);
246 temp *= -1.;
247 // then add connecting vector from plane to point
248 temp += (*this);
249 temp -= PlaneOffset;
250 double sign = temp.ScalarProduct(PlaneNormal);
251 if (fabs(sign) > MYEPSILON)
252 sign /= fabs(sign);
253 else
254 sign = 0.;
255
256 return (temp.Norm()*sign);
257};
258
259/** Calculates the projection of a vector onto another \a *y.
260 * \param *y array to second vector
261 */
262void Vector::ProjectIt(const Vector &y)
263{
264 Vector helper = y;
265 helper.Scale(-(ScalarProduct(y)));
266 AddVector(helper);
267};
268
269/** Calculates the projection of a vector onto another \a *y.
270 * \param *y array to second vector
271 * \return Vector
272 */
273Vector Vector::Projection(const Vector &y) const
274{
275 Vector helper = y;
276 helper.Scale((ScalarProduct(y)/y.NormSquared()));
277
278 return helper;
279};
280
281/** Calculates norm of this vector.
282 * \return \f$|x|\f$
283 */
284double Vector::Norm() const
285{
286 return (sqrt(NormSquared()));
287};
288
289/** Calculates squared norm of this vector.
290 * \return \f$|x|^2\f$
291 */
292double Vector::NormSquared() const
293{
294 return (ScalarProduct(*this));
295};
296
297/** Normalizes this vector.
298 */
299void Vector::Normalize()
300{
301 double res = 0.;
302 for (int i=NDIM;i--;)
303 res += this->x[i]*this->x[i];
304 if (fabs(res) > MYEPSILON)
305 res = 1./sqrt(res);
306 Scale(&res);
307};
308
309/** Zeros all components of this vector.
310 */
311void Vector::Zero()
312{
313 for (int i=NDIM;i--;)
314 this->x[i] = 0.;
315};
316
317/** Zeros all components of this vector.
318 */
319void Vector::One(const double one)
320{
321 for (int i=NDIM;i--;)
322 this->x[i] = one;
323};
324
325/** Initialises all components of this vector.
326 */
327void Vector::Init(const double x1, const double x2, const double x3)
328{
329 x[0] = x1;
330 x[1] = x2;
331 x[2] = x3;
332};
333
334/** Checks whether vector has all components zero.
335 * @return true - vector is zero, false - vector is not
336 */
337bool Vector::IsZero() const
338{
339 return (fabs(x[0])+fabs(x[1])+fabs(x[2]) < MYEPSILON);
340};
341
342/** Checks whether vector has length of 1.
343 * @return true - vector is normalized, false - vector is not
344 */
345bool Vector::IsOne() const
346{
347 return (fabs(Norm() - 1.) < MYEPSILON);
348};
349
350/** Checks whether vector is normal to \a *normal.
351 * @return true - vector is normalized, false - vector is not
352 */
353bool Vector::IsNormalTo(const Vector &normal) const
354{
355 if (ScalarProduct(normal) < MYEPSILON)
356 return true;
357 else
358 return false;
359};
360
361/** Checks whether vector is normal to \a *normal.
362 * @return true - vector is normalized, false - vector is not
363 */
364bool Vector::IsEqualTo(const Vector &a) const
365{
366 bool status = true;
367 for (int i=0;i<NDIM;i++) {
368 if (fabs(x[i] - a[i]) > MYEPSILON)
369 status = false;
370 }
371 return status;
372};
373
374/** Calculates the angle between this and another vector.
375 * \param *y array to second vector
376 * \return \f$\acos\bigl(frac{\langle x, y \rangle}{|x||y|}\bigr)\f$
377 */
378double Vector::Angle(const Vector &y) const
379{
380 double norm1 = Norm(), norm2 = y.Norm();
381 double angle = -1;
382 if ((fabs(norm1) > MYEPSILON) && (fabs(norm2) > MYEPSILON))
383 angle = this->ScalarProduct(y)/norm1/norm2;
384 // -1-MYEPSILON occured due to numerical imprecision, catch ...
385 //Log() << Verbose(2) << "INFO: acos(-1) = " << acos(-1) << ", acos(-1+MYEPSILON) = " << acos(-1+MYEPSILON) << ", acos(-1-MYEPSILON) = " << acos(-1-MYEPSILON) << "." << endl;
386 if (angle < -1)
387 angle = -1;
388 if (angle > 1)
389 angle = 1;
390 return acos(angle);
391};
392
393
394double& Vector::operator[](size_t i){
395 ASSERT(i<=NDIM && i>=0,"Vector Index out of Range");
396 return x[i];
397}
398
399const double& Vector::operator[](size_t i) const{
400 ASSERT(i<=NDIM && i>=0,"Vector Index out of Range");
401 return x[i];
402}
403
404double& Vector::at(size_t i){
405 return (*this)[i];
406}
407
408const double& Vector::at(size_t i) const{
409 return (*this)[i];
410}
411
412double* Vector::get(){
413 return x;
414}
415
416/** Compares vector \a to vector \a b component-wise.
417 * \param a base vector
418 * \param b vector components to add
419 * \return a == b
420 */
421bool Vector::operator==(const Vector& b) const
422{
423 bool status = true;
424 for (int i=0;i<NDIM;i++)
425 status = status && (fabs((*this)[i] - b[i]) < MYEPSILON);
426 return status;
427};
428
429/** Sums vector \a to this lhs component-wise.
430 * \param a base vector
431 * \param b vector components to add
432 * \return lhs + a
433 */
434const Vector& Vector::operator+=(const Vector& b)
435{
436 this->AddVector(b);
437 return *this;
438};
439
440/** Subtracts vector \a from this lhs component-wise.
441 * \param a base vector
442 * \param b vector components to add
443 * \return lhs - a
444 */
445const Vector& Vector::operator-=(const Vector& b)
446{
447 this->SubtractVector(b);
448 return *this;
449};
450
451/** factor each component of \a a times a double \a m.
452 * \param a base vector
453 * \param m factor
454 * \return lhs.x[i] * m
455 */
456const Vector& operator*=(Vector& a, const double m)
457{
458 a.Scale(m);
459 return a;
460};
461
462/** Sums two vectors \a and \b component-wise.
463 * \param a first vector
464 * \param b second vector
465 * \return a + b
466 */
467Vector const Vector::operator+(const Vector& b) const
468{
469 Vector x = *this;
470 x.AddVector(b);
471 return x;
472};
473
474/** Subtracts vector \a from \b component-wise.
475 * \param a first vector
476 * \param b second vector
477 * \return a - b
478 */
479Vector const Vector::operator-(const Vector& b) const
480{
481 Vector x = *this;
482 x.SubtractVector(b);
483 return x;
484};
485
486/** Factors given vector \a a times \a m.
487 * \param a vector
488 * \param m factor
489 * \return m * a
490 */
491Vector const operator*(const Vector& a, const double m)
492{
493 Vector x(a);
494 x.Scale(m);
495 return x;
496};
497
498/** Factors given vector \a a times \a m.
499 * \param m factor
500 * \param a vector
501 * \return m * a
502 */
503Vector const operator*(const double m, const Vector& a )
504{
505 Vector x(a);
506 x.Scale(m);
507 return x;
508};
509
510ostream& operator<<(ostream& ost, const Vector& m)
511{
512 ost << "(";
513 for (int i=0;i<NDIM;i++) {
514 ost << m[i];
515 if (i != 2)
516 ost << ",";
517 }
518 ost << ")";
519 return ost;
520};
521
522/** Scales each atom coordinate by an individual \a factor.
523 * \param *factor pointer to scaling factor
524 */
525void Vector::Scale(const double ** const factor)
526{
527 for (int i=NDIM;i--;)
528 x[i] *= (*factor)[i];
529};
530
531void Vector::Scale(const double * const factor)
532{
533 for (int i=NDIM;i--;)
534 x[i] *= *factor;
535};
536
537void Vector::Scale(const double factor)
538{
539 for (int i=NDIM;i--;)
540 x[i] *= factor;
541};
542
543/** Translate atom by given vector.
544 * \param trans[] translation vector.
545 */
546void Vector::Translate(const Vector &trans)
547{
548 for (int i=NDIM;i--;)
549 x[i] += trans[i];
550};
551
552/** Given a box by its matrix \a *M and its inverse *Minv the vector is made to point within that box.
553 * \param *M matrix of box
554 * \param *Minv inverse matrix
555 */
556void Vector::WrapPeriodically(const double * const M, const double * const Minv)
557{
558 MatrixMultiplication(Minv);
559 // truncate to [0,1] for each axis
560 for (int i=0;i<NDIM;i++) {
561 x[i] += 0.5; // set to center of box
562 while (x[i] >= 1.)
563 x[i] -= 1.;
564 while (x[i] < 0.)
565 x[i] += 1.;
566 }
567 MatrixMultiplication(M);
568};
569
570/** Do a matrix multiplication.
571 * \param *matrix NDIM_NDIM array
572 */
573void Vector::MatrixMultiplication(const double * const M)
574{
575 Vector C;
576 // do the matrix multiplication
577 C.x[0] = M[0]*x[0]+M[3]*x[1]+M[6]*x[2];
578 C.x[1] = M[1]*x[0]+M[4]*x[1]+M[7]*x[2];
579 C.x[2] = M[2]*x[0]+M[5]*x[1]+M[8]*x[2];
580 // transfer the result into this
581 for (int i=NDIM;i--;)
582 x[i] = C.x[i];
583};
584
585/** Do a matrix multiplication with the \a *A' inverse.
586 * \param *matrix NDIM_NDIM array
587 */
588bool Vector::InverseMatrixMultiplication(const double * const A)
589{
590 Vector C;
591 double B[NDIM*NDIM];
592 double detA = RDET3(A);
593 double detAReci;
594
595 // calculate the inverse B
596 if (fabs(detA) > MYEPSILON) {; // RDET3(A) yields precisely zero if A irregular
597 detAReci = 1./detA;
598 B[0] = detAReci*RDET2(A[4],A[5],A[7],A[8]); // A_11
599 B[1] = -detAReci*RDET2(A[1],A[2],A[7],A[8]); // A_12
600 B[2] = detAReci*RDET2(A[1],A[2],A[4],A[5]); // A_13
601 B[3] = -detAReci*RDET2(A[3],A[5],A[6],A[8]); // A_21
602 B[4] = detAReci*RDET2(A[0],A[2],A[6],A[8]); // A_22
603 B[5] = -detAReci*RDET2(A[0],A[2],A[3],A[5]); // A_23
604 B[6] = detAReci*RDET2(A[3],A[4],A[6],A[7]); // A_31
605 B[7] = -detAReci*RDET2(A[0],A[1],A[6],A[7]); // A_32
606 B[8] = detAReci*RDET2(A[0],A[1],A[3],A[4]); // A_33
607
608 // do the matrix multiplication
609 C.x[0] = B[0]*x[0]+B[3]*x[1]+B[6]*x[2];
610 C.x[1] = B[1]*x[0]+B[4]*x[1]+B[7]*x[2];
611 C.x[2] = B[2]*x[0]+B[5]*x[1]+B[8]*x[2];
612 // transfer the result into this
613 for (int i=NDIM;i--;)
614 x[i] = C.x[i];
615 return true;
616 } else {
617 return false;
618 }
619};
620
621
622/** Creates this vector as the b y *factors' components scaled linear combination of the given three.
623 * this vector = x1*factors[0] + x2* factors[1] + x3*factors[2]
624 * \param *x1 first vector
625 * \param *x2 second vector
626 * \param *x3 third vector
627 * \param *factors three-component vector with the factor for each given vector
628 */
629void Vector::LinearCombinationOfVectors(const Vector &x1, const Vector &x2, const Vector &x3, const double * const factors)
630{
631 (*this) = (factors[0]*x1) +
632 (factors[1]*x2) +
633 (factors[2]*x3);
634};
635
636/** Mirrors atom against a given plane.
637 * \param n[] normal vector of mirror plane.
638 */
639void Vector::Mirror(const Vector &n)
640{
641 double projection;
642 projection = ScalarProduct(n)/n.NormSquared(); // remove constancy from n (keep as logical one)
643 // withdraw projected vector twice from original one
644 for (int i=NDIM;i--;)
645 x[i] -= 2.*projection*n[i];
646};
647
648
649/** Calculates orthonormal vector to one given vector.
650 * Just subtracts the projection onto the given vector from this vector.
651 * The removed part of the vector is Vector::Projection()
652 * \param *x1 vector
653 * \return true - success, false - vector is zero
654 */
655bool Vector::MakeNormalTo(const Vector &y1)
656{
657 bool result = false;
658 double factor = y1.ScalarProduct(*this)/y1.NormSquared();
659 Vector x1 = factor * y1 ;
660 SubtractVector(x1);
661 for (int i=NDIM;i--;)
662 result = result || (fabs(x[i]) > MYEPSILON);
663
664 return result;
665};
666
667/** Creates this vector as one of the possible orthonormal ones to the given one.
668 * Just scan how many components of given *vector are unequal to zero and
669 * try to get the skp of both to be zero accordingly.
670 * \param *vector given vector
671 * \return true - success, false - failure (null vector given)
672 */
673bool Vector::GetOneNormalVector(const Vector &GivenVector)
674{
675 int Components[NDIM]; // contains indices of non-zero components
676 int Last = 0; // count the number of non-zero entries in vector
677 int j; // loop variables
678 double norm;
679
680 for (j=NDIM;j--;)
681 Components[j] = -1;
682 // find two components != 0
683 for (j=0;j<NDIM;j++)
684 if (fabs(GivenVector[j]) > MYEPSILON)
685 Components[Last++] = j;
686
687 switch(Last) {
688 case 3: // threecomponent system
689 case 2: // two component system
690 norm = sqrt(1./(GivenVector[Components[1]]*GivenVector[Components[1]]) + 1./(GivenVector[Components[0]]*GivenVector[Components[0]]));
691 x[Components[2]] = 0.;
692 // in skp both remaining parts shall become zero but with opposite sign and third is zero
693 x[Components[1]] = -1./GivenVector[Components[1]] / norm;
694 x[Components[0]] = 1./GivenVector[Components[0]] / norm;
695 return true;
696 break;
697 case 1: // one component system
698 // set sole non-zero component to 0, and one of the other zero component pendants to 1
699 x[(Components[0]+2)%NDIM] = 0.;
700 x[(Components[0]+1)%NDIM] = 1.;
701 x[Components[0]] = 0.;
702 return true;
703 break;
704 default:
705 return false;
706 }
707};
708
709/** Adds vector \a *y componentwise.
710 * \param *y vector
711 */
712void Vector::AddVector(const Vector &y)
713{
714 for (int i=NDIM;i--;)
715 this->x[i] += y[i];
716}
717
718/** Adds vector \a *y componentwise.
719 * \param *y vector
720 */
721void Vector::SubtractVector(const Vector &y)
722{
723 for (int i=NDIM;i--;)
724 this->x[i] -= y[i];
725}
726
727/** Copy vector \a y componentwise.
728 * \param y vector
729 */
730void Vector::CopyVector(const Vector &y)
731{
732 // check for self assignment
733 if(&y!=this) {
734 for (int i=NDIM;i--;)
735 this->x[i] = y.x[i];
736 }
737}
738
739// this function is completely unused so it is deactivated until new uses arrive and a new
740// place can be found
741#if 0
742/** Solves a vectorial system consisting of two orthogonal statements and a norm statement.
743 * This is linear system of equations to be solved, however of the three given (skp of this vector\
744 * with either of the three hast to be zero) only two are linear independent. The third equation
745 * is that the vector should be of magnitude 1 (orthonormal). This all leads to a case-based solution
746 * where very often it has to be checked whether a certain value is zero or not and thus forked into
747 * another case.
748 * \param *x1 first vector
749 * \param *x2 second vector
750 * \param *y third vector
751 * \param alpha first angle
752 * \param beta second angle
753 * \param c norm of final vector
754 * \return a vector with \f$\langle x1,x2 \rangle=A\f$, \f$\langle x1,y \rangle = B\f$ and with norm \a c.
755 * \bug this is not yet working properly
756 */
757bool Vector::SolveSystem(Vector * x1, Vector * x2, Vector * y, const double alpha, const double beta, const double c)
758{
759 double D1,D2,D3,E1,E2,F1,F2,F3,p,q=0., A, B1, B2, C;
760 double ang; // angle on testing
761 double sign[3];
762 int i,j,k;
763 A = cos(alpha) * x1->Norm() * c;
764 B1 = cos(beta + M_PI/2.) * y->Norm() * c;
765 B2 = cos(beta) * x2->Norm() * c;
766 C = c * c;
767 Log() << Verbose(2) << "A " << A << "\tB " << B1 << "\tC " << C << endl;
768 int flag = 0;
769 if (fabs(x1->x[0]) < MYEPSILON) { // check for zero components for the later flipping and back-flipping
770 if (fabs(x1->x[1]) > MYEPSILON) {
771 flag = 1;
772 } else if (fabs(x1->x[2]) > MYEPSILON) {
773 flag = 2;
774 } else {
775 return false;
776 }
777 }
778 switch (flag) {
779 default:
780 case 0:
781 break;
782 case 2:
783 flip(x1->x[0],x1->x[1]);
784 flip(x2->x[0],x2->x[1]);
785 flip(y->x[0],y->x[1]);
786 //flip(x[0],x[1]);
787 flip(x1->x[1],x1->x[2]);
788 flip(x2->x[1],x2->x[2]);
789 flip(y->x[1],y->x[2]);
790 //flip(x[1],x[2]);
791 case 1:
792 flip(x1->x[0],x1->x[1]);
793 flip(x2->x[0],x2->x[1]);
794 flip(y->x[0],y->x[1]);
795 //flip(x[0],x[1]);
796 flip(x1->x[1],x1->x[2]);
797 flip(x2->x[1],x2->x[2]);
798 flip(y->x[1],y->x[2]);
799 //flip(x[1],x[2]);
800 break;
801 }
802 // now comes the case system
803 D1 = -y->x[0]/x1->x[0]*x1->x[1]+y->x[1];
804 D2 = -y->x[0]/x1->x[0]*x1->x[2]+y->x[2];
805 D3 = y->x[0]/x1->x[0]*A-B1;
806 Log() << Verbose(2) << "D1 " << D1 << "\tD2 " << D2 << "\tD3 " << D3 << "\n";
807 if (fabs(D1) < MYEPSILON) {
808 Log() << Verbose(2) << "D1 == 0!\n";
809 if (fabs(D2) > MYEPSILON) {
810 Log() << Verbose(3) << "D2 != 0!\n";
811 x[2] = -D3/D2;
812 E1 = A/x1->x[0] + x1->x[2]/x1->x[0]*D3/D2;
813 E2 = -x1->x[1]/x1->x[0];
814 Log() << Verbose(3) << "E1 " << E1 << "\tE2 " << E2 << "\n";
815 F1 = E1*E1 + 1.;
816 F2 = -E1*E2;
817 F3 = E1*E1 + D3*D3/(D2*D2) - C;
818 Log() << Verbose(3) << "F1 " << F1 << "\tF2 " << F2 << "\tF3 " << F3 << "\n";
819 if (fabs(F1) < MYEPSILON) {
820 Log() << Verbose(4) << "F1 == 0!\n";
821 Log() << Verbose(4) << "Gleichungssystem linear\n";
822 x[1] = F3/(2.*F2);
823 } else {
824 p = F2/F1;
825 q = p*p - F3/F1;
826 Log() << Verbose(4) << "p " << p << "\tq " << q << endl;
827 if (q < 0) {
828 Log() << Verbose(4) << "q < 0" << endl;
829 return false;
830 }
831 x[1] = p + sqrt(q);
832 }
833 x[0] = A/x1->x[0] - x1->x[1]/x1->x[0]*x[1] + x1->x[2]/x1->x[0]*x[2];
834 } else {
835 Log() << Verbose(2) << "Gleichungssystem unterbestimmt\n";
836 return false;
837 }
838 } else {
839 E1 = A/x1->x[0]+x1->x[1]/x1->x[0]*D3/D1;
840 E2 = x1->x[1]/x1->x[0]*D2/D1 - x1->x[2];
841 Log() << Verbose(2) << "E1 " << E1 << "\tE2 " << E2 << "\n";
842 F1 = E2*E2 + D2*D2/(D1*D1) + 1.;
843 F2 = -(E1*E2 + D2*D3/(D1*D1));
844 F3 = E1*E1 + D3*D3/(D1*D1) - C;
845 Log() << Verbose(2) << "F1 " << F1 << "\tF2 " << F2 << "\tF3 " << F3 << "\n";
846 if (fabs(F1) < MYEPSILON) {
847 Log() << Verbose(3) << "F1 == 0!\n";
848 Log() << Verbose(3) << "Gleichungssystem linear\n";
849 x[2] = F3/(2.*F2);
850 } else {
851 p = F2/F1;
852 q = p*p - F3/F1;
853 Log() << Verbose(3) << "p " << p << "\tq " << q << endl;
854 if (q < 0) {
855 Log() << Verbose(3) << "q < 0" << endl;
856 return false;
857 }
858 x[2] = p + sqrt(q);
859 }
860 x[1] = (-D2 * x[2] - D3)/D1;
861 x[0] = A/x1->x[0] - x1->x[1]/x1->x[0]*x[1] + x1->x[2]/x1->x[0]*x[2];
862 }
863 switch (flag) { // back-flipping
864 default:
865 case 0:
866 break;
867 case 2:
868 flip(x1->x[0],x1->x[1]);
869 flip(x2->x[0],x2->x[1]);
870 flip(y->x[0],y->x[1]);
871 flip(x[0],x[1]);
872 flip(x1->x[1],x1->x[2]);
873 flip(x2->x[1],x2->x[2]);
874 flip(y->x[1],y->x[2]);
875 flip(x[1],x[2]);
876 case 1:
877 flip(x1->x[0],x1->x[1]);
878 flip(x2->x[0],x2->x[1]);
879 flip(y->x[0],y->x[1]);
880 //flip(x[0],x[1]);
881 flip(x1->x[1],x1->x[2]);
882 flip(x2->x[1],x2->x[2]);
883 flip(y->x[1],y->x[2]);
884 flip(x[1],x[2]);
885 break;
886 }
887 // one z component is only determined by its radius (without sign)
888 // thus check eight possible sign flips and determine by checking angle with second vector
889 for (i=0;i<8;i++) {
890 // set sign vector accordingly
891 for (j=2;j>=0;j--) {
892 k = (i & pot(2,j)) << j;
893 Log() << Verbose(2) << "k " << k << "\tpot(2,j) " << pot(2,j) << endl;
894 sign[j] = (k == 0) ? 1. : -1.;
895 }
896 Log() << Verbose(2) << i << ": sign matrix is " << sign[0] << "\t" << sign[1] << "\t" << sign[2] << "\n";
897 // apply sign matrix
898 for (j=NDIM;j--;)
899 x[j] *= sign[j];
900 // calculate angle and check
901 ang = x2->Angle (this);
902 Log() << Verbose(1) << i << "th angle " << ang << "\tbeta " << cos(beta) << " :\t";
903 if (fabs(ang - cos(beta)) < MYEPSILON) {
904 break;
905 }
906 // unapply sign matrix (is its own inverse)
907 for (j=NDIM;j--;)
908 x[j] *= sign[j];
909 }
910 return true;
911};
912
913#endif
914
915/**
916 * Checks whether this vector is within the parallelepiped defined by the given three vectors and
917 * their offset.
918 *
919 * @param offest for the origin of the parallelepiped
920 * @param three vectors forming the matrix that defines the shape of the parallelpiped
921 */
922bool Vector::IsInParallelepiped(const Vector &offset, const double * const parallelepiped) const
923{
924 Vector a = (*this) - offset;
925 a.InverseMatrixMultiplication(parallelepiped);
926 bool isInside = true;
927
928 for (int i=NDIM;i--;)
929 isInside = isInside && ((a.x[i] <= 1) && (a.x[i] >= 0));
930
931 return isInside;
932}
Note: See TracBrowser for help on using the repository browser.