source: src/LinearAlgebra/Line.cpp@ 0a60ee

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 0a60ee was 71129f, checked in by Frederik Heber <heber@…>, 14 years ago

Removed inclusion of Helpers/...hpp from LinearAlgebra.

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