source: src/LinearAlgebra/Line.cpp@ 882678

Action_Thermostats Add_AtomRandomPerturbation Add_FitFragmentPartialChargesAction Add_RotateAroundBondAction Add_SelectAtomByNameAction Added_ParseSaveFragmentResults AddingActions_SaveParseParticleParameters Adding_Graph_to_ChangeBondActions Adding_MD_integration_tests Adding_ParticleName_to_Atom Adding_StructOpt_integration_tests AtomFragments Automaking_mpqc_open AutomationFragmentation_failures Candidate_v1.5.4 Candidate_v1.6.0 Candidate_v1.6.1 ChangeBugEmailaddress ChangingTestPorts ChemicalSpaceEvaluator CombiningParticlePotentialParsing Combining_Subpackages Debian_Package_split Debian_package_split_molecuildergui_only Disabling_MemDebug Docu_Python_wait EmpiricalPotential_contain_HomologyGraph EmpiricalPotential_contain_HomologyGraph_documentation Enable_parallel_make_install Enhance_userguide Enhanced_StructuralOptimization Enhanced_StructuralOptimization_continued Example_ManyWaysToTranslateAtom Exclude_Hydrogens_annealWithBondGraph FitPartialCharges_GlobalError Fix_BoundInBox_CenterInBox_MoleculeActions Fix_ChargeSampling_PBC Fix_ChronosMutex Fix_FitPartialCharges Fix_FitPotential_needs_atomicnumbers Fix_ForceAnnealing Fix_IndependentFragmentGrids Fix_ParseParticles Fix_ParseParticles_split_forward_backward_Actions Fix_PopActions Fix_QtFragmentList_sorted_selection Fix_Restrictedkeyset_FragmentMolecule Fix_StatusMsg Fix_StepWorldTime_single_argument Fix_Verbose_Codepatterns Fix_fitting_potentials Fixes ForceAnnealing_goodresults ForceAnnealing_oldresults ForceAnnealing_tocheck ForceAnnealing_with_BondGraph ForceAnnealing_with_BondGraph_continued ForceAnnealing_with_BondGraph_continued_betteresults ForceAnnealing_with_BondGraph_contraction-expansion FragmentAction_writes_AtomFragments FragmentMolecule_checks_bonddegrees GeometryObjects Gui_Fixes Gui_displays_atomic_force_velocity ImplicitCharges IndependentFragmentGrids IndependentFragmentGrids_IndividualZeroInstances IndependentFragmentGrids_IntegrationTest IndependentFragmentGrids_Sole_NN_Calculation JobMarket_RobustOnKillsSegFaults JobMarket_StableWorkerPool JobMarket_unresolvable_hostname_fix MoreRobust_FragmentAutomation ODR_violation_mpqc_open PartialCharges_OrthogonalSummation PdbParser_setsAtomName PythonUI_with_named_parameters QtGui_reactivate_TimeChanged_changes Recreated_GuiChecks Rewrite_FitPartialCharges RotateToPrincipalAxisSystem_UndoRedo SaturateAtoms_findBestMatching SaturateAtoms_singleDegree StoppableMakroAction Subpackage_CodePatterns Subpackage_JobMarket Subpackage_LinearAlgebra Subpackage_levmar Subpackage_mpqc_open Subpackage_vmg Switchable_LogView ThirdParty_MPQC_rebuilt_buildsystem TrajectoryDependenant_MaxOrder TremoloParser_IncreasedPrecision TremoloParser_MultipleTimesteps TremoloParser_setsAtomName Ubuntu_1604_changes stable
Last change on this file since 882678 was 783e88, checked in by Frederik Heber <heber@…>, 14 years ago

Removed LinearDependenceException, MultipleSolutionsException and MathException from Exceptions.

  • Property mode set to 100644
File size: 10.6 KB
Line 
1/*
2 * Project: MoleCuilder
3 * Description: creates and alters molecular systems
4 * Copyright (C) 2010 University of Bonn. All rights reserved.
5 * Please see the LICENSE file or "Copyright notice" in builder.cpp for details.
6 */
7
8/*
9 * Line.cpp
10 *
11 * Created on: Apr 30, 2010
12 * Author: crueger
13 */
14
15// include config.h
16#ifdef HAVE_CONFIG_H
17#include <config.h>
18#endif
19
20#include "CodePatterns/MemDebug.hpp"
21
22#include "LinearAlgebra/Line.hpp"
23
24#include <cmath>
25#include <iostream>
26#include <limits>
27
28#include "CodePatterns/Info.hpp"
29#include "CodePatterns/Log.hpp"
30#include "CodePatterns/Verbose.hpp"
31#include "LinearAlgebra/defs.hpp"
32#include "LinearAlgebra/Exceptions.hpp"
33#include "LinearAlgebra/MatrixContent.hpp"
34#include "LinearAlgebra/Plane.hpp"
35#include "LinearAlgebra/Vector.hpp"
36
37using namespace std;
38
39Line::Line(const Vector &_origin, const Vector &_direction) :
40 direction(new Vector(_direction))
41{
42 direction->Normalize();
43 origin.reset(new Vector(_origin.partition(*direction).second));
44}
45
46Line::Line(const Line &src) :
47 origin(new Vector(*src.origin)),
48 direction(new Vector(*src.direction))
49{}
50
51Line::~Line()
52{}
53
54Line &Line::operator=(const Line& rhs){
55 if(this!=&rhs){
56 origin.reset(new Vector(*rhs.origin));
57 direction.reset(new Vector(*rhs.direction));
58 }
59 return *this;
60}
61
62
63double Line::distance(const Vector &point) const{
64 // get any vector from line to point
65 Vector helper = point - *origin;
66 // partition this vector along direction
67 // the residue points from the line to the point
68 return helper.partition(*direction).second.Norm();
69}
70
71Vector Line::getClosestPoint(const Vector &point) const{
72 // get any vector from line to point
73 Vector helper = point - *origin;
74 // partition this vector along direction
75 // add only the part along the direction
76 return *origin + helper.partition(*direction).first;
77}
78
79Vector Line::getDirection() const{
80 return *direction;
81}
82
83Vector Line::getOrigin() const{
84 return *origin;
85}
86
87vector<Vector> Line::getPointsOnLine() const{
88 vector<Vector> res;
89 res.reserve(2);
90 res.push_back(*origin);
91 res.push_back(*origin+*direction);
92 return res;
93}
94
95/** Calculates the intersection of the two lines that are both on the same plane.
96 * This is taken from Weisstein, Eric W. "Line-Line Intersection." From MathWorld--A Wolfram Web Resource. http://mathworld.wolfram.com/Line-LineIntersection.html
97 * \param *out output stream for debugging
98 * \param *Line1a first vector of first line
99 * \param *Line1b second vector of first line
100 * \param *Line2a first vector of second line
101 * \param *Line2b second vector of second line
102 * \return true - \a this will contain the intersection on return, false - lines are parallel
103 */
104Vector Line::getIntersection(const Line& otherLine) const{
105 Info FunctionInfo(__func__);
106
107 pointset line1Points = getPointsOnLine();
108
109 Vector Line1a = line1Points[0];
110 Vector Line1b = line1Points[1];
111
112 pointset line2Points = otherLine.getPointsOnLine();
113
114 Vector Line2a = line2Points[0];
115 Vector Line2b = line2Points[1];
116
117 Vector res;
118
119 auto_ptr<MatrixContent> M = auto_ptr<MatrixContent>(new MatrixContent(4,4));
120
121 M->setValue(1.);
122 for (int i=0;i<3;i++) {
123 M->set(0, i, Line1a[i]);
124 M->set(1, i, Line1b[i]);
125 M->set(2, i, Line2a[i]);
126 M->set(3, i, Line2b[i]);
127 }
128
129 //Log() << Verbose(1) << "Coefficent matrix is:" << endl;
130 //for (int i=0;i<4;i++) {
131 // for (int j=0;j<4;j++)
132 // cout << "\t" << M->Get(i,j);
133 // cout << endl;
134 //}
135 if (fabs(M->Determinant()) > LINALG_MYEPSILON()) {
136 Log() << Verbose(1) << "Determinant of coefficient matrix is NOT zero." << endl;
137 throw SkewException() << LinearAlgebraDeterminant(M->Determinant()) << LinearAlgebraMatrixContent(&(*M));
138 }
139
140 Log() << Verbose(1) << "INFO: Line1a = " << Line1a << ", Line1b = " << Line1b << ", Line2a = " << Line2a << ", Line2b = " << Line2b << "." << endl;
141
142
143 // constuct a,b,c
144 Vector a = Line1b - Line1a;
145 Vector b = Line2b - Line2a;
146 Vector c = Line2a - Line1a;
147 Vector d = Line2b - Line1b;
148 Log() << Verbose(1) << "INFO: a = " << a << ", b = " << b << ", c = " << c << "." << endl;
149 if ((a.NormSquared() <= LINALG_MYEPSILON()) || (b.NormSquared() <= LINALG_MYEPSILON())) {
150 res.Zero();
151 Log() << Verbose(1) << "At least one of the lines is ill-defined, i.e. offset equals second vector." << endl;
152 throw LinearDependenceException() << LinearAlgebraVectorPair( make_pair(&a, &b) );
153 }
154
155 // check for parallelity
156 Vector parallel;
157 double factor = 0.;
158 if (fabs(a.ScalarProduct(b)*a.ScalarProduct(b)/a.NormSquared()/b.NormSquared() - 1.) <= LINALG_MYEPSILON()) {
159 parallel = Line1a - Line2a;
160 factor = parallel.ScalarProduct(a)/a.Norm();
161 if ((factor > -LINALG_MYEPSILON()) && (factor - 1. <= LINALG_MYEPSILON())) {
162 res = Line2a;
163 Log() << Verbose(1) << "Lines conincide." << endl;
164 return res;
165 } else {
166 parallel = Line1a - Line2b;
167 factor = parallel.ScalarProduct(a)/a.Norm();
168 if ((factor > -LINALG_MYEPSILON()) && (factor - 1. <= LINALG_MYEPSILON())) {
169 res = Line2b;
170 Log() << Verbose(1) << "Lines conincide." << endl;
171 return res;
172 }
173 }
174 Log() << Verbose(1) << "Lines are parallel." << endl;
175 res.Zero();
176 throw LinearDependenceException() << LinearAlgebraVectorPair( make_pair(&a, &b) );
177 }
178
179 // obtain s
180 double s;
181 Vector temp1, temp2;
182 temp1 = c;
183 temp1.VectorProduct(b);
184 temp2 = a;
185 temp2.VectorProduct(b);
186 Log() << Verbose(1) << "INFO: temp1 = " << temp1 << ", temp2 = " << temp2 << "." << endl;
187 if (fabs(temp2.NormSquared()) > LINALG_MYEPSILON())
188 s = temp1.ScalarProduct(temp2)/temp2.NormSquared();
189 else
190 s = 0.;
191 Log() << Verbose(1) << "Factor s is " << temp1.ScalarProduct(temp2) << "/" << temp2.NormSquared() << " = " << s << "." << endl;
192
193 // construct intersection
194 res = a;
195 res.Scale(s);
196 res += Line1a;
197 Log() << Verbose(1) << "Intersection is at " << res << "." << endl;
198
199 return res;
200}
201
202/** Rotates the vector by an angle of \a alpha around this line.
203 * \param rhs Vector to rotate
204 * \param alpha rotation angle in radian
205 */
206Vector Line::rotateVector(const Vector &rhs, double alpha) const{
207 Vector helper = rhs;
208
209 // translate the coordinate system so that the line goes through (0,0,0)
210 helper -= *origin;
211
212 // partition the vector into a part that gets rotated and a part that lies along the line
213 pair<Vector,Vector> parts = helper.partition(*direction);
214
215 // we just keep anything that is along the axis
216 Vector res = parts.first;
217
218 // the rest has to be rotated
219 Vector a = parts.second;
220 // we only have to do the rest, if we actually could partition the vector
221 if(!a.IsZero()){
222 // construct a vector that is orthogonal to a and direction and has length |a|
223 Vector y = a;
224 // direction is normalized, so the result has length |a|
225 y.VectorProduct(*direction);
226
227 res += cos(alpha) * a + sin(alpha) * y;
228 }
229
230 // translate the coordinate system back
231 res += *origin;
232 return res;
233}
234
235Line Line::rotateLine(const Line &rhs, double alpha) const{
236 Vector lineOrigin = rotateVector(rhs.getOrigin(),alpha);
237 Vector helper = rhs.getDirection();
238 // rotate the direction without considering the ofset
239 pair<Vector,Vector> parts = helper.partition(*direction);
240 Vector lineDirection = parts.first;
241 Vector a = parts.second;
242 if(!a.IsZero()){
243 // construct a vector that is orthogonal to a and direction and has length |a|
244 Vector y = a;
245 // direction is normalized, so the result has length |a|
246 y.VectorProduct(*direction);
247
248 lineDirection += cos(alpha) * a + sin(alpha) * y;
249 }
250 return Line(lineOrigin,lineDirection);
251}
252
253Plane Line::rotatePlane(const Plane &rhs, double alpha) const{
254 vector<Vector> points = rhs.getPointsOnPlane();
255 transform(points.begin(),
256 points.end(),
257 points.begin(),
258 boost::bind(&Line::rotateVector,this,_1,alpha));
259 return Plane(points[0],points[1],points[2]);
260}
261
262Plane Line::getOrthogonalPlane(const Vector &origin) const{
263 return Plane(getDirection(),origin);
264}
265
266std::vector<Vector> Line::getSphereIntersections() const{
267 std::vector<Vector> res;
268
269 // line is kept in normalized form, so we can skip a lot of calculations
270 double discriminant = 1-origin->NormSquared();
271 // we might have 2, 1 or 0 solutions, depending on discriminant
272 if(discriminant>=0){
273 if(discriminant==0){
274 res.push_back(*origin);
275 }
276 else{
277 Vector helper = sqrt(discriminant)*(*direction);
278 res.push_back(*origin+helper);
279 res.push_back(*origin-helper);
280 }
281 }
282 return res;
283}
284
285LinePoint Line::getLinePoint(const Vector &point) const{
286 ASSERT(isContained(point),"Line point queried for point not on line");
287 Vector helper = point - (*origin);
288 double param = helper.ScalarProduct(*direction);
289 return LinePoint(*this,param);
290}
291
292LinePoint Line::posEndpoint() const{
293 return LinePoint(*this, numeric_limits<double>::infinity());
294}
295LinePoint Line::negEndpoint() const{
296 return LinePoint(*this,-numeric_limits<double>::infinity());
297}
298
299bool operator==(const Line &x,const Line &y){
300 return *x.origin == *y.origin && *x.direction == *y.direction;
301}
302
303Line makeLineThrough(const Vector &x1, const Vector &x2){
304 if(x1==x2){
305 throw LinearDependenceException() << LinearAlgebraVectorPair( make_pair(&x1, &x2) );
306 }
307 return Line(x1,x1-x2);
308}
309
310/******************************** Points on the line ********************/
311
312LinePoint::LinePoint(const LinePoint &src) :
313 line(src.line),param(src.param)
314{}
315
316LinePoint::LinePoint(const Line &_line, double _param) :
317 line(_line),param(_param)
318{}
319
320LinePoint& LinePoint::operator=(const LinePoint &src){
321 line=src.line;
322 param=src.param;
323 return *this;
324}
325
326Vector LinePoint::getPoint() const{
327 ASSERT(!isInfinite(),"getPoint() on infinite LinePoint called");
328 return (*line.origin)+param*(*line.direction);
329}
330
331Line LinePoint::getLine() const{
332 return line;
333}
334
335bool LinePoint::isInfinite() const{
336 return isPosInfinity() || isNegInfinity();
337}
338bool LinePoint::isPosInfinity() const{
339 return param == numeric_limits<double>::infinity();
340}
341bool LinePoint::isNegInfinity() const{
342 return param ==-numeric_limits<double>::infinity();
343}
344
345bool operator==(const LinePoint &x, const LinePoint &y){
346 ASSERT(x.line==y.line,"Operation on two points of different lines");
347 return x.param == y.param;
348
349}
350bool operator<(const LinePoint &x, const LinePoint &y){
351 ASSERT(x.line==y.line,"Operation on two points of different lines");
352 return x.param<y.param;
353}
354
355ostream& operator<<(ostream& ost, const Line& m)
356{
357 const Vector origin = m.getOrigin();
358 const Vector direction = m.getDirection();
359 ost << "(";
360 for (int i=0;i<NDIM;i++) {
361 ost << origin[i];
362 if (i != 2)
363 ost << ",";
364 }
365 ost << ") -> (";
366 for (int i=0;i<NDIM;i++) {
367 ost << direction[i];
368 if (i != 2)
369 ost << ",";
370 }
371 ost << ")";
372 return ost;
373};
374
Note: See TracBrowser for help on using the repository browser.