source: src/boundary.cpp@ 51695c

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 51695c was 450d63, checked in by Frederik Heber <heber@…>, 16 years ago

VolumeOfConvexEnvelope() has new parameter with tecplot ofstream and the file is stored there and not in Tesselation::Tesselation().

+ BUGFIX: As we shift the molecule to the center of gravity for the "projection onto axis planes" method to work, we forgot about shifting it back before storing nodes and triangles in the tecplot file. Now, we store the data to file in VolumeOfConvexEnvelope(), where the molecule has been shifted back already.
+ VolumeOfConvexEnvelope() now gets an additional parameter with the tecplot ofstream, so that the name of the tecplot file may be chosen on the command line (with checks whether the argument was given or not)

  • Property mode set to 100644
File size: 48.4 KB
Line 
1#include "molecules.hpp"
2#include "boundary.hpp"
3
4// ======================================== Points on Boundary =================================
5
6BoundaryPointSet::BoundaryPointSet()
7{
8 LinesCount = 0;
9 Nr = -1;
10};
11
12BoundaryPointSet::BoundaryPointSet(atom *Walker)
13{
14 node = Walker;
15 LinesCount = 0;
16 Nr = Walker->nr;
17};
18
19BoundaryPointSet::~BoundaryPointSet()
20{
21 cout << Verbose(5) << "Erasing point nr. " << Nr << "." << endl;
22 node = NULL;
23};
24
25void BoundaryPointSet::AddLine(class BoundaryLineSet *line)
26{
27 cout << Verbose(6) << "Adding line " << *line << " to " << *this << "." << endl;
28 if (line->endpoints[0] == this) {
29 lines.insert ( LinePair( line->endpoints[1]->Nr, line) );
30 } else {
31 lines.insert ( LinePair( line->endpoints[0]->Nr, line) );
32 }
33 LinesCount++;
34};
35
36ostream & operator << (ostream &ost, BoundaryPointSet &a)
37{
38 ost << "[" << a.Nr << "|" << a.node->Name << "]";
39 return ost;
40};
41
42// ======================================== Lines on Boundary =================================
43
44BoundaryLineSet::BoundaryLineSet()
45{
46 for (int i=0;i<2;i++)
47 endpoints[i] = NULL;
48 TrianglesCount = 0;
49 Nr = -1;
50};
51
52BoundaryLineSet::BoundaryLineSet(class BoundaryPointSet *Point[2], int number)
53{
54 // set number
55 Nr = number;
56 // set endpoints in ascending order
57 SetEndpointsOrdered(endpoints, Point[0], Point[1]);
58 // add this line to the hash maps of both endpoints
59 Point[0]->AddLine(this);
60 Point[1]->AddLine(this);
61 // clear triangles list
62 TrianglesCount = 0;
63 cout << Verbose(5) << "New Line with endpoints " << *this << "." << endl;
64};
65
66BoundaryLineSet::~BoundaryLineSet()
67{
68 for (int i=0;i<2;i++) {
69 cout << Verbose(5) << "Erasing Line Nr. " << Nr << " in boundary point " << *endpoints[i] << "." << endl;
70 endpoints[i]->lines.erase(Nr);
71 LineMap::iterator tester = endpoints[i]->lines.begin();
72 tester++;
73 if (tester == endpoints[i]->lines.end()) {
74 cout << Verbose(5) << *endpoints[i] << " has no more lines it's attached to, erasing." << endl;
75 delete(endpoints[i]);
76 } else
77 cout << Verbose(5) << *endpoints[i] << " has still lines it's attached to." << endl;
78 }
79};
80
81void BoundaryLineSet::AddTriangle(class BoundaryTriangleSet *triangle)
82{
83 cout << Verbose(6) << "Add " << triangle->Nr << " to line " << *this << "." << endl;
84 triangles.insert ( TrianglePair( TrianglesCount, triangle) );
85 TrianglesCount++;
86};
87
88ostream & operator << (ostream &ost, BoundaryLineSet &a)
89{
90 ost << "[" << a.Nr << "|" << a.endpoints[0]->node->Name << "," << a.endpoints[1]->node->Name << "]";
91 return ost;
92};
93
94// ======================================== Triangles on Boundary =================================
95
96
97BoundaryTriangleSet::BoundaryTriangleSet()
98{
99 for (int i=0;i<3;i++) {
100 endpoints[i] = NULL;
101 lines[i] = NULL;
102 }
103 Nr = -1;
104};
105
106BoundaryTriangleSet::BoundaryTriangleSet(class BoundaryLineSet *line[3], int number)
107{
108 // set number
109 Nr = number;
110 // set lines
111 cout << Verbose(5) << "New triangle " << Nr << ":" << endl;
112 for (int i=0;i<3;i++) {
113 lines[i] = line[i];
114 lines[i]->AddTriangle(this);
115 }
116 // get ascending order of endpoints
117 map <int, class BoundaryPointSet * > OrderMap;
118 for(int i=0;i<3;i++) // for all three lines
119 for (int j=0;j<2;j++) { // for both endpoints
120 OrderMap.insert ( pair <int, class BoundaryPointSet * >( line[i]->endpoints[j]->Nr, line[i]->endpoints[j]) );
121 // and we don't care whether insertion fails
122 }
123 // set endpoints
124 int Counter = 0;
125 cout << Verbose(6) << " with end points ";
126 for (map <int, class BoundaryPointSet * >::iterator runner = OrderMap.begin(); runner != OrderMap.end(); runner++) {
127 endpoints[Counter] = runner->second;
128 cout << " " << *endpoints[Counter];
129 Counter++;
130 }
131 if (Counter < 3) {
132 cerr << "ERROR! We have a triangle with only two distinct endpoints!" << endl;
133 //exit(1);
134 }
135 cout << "." << endl;
136};
137
138BoundaryTriangleSet::~BoundaryTriangleSet()
139{
140 for (int i=0;i<3;i++) {
141 cout << Verbose(5) << "Erasing triangle Nr." << Nr << endl;
142 lines[i]->triangles.erase(Nr);
143 TriangleMap::iterator tester = lines[i]->triangles.begin();
144 tester++;
145 if (tester == lines[i]->triangles.end()) {
146 cout << Verbose(5) << *lines[i] << " is no more attached to any triangle, erasing." << endl;
147 delete(lines[i]);
148 } else
149 cout << Verbose(5) << *lines[i] << " is still attached to a triangle." << endl;
150 }
151};
152
153void BoundaryTriangleSet::GetNormalVector(Vector &NormalVector)
154{
155 // get normal vector
156 NormalVector.MakeNormalVector(&endpoints[0]->node->x, &endpoints[1]->node->x, &endpoints[2]->node->x);
157
158 // make it always point inward (any offset vector onto plane projected onto normal vector suffices)
159 if (endpoints[0]->node->x.Projection(&NormalVector) > 0)
160 NormalVector.Scale(-1.);
161};
162
163ostream & operator << (ostream &ost, BoundaryTriangleSet &a)
164{
165 ost << "[" << a.Nr << "|" << a.endpoints[0]->node->Name << "," << a.endpoints[1]->node->Name << "," << a.endpoints[2]->node->Name << "]";
166 return ost;
167};
168
169// ========================================== F U N C T I O N S =================================
170
171/** Finds the endpoint two lines are sharing.
172 * \param *line1 first line
173 * \param *line2 second line
174 * \return point which is shared or NULL if none
175 */
176class BoundaryPointSet * GetCommonEndpoint(class BoundaryLineSet * line1, class BoundaryLineSet * line2)
177{
178 class BoundaryLineSet * lines[2] = {line1, line2};
179 class BoundaryPointSet *node = NULL;
180 map <int, class BoundaryPointSet * > OrderMap;
181 pair < map <int, class BoundaryPointSet * >::iterator, bool > OrderTest;
182 for(int i=0;i<2;i++) // for both lines
183 for (int j=0;j<2;j++) { // for both endpoints
184 OrderTest = OrderMap.insert ( pair <int, class BoundaryPointSet * >( lines[i]->endpoints[j]->Nr, lines[i]->endpoints[j]) );
185 if (!OrderTest.second) { // if insertion fails, we have common endpoint
186 node = OrderTest.first->second;
187 cout << Verbose(5) << "Common endpoint of lines " << *line1 << " and " << *line2 << " is: " << *node << "." << endl;
188 j=2;
189 i=2;
190 break;
191 }
192 }
193 return node;
194};
195
196/** Determines the boundary points of a cluster.
197 * Does a projection per axis onto the orthogonal plane, transforms into spherical coordinates, sorts them by the angle
198 * and looks at triples: if the middle has less a distance than the allowed maximum height of the triangle formed by the plane's
199 * center and first and last point in the triple, it is thrown out.
200 * \param *out output stream for debugging
201 * \param *mol molecule structure representing the cluster
202 */
203Boundaries * GetBoundaryPoints(ofstream *out, molecule *mol)
204{
205 atom *Walker = NULL;
206 PointMap PointsOnBoundary;
207 LineMap LinesOnBoundary;
208 TriangleMap TrianglesOnBoundary;
209
210 *out << Verbose(1) << "Finding all boundary points." << endl;
211 Boundaries *BoundaryPoints = new Boundaries [NDIM]; // first is alpha, second is (r, nr)
212 BoundariesTestPair BoundaryTestPair;
213 Vector AxisVector, AngleReferenceVector, AngleReferenceNormalVector;
214 double radius, angle;
215 // 3a. Go through every axis
216 for (int axis=0; axis<NDIM; axis++) {
217 AxisVector.Zero();
218 AngleReferenceVector.Zero();
219 AngleReferenceNormalVector.Zero();
220 AxisVector.x[axis] = 1.;
221 AngleReferenceVector.x[(axis+1)%NDIM] = 1.;
222 AngleReferenceNormalVector.x[(axis+2)%NDIM] = 1.;
223 // *out << Verbose(1) << "Axisvector is ";
224 // AxisVector.Output(out);
225 // *out << " and AngleReferenceVector is ";
226 // AngleReferenceVector.Output(out);
227 // *out << "." << endl;
228 // *out << " and AngleReferenceNormalVector is ";
229 // AngleReferenceNormalVector.Output(out);
230 // *out << "." << endl;
231 // 3b. construct set of all points, transformed into cylindrical system and with left and right neighbours
232 Walker = mol->start;
233 while (Walker->next != mol->end) {
234 Walker = Walker->next;
235 Vector ProjectedVector;
236 ProjectedVector.CopyVector(&Walker->x);
237 ProjectedVector.ProjectOntoPlane(&AxisVector);
238 // correct for negative side
239 //if (Projection(y) < 0)
240 //angle = 2.*M_PI - angle;
241 radius = ProjectedVector.Norm();
242 if (fabs(radius) > MYEPSILON)
243 angle = ProjectedVector.Angle(&AngleReferenceVector);
244 else
245 angle = 0.; // otherwise it's a vector in Axis Direction and unimportant for boundary issues
246
247 //*out << "Checking sign in quadrant : " << ProjectedVector.Projection(&AngleReferenceNormalVector) << "." << endl;
248 if (ProjectedVector.Projection(&AngleReferenceNormalVector) > 0) {
249 angle = 2.*M_PI - angle;
250 }
251 //*out << Verbose(2) << "Inserting " << *Walker << ": (r, alpha) = (" << radius << "," << angle << "): ";
252 //ProjectedVector.Output(out);
253 //*out << endl;
254 BoundaryTestPair = BoundaryPoints[axis].insert( BoundariesPair (angle, DistancePair (radius, Walker) ) );
255 if (BoundaryTestPair.second) { // successfully inserted
256 } else { // same point exists, check first r, then distance of original vectors to center of gravity
257 *out << Verbose(2) << "Encountered two vectors whose projection onto axis " << axis << " is equal: " << endl;
258 *out << Verbose(2) << "Present vector: ";
259 BoundaryTestPair.first->second.second->x.Output(out);
260 *out << endl;
261 *out << Verbose(2) << "New vector: ";
262 Walker->x.Output(out);
263 *out << endl;
264 double tmp = ProjectedVector.Norm();
265 if (tmp > BoundaryTestPair.first->second.first) {
266 BoundaryTestPair.first->second.first = tmp;
267 BoundaryTestPair.first->second.second = Walker;
268 *out << Verbose(2) << "Keeping new vector." << endl;
269 } else if (tmp == BoundaryTestPair.first->second.first) {
270 if (BoundaryTestPair.first->second.second->x.ScalarProduct(&BoundaryTestPair.first->second.second->x) < Walker->x.ScalarProduct(&Walker->x)) { // Norm() does a sqrt, which makes it a lot slower
271 BoundaryTestPair.first->second.second = Walker;
272 *out << Verbose(2) << "Keeping new vector." << endl;
273 } else {
274 *out << Verbose(2) << "Keeping present vector." << endl;
275 }
276 } else {
277 *out << Verbose(2) << "Keeping present vector." << endl;
278 }
279 }
280 }
281 // printing all inserted for debugging
282 // {
283 // *out << Verbose(2) << "Printing list of candidates for axis " << axis << " which we have inserted so far." << endl;
284 // int i=0;
285 // for(Boundaries::iterator runner = BoundaryPoints[axis].begin(); runner != BoundaryPoints[axis].end(); runner++) {
286 // if (runner != BoundaryPoints[axis].begin())
287 // *out << ", " << i << ": " << *runner->second.second;
288 // else
289 // *out << i << ": " << *runner->second.second;
290 // i++;
291 // }
292 // *out << endl;
293 // }
294 // 3c. throw out points whose distance is less than the mean of left and right neighbours
295 bool flag = false;
296 do { // do as long as we still throw one out per round
297 *out << Verbose(1) << "Looking for candidates to kick out by convex condition ... " << endl;
298 flag = false;
299 Boundaries::iterator left = BoundaryPoints[axis].end();
300 Boundaries::iterator right = BoundaryPoints[axis].end();
301 for(Boundaries::iterator runner = BoundaryPoints[axis].begin(); runner != BoundaryPoints[axis].end(); runner++) {
302 // set neighbours correctly
303 if (runner == BoundaryPoints[axis].begin()) {
304 left = BoundaryPoints[axis].end();
305 } else {
306 left = runner;
307 }
308 left--;
309 right = runner;
310 right++;
311 if (right == BoundaryPoints[axis].end()) {
312 right = BoundaryPoints[axis].begin();
313 }
314 // check distance
315
316 // construct the vector of each side of the triangle on the projected plane (defined by normal vector AxisVector)
317 {
318 Vector SideA, SideB, SideC, SideH;
319 SideA.CopyVector(&left->second.second->x);
320 SideA.ProjectOntoPlane(&AxisVector);
321 // *out << "SideA: ";
322 // SideA.Output(out);
323 // *out << endl;
324
325 SideB.CopyVector(&right->second.second->x);
326 SideB.ProjectOntoPlane(&AxisVector);
327 // *out << "SideB: ";
328 // SideB.Output(out);
329 // *out << endl;
330
331 SideC.CopyVector(&left->second.second->x);
332 SideC.SubtractVector(&right->second.second->x);
333 SideC.ProjectOntoPlane(&AxisVector);
334 // *out << "SideC: ";
335 // SideC.Output(out);
336 // *out << endl;
337
338 SideH.CopyVector(&runner->second.second->x);
339 SideH.ProjectOntoPlane(&AxisVector);
340 // *out << "SideH: ";
341 // SideH.Output(out);
342 // *out << endl;
343
344 // calculate each length
345 double a = SideA.Norm();
346 //double b = SideB.Norm();
347 //double c = SideC.Norm();
348 double h = SideH.Norm();
349 // calculate the angles
350 double alpha = SideA.Angle(&SideH);
351 double beta = SideA.Angle(&SideC);
352 double gamma = SideB.Angle(&SideH);
353 double delta = SideC.Angle(&SideH);
354 double MinDistance = a * sin(beta)/(sin(delta)) * (((alpha < M_PI/2.) || (gamma < M_PI/2.)) ? 1. : -1.);
355 // *out << Verbose(2) << " I calculated: a = " << a << ", h = " << h << ", beta(" << left->second.second->Name << "," << left->second.second->Name << "-" << right->second.second->Name << ") = " << beta << ", delta(" << left->second.second->Name << "," << runner->second.second->Name << ") = " << delta << ", Min = " << MinDistance << "." << endl;
356 //*out << Verbose(1) << "Checking CoG distance of runner " << *runner->second.second << " " << h << " against triangle's side length spanned by (" << *left->second.second << "," << *right->second.second << ") of " << MinDistance << "." << endl;
357 if ((fabs(h/fabs(h) - MinDistance/fabs(MinDistance)) < MYEPSILON) && (h < MinDistance)) {
358 // throw out point
359 //*out << Verbose(1) << "Throwing out " << *runner->second.second << "." << endl;
360 BoundaryPoints[axis].erase(runner);
361 flag = true;
362 }
363 }
364 }
365 } while (flag);
366 }
367 return BoundaryPoints;
368};
369
370/** Determines greatest diameters of a cluster defined by its convex envelope.
371 * Looks at lines parallel to one axis and where they intersect on the projected planes
372 * \param *out output stream for debugging
373 * \param *BoundaryPoints NDIM set of boundary points defining the convex envelope on each projected plane
374 * \param *mol molecule structure representing the cluster
375 * \param IsAngstroem whether we have angstroem or atomic units
376 * \return NDIM array of the diameters
377 */
378double * GetDiametersOfCluster(ofstream *out, Boundaries *BoundaryPtr, molecule *mol, bool IsAngstroem)
379{
380 // get points on boundary of NULL was given as parameter
381 bool BoundaryFreeFlag = false;
382 Boundaries *BoundaryPoints = BoundaryPtr;
383 if (BoundaryPoints == NULL) {
384 BoundaryFreeFlag = true;
385 BoundaryPoints = GetBoundaryPoints(out, mol);
386 } else {
387 *out << Verbose(1) << "Using given boundary points set." << endl;
388 }
389
390 // determine biggest "diameter" of cluster for each axis
391 Boundaries::iterator Neighbour, OtherNeighbour;
392 double *GreatestDiameter = new double[NDIM];
393 for(int i=0;i<NDIM;i++)
394 GreatestDiameter[i] = 0.;
395 double OldComponent, tmp, w1, w2;
396 Vector DistanceVector, OtherVector;
397 int component, Othercomponent;
398 for(int axis=0;axis<NDIM;axis++) { // regard each projected plane
399 //*out << Verbose(1) << "Current axis is " << axis << "." << endl;
400 for (int j=0;j<2;j++) { // and for both axis on the current plane
401 component = (axis+j+1)%NDIM;
402 Othercomponent = (axis+1+((j+1) & 1))%NDIM;
403 //*out << Verbose(1) << "Current component is " << component << ", Othercomponent is " << Othercomponent << "." << endl;
404 for(Boundaries::iterator runner = BoundaryPoints[axis].begin(); runner != BoundaryPoints[axis].end(); runner++) {
405 //*out << Verbose(2) << "Current runner is " << *(runner->second.second) << "." << endl;
406 // seek for the neighbours pair where the Othercomponent sign flips
407 Neighbour = runner;
408 Neighbour++;
409 if (Neighbour == BoundaryPoints[axis].end()) // make it wrap around
410 Neighbour = BoundaryPoints[axis].begin();
411 DistanceVector.CopyVector(&runner->second.second->x);
412 DistanceVector.SubtractVector(&Neighbour->second.second->x);
413 do { // seek for neighbour pair where it flips
414 OldComponent = DistanceVector.x[Othercomponent];
415 Neighbour++;
416 if (Neighbour == BoundaryPoints[axis].end()) // make it wrap around
417 Neighbour = BoundaryPoints[axis].begin();
418 DistanceVector.CopyVector(&runner->second.second->x);
419 DistanceVector.SubtractVector(&Neighbour->second.second->x);
420 //*out << Verbose(3) << "OldComponent is " << OldComponent << ", new one is " << DistanceVector.x[Othercomponent] << "." << endl;
421 } while ((runner != Neighbour) && ( fabs( OldComponent/fabs(OldComponent) - DistanceVector.x[Othercomponent]/fabs(DistanceVector.x[Othercomponent]) ) < MYEPSILON)); // as long as sign does not flip
422 if (runner != Neighbour) {
423 OtherNeighbour = Neighbour;
424 if (OtherNeighbour == BoundaryPoints[axis].begin()) // make it wrap around
425 OtherNeighbour = BoundaryPoints[axis].end();
426 OtherNeighbour--;
427 //*out << Verbose(2) << "The pair, where the sign of OtherComponent flips, is: " << *(Neighbour->second.second) << " and " << *(OtherNeighbour->second.second) << "." << endl;
428 // now we have found the pair: Neighbour and OtherNeighbour
429 OtherVector.CopyVector(&runner->second.second->x);
430 OtherVector.SubtractVector(&OtherNeighbour->second.second->x);
431 //*out << Verbose(2) << "Distances to Neighbour and OtherNeighbour are " << DistanceVector.x[component] << " and " << OtherVector.x[component] << "." << endl;
432 //*out << Verbose(2) << "OtherComponents to Neighbour and OtherNeighbour are " << DistanceVector.x[Othercomponent] << " and " << OtherVector.x[Othercomponent] << "." << endl;
433 // do linear interpolation between points (is exact) to extract exact intersection between Neighbour and OtherNeighbour
434 w1 = fabs(OtherVector.x[Othercomponent]);
435 w2 = fabs(DistanceVector.x[Othercomponent]);
436 tmp = fabs((w1*DistanceVector.x[component] + w2*OtherVector.x[component])/(w1+w2));
437 // mark if it has greater diameter
438 //*out << Verbose(2) << "Comparing current greatest " << GreatestDiameter[component] << " to new " << tmp << "." << endl;
439 GreatestDiameter[component] = (GreatestDiameter[component] > tmp) ? GreatestDiameter[component] : tmp;
440 } //else
441 //*out << Verbose(2) << "Saw no sign flip, probably top or bottom node." << endl;
442 }
443 }
444 }
445 *out << Verbose(0) << "RESULT: The biggest diameters are " << GreatestDiameter[0] << " and " << GreatestDiameter[1] << " and " << GreatestDiameter[2] << " " << (IsAngstroem ? "angstrom" : "atomiclength") << "." << endl;
446
447 // free reference lists
448 if (BoundaryFreeFlag)
449 delete[](BoundaryPoints);
450
451 return GreatestDiameter;
452};
453
454
455/** Determines the volume of a cluster.
456 * Determines first the convex envelope, then tesselates it and calculates its volume.
457 * \param *out output stream for debugging
458 * \param *tecplot output stream for tecplot data
459 * \param *configuration needed for path to store convex envelope file
460 * \param *BoundaryPoints NDIM set of boundary points on the projected plane per axis, on return if desired
461 * \param *mol molecule structure representing the cluster
462 * \return determined volume of the cluster in cubed config:GetIsAngstroem()
463 */
464double VolumeOfConvexEnvelope(ofstream *out, ofstream *tecplot, config *configuration, Boundaries *BoundaryPtr, molecule *mol)
465{
466 bool IsAngstroem = configuration->GetIsAngstroem();
467 atom *Walker = NULL;
468 struct Tesselation *TesselStruct = new Tesselation;
469 bool BoundaryFreeFlag = false;
470 Boundaries *BoundaryPoints = BoundaryPtr;
471 double volume = 0.;
472 double PyramidVolume = 0.;
473 double G,h;
474 Vector x,y;
475 double a,b,c;
476
477 // 1. calculate center of gravity
478 *out << endl;
479 Vector *CenterOfGravity = mol->DetermineCenterOfGravity(out);
480
481 // 2. translate all points into CoG
482 *out << Verbose(1) << "Translating system to Center of Gravity." << endl;
483 Walker = mol->start;
484 while (Walker->next != mol->end) {
485 Walker = Walker->next;
486 Walker->x.Translate(CenterOfGravity);
487 }
488
489 // 3. Find all points on the boundary
490 if (BoundaryPoints == NULL) {
491 BoundaryFreeFlag = true;
492 BoundaryPoints = GetBoundaryPoints(out, mol);
493 } else {
494 *out << Verbose(1) << "Using given boundary points set." << endl;
495 }
496
497 // 4. fill the boundary point list
498 for (int axis=0;axis<NDIM;axis++)
499 for(Boundaries::iterator runner = BoundaryPoints[axis].begin(); runner != BoundaryPoints[axis].end(); runner++) {
500 TesselStruct->AddPoint(runner->second.second);
501 }
502
503 *out << Verbose(2) << "I found " << TesselStruct->PointsOnBoundaryCount << " points on the convex boundary." << endl;
504 // now we have the whole set of edge points in the BoundaryList
505
506 // listing for debugging
507// *out << Verbose(1) << "Listing PointsOnBoundary:";
508// for(PointMap::iterator runner = PointsOnBoundary.begin(); runner != PointsOnBoundary.end(); runner++) {
509// *out << " " << *runner->second;
510// }
511// *out << endl;
512
513 // 5a. guess starting triangle
514 TesselStruct->GuessStartingTriangle(out);
515
516 // 5b. go through all lines, that are not yet part of two triangles (only of one so far)
517 TesselStruct->TesselateOnBoundary(out, configuration, mol);
518
519 *out << Verbose(2) << "I created " << TesselStruct->TrianglesOnBoundaryCount << " triangles with " << TesselStruct->LinesOnBoundaryCount << " lines and " << TesselStruct->PointsOnBoundaryCount << " points." << endl;
520
521 // 6a. Every triangle forms a pyramid with the center of gravity as its peak, sum up the volumes
522 *out << Verbose(1) << "Calculating the volume of the pyramids formed out of triangles and center of gravity." << endl;
523 for (TriangleMap::iterator runner = TesselStruct->TrianglesOnBoundary.begin(); runner != TesselStruct->TrianglesOnBoundary.end(); runner++) { // go through every triangle, calculate volume of its pyramid with CoG as peak
524 x.CopyVector(&runner->second->endpoints[0]->node->x);
525 x.SubtractVector(&runner->second->endpoints[1]->node->x);
526 y.CopyVector(&runner->second->endpoints[0]->node->x);
527 y.SubtractVector(&runner->second->endpoints[2]->node->x);
528 a = sqrt(runner->second->endpoints[0]->node->x.Distance(&runner->second->endpoints[1]->node->x));
529 b = sqrt(runner->second->endpoints[0]->node->x.Distance(&runner->second->endpoints[2]->node->x));
530 c = sqrt(runner->second->endpoints[2]->node->x.Distance(&runner->second->endpoints[1]->node->x));
531 G = sqrt( ( (a*a+b*b+c*c)*(a*a+b*b+c*c) - 2*(a*a*a*a + b*b*b*b + c*c*c*c) )/16.); // area of tesselated triangle
532 x.MakeNormalVector(&runner->second->endpoints[0]->node->x, &runner->second->endpoints[1]->node->x, &runner->second->endpoints[2]->node->x);
533 x.Scale(runner->second->endpoints[1]->node->x.Projection(&x));
534 h = x.Norm(); // distance of CoG to triangle
535 PyramidVolume = (1./3.) * G * h; // this formula holds for _all_ pyramids (independent of n-edge base or (not) centered peak)
536 *out << Verbose(2) << "Area of triangle is " << G << " " << (IsAngstroem ? "angstrom" : "atomiclength") << "^2, height is " << h << " and the volume is " << PyramidVolume << " " << (IsAngstroem ? "angstrom" : "atomiclength") << "^3." << endl;
537 volume += PyramidVolume;
538 }
539 *out << Verbose(0) << "RESULT: The summed volume is " << setprecision(10) << volume << " " << (IsAngstroem ? "angstrom" : "atomiclength") << "^3." << endl;
540
541
542 // 7. translate all points back from CoG
543 *out << Verbose(1) << "Translating system back from Center of Gravity." << endl;
544 CenterOfGravity->Scale(-1);
545 Walker = mol->start;
546 while (Walker->next != mol->end) {
547 Walker = Walker->next;
548 Walker->x.Translate(CenterOfGravity);
549 }
550
551 // 8. Store triangles in tecplot file
552 if (tecplot != NULL) {
553 *tecplot << "TITLE = \"3D CONVEX SHELL\"" << endl;
554 *tecplot << "VARIABLES = \"X\" \"Y\" \"Z\"" << endl;
555 *tecplot << "ZONE T=\"TRIANGLES\", N=" << TesselStruct->PointsOnBoundaryCount << ", E=" << TesselStruct->TrianglesOnBoundaryCount << ", DATAPACKING=POINT, ZONETYPE=FETRIANGLE" << endl;
556 int *LookupList = new int[mol->AtomCount];
557 for (int i=0;i<mol->AtomCount;i++)
558 LookupList[i] = -1;
559
560 // print atom coordinates
561 *out << Verbose(2) << "The following triangles were created:";
562 int Counter = 1;
563 atom *Walker = NULL;
564 for (PointMap::iterator target = TesselStruct->PointsOnBoundary.begin(); target != TesselStruct->PointsOnBoundary.end(); target++) {
565 Walker = target->second->node;
566 LookupList[Walker->nr] = Counter++;
567 *tecplot << Walker->x.x[0] << " " << Walker->x.x[1] << " " << Walker->x.x[2] << " " << endl;
568 }
569 *tecplot << endl;
570 // print connectivity
571 for (TriangleMap::iterator runner = TesselStruct->TrianglesOnBoundary.begin(); runner != TesselStruct->TrianglesOnBoundary.end(); runner++) {
572 *out << " " << runner->second->endpoints[0]->node->Name << "<->" << runner->second->endpoints[1]->node->Name << "<->" << runner->second->endpoints[2]->node->Name;
573 *tecplot << LookupList[runner->second->endpoints[0]->node->nr] << " " << LookupList[runner->second->endpoints[1]->node->nr] << " " << LookupList[runner->second->endpoints[2]->node->nr] << endl;
574 }
575 delete[](LookupList);
576 *out << endl;
577 }
578
579 // free reference lists
580 if (BoundaryFreeFlag)
581 delete[](BoundaryPoints);
582
583 return volume;
584};
585
586
587/** Creates multiples of the by \a *mol given cluster and suspends them in water with a given final density.
588 * We get cluster volume by VolumeOfConvexEnvelope() and its diameters by GetDiametersOfCluster()
589 * \param *out output stream for debugging
590 * \param *configuration needed for path to store convex envelope file
591 * \param *mol molecule structure representing the cluster
592 * \param ClusterVolume guesstimated cluster volume, if equal 0 we used VolumeOfConvexEnvelope() instead.
593 * \param celldensity desired average density in final cell
594 */
595void PrepareClustersinWater(ofstream *out, config *configuration, molecule *mol, double ClusterVolume, double celldensity)
596{
597 // transform to PAS
598 mol->PrincipalAxisSystem(out, true);
599
600 // some preparations beforehand
601 bool IsAngstroem = configuration->GetIsAngstroem();
602 Boundaries *BoundaryPoints = GetBoundaryPoints(out, mol);
603 double clustervolume;
604 if (ClusterVolume == 0)
605 clustervolume = VolumeOfConvexEnvelope(out, NULL, configuration, BoundaryPoints, mol);
606 else
607 clustervolume = ClusterVolume;
608 double *GreatestDiameter = GetDiametersOfCluster(out, BoundaryPoints, mol, IsAngstroem);
609 Vector BoxLengths;
610 int repetition[NDIM] = {1, 1, 1};
611 int TotalNoClusters = 1;
612 for (int i=0;i<NDIM;i++)
613 TotalNoClusters *= repetition[i];
614
615 // sum up the atomic masses
616 double totalmass = 0.;
617 atom *Walker = mol->start;
618 while (Walker->next != mol->end) {
619 Walker = Walker->next;
620 totalmass += Walker->type->mass;
621 }
622 *out << Verbose(0) << "RESULT: The summed mass is " << setprecision(10) << totalmass << " atomicmassunit." << endl;
623
624 *out << Verbose(0) << "RESULT: The average density is " << setprecision(10) << totalmass/clustervolume << " atomicmassunit/" << (IsAngstroem ? "angstrom" : "atomiclength") << "^3." << endl;
625
626 // solve cubic polynomial
627 *out << Verbose(1) << "Solving equidistant suspension in water problem ..." << endl;
628 double cellvolume;
629 if (IsAngstroem)
630 cellvolume = (TotalNoClusters*totalmass/SOLVENTDENSITY_A - (totalmass/clustervolume))/(celldensity-1);
631 else
632 cellvolume = (TotalNoClusters*totalmass/SOLVENTDENSITY_a0 - (totalmass/clustervolume))/(celldensity-1);
633 *out << Verbose(1) << "Cellvolume needed for a density of " << celldensity << " g/cm^3 is " << cellvolume << " " << (IsAngstroem ? "angstrom" : "atomiclength") << "^3." << endl;
634
635 double minimumvolume = TotalNoClusters*(GreatestDiameter[0]*GreatestDiameter[1]*GreatestDiameter[2]);
636 *out << Verbose(1) << "Minimum volume of the convex envelope contained in a rectangular box is " << minimumvolume << " atomicmassunit/" << (IsAngstroem ? "angstrom" : "atomiclength") << "^3." << endl;
637 if (minimumvolume > cellvolume) {
638 cerr << Verbose(0) << "ERROR: the containing box already has a greater volume than the envisaged cell volume!" << endl;
639 cout << Verbose(0) << "Setting Box dimensions to minimum possible, the greatest diameters." << endl;
640 for(int i=0;i<NDIM;i++)
641 BoxLengths.x[i] = GreatestDiameter[i];
642 mol->CenterEdge(out, &BoxLengths);
643 } else {
644 BoxLengths.x[0] = (repetition[0]*GreatestDiameter[0] + repetition[1]*GreatestDiameter[1] + repetition[2]*GreatestDiameter[2]);
645 BoxLengths.x[1] = (repetition[0]*repetition[1]*GreatestDiameter[0]*GreatestDiameter[1]
646 + repetition[0]*repetition[2]*GreatestDiameter[0]*GreatestDiameter[2]
647 + repetition[1]*repetition[2]*GreatestDiameter[1]*GreatestDiameter[2]);
648 BoxLengths.x[2] = minimumvolume - cellvolume;
649 double x0 = 0.,x1 = 0.,x2 = 0.;
650 if (gsl_poly_solve_cubic(BoxLengths.x[0],BoxLengths.x[1],BoxLengths.x[2],&x0,&x1,&x2) == 1) // either 1 or 3 on return
651 *out << Verbose(0) << "RESULT: The resulting spacing is: " << x0 << " ." << endl;
652 else {
653 *out << Verbose(0) << "RESULT: The resulting spacings are: " << x0 << " and " << x1 << " and " << x2 << " ." << endl;
654 x0 = x2; // sorted in ascending order
655 }
656
657 cellvolume = 1;
658 for(int i=0;i<NDIM;i++) {
659 BoxLengths.x[i] = repetition[i] * (x0 + GreatestDiameter[i]);
660 cellvolume *= BoxLengths.x[i];
661 }
662
663 // set new box dimensions
664 *out << Verbose(0) << "Translating to box with these boundaries." << endl;
665 mol->CenterInBox((ofstream *)&cout, &BoxLengths);
666 }
667 // update Box of atoms by boundary
668 mol->SetBoxDimension(&BoxLengths);
669 *out << Verbose(0) << "RESULT: The resulting cell dimensions are: " << BoxLengths.x[0] << " and " << BoxLengths.x[1] << " and " << BoxLengths.x[2] << " with total volume of " << cellvolume << " " << (IsAngstroem ? "angstrom" : "atomiclength") << "^3." << endl;
670};
671
672
673// =========================================================== class TESSELATION ===========================================
674
675/** Constructor of class Tesselation.
676 */
677Tesselation::Tesselation()
678{
679 PointsOnBoundaryCount = 0;
680 LinesOnBoundaryCount = 0;
681 TrianglesOnBoundaryCount = 0;
682};
683
684/** Constructor of class Tesselation.
685 * We have to free all points, lines and triangles.
686 */
687Tesselation::~Tesselation()
688{
689 for (TriangleMap::iterator runner = TrianglesOnBoundary.begin(); runner != TrianglesOnBoundary.end(); runner++) {
690 delete(runner->second);
691 }
692};
693
694/** Gueses first starting triangle of the convex envelope.
695 * We guess the starting triangle by taking the smallest distance between two points and looking for a fitting third.
696 * \param *out output stream for debugging
697 * \param PointsOnBoundary set of boundary points defining the convex envelope of the cluster
698 */
699void Tesselation::GuessStartingTriangle(ofstream *out)
700{
701 // 4b. create a starting triangle
702 // 4b1. create all distances
703 DistanceMultiMap DistanceMMap;
704 double distance, tmp;
705 Vector PlaneVector, TrialVector;
706 PointMap::iterator A, B, C; // three nodes of the first triangle
707 A = PointsOnBoundary.begin(); // the first may be chosen arbitrarily
708
709 // with A chosen, take each pair B,C and sort
710 if (A != PointsOnBoundary.end()) {
711 B = A;
712 B++;
713 for (; B != PointsOnBoundary.end(); B++) {
714 C = B;
715 C++;
716 for (; C != PointsOnBoundary.end(); C++) {
717 tmp = A->second->node->x.Distance(&B->second->node->x);
718 distance = tmp*tmp;
719 tmp = A->second->node->x.Distance(&C->second->node->x);
720 distance += tmp*tmp;
721 tmp = B->second->node->x.Distance(&C->second->node->x);
722 distance += tmp*tmp;
723 DistanceMMap.insert( DistanceMultiMapPair(distance, pair<PointMap::iterator, PointMap::iterator>(B,C) ) );
724 }
725 }
726 }
727// // listing distances
728// *out << Verbose(1) << "Listing DistanceMMap:";
729// for(DistanceMultiMap::iterator runner = DistanceMMap.begin(); runner != DistanceMMap.end(); runner++) {
730// *out << " " << runner->first << "(" << *runner->second.first->second << ", " << *runner->second.second->second << ")";
731// }
732// *out << endl;
733
734 // 4b2. pick three baselines forming a triangle
735 // 1. we take from the smallest sum of squared distance as the base line BC (with peak A) onward as the triangle candidate
736 DistanceMultiMap::iterator baseline = DistanceMMap.begin();
737 for (; baseline != DistanceMMap.end(); baseline++) {
738 // we take from the smallest sum of squared distance as the base line BC (with peak A) onward as the triangle candidate
739 // 2. next, we have to check whether all points reside on only one side of the triangle
740 // 3. construct plane vector
741 PlaneVector.MakeNormalVector(&A->second->node->x, &baseline->second.first->second->node->x, &baseline->second.second->second->node->x);
742 *out << Verbose(2) << "Plane vector of candidate triangle is ";
743 PlaneVector.Output(out);
744 *out << endl;
745 // 4. loop over all points
746 double sign = 0.;
747 PointMap::iterator checker = PointsOnBoundary.begin();
748 for (; checker != PointsOnBoundary.end(); checker++) {
749 // (neglecting A,B,C)
750 if ((checker == A) || (checker == baseline->second.first) || (checker == baseline->second.second))
751 continue;
752 // 4a. project onto plane vector
753 TrialVector.CopyVector(&checker->second->node->x);
754 TrialVector.SubtractVector(&A->second->node->x);
755 distance = TrialVector.Projection(&PlaneVector);
756 if (fabs(distance) < 1e-4) // we need to have a small epsilon around 0 which is still ok
757 continue;
758 *out << Verbose(3) << "Projection of " << checker->second->node->Name << " yields distance of " << distance << "." << endl;
759 tmp = distance/fabs(distance);
760 // 4b. Any have different sign to than before? (i.e. would lie outside convex hull with this starting triangle)
761 if ((sign != 0) && (tmp != sign)) {
762 // 4c. If so, break 4. loop and continue with next candidate in 1. loop
763 *out << Verbose(2) << "Current candidates: " << A->second->node->Name << "," << baseline->second.first->second->node->Name << "," << baseline->second.second->second->node->Name << " leave " << checker->second->node->Name << " outside the convex hull." << endl;
764 break;
765 } else { // note the sign for later
766 *out << Verbose(2) << "Current candidates: " << A->second->node->Name << "," << baseline->second.first->second->node->Name << "," << baseline->second.second->second->node->Name << " leave " << checker->second->node->Name << " inside the convex hull." << endl;
767 sign = tmp;
768 }
769 // 4d. Check whether the point is inside the triangle (check distance to each node
770 tmp = checker->second->node->x.Distance(&A->second->node->x);
771 int innerpoint = 0;
772 if ((tmp < A->second->node->x.Distance(&baseline->second.first->second->node->x))
773 && (tmp < A->second->node->x.Distance(&baseline->second.second->second->node->x)))
774 innerpoint++;
775 tmp = checker->second->node->x.Distance(&baseline->second.first->second->node->x);
776 if ((tmp < baseline->second.first->second->node->x.Distance(&A->second->node->x))
777 && (tmp < baseline->second.first->second->node->x.Distance(&baseline->second.second->second->node->x)))
778 innerpoint++;
779 tmp = checker->second->node->x.Distance(&baseline->second.second->second->node->x);
780 if ((tmp < baseline->second.second->second->node->x.Distance(&baseline->second.first->second->node->x))
781 && (tmp < baseline->second.second->second->node->x.Distance(&A->second->node->x)))
782 innerpoint++;
783 // 4e. If so, break 4. loop and continue with next candidate in 1. loop
784 if (innerpoint == 3)
785 break;
786 }
787 // 5. come this far, all on same side? Then break 1. loop and construct triangle
788 if (checker == PointsOnBoundary.end()) {
789 *out << "Looks like we have a candidate!" << endl;
790 break;
791 }
792 }
793 if (baseline != DistanceMMap.end()) {
794 BPS[0] = baseline->second.first->second;
795 BPS[1] = baseline->second.second->second;
796 BLS[0] = new class BoundaryLineSet(BPS , LinesOnBoundaryCount);
797 BPS[0] = A->second;
798 BPS[1] = baseline->second.second->second;
799 BLS[1] = new class BoundaryLineSet(BPS , LinesOnBoundaryCount);
800 BPS[0] = baseline->second.first->second;
801 BPS[1] = A->second;
802 BLS[2] = new class BoundaryLineSet(BPS , LinesOnBoundaryCount);
803
804 // 4b3. insert created triangle
805 BTS = new class BoundaryTriangleSet(BLS, TrianglesOnBoundaryCount);
806 TrianglesOnBoundary.insert( TrianglePair(TrianglesOnBoundaryCount, BTS) );
807 TrianglesOnBoundaryCount++;
808 for(int i=0;i<NDIM;i++) {
809 LinesOnBoundary.insert( LinePair(LinesOnBoundaryCount, BTS->lines[i]) );
810 LinesOnBoundaryCount++;
811 }
812
813 *out << Verbose(1) << "Starting triangle is " << *BTS << "." << endl;
814 } else {
815 *out << Verbose(1) << "No starting triangle found." << endl;
816 exit(255);
817 }
818};
819
820
821/** Tesselates the convex envelope of a cluster from a single starting triangle.
822 * The starting triangle is made out of three baselines. Each line in the final tesselated cluster may belong to at most
823 * 2 triangles. Hence, we go through all current lines:
824 * -# if the lines contains to only one triangle
825 * -# We search all points in the boundary
826 * -# if the triangle with the baseline and the current point has the smallest of angles (comparison between normal vectors
827 * -# if the triangle is in forward direction of the baseline (at most 90 degrees angle between vector orthogonal to
828 * baseline in triangle plane pointing out of the triangle and normal vector of new triangle)
829 * -# then we have a new triangle, whose baselines we again add (or increase their TriangleCount)
830 * \param *out output stream for debugging
831 * \param *configuration for IsAngstroem
832 * \param *mol the cluster as a molecule structure
833 */
834void Tesselation::TesselateOnBoundary(ofstream *out, config *configuration, molecule *mol)
835{
836 bool flag;
837 PointMap::iterator winner;
838 class BoundaryPointSet *peak = NULL;
839 double SmallestAngle, TempAngle;
840 Vector NormalVector, VirtualNormalVector, CenterVector, TempVector, PropagationVector;
841 LineMap::iterator LineChecker[2];
842 do {
843 flag = false;
844 for (LineMap::iterator baseline = LinesOnBoundary.begin(); baseline != LinesOnBoundary.end(); baseline++)
845 if (baseline->second->TrianglesCount == 1) {
846 *out << Verbose(2) << "Current baseline is between " << *(baseline->second) << "." << endl;
847 // 5a. go through each boundary point if not _both_ edges between either endpoint of the current line and this point exist (and belong to 2 triangles)
848 SmallestAngle = M_PI;
849 BTS = baseline->second->triangles.begin()->second; // there is only one triangle so far
850 // get peak point with respect to this base line's only triangle
851 for(int i=0;i<3;i++)
852 if ((BTS->endpoints[i] != baseline->second->endpoints[0]) && (BTS->endpoints[i] != baseline->second->endpoints[1]))
853 peak = BTS->endpoints[i];
854 *out << Verbose(3) << " and has peak " << *peak << "." << endl;
855 // normal vector of triangle
856 BTS->GetNormalVector(NormalVector);
857 *out << Verbose(4) << "NormalVector of base triangle is ";
858 NormalVector.Output(out);
859 *out << endl;
860 // offset to center of triangle
861 CenterVector.Zero();
862 for(int i=0;i<3;i++)
863 CenterVector.AddVector(&BTS->endpoints[i]->node->x);
864 CenterVector.Scale(1./3.);
865 *out << Verbose(4) << "CenterVector of base triangle is ";
866 CenterVector.Output(out);
867 *out << endl;
868 // vector in propagation direction (out of triangle)
869 // project center vector onto triangle plane (points from intersection plane-NormalVector to plane-CenterVector intersection)
870 TempVector.CopyVector(&baseline->second->endpoints[0]->node->x);
871 TempVector.SubtractVector(&baseline->second->endpoints[1]->node->x);
872 PropagationVector.MakeNormalVector(&TempVector, &NormalVector);
873 TempVector.CopyVector(&CenterVector);
874 TempVector.SubtractVector(&baseline->second->endpoints[0]->node->x); // TempVector is vector on triangle plane pointing from one baseline egde towards center!
875 //*out << Verbose(2) << "Projection of propagation onto temp: " << PropagationVector.Projection(&TempVector) << "." << endl;
876 if (PropagationVector.Projection(&TempVector) > 0) // make sure normal propagation vector points outward from baseline
877 PropagationVector.Scale(-1.);
878 *out << Verbose(4) << "PropagationVector of base triangle is ";
879 PropagationVector.Output(out);
880 *out << endl;
881 winner = PointsOnBoundary.end();
882 for (PointMap::iterator target = PointsOnBoundary.begin(); target != PointsOnBoundary.end(); target++)
883 if ((target->second != baseline->second->endpoints[0]) && (target->second != baseline->second->endpoints[1])) { // don't take the same endpoints
884 *out << Verbose(3) << "Target point is " << *(target->second) << ":";
885 bool continueflag = true;
886
887 VirtualNormalVector.CopyVector(&baseline->second->endpoints[0]->node->x);
888 VirtualNormalVector.AddVector(&baseline->second->endpoints[0]->node->x);
889 VirtualNormalVector.Scale(-1./2.); // points now to center of base line
890 VirtualNormalVector.AddVector(&target->second->node->x); // points from center of base line to target
891 TempAngle = VirtualNormalVector.Angle(&PropagationVector);
892 continueflag = continueflag && (TempAngle < (M_PI/2.)); // no bends bigger than Pi/2 (90 degrees)
893 if (!continueflag) {
894 *out << Verbose(4) << "Angle between propagation direction and base line to " << *(target->second) << " is " << TempAngle << ", bad direction!" << endl;
895 continue;
896 } else
897 *out << Verbose(4) << "Angle between propagation direction and base line to " << *(target->second) << " is " << TempAngle << ", good direction!" << endl;
898 LineChecker[0] = baseline->second->endpoints[0]->lines.find(target->first);
899 LineChecker[1] = baseline->second->endpoints[1]->lines.find(target->first);
900 // if (LineChecker[0] != baseline->second->endpoints[0]->lines.end())
901 // *out << Verbose(4) << *(baseline->second->endpoints[0]) << " has line " << *(LineChecker[0]->second) << " to " << *(target->second) << " as endpoint with " << LineChecker[0]->second->TrianglesCount << " triangles." << endl;
902 // else
903 // *out << Verbose(4) << *(baseline->second->endpoints[0]) << " has no line to " << *(target->second) << " as endpoint." << endl;
904 // if (LineChecker[1] != baseline->second->endpoints[1]->lines.end())
905 // *out << Verbose(4) << *(baseline->second->endpoints[1]) << " has line " << *(LineChecker[1]->second) << " to " << *(target->second) << " as endpoint with " << LineChecker[1]->second->TrianglesCount << " triangles." << endl;
906 // else
907 // *out << Verbose(4) << *(baseline->second->endpoints[1]) << " has no line to " << *(target->second) << " as endpoint." << endl;
908 // check first endpoint (if any connecting line goes to target or at least not more than 1)
909 continueflag = continueflag && (( (LineChecker[0] == baseline->second->endpoints[0]->lines.end()) || (LineChecker[0]->second->TrianglesCount == 1)));
910 if (!continueflag) {
911 *out << Verbose(4) << *(baseline->second->endpoints[0]) << " has line " << *(LineChecker[0]->second) << " to " << *(target->second) << " as endpoint with " << LineChecker[0]->second->TrianglesCount << " triangles." << endl;
912 continue;
913 }
914 // check second endpoint (if any connecting line goes to target or at least not more than 1)
915 continueflag = continueflag && (( (LineChecker[1] == baseline->second->endpoints[1]->lines.end()) || (LineChecker[1]->second->TrianglesCount == 1)));
916 if (!continueflag) {
917 *out << Verbose(4) << *(baseline->second->endpoints[1]) << " has line " << *(LineChecker[1]->second) << " to " << *(target->second) << " as endpoint with " << LineChecker[1]->second->TrianglesCount << " triangles." << endl;
918 continue;
919 }
920 // check whether the envisaged triangle does not already exist (if both lines exist and have same endpoint)
921 continueflag = continueflag && (!(
922 ((LineChecker[0] != baseline->second->endpoints[0]->lines.end()) && (LineChecker[1] != baseline->second->endpoints[1]->lines.end())
923 && (GetCommonEndpoint(LineChecker[0]->second, LineChecker[1]->second) == peak))
924 ));
925 if (!continueflag) {
926 *out << Verbose(4) << "Current target is peak!" << endl;
927 continue;
928 }
929 // in case NOT both were found
930 if (continueflag) { // create virtually this triangle, get its normal vector, calculate angle
931 flag = true;
932 VirtualNormalVector.MakeNormalVector(&baseline->second->endpoints[0]->node->x, &baseline->second->endpoints[1]->node->x, &target->second->node->x);
933 // make it always point inward
934 if (baseline->second->endpoints[0]->node->x.Projection(&VirtualNormalVector) > 0)
935 VirtualNormalVector.Scale(-1.);
936 // calculate angle
937 TempAngle = NormalVector.Angle(&VirtualNormalVector);
938 *out << Verbose(4) << "NormalVector is ";
939 VirtualNormalVector.Output(out);
940 *out << " and the angle is " << TempAngle << "." << endl;
941 if (SmallestAngle > TempAngle) { // set to new possible winner
942 SmallestAngle = TempAngle;
943 winner = target;
944 }
945 }
946 }
947 // 5b. The point of the above whose triangle has the greatest angle with the triangle the current line belongs to (it only belongs to one, remember!): New triangle
948 if (winner != PointsOnBoundary.end()) {
949 *out << Verbose(2) << "Winning target point is " << *(winner->second) << " with angle " << SmallestAngle << "." << endl;
950 // create the lins of not yet present
951 BLS[0] = baseline->second;
952 // 5c. add lines to the line set if those were new (not yet part of a triangle), delete lines that belong to two triangles)
953 LineChecker[0] = baseline->second->endpoints[0]->lines.find(winner->first);
954 LineChecker[1] = baseline->second->endpoints[1]->lines.find(winner->first);
955 if (LineChecker[0] == baseline->second->endpoints[0]->lines.end()) { // create
956 BPS[0] = baseline->second->endpoints[0];
957 BPS[1] = winner->second;
958 BLS[1] = new class BoundaryLineSet(BPS , LinesOnBoundaryCount);
959 LinesOnBoundary.insert( LinePair(LinesOnBoundaryCount, BLS[1]) );
960 LinesOnBoundaryCount++;
961 } else
962 BLS[1] = LineChecker[0]->second;
963 if (LineChecker[1] == baseline->second->endpoints[1]->lines.end()) { // create
964 BPS[0] = baseline->second->endpoints[1];
965 BPS[1] = winner->second;
966 BLS[2] = new class BoundaryLineSet(BPS, LinesOnBoundaryCount);
967 LinesOnBoundary.insert( LinePair(LinesOnBoundaryCount, BLS[2]) );
968 LinesOnBoundaryCount++;
969 } else
970 BLS[2] = LineChecker[1]->second;
971 BTS = new class BoundaryTriangleSet(BLS, TrianglesOnBoundaryCount);
972 TrianglesOnBoundary.insert( TrianglePair(TrianglesOnBoundaryCount, BTS) );
973 TrianglesOnBoundaryCount++;
974 } else {
975 *out << Verbose(1) << "I could not determine a winner for this baseline " << *(baseline->second) << "." << endl;
976 }
977
978 // 5d. If the set of lines is not yet empty, go to 5. and continue
979 } else
980 *out << Verbose(2) << "Baseline candidate " << *(baseline->second) << " has a triangle count of " << baseline->second->TrianglesCount << "." << endl;
981 } while (flag);
982
983};
984
985/** Adds an atom to the tesselation::PointsOnBoundary list.
986 * \param *Walker atom to add
987 */
988void Tesselation::AddPoint(atom *Walker)
989{
990 PointTestPair InsertUnique;
991 BPS[0] = new class BoundaryPointSet(Walker);
992 InsertUnique = PointsOnBoundary.insert( PointPair(Walker->nr, BPS[0]) );
993 if (InsertUnique.second) // if new point was not present before, increase counter
994 PointsOnBoundaryCount++;
995};
Note: See TracBrowser for help on using the repository browser.