source: src/boundary.cpp@ 02bfde

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 02bfde was 02bfde, checked in by Frederik Heber <heber@…>, 17 years ago

Merge branch 'ConcaveHull' of ssh://stud64dc-01/home/neuen/workspace/ESPACK into ConcaveHull

Conflicts:

molecuilder/src/boundary.cpp

+ Merge is solved (was Christian's fault :)
+ find_non_convex_hull is checked and working on Heptan boundary

  • Property mode set to 100644
File size: 98.4 KB
Line 
1#include "molecules.hpp"
2#include "boundary.hpp"
3
4#define DEBUG 1
5
6// ======================================== Points on Boundary =================================
7
8BoundaryPointSet::BoundaryPointSet()
9{
10 LinesCount = 0;
11 Nr = -1;
12}
13;
14
15BoundaryPointSet::BoundaryPointSet(atom *Walker)
16{
17 node = Walker;
18 LinesCount = 0;
19 Nr = Walker->nr;
20}
21;
22
23BoundaryPointSet::~BoundaryPointSet()
24{
25 cout << Verbose(5) << "Erasing point nr. " << Nr << "." << endl;
26 node = NULL;
27}
28;
29
30void
31BoundaryPointSet::AddLine(class BoundaryLineSet *line)
32{
33 cout << Verbose(6) << "Adding " << *this << " to line " << *line << "."
34 << endl;
35 if (line->endpoints[0] == this)
36 {
37 lines.insert(LinePair(line->endpoints[1]->Nr, line));
38 }
39 else
40 {
41 lines.insert(LinePair(line->endpoints[0]->Nr, line));
42 }
43 LinesCount++;
44}
45;
46
47ostream &
48operator <<(ostream &ost, BoundaryPointSet &a)
49{
50 ost << "[" << a.Nr << "|" << a.node->Name << "]";
51 return ost;
52}
53;
54
55// ======================================== Lines on Boundary =================================
56
57BoundaryLineSet::BoundaryLineSet()
58{
59 for (int i = 0; i < 2; i++)
60 endpoints[i] = NULL;
61 TrianglesCount = 0;
62 Nr = -1;
63}
64;
65
66BoundaryLineSet::BoundaryLineSet(class BoundaryPointSet *Point[2], int number)
67{
68 // set number
69 Nr = number;
70 // set endpoints in ascending order
71 SetEndpointsOrdered(endpoints, Point[0], Point[1]);
72 // add this line to the hash maps of both endpoints
73 Point[0]->AddLine(this); //Taken out, to check whether we can avoid unwanted double adding.
74 Point[1]->AddLine(this); //
75 // clear triangles list
76 TrianglesCount = 0;
77 cout << Verbose(5) << "New Line with endpoints " << *this << "." << endl;
78}
79;
80
81BoundaryLineSet::~BoundaryLineSet()
82{
83 for (int i = 0; i < 2; i++)
84 {
85 cout << Verbose(5) << "Erasing Line Nr. " << Nr << " in boundary point "
86 << *endpoints[i] << "." << endl;
87 endpoints[i]->lines.erase(Nr);
88 LineMap::iterator tester = endpoints[i]->lines.begin();
89 tester++;
90 if (tester == endpoints[i]->lines.end())
91 {
92 cout << Verbose(5) << *endpoints[i]
93 << " has no more lines it's attached to, erasing." << endl;
94 //delete(endpoints[i]);
95 }
96 else
97 cout << Verbose(5) << *endpoints[i]
98 << " has still lines it's attached to." << endl;
99 }
100}
101;
102
103void
104BoundaryLineSet::AddTriangle(class BoundaryTriangleSet *triangle)
105{
106 cout << Verbose(6) << "Add " << triangle->Nr << " to line " << *this << "."
107 << endl;
108 triangles.insert(TrianglePair(TrianglesCount, triangle));
109 TrianglesCount++;
110}
111;
112
113ostream &
114operator <<(ostream &ost, BoundaryLineSet &a)
115{
116 ost << "[" << a.Nr << "|" << a.endpoints[0]->node->Name << ","
117 << a.endpoints[1]->node->Name << "]";
118 return ost;
119}
120;
121
122// ======================================== Triangles on Boundary =================================
123
124
125BoundaryTriangleSet::BoundaryTriangleSet()
126{
127 for (int i = 0; i < 3; i++)
128 {
129 endpoints[i] = NULL;
130 lines[i] = NULL;
131 }
132 Nr = -1;
133}
134;
135
136BoundaryTriangleSet::BoundaryTriangleSet(class BoundaryLineSet *line[3],
137 int number)
138{
139 // set number
140 Nr = number;
141 // set lines
142 cout << Verbose(5) << "New triangle " << Nr << ":" << endl;
143 for (int i = 0; i < 3; i++)
144 {
145 lines[i] = line[i];
146 lines[i]->AddTriangle(this);
147 }
148 // get ascending order of endpoints
149 map<int, class BoundaryPointSet *> OrderMap;
150 for (int i = 0; i < 3; i++)
151 // for all three lines
152 for (int j = 0; j < 2; j++)
153 { // for both endpoints
154 OrderMap.insert(pair<int, class BoundaryPointSet *> (
155 line[i]->endpoints[j]->Nr, line[i]->endpoints[j]));
156 // and we don't care whether insertion fails
157 }
158 // set endpoints
159 int Counter = 0;
160 cout << Verbose(6) << " with end points ";
161 for (map<int, class BoundaryPointSet *>::iterator runner = OrderMap.begin(); runner
162 != OrderMap.end(); runner++)
163 {
164 endpoints[Counter] = runner->second;
165 cout << " " << *endpoints[Counter];
166 Counter++;
167 }
168 if (Counter < 3)
169 {
170 cerr << "ERROR! We have a triangle with only two distinct endpoints!"
171 << endl;
172 //exit(1);
173 }
174 cout << "." << endl;
175}
176;
177
178BoundaryTriangleSet::~BoundaryTriangleSet()
179{
180 for (int i = 0; i < 3; i++)
181 {
182 cout << Verbose(5) << "Erasing triangle Nr." << Nr << endl;
183 lines[i]->triangles.erase(Nr);
184 TriangleMap::iterator tester = lines[i]->triangles.begin();
185 tester++;
186 if (tester == lines[i]->triangles.end())
187 {
188 cout << Verbose(5) << *lines[i]
189 << " is no more attached to any triangle, erasing." << endl;
190 delete (lines[i]);
191 }
192 else
193 cout << Verbose(5) << *lines[i] << " is still attached to a triangle."
194 << endl;
195 }
196}
197;
198
199void
200BoundaryTriangleSet::GetNormalVector(Vector &OtherVector)
201{
202 // get normal vector
203 NormalVector.MakeNormalVector(&endpoints[0]->node->x, &endpoints[1]->node->x,
204 &endpoints[2]->node->x);
205
206 // make it always point inward (any offset vector onto plane projected onto normal vector suffices)
207 if (endpoints[0]->node->x.Projection(&OtherVector) > 0)
208 NormalVector.Scale(-1.);
209}
210;
211
212ostream &
213operator <<(ostream &ost, BoundaryTriangleSet &a)
214{
215 ost << "[" << a.Nr << "|" << a.endpoints[0]->node->Name << ","
216 << a.endpoints[1]->node->Name << "," << a.endpoints[2]->node->Name << "]";
217 return ost;
218}
219;
220
221// ========================================== F U N C T I O N S =================================
222
223/** Finds the endpoint two lines are sharing.
224 * \param *line1 first line
225 * \param *line2 second line
226 * \return point which is shared or NULL if none
227 */
228class BoundaryPointSet *
229GetCommonEndpoint(class BoundaryLineSet * line1, class BoundaryLineSet * line2)
230{
231 class BoundaryLineSet * lines[2] =
232 { line1, line2 };
233 class BoundaryPointSet *node = NULL;
234 map<int, class BoundaryPointSet *> OrderMap;
235 pair<map<int, class BoundaryPointSet *>::iterator, bool> OrderTest;
236 for (int i = 0; i < 2; i++)
237 // for both lines
238 for (int j = 0; j < 2; j++)
239 { // for both endpoints
240 OrderTest = OrderMap.insert(pair<int, class BoundaryPointSet *> (
241 lines[i]->endpoints[j]->Nr, lines[i]->endpoints[j]));
242 if (!OrderTest.second)
243 { // if insertion fails, we have common endpoint
244 node = OrderTest.first->second;
245 cout << Verbose(5) << "Common endpoint of lines " << *line1
246 << " and " << *line2 << " is: " << *node << "." << endl;
247 j = 2;
248 i = 2;
249 break;
250 }
251 }
252 return node;
253}
254;
255
256/** Determines the boundary points of a cluster.
257 * Does a projection per axis onto the orthogonal plane, transforms into spherical coordinates, sorts them by the angle
258 * and looks at triples: if the middle has less a distance than the allowed maximum height of the triangle formed by the plane's
259 * center and first and last point in the triple, it is thrown out.
260 * \param *out output stream for debugging
261 * \param *mol molecule structure representing the cluster
262 */
263Boundaries *
264GetBoundaryPoints(ofstream *out, molecule *mol)
265{
266 atom *Walker = NULL;
267 PointMap PointsOnBoundary;
268 LineMap LinesOnBoundary;
269 TriangleMap TrianglesOnBoundary;
270
271 *out << Verbose(1) << "Finding all boundary points." << endl;
272 Boundaries *BoundaryPoints = new Boundaries[NDIM]; // first is alpha, second is (r, nr)
273 BoundariesTestPair BoundaryTestPair;
274 Vector AxisVector, AngleReferenceVector, AngleReferenceNormalVector;
275 double radius, angle;
276 // 3a. Go through every axis
277 for (int axis = 0; axis < NDIM; axis++)
278 {
279 AxisVector.Zero();
280 AngleReferenceVector.Zero();
281 AngleReferenceNormalVector.Zero();
282 AxisVector.x[axis] = 1.;
283 AngleReferenceVector.x[(axis + 1) % NDIM] = 1.;
284 AngleReferenceNormalVector.x[(axis + 2) % NDIM] = 1.;
285 // *out << Verbose(1) << "Axisvector is ";
286 // AxisVector.Output(out);
287 // *out << " and AngleReferenceVector is ";
288 // AngleReferenceVector.Output(out);
289 // *out << "." << endl;
290 // *out << " and AngleReferenceNormalVector is ";
291 // AngleReferenceNormalVector.Output(out);
292 // *out << "." << endl;
293 // 3b. construct set of all points, transformed into cylindrical system and with left and right neighbours
294 Walker = mol->start;
295 while (Walker->next != mol->end)
296 {
297 Walker = Walker->next;
298 Vector ProjectedVector;
299 ProjectedVector.CopyVector(&Walker->x);
300 ProjectedVector.ProjectOntoPlane(&AxisVector);
301 // correct for negative side
302 //if (Projection(y) < 0)
303 //angle = 2.*M_PI - angle;
304 radius = ProjectedVector.Norm();
305 if (fabs(radius) > MYEPSILON)
306 angle = ProjectedVector.Angle(&AngleReferenceVector);
307 else
308 angle = 0.; // otherwise it's a vector in Axis Direction and unimportant for boundary issues
309
310 //*out << "Checking sign in quadrant : " << ProjectedVector.Projection(&AngleReferenceNormalVector) << "." << endl;
311 if (ProjectedVector.Projection(&AngleReferenceNormalVector) > 0)
312 {
313 angle = 2. * M_PI - angle;
314 }
315 //*out << Verbose(2) << "Inserting " << *Walker << ": (r, alpha) = (" << radius << "," << angle << "): ";
316 //ProjectedVector.Output(out);
317 //*out << endl;
318 BoundaryTestPair = BoundaryPoints[axis].insert(BoundariesPair(angle,
319 DistancePair (radius, Walker)));
320 if (BoundaryTestPair.second)
321 { // successfully inserted
322 }
323 else
324 { // same point exists, check first r, then distance of original vectors to center of gravity
325 *out << Verbose(2)
326 << "Encountered two vectors whose projection onto axis "
327 << axis << " is equal: " << endl;
328 *out << Verbose(2) << "Present vector: ";
329 BoundaryTestPair.first->second.second->x.Output(out);
330 *out << endl;
331 *out << Verbose(2) << "New vector: ";
332 Walker->x.Output(out);
333 *out << endl;
334 double tmp = ProjectedVector.Norm();
335 if (tmp > BoundaryTestPair.first->second.first)
336 {
337 BoundaryTestPair.first->second.first = tmp;
338 BoundaryTestPair.first->second.second = Walker;
339 *out << Verbose(2) << "Keeping new vector." << endl;
340 }
341 else if (tmp == BoundaryTestPair.first->second.first)
342 {
343 if (BoundaryTestPair.first->second.second->x.ScalarProduct(
344 &BoundaryTestPair.first->second.second->x)
345 < Walker->x.ScalarProduct(&Walker->x))
346 { // Norm() does a sqrt, which makes it a lot slower
347 BoundaryTestPair.first->second.second = Walker;
348 *out << Verbose(2) << "Keeping new vector." << endl;
349 }
350 else
351 {
352 *out << Verbose(2) << "Keeping present vector." << endl;
353 }
354 }
355 else
356 {
357 *out << Verbose(2) << "Keeping present vector." << endl;
358 }
359 }
360 }
361 // printing all inserted for debugging
362 // {
363 // *out << Verbose(2) << "Printing list of candidates for axis " << axis << " which we have inserted so far." << endl;
364 // int i=0;
365 // for(Boundaries::iterator runner = BoundaryPoints[axis].begin(); runner != BoundaryPoints[axis].end(); runner++) {
366 // if (runner != BoundaryPoints[axis].begin())
367 // *out << ", " << i << ": " << *runner->second.second;
368 // else
369 // *out << i << ": " << *runner->second.second;
370 // i++;
371 // }
372 // *out << endl;
373 // }
374 // 3c. throw out points whose distance is less than the mean of left and right neighbours
375 bool flag = false;
376 do
377 { // do as long as we still throw one out per round
378 *out << Verbose(1)
379 << "Looking for candidates to kick out by convex condition ... "
380 << endl;
381 flag = false;
382 Boundaries::iterator left = BoundaryPoints[axis].end();
383 Boundaries::iterator right = BoundaryPoints[axis].end();
384 for (Boundaries::iterator runner = BoundaryPoints[axis].begin(); runner
385 != BoundaryPoints[axis].end(); runner++)
386 {
387 // set neighbours correctly
388 if (runner == BoundaryPoints[axis].begin())
389 {
390 left = BoundaryPoints[axis].end();
391 }
392 else
393 {
394 left = runner;
395 }
396 left--;
397 right = runner;
398 right++;
399 if (right == BoundaryPoints[axis].end())
400 {
401 right = BoundaryPoints[axis].begin();
402 }
403 // check distance
404
405 // construct the vector of each side of the triangle on the projected plane (defined by normal vector AxisVector)
406 {
407 Vector SideA, SideB, SideC, SideH;
408 SideA.CopyVector(&left->second.second->x);
409 SideA.ProjectOntoPlane(&AxisVector);
410 // *out << "SideA: ";
411 // SideA.Output(out);
412 // *out << endl;
413
414 SideB.CopyVector(&right->second.second->x);
415 SideB.ProjectOntoPlane(&AxisVector);
416 // *out << "SideB: ";
417 // SideB.Output(out);
418 // *out << endl;
419
420 SideC.CopyVector(&left->second.second->x);
421 SideC.SubtractVector(&right->second.second->x);
422 SideC.ProjectOntoPlane(&AxisVector);
423 // *out << "SideC: ";
424 // SideC.Output(out);
425 // *out << endl;
426
427 SideH.CopyVector(&runner->second.second->x);
428 SideH.ProjectOntoPlane(&AxisVector);
429 // *out << "SideH: ";
430 // SideH.Output(out);
431 // *out << endl;
432
433 // calculate each length
434 double a = SideA.Norm();
435 //double b = SideB.Norm();
436 //double c = SideC.Norm();
437 double h = SideH.Norm();
438 // calculate the angles
439 double alpha = SideA.Angle(&SideH);
440 double beta = SideA.Angle(&SideC);
441 double gamma = SideB.Angle(&SideH);
442 double delta = SideC.Angle(&SideH);
443 double MinDistance = a * sin(beta) / (sin(delta)) * (((alpha
444 < M_PI / 2.) || (gamma < M_PI / 2.)) ? 1. : -1.);
445 // *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;
446 //*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;
447 if ((fabs(h / fabs(h) - MinDistance / fabs(MinDistance))
448 < MYEPSILON) && (h < MinDistance))
449 {
450 // throw out point
451 //*out << Verbose(1) << "Throwing out " << *runner->second.second << "." << endl;
452 BoundaryPoints[axis].erase(runner);
453 flag = true;
454 }
455 }
456 }
457 }
458 while (flag);
459 }
460 return BoundaryPoints;
461}
462;
463
464/** Determines greatest diameters of a cluster defined by its convex envelope.
465 * Looks at lines parallel to one axis and where they intersect on the projected planes
466 * \param *out output stream for debugging
467 * \param *BoundaryPoints NDIM set of boundary points defining the convex envelope on each projected plane
468 * \param *mol molecule structure representing the cluster
469 * \param IsAngstroem whether we have angstroem or atomic units
470 * \return NDIM array of the diameters
471 */
472double *
473GetDiametersOfCluster(ofstream *out, Boundaries *BoundaryPtr, molecule *mol,
474 bool IsAngstroem)
475{
476 // get points on boundary of NULL was given as parameter
477 bool BoundaryFreeFlag = false;
478 Boundaries *BoundaryPoints = BoundaryPtr;
479 if (BoundaryPoints == NULL)
480 {
481 BoundaryFreeFlag = true;
482 BoundaryPoints = GetBoundaryPoints(out, mol);
483 }
484 else
485 {
486 *out << Verbose(1) << "Using given boundary points set." << endl;
487 }
488 // determine biggest "diameter" of cluster for each axis
489 Boundaries::iterator Neighbour, OtherNeighbour;
490 double *GreatestDiameter = new double[NDIM];
491 for (int i = 0; i < NDIM; i++)
492 GreatestDiameter[i] = 0.;
493 double OldComponent, tmp, w1, w2;
494 Vector DistanceVector, OtherVector;
495 int component, Othercomponent;
496 for (int axis = 0; axis < NDIM; axis++)
497 { // regard each projected plane
498 //*out << Verbose(1) << "Current axis is " << axis << "." << endl;
499 for (int j = 0; j < 2; j++)
500 { // and for both axis on the current plane
501 component = (axis + j + 1) % NDIM;
502 Othercomponent = (axis + 1 + ((j + 1) & 1)) % NDIM;
503 //*out << Verbose(1) << "Current component is " << component << ", Othercomponent is " << Othercomponent << "." << endl;
504 for (Boundaries::iterator runner = BoundaryPoints[axis].begin(); runner
505 != BoundaryPoints[axis].end(); runner++)
506 {
507 //*out << Verbose(2) << "Current runner is " << *(runner->second.second) << "." << endl;
508 // seek for the neighbours pair where the Othercomponent sign flips
509 Neighbour = runner;
510 Neighbour++;
511 if (Neighbour == BoundaryPoints[axis].end()) // make it wrap around
512 Neighbour = BoundaryPoints[axis].begin();
513 DistanceVector.CopyVector(&runner->second.second->x);
514 DistanceVector.SubtractVector(&Neighbour->second.second->x);
515 do
516 { // seek for neighbour pair where it flips
517 OldComponent = DistanceVector.x[Othercomponent];
518 Neighbour++;
519 if (Neighbour == BoundaryPoints[axis].end()) // make it wrap around
520 Neighbour = BoundaryPoints[axis].begin();
521 DistanceVector.CopyVector(&runner->second.second->x);
522 DistanceVector.SubtractVector(&Neighbour->second.second->x);
523 //*out << Verbose(3) << "OldComponent is " << OldComponent << ", new one is " << DistanceVector.x[Othercomponent] << "." << endl;
524 }
525 while ((runner != Neighbour) && (fabs(OldComponent / fabs(
526 OldComponent) - DistanceVector.x[Othercomponent] / fabs(
527 DistanceVector.x[Othercomponent])) < MYEPSILON)); // as long as sign does not flip
528 if (runner != Neighbour)
529 {
530 OtherNeighbour = Neighbour;
531 if (OtherNeighbour == BoundaryPoints[axis].begin()) // make it wrap around
532 OtherNeighbour = BoundaryPoints[axis].end();
533 OtherNeighbour--;
534 //*out << Verbose(2) << "The pair, where the sign of OtherComponent flips, is: " << *(Neighbour->second.second) << " and " << *(OtherNeighbour->second.second) << "." << endl;
535 // now we have found the pair: Neighbour and OtherNeighbour
536 OtherVector.CopyVector(&runner->second.second->x);
537 OtherVector.SubtractVector(&OtherNeighbour->second.second->x);
538 //*out << Verbose(2) << "Distances to Neighbour and OtherNeighbour are " << DistanceVector.x[component] << " and " << OtherVector.x[component] << "." << endl;
539 //*out << Verbose(2) << "OtherComponents to Neighbour and OtherNeighbour are " << DistanceVector.x[Othercomponent] << " and " << OtherVector.x[Othercomponent] << "." << endl;
540 // do linear interpolation between points (is exact) to extract exact intersection between Neighbour and OtherNeighbour
541 w1 = fabs(OtherVector.x[Othercomponent]);
542 w2 = fabs(DistanceVector.x[Othercomponent]);
543 tmp = fabs((w1 * DistanceVector.x[component] + w2
544 * OtherVector.x[component]) / (w1 + w2));
545 // mark if it has greater diameter
546 //*out << Verbose(2) << "Comparing current greatest " << GreatestDiameter[component] << " to new " << tmp << "." << endl;
547 GreatestDiameter[component] = (GreatestDiameter[component]
548 > tmp) ? GreatestDiameter[component] : tmp;
549 } //else
550 //*out << Verbose(2) << "Saw no sign flip, probably top or bottom node." << endl;
551 }
552 }
553 }
554 *out << Verbose(0) << "RESULT: The biggest diameters are "
555 << GreatestDiameter[0] << " and " << GreatestDiameter[1] << " and "
556 << GreatestDiameter[2] << " " << (IsAngstroem ? "angstrom"
557 : "atomiclength") << "." << endl;
558
559 // free reference lists
560 if (BoundaryFreeFlag)
561 delete[] (BoundaryPoints);
562
563 return GreatestDiameter;
564}
565;
566
567/*
568 * This function creates the tecplot file, displaying the tesselation of the hull.
569 * \param *out output stream for debugging
570 * \param *tecplot output stream for tecplot data
571 * \param N arbitrary number to differentiate various zones in the tecplot format
572 */
573void
574write_tecplot_file(ofstream *out, ofstream *tecplot,
575 class Tesselation *TesselStruct, class molecule *mol, int N)
576{
577 if (tecplot != NULL)
578 {
579 *tecplot << "TITLE = \"3D CONVEX SHELL\"" << endl;
580 *tecplot << "VARIABLES = \"X\" \"Y\" \"Z\"" << endl;
581 *tecplot << "ZONE T=\"TRIANGLES" << N << "\", N="
582 << TesselStruct->PointsOnBoundaryCount << ", E="
583 << TesselStruct->TrianglesOnBoundaryCount
584 << ", DATAPACKING=POINT, ZONETYPE=FETRIANGLE" << endl;
585 int *LookupList = new int[mol->AtomCount];
586 for (int i = 0; i < mol->AtomCount; i++)
587 LookupList[i] = -1;
588
589 // print atom coordinates
590 *out << Verbose(2) << "The following triangles were created:";
591 int Counter = 1;
592 atom *Walker = NULL;
593 for (PointMap::iterator target = TesselStruct->PointsOnBoundary.begin(); target
594 != TesselStruct->PointsOnBoundary.end(); target++)
595 {
596 Walker = target->second->node;
597 LookupList[Walker->nr] = Counter++;
598 *tecplot << Walker->x.x[0] << " " << Walker->x.x[1] << " "
599 << Walker->x.x[2] << " " << endl;
600 }
601 *tecplot << endl;
602 // print connectivity
603 for (TriangleMap::iterator runner =
604 TesselStruct->TrianglesOnBoundary.begin(); runner
605 != TesselStruct->TrianglesOnBoundary.end(); runner++)
606 {
607 *out << " " << runner->second->endpoints[0]->node->Name << "<->"
608 << runner->second->endpoints[1]->node->Name << "<->"
609 << runner->second->endpoints[2]->node->Name;
610 *tecplot << LookupList[runner->second->endpoints[0]->node->nr] << " "
611 << LookupList[runner->second->endpoints[1]->node->nr] << " "
612 << LookupList[runner->second->endpoints[2]->node->nr] << endl;
613 }
614 delete[] (LookupList);
615 *out << endl;
616 }
617}
618
619/** Determines the volume of a cluster.
620 * Determines first the convex envelope, then tesselates it and calculates its volume.
621 * \param *out output stream for debugging
622 * \param *tecplot output stream for tecplot data
623 * \param *configuration needed for path to store convex envelope file
624 * \param *BoundaryPoints NDIM set of boundary points on the projected plane per axis, on return if desired
625 * \param *mol molecule structure representing the cluster
626 * \return determined volume of the cluster in cubed config:GetIsAngstroem()
627 */
628double
629VolumeOfConvexEnvelope(ofstream *out, ofstream *tecplot, config *configuration,
630 Boundaries *BoundaryPtr, molecule *mol)
631{
632 bool IsAngstroem = configuration->GetIsAngstroem();
633 atom *Walker = NULL;
634 struct Tesselation *TesselStruct = new Tesselation;
635 bool BoundaryFreeFlag = false;
636 Boundaries *BoundaryPoints = BoundaryPtr;
637 double volume = 0.;
638 double PyramidVolume = 0.;
639 double G, h;
640 Vector x, y;
641 double a, b, c;
642
643 //Find_non_convex_border(out, tecplot, *TesselStruct, mol); // Is now called from command line.
644
645 // 1. calculate center of gravity
646 *out << endl;
647 Vector *CenterOfGravity = mol->DetermineCenterOfGravity(out);
648
649 // 2. translate all points into CoG
650 *out << Verbose(1) << "Translating system to Center of Gravity." << endl;
651 Walker = mol->start;
652 while (Walker->next != mol->end)
653 {
654 Walker = Walker->next;
655 Walker->x.Translate(CenterOfGravity);
656 }
657
658 // 3. Find all points on the boundary
659 if (BoundaryPoints == NULL)
660 {
661 BoundaryFreeFlag = true;
662 BoundaryPoints = GetBoundaryPoints(out, mol);
663 }
664 else
665 {
666 *out << Verbose(1) << "Using given boundary points set." << endl;
667 }
668
669 // 4. fill the boundary point list
670 for (int axis = 0; axis < NDIM; axis++)
671 for (Boundaries::iterator runner = BoundaryPoints[axis].begin(); runner
672 != BoundaryPoints[axis].end(); runner++)
673 {
674 TesselStruct->AddPoint(runner->second.second);
675 }
676
677 *out << Verbose(2) << "I found " << TesselStruct->PointsOnBoundaryCount
678 << " points on the convex boundary." << endl;
679 // now we have the whole set of edge points in the BoundaryList
680
681 // listing for debugging
682 // *out << Verbose(1) << "Listing PointsOnBoundary:";
683 // for(PointMap::iterator runner = PointsOnBoundary.begin(); runner != PointsOnBoundary.end(); runner++) {
684 // *out << " " << *runner->second;
685 // }
686 // *out << endl;
687
688 // 5a. guess starting triangle
689 TesselStruct->GuessStartingTriangle(out);
690
691 // 5b. go through all lines, that are not yet part of two triangles (only of one so far)
692 TesselStruct->TesselateOnBoundary(out, configuration, mol);
693
694 *out << Verbose(2) << "I created " << TesselStruct->TrianglesOnBoundaryCount
695 << " triangles with " << TesselStruct->LinesOnBoundaryCount
696 << " lines and " << TesselStruct->PointsOnBoundaryCount << " points."
697 << endl;
698
699 // 6a. Every triangle forms a pyramid with the center of gravity as its peak, sum up the volumes
700 *out << Verbose(1)
701 << "Calculating the volume of the pyramids formed out of triangles and center of gravity."
702 << endl;
703 for (TriangleMap::iterator runner = TesselStruct->TrianglesOnBoundary.begin(); runner
704 != TesselStruct->TrianglesOnBoundary.end(); runner++)
705 { // go through every triangle, calculate volume of its pyramid with CoG as peak
706 x.CopyVector(&runner->second->endpoints[0]->node->x);
707 x.SubtractVector(&runner->second->endpoints[1]->node->x);
708 y.CopyVector(&runner->second->endpoints[0]->node->x);
709 y.SubtractVector(&runner->second->endpoints[2]->node->x);
710 a = sqrt(runner->second->endpoints[0]->node->x.Distance(
711 &runner->second->endpoints[1]->node->x));
712 b = sqrt(runner->second->endpoints[0]->node->x.Distance(
713 &runner->second->endpoints[2]->node->x));
714 c = sqrt(runner->second->endpoints[2]->node->x.Distance(
715 &runner->second->endpoints[1]->node->x));
716 G = sqrt(((a * a + b * b + c * c) * (a * a + b * b + c * c) - 2 * (a * a
717 * a * a + b * b * b * b + c * c * c * c)) / 16.); // area of tesselated triangle
718 x.MakeNormalVector(&runner->second->endpoints[0]->node->x,
719 &runner->second->endpoints[1]->node->x,
720 &runner->second->endpoints[2]->node->x);
721 x.Scale(runner->second->endpoints[1]->node->x.Projection(&x));
722 h = x.Norm(); // distance of CoG to triangle
723 PyramidVolume = (1. / 3.) * G * h; // this formula holds for _all_ pyramids (independent of n-edge base or (not) centered peak)
724 *out << Verbose(2) << "Area of triangle is " << G << " "
725 << (IsAngstroem ? "angstrom" : "atomiclength") << "^2, height is "
726 << h << " and the volume is " << PyramidVolume << " "
727 << (IsAngstroem ? "angstrom" : "atomiclength") << "^3." << endl;
728 volume += PyramidVolume;
729 }
730 *out << Verbose(0) << "RESULT: The summed volume is " << setprecision(10)
731 << volume << " " << (IsAngstroem ? "angstrom" : "atomiclength") << "^3."
732 << endl;
733
734 // 7. translate all points back from CoG
735 *out << Verbose(1) << "Translating system back from Center of Gravity."
736 << endl;
737 CenterOfGravity->Scale(-1);
738 Walker = mol->start;
739 while (Walker->next != mol->end)
740 {
741 Walker = Walker->next;
742 Walker->x.Translate(CenterOfGravity);
743 }
744
745 // 8. Store triangles in tecplot file
746 write_tecplot_file(out, tecplot, TesselStruct, mol, 0);
747
748 // free reference lists
749 if (BoundaryFreeFlag)
750 delete[] (BoundaryPoints);
751
752 return volume;
753}
754;
755
756/** Creates multiples of the by \a *mol given cluster and suspends them in water with a given final density.
757 * We get cluster volume by VolumeOfConvexEnvelope() and its diameters by GetDiametersOfCluster()
758 * \param *out output stream for debugging
759 * \param *configuration needed for path to store convex envelope file
760 * \param *mol molecule structure representing the cluster
761 * \param ClusterVolume guesstimated cluster volume, if equal 0 we used VolumeOfConvexEnvelope() instead.
762 * \param celldensity desired average density in final cell
763 */
764void
765PrepareClustersinWater(ofstream *out, config *configuration, molecule *mol,
766 double ClusterVolume, double celldensity)
767{
768 // transform to PAS
769 mol->PrincipalAxisSystem(out, true);
770
771 // some preparations beforehand
772 bool IsAngstroem = configuration->GetIsAngstroem();
773 Boundaries *BoundaryPoints = GetBoundaryPoints(out, mol);
774 double clustervolume;
775 if (ClusterVolume == 0)
776 clustervolume = VolumeOfConvexEnvelope(out, NULL, configuration,
777 BoundaryPoints, mol);
778 else
779 clustervolume = ClusterVolume;
780 double *GreatestDiameter = GetDiametersOfCluster(out, BoundaryPoints, mol,
781 IsAngstroem);
782 Vector BoxLengths;
783 int repetition[NDIM] =
784 { 1, 1, 1 };
785 int TotalNoClusters = 1;
786 for (int i = 0; i < NDIM; i++)
787 TotalNoClusters *= repetition[i];
788
789 // sum up the atomic masses
790 double totalmass = 0.;
791 atom *Walker = mol->start;
792 while (Walker->next != mol->end)
793 {
794 Walker = Walker->next;
795 totalmass += Walker->type->mass;
796 }
797 *out << Verbose(0) << "RESULT: The summed mass is " << setprecision(10)
798 << totalmass << " atomicmassunit." << endl;
799
800 *out << Verbose(0) << "RESULT: The average density is " << setprecision(10)
801 << totalmass / clustervolume << " atomicmassunit/"
802 << (IsAngstroem ? "angstrom" : "atomiclength") << "^3." << endl;
803
804 // solve cubic polynomial
805 *out << Verbose(1) << "Solving equidistant suspension in water problem ..."
806 << endl;
807 double cellvolume;
808 if (IsAngstroem)
809 cellvolume = (TotalNoClusters * totalmass / SOLVENTDENSITY_A - (totalmass
810 / clustervolume)) / (celldensity - 1);
811 else
812 cellvolume = (TotalNoClusters * totalmass / SOLVENTDENSITY_a0 - (totalmass
813 / clustervolume)) / (celldensity - 1);
814 *out << Verbose(1) << "Cellvolume needed for a density of " << celldensity
815 << " g/cm^3 is " << cellvolume << " " << (IsAngstroem ? "angstrom"
816 : "atomiclength") << "^3." << endl;
817
818 double minimumvolume = TotalNoClusters * (GreatestDiameter[0]
819 * GreatestDiameter[1] * GreatestDiameter[2]);
820 *out << Verbose(1)
821 << "Minimum volume of the convex envelope contained in a rectangular box is "
822 << minimumvolume << " atomicmassunit/" << (IsAngstroem ? "angstrom"
823 : "atomiclength") << "^3." << endl;
824 if (minimumvolume > cellvolume)
825 {
826 cerr << Verbose(0)
827 << "ERROR: the containing box already has a greater volume than the envisaged cell volume!"
828 << endl;
829 cout << Verbose(0)
830 << "Setting Box dimensions to minimum possible, the greatest diameters."
831 << endl;
832 for (int i = 0; i < NDIM; i++)
833 BoxLengths.x[i] = GreatestDiameter[i];
834 mol->CenterEdge(out, &BoxLengths);
835 }
836 else
837 {
838 BoxLengths.x[0] = (repetition[0] * GreatestDiameter[0] + repetition[1]
839 * GreatestDiameter[1] + repetition[2] * GreatestDiameter[2]);
840 BoxLengths.x[1] = (repetition[0] * repetition[1] * GreatestDiameter[0]
841 * GreatestDiameter[1] + repetition[0] * repetition[2]
842 * GreatestDiameter[0] * GreatestDiameter[2] + repetition[1]
843 * repetition[2] * GreatestDiameter[1] * GreatestDiameter[2]);
844 BoxLengths.x[2] = minimumvolume - cellvolume;
845 double x0 = 0., x1 = 0., x2 = 0.;
846 if (gsl_poly_solve_cubic(BoxLengths.x[0], BoxLengths.x[1],
847 BoxLengths.x[2], &x0, &x1, &x2) == 1) // either 1 or 3 on return
848 *out << Verbose(0) << "RESULT: The resulting spacing is: " << x0
849 << " ." << endl;
850 else
851 {
852 *out << Verbose(0) << "RESULT: The resulting spacings are: " << x0
853 << " and " << x1 << " and " << x2 << " ." << endl;
854 x0 = x2; // sorted in ascending order
855 }
856
857 cellvolume = 1;
858 for (int i = 0; i < NDIM; i++)
859 {
860 BoxLengths.x[i] = repetition[i] * (x0 + GreatestDiameter[i]);
861 cellvolume *= BoxLengths.x[i];
862 }
863
864 // set new box dimensions
865 *out << Verbose(0) << "Translating to box with these boundaries." << endl;
866 mol->CenterInBox((ofstream *) &cout, &BoxLengths);
867 }
868 // update Box of atoms by boundary
869 mol->SetBoxDimension(&BoxLengths);
870 *out << Verbose(0) << "RESULT: The resulting cell dimensions are: "
871 << BoxLengths.x[0] << " and " << BoxLengths.x[1] << " and "
872 << BoxLengths.x[2] << " with total volume of " << cellvolume << " "
873 << (IsAngstroem ? "angstrom" : "atomiclength") << "^3." << endl;
874}
875;
876
877// =========================================================== class TESSELATION ===========================================
878
879/** Constructor of class Tesselation.
880 */
881Tesselation::Tesselation()
882{
883 PointsOnBoundaryCount = 0;
884 LinesOnBoundaryCount = 0;
885 TrianglesOnBoundaryCount = 0;
886 TriangleFilesWritten = 0;
887}
888;
889
890/** Constructor of class Tesselation.
891 * We have to free all points, lines and triangles.
892 */
893Tesselation::~Tesselation()
894{
895 cout << Verbose(1) << "Free'ing TesselStruct ... " << endl;
896 for (TriangleMap::iterator runner = TrianglesOnBoundary.begin(); runner
897 != TrianglesOnBoundary.end(); runner++)
898 {
899 delete (runner->second);
900 }
901}
902;
903
904/** Gueses first starting triangle of the convex envelope.
905 * We guess the starting triangle by taking the smallest distance between two points and looking for a fitting third.
906 * \param *out output stream for debugging
907 * \param PointsOnBoundary set of boundary points defining the convex envelope of the cluster
908 */
909void
910Tesselation::GuessStartingTriangle(ofstream *out)
911{
912 // 4b. create a starting triangle
913 // 4b1. create all distances
914 DistanceMultiMap DistanceMMap;
915 double distance, tmp;
916 Vector PlaneVector, TrialVector;
917 PointMap::iterator A, B, C; // three nodes of the first triangle
918 A = PointsOnBoundary.begin(); // the first may be chosen arbitrarily
919
920 // with A chosen, take each pair B,C and sort
921 if (A != PointsOnBoundary.end())
922 {
923 B = A;
924 B++;
925 for (; B != PointsOnBoundary.end(); B++)
926 {
927 C = B;
928 C++;
929 for (; C != PointsOnBoundary.end(); C++)
930 {
931 tmp = A->second->node->x.Distance(&B->second->node->x);
932 distance = tmp * tmp;
933 tmp = A->second->node->x.Distance(&C->second->node->x);
934 distance += tmp * tmp;
935 tmp = B->second->node->x.Distance(&C->second->node->x);
936 distance += tmp * tmp;
937 DistanceMMap.insert(DistanceMultiMapPair(distance, pair<
938 PointMap::iterator, PointMap::iterator> (B, C)));
939 }
940 }
941 }
942 // // listing distances
943 // *out << Verbose(1) << "Listing DistanceMMap:";
944 // for(DistanceMultiMap::iterator runner = DistanceMMap.begin(); runner != DistanceMMap.end(); runner++) {
945 // *out << " " << runner->first << "(" << *runner->second.first->second << ", " << *runner->second.second->second << ")";
946 // }
947 // *out << endl;
948 // 4b2. pick three baselines forming a triangle
949 // 1. we take from the smallest sum of squared distance as the base line BC (with peak A) onward as the triangle candidate
950 DistanceMultiMap::iterator baseline = DistanceMMap.begin();
951 for (; baseline != DistanceMMap.end(); baseline++)
952 {
953 // we take from the smallest sum of squared distance as the base line BC (with peak A) onward as the triangle candidate
954 // 2. next, we have to check whether all points reside on only one side of the triangle
955 // 3. construct plane vector
956 PlaneVector.MakeNormalVector(&A->second->node->x,
957 &baseline->second.first->second->node->x,
958 &baseline->second.second->second->node->x);
959 *out << Verbose(2) << "Plane vector of candidate triangle is ";
960 PlaneVector.Output(out);
961 *out << endl;
962 // 4. loop over all points
963 double sign = 0.;
964 PointMap::iterator checker = PointsOnBoundary.begin();
965 for (; checker != PointsOnBoundary.end(); checker++)
966 {
967 // (neglecting A,B,C)
968 if ((checker == A) || (checker == baseline->second.first) || (checker
969 == baseline->second.second))
970 continue;
971 // 4a. project onto plane vector
972 TrialVector.CopyVector(&checker->second->node->x);
973 TrialVector.SubtractVector(&A->second->node->x);
974 distance = TrialVector.Projection(&PlaneVector);
975 if (fabs(distance) < 1e-4) // we need to have a small epsilon around 0 which is still ok
976 continue;
977 *out << Verbose(3) << "Projection of " << checker->second->node->Name
978 << " yields distance of " << distance << "." << endl;
979 tmp = distance / fabs(distance);
980 // 4b. Any have different sign to than before? (i.e. would lie outside convex hull with this starting triangle)
981 if ((sign != 0) && (tmp != sign))
982 {
983 // 4c. If so, break 4. loop and continue with next candidate in 1. loop
984 *out << Verbose(2) << "Current candidates: "
985 << A->second->node->Name << ","
986 << baseline->second.first->second->node->Name << ","
987 << baseline->second.second->second->node->Name << " leave "
988 << checker->second->node->Name << " outside the convex hull."
989 << endl;
990 break;
991 }
992 else
993 { // note the sign for later
994 *out << Verbose(2) << "Current candidates: "
995 << A->second->node->Name << ","
996 << baseline->second.first->second->node->Name << ","
997 << baseline->second.second->second->node->Name << " leave "
998 << checker->second->node->Name << " inside the convex hull."
999 << endl;
1000 sign = tmp;
1001 }
1002 // 4d. Check whether the point is inside the triangle (check distance to each node
1003 tmp = checker->second->node->x.Distance(&A->second->node->x);
1004 int innerpoint = 0;
1005 if ((tmp < A->second->node->x.Distance(
1006 &baseline->second.first->second->node->x)) && (tmp
1007 < A->second->node->x.Distance(
1008 &baseline->second.second->second->node->x)))
1009 innerpoint++;
1010 tmp = checker->second->node->x.Distance(
1011 &baseline->second.first->second->node->x);
1012 if ((tmp < baseline->second.first->second->node->x.Distance(
1013 &A->second->node->x)) && (tmp
1014 < baseline->second.first->second->node->x.Distance(
1015 &baseline->second.second->second->node->x)))
1016 innerpoint++;
1017 tmp = checker->second->node->x.Distance(
1018 &baseline->second.second->second->node->x);
1019 if ((tmp < baseline->second.second->second->node->x.Distance(
1020 &baseline->second.first->second->node->x)) && (tmp
1021 < baseline->second.second->second->node->x.Distance(
1022 &A->second->node->x)))
1023 innerpoint++;
1024 // 4e. If so, break 4. loop and continue with next candidate in 1. loop
1025 if (innerpoint == 3)
1026 break;
1027 }
1028 // 5. come this far, all on same side? Then break 1. loop and construct triangle
1029 if (checker == PointsOnBoundary.end())
1030 {
1031 *out << "Looks like we have a candidate!" << endl;
1032 break;
1033 }
1034 }
1035 if (baseline != DistanceMMap.end())
1036 {
1037 BPS[0] = baseline->second.first->second;
1038 BPS[1] = baseline->second.second->second;
1039 BLS[0] = new class BoundaryLineSet(BPS, LinesOnBoundaryCount);
1040 BPS[0] = A->second;
1041 BPS[1] = baseline->second.second->second;
1042 BLS[1] = new class BoundaryLineSet(BPS, LinesOnBoundaryCount);
1043 BPS[0] = baseline->second.first->second;
1044 BPS[1] = A->second;
1045 BLS[2] = new class BoundaryLineSet(BPS, LinesOnBoundaryCount);
1046
1047 // 4b3. insert created triangle
1048 BTS = new class BoundaryTriangleSet(BLS, TrianglesOnBoundaryCount);
1049 TrianglesOnBoundary.insert(TrianglePair(TrianglesOnBoundaryCount, BTS));
1050 TrianglesOnBoundaryCount++;
1051 for (int i = 0; i < NDIM; i++)
1052 {
1053 LinesOnBoundary.insert(LinePair(LinesOnBoundaryCount, BTS->lines[i]));
1054 LinesOnBoundaryCount++;
1055 }
1056
1057 *out << Verbose(1) << "Starting triangle is " << *BTS << "." << endl;
1058 }
1059 else
1060 {
1061 *out << Verbose(1) << "No starting triangle found." << endl;
1062 exit(255);
1063 }
1064}
1065;
1066
1067/** Tesselates the convex envelope of a cluster from a single starting triangle.
1068 * The starting triangle is made out of three baselines. Each line in the final tesselated cluster may belong to at most
1069 * 2 triangles. Hence, we go through all current lines:
1070 * -# if the lines contains to only one triangle
1071 * -# We search all points in the boundary
1072 * -# if the triangle with the baseline and the current point has the smallest of angles (comparison between normal vectors
1073 * -# if the triangle is in forward direction of the baseline (at most 90 degrees angle between vector orthogonal to
1074 * baseline in triangle plane pointing out of the triangle and normal vector of new triangle)
1075 * -# then we have a new triangle, whose baselines we again add (or increase their TriangleCount)
1076 * \param *out output stream for debugging
1077 * \param *configuration for IsAngstroem
1078 * \param *mol the cluster as a molecule structure
1079 */
1080void
1081Tesselation::TesselateOnBoundary(ofstream *out, config *configuration,
1082 molecule *mol)
1083{
1084 bool flag;
1085 PointMap::iterator winner;
1086 class BoundaryPointSet *peak = NULL;
1087 double SmallestAngle, TempAngle;
1088 Vector NormalVector, VirtualNormalVector, CenterVector, TempVector,
1089 PropagationVector;
1090 LineMap::iterator LineChecker[2];
1091 do
1092 {
1093 flag = false;
1094 for (LineMap::iterator baseline = LinesOnBoundary.begin(); baseline
1095 != LinesOnBoundary.end(); baseline++)
1096 if (baseline->second->TrianglesCount == 1)
1097 {
1098 *out << Verbose(2) << "Current baseline is between "
1099 << *(baseline->second) << "." << endl;
1100 // 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)
1101 SmallestAngle = M_PI;
1102 BTS = baseline->second->triangles.begin()->second; // there is only one triangle so far
1103 // get peak point with respect to this base line's only triangle
1104 for (int i = 0; i < 3; i++)
1105 if ((BTS->endpoints[i] != baseline->second->endpoints[0])
1106 && (BTS->endpoints[i] != baseline->second->endpoints[1]))
1107 peak = BTS->endpoints[i];
1108 *out << Verbose(3) << " and has peak " << *peak << "." << endl;
1109 // normal vector of triangle
1110 BTS->GetNormalVector(NormalVector);
1111 *out << Verbose(4) << "NormalVector of base triangle is ";
1112 NormalVector.Output(out);
1113 *out << endl;
1114 // offset to center of triangle
1115 CenterVector.Zero();
1116 for (int i = 0; i < 3; i++)
1117 CenterVector.AddVector(&BTS->endpoints[i]->node->x);
1118 CenterVector.Scale(1. / 3.);
1119 *out << Verbose(4) << "CenterVector of base triangle is ";
1120 CenterVector.Output(out);
1121 *out << endl;
1122 // vector in propagation direction (out of triangle)
1123 // project center vector onto triangle plane (points from intersection plane-NormalVector to plane-CenterVector intersection)
1124 TempVector.CopyVector(&baseline->second->endpoints[0]->node->x);
1125 TempVector.SubtractVector(&baseline->second->endpoints[1]->node->x);
1126 PropagationVector.MakeNormalVector(&TempVector, &NormalVector);
1127 TempVector.CopyVector(&CenterVector);
1128 TempVector.SubtractVector(&baseline->second->endpoints[0]->node->x); // TempVector is vector on triangle plane pointing from one baseline egde towards center!
1129 //*out << Verbose(2) << "Projection of propagation onto temp: " << PropagationVector.Projection(&TempVector) << "." << endl;
1130 if (PropagationVector.Projection(&TempVector) > 0) // make sure normal propagation vector points outward from baseline
1131 PropagationVector.Scale(-1.);
1132 *out << Verbose(4) << "PropagationVector of base triangle is ";
1133 PropagationVector.Output(out);
1134 *out << endl;
1135 winner = PointsOnBoundary.end();
1136 for (PointMap::iterator target = PointsOnBoundary.begin(); target
1137 != PointsOnBoundary.end(); target++)
1138 if ((target->second != baseline->second->endpoints[0])
1139 && (target->second != baseline->second->endpoints[1]))
1140 { // don't take the same endpoints
1141 *out << Verbose(3) << "Target point is " << *(target->second)
1142 << ":";
1143 bool continueflag = true;
1144
1145 VirtualNormalVector.CopyVector(
1146 &baseline->second->endpoints[0]->node->x);
1147 VirtualNormalVector.AddVector(
1148 &baseline->second->endpoints[0]->node->x);
1149 VirtualNormalVector.Scale(-1. / 2.); // points now to center of base line
1150 VirtualNormalVector.AddVector(&target->second->node->x); // points from center of base line to target
1151 TempAngle = VirtualNormalVector.Angle(&PropagationVector);
1152 continueflag = continueflag && (TempAngle < (M_PI/2.)); // no bends bigger than Pi/2 (90 degrees)
1153 if (!continueflag)
1154 {
1155 *out << Verbose(4)
1156 << "Angle between propagation direction and base line to "
1157 << *(target->second) << " is " << TempAngle
1158 << ", bad direction!" << endl;
1159 continue;
1160 }
1161 else
1162 *out << Verbose(4)
1163 << "Angle between propagation direction and base line to "
1164 << *(target->second) << " is " << TempAngle
1165 << ", good direction!" << endl;
1166 LineChecker[0] = baseline->second->endpoints[0]->lines.find(
1167 target->first);
1168 LineChecker[1] = baseline->second->endpoints[1]->lines.find(
1169 target->first);
1170 // if (LineChecker[0] != baseline->second->endpoints[0]->lines.end())
1171 // *out << Verbose(4) << *(baseline->second->endpoints[0]) << " has line " << *(LineChecker[0]->second) << " to " << *(target->second) << " as endpoint with " << LineChecker[0]->second->TrianglesCount << " triangles." << endl;
1172 // else
1173 // *out << Verbose(4) << *(baseline->second->endpoints[0]) << " has no line to " << *(target->second) << " as endpoint." << endl;
1174 // if (LineChecker[1] != baseline->second->endpoints[1]->lines.end())
1175 // *out << Verbose(4) << *(baseline->second->endpoints[1]) << " has line " << *(LineChecker[1]->second) << " to " << *(target->second) << " as endpoint with " << LineChecker[1]->second->TrianglesCount << " triangles." << endl;
1176 // else
1177 // *out << Verbose(4) << *(baseline->second->endpoints[1]) << " has no line to " << *(target->second) << " as endpoint." << endl;
1178 // check first endpoint (if any connecting line goes to target or at least not more than 1)
1179 continueflag = continueflag && (((LineChecker[0]
1180 == baseline->second->endpoints[0]->lines.end())
1181 || (LineChecker[0]->second->TrianglesCount == 1)));
1182 if (!continueflag)
1183 {
1184 *out << Verbose(4) << *(baseline->second->endpoints[0])
1185 << " has line " << *(LineChecker[0]->second)
1186 << " to " << *(target->second)
1187 << " as endpoint with "
1188 << LineChecker[0]->second->TrianglesCount
1189 << " triangles." << endl;
1190 continue;
1191 }
1192 // check second endpoint (if any connecting line goes to target or at least not more than 1)
1193 continueflag = continueflag && (((LineChecker[1]
1194 == baseline->second->endpoints[1]->lines.end())
1195 || (LineChecker[1]->second->TrianglesCount == 1)));
1196 if (!continueflag)
1197 {
1198 *out << Verbose(4) << *(baseline->second->endpoints[1])
1199 << " has line " << *(LineChecker[1]->second)
1200 << " to " << *(target->second)
1201 << " as endpoint with "
1202 << LineChecker[1]->second->TrianglesCount
1203 << " triangles." << endl;
1204 continue;
1205 }
1206 // check whether the envisaged triangle does not already exist (if both lines exist and have same endpoint)
1207 continueflag = continueflag && (!(((LineChecker[0]
1208 != baseline->second->endpoints[0]->lines.end())
1209 && (LineChecker[1]
1210 != baseline->second->endpoints[1]->lines.end())
1211 && (GetCommonEndpoint(LineChecker[0]->second,
1212 LineChecker[1]->second) == peak))));
1213 if (!continueflag)
1214 {
1215 *out << Verbose(4) << "Current target is peak!" << endl;
1216 continue;
1217 }
1218 // in case NOT both were found
1219 if (continueflag)
1220 { // create virtually this triangle, get its normal vector, calculate angle
1221 flag = true;
1222 VirtualNormalVector.MakeNormalVector(
1223 &baseline->second->endpoints[0]->node->x,
1224 &baseline->second->endpoints[1]->node->x,
1225 &target->second->node->x);
1226 // make it always point inward
1227 if (baseline->second->endpoints[0]->node->x.Projection(
1228 &VirtualNormalVector) > 0)
1229 VirtualNormalVector.Scale(-1.);
1230 // calculate angle
1231 TempAngle = NormalVector.Angle(&VirtualNormalVector);
1232 *out << Verbose(4) << "NormalVector is ";
1233 VirtualNormalVector.Output(out);
1234 *out << " and the angle is " << TempAngle << "." << endl;
1235 if (SmallestAngle > TempAngle)
1236 { // set to new possible winner
1237 SmallestAngle = TempAngle;
1238 winner = target;
1239 }
1240 }
1241 }
1242 // 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
1243 if (winner != PointsOnBoundary.end())
1244 {
1245 *out << Verbose(2) << "Winning target point is "
1246 << *(winner->second) << " with angle " << SmallestAngle
1247 << "." << endl;
1248 // create the lins of not yet present
1249 BLS[0] = baseline->second;
1250 // 5c. add lines to the line set if those were new (not yet part of a triangle), delete lines that belong to two triangles)
1251 LineChecker[0] = baseline->second->endpoints[0]->lines.find(
1252 winner->first);
1253 LineChecker[1] = baseline->second->endpoints[1]->lines.find(
1254 winner->first);
1255 if (LineChecker[0]
1256 == baseline->second->endpoints[0]->lines.end())
1257 { // create
1258 BPS[0] = baseline->second->endpoints[0];
1259 BPS[1] = winner->second;
1260 BLS[1] = new class BoundaryLineSet(BPS,
1261 LinesOnBoundaryCount);
1262 LinesOnBoundary.insert(LinePair(LinesOnBoundaryCount,
1263 BLS[1]));
1264 LinesOnBoundaryCount++;
1265 }
1266 else
1267 BLS[1] = LineChecker[0]->second;
1268 if (LineChecker[1]
1269 == baseline->second->endpoints[1]->lines.end())
1270 { // create
1271 BPS[0] = baseline->second->endpoints[1];
1272 BPS[1] = winner->second;
1273 BLS[2] = new class BoundaryLineSet(BPS,
1274 LinesOnBoundaryCount);
1275 LinesOnBoundary.insert(LinePair(LinesOnBoundaryCount,
1276 BLS[2]));
1277 LinesOnBoundaryCount++;
1278 }
1279 else
1280 BLS[2] = LineChecker[1]->second;
1281 BTS = new class BoundaryTriangleSet(BLS,
1282 TrianglesOnBoundaryCount);
1283 TrianglesOnBoundary.insert(TrianglePair(
1284 TrianglesOnBoundaryCount, BTS));
1285 TrianglesOnBoundaryCount++;
1286 }
1287 else
1288 {
1289 *out << Verbose(1)
1290 << "I could not determine a winner for this baseline "
1291 << *(baseline->second) << "." << endl;
1292 }
1293
1294 // 5d. If the set of lines is not yet empty, go to 5. and continue
1295 }
1296 else
1297 *out << Verbose(2) << "Baseline candidate " << *(baseline->second)
1298 << " has a triangle count of "
1299 << baseline->second->TrianglesCount << "." << endl;
1300 }
1301 while (flag);
1302
1303}
1304;
1305
1306/** Adds an atom to the tesselation::PointsOnBoundary list.
1307 * \param *Walker atom to add
1308 */
1309void
1310Tesselation::AddPoint(atom *Walker)
1311{
1312 PointTestPair InsertUnique;
1313 BPS[0] = new class BoundaryPointSet(Walker);
1314 InsertUnique = PointsOnBoundary.insert(PointPair(Walker->nr, BPS[0]));
1315 if (InsertUnique.second) // if new point was not present before, increase counter
1316 PointsOnBoundaryCount++;
1317}
1318;
1319
1320/** Adds point to Tesselation::PointsOnBoundary if not yet present.
1321 * Tesselation::TPS is set to either this new BoundaryPointSet or to the existing one of not unique.
1322 * @param Candidate point to add
1323 * @param n index for this point in Tesselation::TPS array
1324 */
1325void
1326Tesselation::AddTrianglePoint(atom* Candidate, int n)
1327{
1328 PointTestPair InsertUnique;
1329 TPS[n] = new class BoundaryPointSet(Candidate);
1330 InsertUnique = PointsOnBoundary.insert(PointPair(Candidate->nr, TPS[n]));
1331 if (InsertUnique.second) // if new point was not present before, increase counter
1332 {
1333 PointsOnBoundaryCount++;
1334 }
1335 else
1336 {
1337 delete TPS[n];
1338 cout << Verbose(2) << "Atom " << *((InsertUnique.first)->second->node)
1339 << " gibt's schon in der PointMap." << endl;
1340 TPS[n] = (InsertUnique.first)->second;
1341 }
1342}
1343;
1344
1345/** Function tries to add line from current Points in BPS to BoundaryLineSet.
1346 * If succesful it raises the line count and inserts the new line into the BLS,
1347 * if unsuccesful, it writes the line which had been present into the BLS, deleting the new constructed one.
1348 * @param *a first endpoint
1349 * @param *b second endpoint
1350 * @param n index of Tesselation::BLS giving the line with both endpoints
1351 */
1352void
1353Tesselation::AddTriangleLine(class BoundaryPointSet *a,
1354 class BoundaryPointSet *b, int n)
1355{
1356 LineMap::iterator LineWalker;
1357 //cout << "Manually checking endpoints for line." << endl;
1358 if ((a->lines.find(b->node->nr)) != a->lines.end()) // ->first == b->node->nr)
1359 //If a line is there, how do I recognize that beyond a shadow of a doubt?
1360 {
1361 //cout << Verbose(2) << "Line exists already, retrieving it from LinesOnBoundarySet" << endl;
1362
1363 LineWalker = LinesOnBoundary.end();
1364 LineWalker--;
1365
1366 while (LineWalker->second->endpoints[0]->node->nr != min(a->node->nr,
1367 b->node->nr) or LineWalker->second->endpoints[1]->node->nr != max(
1368 a->node->nr, b->node->nr))
1369 {
1370 //cout << Verbose(1) << "Looking for line which already exists"<< endl;
1371 LineWalker--;
1372 }
1373 BPS[0] = LineWalker->second->endpoints[0];
1374 BPS[1] = LineWalker->second->endpoints[1];
1375 BLS[n] = LineWalker->second;
1376
1377 }
1378 else
1379 {
1380 cout << Verbose(2)
1381 << "Adding line which has not been used before between "
1382 << *(a->node) << " and " << *(b->node) << "." << endl;
1383 BPS[0] = a;
1384 BPS[1] = b;
1385 BLS[n] = new class BoundaryLineSet(BPS, LinesOnBoundaryCount);
1386
1387 LinesOnBoundary.insert(LinePair(LinesOnBoundaryCount, BLS[n]));
1388 LinesOnBoundaryCount++;
1389
1390 }
1391}
1392;
1393
1394/** Function tries to add Triangle just created to Triangle and remarks if already existent (Failure of algorithm).
1395 * Furthermore it adds the triangle to all of its lines, in order to recognize those which are saturated later.
1396 */
1397void
1398Tesselation::AddTriangleToLines()
1399{
1400
1401 cout << Verbose(1) << "Adding triangle to its lines" << endl;
1402 int i = 0;
1403 TrianglesOnBoundary.insert(TrianglePair(TrianglesOnBoundaryCount, BTS));
1404 TrianglesOnBoundaryCount++;
1405
1406 /*
1407 * this is apparently done when constructing triangle
1408
1409 for (i=0; i<3; i++)
1410 {
1411 BLS[i]->AddTriangle(BTS);
1412 }
1413 */
1414}
1415;
1416
1417/**
1418 * Function returns center of sphere with RADIUS, which rests on points a, b, c
1419 * @param Center this vector will be used for return
1420 * @param a vector first point of triangle
1421 * @param b vector second point of triangle
1422 * @param c vector third point of triangle
1423 * @param *Umkreismittelpunkt new cneter point of circumference
1424 * @param Direction vector indicates up/down
1425 * @param AlternativeDirection vecotr, needed in case the triangles have 90 deg angle
1426 * @param Halfplaneindicator double indicates whether Direction is up or down
1427 * @param AlternativeIndicator doube indicates in case of orthogonal triangles which direction of AlternativeDirection is suitable
1428 * @param alpha double angle at a
1429 * @param beta double, angle at b
1430 * @param gamma, double, angle at c
1431 * @param Radius, double
1432 * @param Umkreisradius double radius of circumscribing circle
1433 */
1434
1435 void Get_center_of_sphere(Vector* Center, Vector a, Vector b, Vector c, Vector *NewUmkreismittelpunkt, Vector* Direction, Vector* AlternativeDirection,
1436 double HalfplaneIndicator, double AlternativeIndicator, double alpha, double beta, double gamma, double RADIUS, double Umkreisradius)
1437 {
1438 Vector TempNormal, helper;
1439 double Restradius;
1440 cout << Verbose(3) << "Begin of Get_center_of_sphere.\n";
1441 *Center = a * sin(2.*alpha) + b * sin(2.*beta) + c * sin(2.*gamma) ;
1442 Center->Scale(1./(sin(2.*alpha) + sin(2.*beta) + sin(2.*gamma)));
1443 NewUmkreismittelpunkt->CopyVector(Center);
1444 cout << Verbose(4) << "Center of new circumference is " << *NewUmkreismittelpunkt << ".\n";
1445 // Here we calculated center of circumscribing circle, using barycentric coordinates
1446 cout << Verbose(4) << "Center of circumference is " << *Center << " in direction " << *Direction << ".\n";
1447
1448 TempNormal.CopyVector(&a);
1449 TempNormal.SubtractVector(&b);
1450 helper.CopyVector(&a);
1451 helper.SubtractVector(&c);
1452 TempNormal.VectorProduct(&helper);
1453 if (fabs(HalfplaneIndicator) < MYEPSILON)
1454 {
1455 if ((TempNormal.ScalarProduct(AlternativeDirection) <0 and AlternativeIndicator >0) or (TempNormal.ScalarProduct(AlternativeDirection) >0 and AlternativeIndicator <0))
1456 {
1457 TempNormal.Scale(-1);
1458 }
1459 }
1460 else
1461 {
1462 if (TempNormal.ScalarProduct(Direction)<0 && HalfplaneIndicator >0 || TempNormal.ScalarProduct(Direction)>0 && HalfplaneIndicator<0)
1463 {
1464 TempNormal.Scale(-1);
1465 }
1466 }
1467
1468 TempNormal.Normalize();
1469 Restradius = sqrt(RADIUS*RADIUS - Umkreisradius*Umkreisradius);
1470 cout << Verbose(4) << "Height of center of circumference to center of sphere is " << Restradius << ".\n";
1471 TempNormal.Scale(Restradius);
1472 cout << Verbose(4) << "Shift vector to sphere of circumference is " << TempNormal << ".\n";
1473
1474 Center->AddVector(&TempNormal);
1475 cout << Verbose(4) << "Center of sphere of circumference is " << *Center << ".\n";
1476 cout << Verbose(3) << "End of Get_center_of_sphere.\n";
1477 }
1478 ;
1479
1480
1481/** This recursive function finds a third point, to form a triangle with two given ones.
1482 * Two atoms are fixed, a candidate is supplied, additionally two vectors for direction distinction, a Storage area to \
1483 * supply results to the calling function, the radius of the sphere which the triangle shall support and the molecule \
1484 * upon which we operate.
1485 * If the candidate is more fitting to support the sphere than the already stored atom is, then we write its general \
1486 * direction and angle into Storage.
1487 * We the determine the recursive level we have reached and if this is not on the threshold yet, call this function again, \
1488 * with all neighbours of the candidate.
1489 * @param a first point
1490 * @param b second point
1491 * *param c atom old third point of old triangle
1492 * @param Candidate base point along whose bonds to start looking from
1493 * @param Parent point to avoid during search as its wrong direction
1494 * @param RecursionLevel contains current recursion depth
1495 * @param Chord baseline vector of first and second point
1496 * @param direction1 second in plane vector (along with \a Chord) of the triangle the baseline belongs to
1497 * @param OldNormal normal of the triangle which the baseline belongs to
1498 * @param ReferencePoint Vector of center of circumscribing circle from which we look towards center of sphere
1499 * @param Opt_Candidate candidate reference to return
1500 * @param Storage array containing two angles of current Opt_Candidate
1501 * @param RADIUS radius of ball
1502 * @param mol molecule structure with atoms and bonds
1503 */
1504
1505void Find_next_suitable_point_via_Angle_of_Sphere(atom* a, atom* b, atom* c, atom* Candidate, atom* Parent,
1506 int RecursionLevel, Vector *Chord, Vector *direction1, Vector *OldNormal, Vector ReferencePoint,
1507 atom*& Opt_Candidate, double *Storage, const double RADIUS, molecule* mol)
1508{
1509 cout << Verbose(2) << "Begin of Find_next_suitable_point_via_Angle_of_Sphere, recursion level " << RecursionLevel << ".\n";
1510 cout << Verbose(3) << "Candidate is "<< *Candidate << endl;
1511 cout << Verbose(4) << "Baseline vector is " << *Chord << "." << endl;
1512 cout << Verbose(4) << "ReferencePoint is " << ReferencePoint << "." << endl;
1513 cout << Verbose(4) << "Normal of base triangle is " << *OldNormal << "." << endl;
1514 cout << Verbose(4) << "Search direction is " << *direction1 << "." << endl;
1515 /* OldNormal is normal vector on the old triangle
1516 * direction1 is normal on the triangle line, from which we come, as well as on OldNormal.
1517 * Chord points from b to a!!!
1518 */
1519 Vector dif_a; //Vector from a to candidate
1520 Vector dif_b; //Vector from b to candidate
1521 Vector AngleCheck;
1522 Vector TempNormal, Umkreismittelpunkt;
1523 Vector Mittelpunkt;
1524
1525 double CurrentEpsilon = 0.1;
1526 double alpha, beta, gamma, SideA, SideB, SideC, sign, Umkreisradius, Restradius, Distance;
1527 double BallAngle, AlternativeSign;
1528 atom *Walker; // variable atom point
1529
1530 Vector NewUmkreismittelpunkt;
1531
1532
1533 if (a != Candidate and b != Candidate and c != Candidate)
1534 {
1535 cout << Verbose(3) << "We have a unique candidate!" << endl;
1536 dif_a.CopyVector(&(a->x));
1537 dif_a.SubtractVector(&(Candidate->x));
1538 dif_b.CopyVector(&(b->x));
1539 dif_b.SubtractVector(&(Candidate->x));
1540 AngleCheck.CopyVector(&(Candidate->x));
1541 AngleCheck.SubtractVector(&(a->x));
1542 AngleCheck.ProjectOntoPlane(Chord);
1543
1544 SideA = dif_b.Norm();
1545 SideB = dif_a.Norm();
1546 SideC = Chord->Norm();
1547 //Chord->Scale(-1);
1548
1549 alpha = Chord->Angle(&dif_a);
1550 beta = M_PI - Chord->Angle(&dif_b);
1551 gamma = dif_a.Angle(&dif_b);
1552
1553 cout << Verbose(2) << "Base triangle has sides " << dif_a << ", " << dif_b << ", " << *Chord << " with angles " << alpha/M_PI*180. << ", " << beta/M_PI*180. << ", " << gamma/M_PI*180. << "." << endl;
1554
1555 if (fabs(M_PI - alpha - beta - gamma) > MYEPSILON)
1556 cerr << Verbose(0) << "WARNING: sum of angles for candidate triangle " << (alpha + beta + gamma)/M_PI*180. << " != 180.\n";
1557
1558 Umkreisradius = SideA / 2.0 / sin(alpha);
1559 //cout << Umkreisradius << endl;
1560 //cout << SideB / 2.0 / sin(beta) << endl;
1561 //cout << SideC / 2.0 / sin(gamma) << endl;
1562
1563 if (Umkreisradius < RADIUS) //Checking whether ball will at least rest on points.
1564 {
1565 cout << Verbose(3) << "Circle of circumference would fit: " << Umkreisradius << " < " << RADIUS << "." << endl;
1566 cout << Verbose(2) << "Candidate is "<< *Candidate << endl;
1567 sign = AngleCheck.ScalarProduct(direction1);
1568 if (fabs(sign)<MYEPSILON)
1569 {
1570 if (AngleCheck.ScalarProduct(OldNormal)<0)
1571 {
1572 sign =0;
1573 AlternativeSign=1;
1574 }
1575 else
1576 {
1577 sign =0;
1578 AlternativeSign=-1;
1579 }
1580 }
1581 else
1582 {
1583 sign /= fabs(sign);
1584 cout << Verbose(3) << "Candidate is in search direction: " << sign << "." << endl;
1585 }
1586
1587 Get_center_of_sphere(&Mittelpunkt, (a->x), (b->x), (Candidate->x), &NewUmkreismittelpunkt, OldNormal, direction1, sign, AlternativeSign, alpha, beta, gamma, RADIUS, Umkreisradius);
1588
1589 AngleCheck.CopyVector(&ReferencePoint);
1590 AngleCheck.Scale(-1);
1591 //cout << "AngleCheck is " << AngleCheck.x[0] << " "<< AngleCheck.x[1] << " "<< AngleCheck.x[2] << " "<< endl;
1592 AngleCheck.AddVector(&Mittelpunkt);
1593 //cout << "AngleCheck is " << AngleCheck.x[0] << " "<< AngleCheck.x[1] << " "<< AngleCheck.x[2] << " "<< endl;
1594 cout << Verbose(4) << "Reference vector to sphere's center is " << AngleCheck << "." << endl;
1595
1596 BallAngle = AngleCheck.Angle(OldNormal);
1597 cout << Verbose(3) << "Angle between normal of base triangle and center of ball sphere is :" << BallAngle << "." << endl;
1598
1599 //cout << "direction1 is " << direction1->x[0] <<" "<< direction1->x[1] <<" "<< direction1->x[2] <<" " << endl;
1600 //cout << "AngleCheck is " << AngleCheck.x[0] << " "<< AngleCheck.x[1] << " "<< AngleCheck.x[2] << " "<< endl;
1601
1602 cout << Verbose(3) << "BallAngle is " << BallAngle << " Sign is " << sign << endl;
1603
1604 NewUmkreismittelpunkt.SubtractVector(&ReferencePoint);
1605
1606 if ((AngleCheck.ScalarProduct(direction1) >=0) || (fabs(NewUmkreismittelpunkt.Norm()) < MYEPSILON))
1607 {
1608 if (Storage[0]< -1.5) // first Candidate at all
1609 {
1610
1611 cout << Verbose(2) << "First good candidate is " << *Candidate << " with ";
1612 Opt_Candidate = Candidate;
1613 Storage[0] = sign;
1614 Storage[1] = AlternativeSign;
1615 Storage[2] = BallAngle;
1616 cout << " angle " << Storage[2] << " and Up/Down "
1617 << Storage[0] << endl;
1618 }
1619 else
1620 {
1621 if ( Storage[2] > BallAngle)
1622 {
1623 cout << Verbose(2) << "Next better candidate is " << *Candidate << " with ";
1624 Opt_Candidate = Candidate;
1625 Storage[0] = sign;
1626 Storage[1] = AlternativeSign;
1627 Storage[2] = BallAngle;
1628 cout << " angle " << Storage[2] << " and Up/Down "
1629 << Storage[0] << endl;
1630 }
1631 else
1632 {
1633 if (DEBUG)
1634 {
1635 cout << Verbose(3) << *Candidate << " looses against better candidate " << *Opt_Candidate << "." << endl;
1636 }
1637 }
1638 }
1639 }
1640 else
1641 {
1642 if (DEBUG)
1643 {
1644 cout << Verbose(3) << *Candidate << " refused due to Up/Down sign which is " << sign << endl;
1645 }
1646 }
1647 }
1648 else
1649 {
1650 if (DEBUG)
1651 {
1652 cout << Verbose(3) << *Candidate << " would have circumference of " << Umkreisradius << " bigger than ball's radius " << RADIUS << "." << endl;
1653 }
1654 }
1655 }
1656 else
1657 {
1658 if (DEBUG)
1659 {
1660 cout << Verbose(3) << *Candidate << " is either " << *a << " or " << *b << "." << endl;
1661 }
1662 }
1663
1664
1665
1666 if (RecursionLevel < 9) // Seven is the recursion level threshold.
1667 {
1668 for (int i = 0; i < mol->NumberOfBondsPerAtom[Candidate->nr]; i++) // go through all bond
1669 {
1670 Walker = mol->ListOfBondsPerAtom[Candidate->nr][i]->GetOtherAtom(
1671 Candidate);
1672 if (Walker == Parent)
1673 { // don't go back the same bond
1674 continue;
1675 }
1676 else
1677 {
1678 Find_next_suitable_point_via_Angle_of_Sphere(a, b, c, Walker, Candidate, RecursionLevel
1679 + 1, Chord, direction1, OldNormal, ReferencePoint, Opt_Candidate, Storage, RADIUS,
1680 mol); //call function again
1681 }
1682 }
1683 }
1684 cout << Verbose(2) << "End of Find_next_suitable_point_via_Angle_of_Sphere, recursion level " << RecursionLevel << ".\n";
1685}
1686;
1687
1688
1689 /** This recursive function finds a third point, to form a triangle with two given ones.
1690 * Two atoms are fixed, a candidate is supplied, additionally two vectors for direction distinction, a Storage area to \
1691 * supply results to the calling function, the radius of the sphere which the triangle shall support and the molecule \
1692 * upon which we operate.
1693 * If the candidate is more fitting to support the sphere than the already stored atom is, then we write its general \
1694 * direction and angle into Storage.
1695 * We the determine the recursive level we have reached and if this is not on the threshold yet, call this function again, \
1696 * with all neighbours of the candidate.
1697 * @param a first point
1698 * @param b second point
1699 * @param Candidate base point along whose bonds to start looking from
1700 * @param Parent point to avoid during search as its wrong direction
1701 * @param RecursionLevel contains current recursion depth
1702 * @param Chord baseline vector of first and second point
1703 * @param d1 second in plane vector (along with \a Chord) of the triangle the baseline belongs to
1704 * @param OldNormal normal of the triangle which the baseline belongs to
1705 * @param Opt_Candidate candidate reference to return
1706 * @param Opt_Mittelpunkt Centerpoint of ball, when resting on Opt_Candidate
1707 * @param Storage array containing two angles of current Opt_Candidate
1708 * @param RADIUS radius of ball
1709 * @param mol molecule structure with atoms and bonds
1710 */
1711
1712void Find_next_suitable_point(atom* a, atom* b, atom* Candidate, atom* Parent,
1713 int RecursionLevel, Vector *Chord, Vector *d1, Vector *OldNormal,
1714 atom*& Opt_Candidate, Vector *Opt_Mittelpunkt, double *Storage, const double RADIUS, molecule* mol)
1715{
1716 /* OldNormal is normal vector on the old triangle
1717 * d1 is normal on the triangle line, from which we come, as well as on OldNormal.
1718 * Chord points from b to a!!!
1719 */
1720 Vector dif_a; //Vector from a to candidate
1721 Vector dif_b; //Vector from b to candidate
1722 Vector AngleCheck, AngleCheckReference, DirectionCheckPoint;
1723 Vector TempNormal, Umkreismittelpunkt, Mittelpunkt;
1724
1725 double CurrentEpsilon = 0.1;
1726 double alpha, beta, gamma, SideA, SideB, SideC, sign, Umkreisradius, Restradius, Distance;
1727 double BallAngle;
1728 atom *Walker; // variable atom point
1729
1730
1731 dif_a.CopyVector(&(a->x));
1732 dif_a.SubtractVector(&(Candidate->x));
1733 dif_b.CopyVector(&(b->x));
1734 dif_b.SubtractVector(&(Candidate->x));
1735 DirectionCheckPoint.CopyVector(&dif_a);
1736 DirectionCheckPoint.Scale(-1);
1737 DirectionCheckPoint.ProjectOntoPlane(Chord);
1738
1739 SideA = dif_b.Norm();
1740 SideB = dif_a.Norm();
1741 SideC = Chord->Norm();
1742 //Chord->Scale(-1);
1743
1744 alpha = Chord->Angle(&dif_a);
1745 beta = M_PI - Chord->Angle(&dif_b);
1746 gamma = dif_a.Angle(&dif_b);
1747
1748
1749 if (DEBUG)
1750 {
1751 cout << "Atom number" << Candidate->nr << endl;
1752 Candidate->x.Output((ofstream *) &cout);
1753 cout << "number of bonds " << mol->NumberOfBondsPerAtom[Candidate->nr]
1754 << endl;
1755 }
1756
1757 if (a != Candidate and b != Candidate)
1758 {
1759 // alpha = dif_a.Angle(&dif_b) / 2.;
1760 // SideA = Chord->Norm() / 2.;// (Chord->Norm()/2.) / sin(0.5*alpha);
1761 // SideB = dif_a.Norm();
1762 // centerline = SideA * SideA + SideB * SideB - 2. * SideA * SideB * cos(
1763 // alpha); // note this is squared of center line length
1764 // centerline = (Chord->Norm()/2.) / sin(0.5*alpha);
1765 // Those are remains from Freddie. Needed?
1766
1767
1768
1769 Umkreisradius = SideA / 2.0 / sin(alpha);
1770 //cout << Umkreisradius << endl;
1771 //cout << SideB / 2.0 / sin(beta) << endl;
1772 //cout << SideC / 2.0 / sin(gamma) << endl;
1773
1774 if (Umkreisradius < RADIUS && DirectionCheckPoint.ScalarProduct(&(Candidate->x))>0) //Checking whether ball will at least rest o points.
1775 {
1776
1777 // intermediate calculations to aquire centre of sphere, called Mittelpunkt:
1778
1779 Umkreismittelpunkt = (a->x) * sin(2.*alpha) + b->x * sin(2.*beta) + (Candidate->x) * sin(2.*gamma) ;
1780 Umkreismittelpunkt.Scale(1/(sin(2*alpha) + sin(2*beta) + sin(2*gamma)));
1781
1782 TempNormal.CopyVector(&dif_a);
1783 TempNormal.VectorProduct(&dif_b);
1784 if (TempNormal.ScalarProduct(OldNormal)<0 && sign>0 || TempNormal.ScalarProduct(OldNormal)>0 && sign<0)
1785 {
1786 TempNormal.Scale(-1);
1787 }
1788 TempNormal.Normalize();
1789 Restradius = sqrt(RADIUS*RADIUS - Umkreisradius*Umkreisradius);
1790 TempNormal.Scale(Restradius);
1791
1792 Mittelpunkt.CopyVector(&Umkreismittelpunkt);
1793 Mittelpunkt.AddVector(&TempNormal); //this is center of sphere supported by a, b and Candidate
1794
1795 AngleCheck.CopyVector(Chord);
1796 AngleCheck.Scale(-0.5);
1797 AngleCheck.SubtractVector(&(b->x));
1798 AngleCheckReference.CopyVector(&AngleCheck);
1799 AngleCheckReference.AddVector(Opt_Mittelpunkt);
1800 AngleCheck.AddVector(&Mittelpunkt);
1801
1802 BallAngle = AngleCheck.Angle(&AngleCheckReference);
1803
1804 d1->ProjectOntoPlane(&AngleCheckReference);
1805 sign = AngleCheck.ScalarProduct(d1);
1806 if (fabs(sign) < MYEPSILON)
1807 sign = 0;
1808 else
1809 sign /= fabs(sign); // +1 if in direction of triangle plane, -1 if in other direction...
1810
1811
1812 if (Storage[0]< -1.5) // first Candidate at all
1813 {
1814
1815 cout << "Next better candidate is " << *Candidate << " with ";
1816 Opt_Candidate = Candidate;
1817 Storage[0] = sign;
1818 Storage[1] = BallAngle;
1819 Opt_Mittelpunkt->CopyVector(&Mittelpunkt);
1820 cout << "Angle is " << Storage[1] << ", Halbraum ist "
1821 << Storage[0] << endl;
1822
1823
1824 }
1825 else
1826 {
1827 /*
1828 * removed due to change in criterium, now checking angle of ball to old normal.
1829 //We will now check for non interference, that is if the new candidate would have the Opt_Candidate
1830 //within the ball.
1831
1832 Distance = Opt_Candidate->x.Distance(&Mittelpunkt);
1833 //cout << "Opt_Candidate " << Opt_Candidate << " has distance " << Distance << " to Center of Candidate " << endl;
1834
1835
1836 if (Distance >RADIUS) // We have no interference and may now check whether the new point is better.
1837 */
1838 {
1839 //cout << "Atom " << Candidate << " has distance " << Candidate->x.Distance(Opt_Mittelpunkt) << " to Center of Candidate " << endl;
1840
1841 if (((Storage[0] < 0 && fabs(sign - Storage[0]) > CurrentEpsilon))) //This will give absolute preference to those in "right-hand" quadrants
1842 //(Candidate->x.Distance(Opt_Mittelpunkt) < RADIUS)) //and those where Candidate would be within old Sphere.
1843 {
1844 cout << "Next better candidate is " << *Candidate << " with ";
1845 Opt_Candidate = Candidate;
1846 Storage[0] = sign;
1847 Storage[1] = BallAngle;
1848 Opt_Mittelpunkt->CopyVector(&Mittelpunkt);
1849 cout << "Angle is " << Storage[1] << ", Halbraum ist "
1850 << Storage[0] << endl;
1851
1852
1853 }
1854 else
1855 {
1856 if ((fabs(sign - Storage[0]) < CurrentEpsilon && sign > 0
1857 && Storage[1] > BallAngle) ||
1858 (fabs(sign - Storage[0]) < CurrentEpsilon && sign < 0
1859 && Storage[1] < BallAngle))
1860 //Depending on quadrant we prefer higher or lower atom with respect to Triangle normal first.
1861 {
1862 cout << "Next better candidate is " << *Candidate << " with ";
1863 Opt_Candidate = Candidate;
1864 Storage[0] = sign;
1865 Storage[1] = BallAngle;
1866 Opt_Mittelpunkt->CopyVector(&Mittelpunkt);
1867 cout << "Angle is " << Storage[1] << ", Halbraum ist "
1868 << Storage[0] << endl;
1869 }
1870
1871 }
1872 }
1873 /*
1874 * This is for checking point-angle and presence of Candidates in Ball, currently we are checking the ball Angle.
1875 *
1876 else
1877 {
1878 if (sign>0 && BallAngle>0 && Storage[0]<0)
1879 {
1880 cout << "Next better candidate is " << *Candidate << " with ";
1881 Opt_Candidate = Candidate;
1882 Storage[0] = sign;
1883 Storage[1] = BallAngle;
1884 Opt_Mittelpunkt->CopyVector(&Mittelpunkt);
1885 cout << "Angle is " << Storage[1] << ", Halbraum ist "
1886 << Storage[0] << endl;
1887
1888//Debugging purposes only
1889 cout << "Umkreismittelpunkt has coordinates" << Umkreismittelpunkt.x[0] << " "<< Umkreismittelpunkt.x[1] <<" "<<Umkreismittelpunkt.x[2] << endl;
1890 cout << "Candidate has coordinates" << Candidate->x.x[0]<< " " << Candidate->x.x[1] << " " << Candidate->x.x[2] << endl;
1891 cout << "a has coordinates" << a->x.x[0]<< " " << a->x.x[1] << " " << a->x.x[2] << endl;
1892 cout << "b has coordinates" << b->x.x[0]<< " " << b->x.x[1] << " " << b->x.x[2] << endl;
1893 cout << "Mittelpunkt has coordinates" << Mittelpunkt.x[0] << " " << Mittelpunkt.x[1]<< " " <<Mittelpunkt.x[2] << endl;
1894 cout << "Umkreisradius ist " << Umkreisradius << endl;
1895 cout << "Restradius ist " << Restradius << endl;
1896 cout << "TempNormal has coordinates " << TempNormal.x[0] << " " << TempNormal.x[1] << " " << TempNormal.x[2] << " " << endl;
1897 cout << "OldNormal has coordinates " << OldNormal->x[0] << " " << OldNormal->x[1] << " " << OldNormal->x[2] << " " << endl;
1898 cout << "Dist a to UmkreisMittelpunkt " << a->x.Distance(&Umkreismittelpunkt) << endl;
1899 cout << "Dist b to UmkreisMittelpunkt " << b->x.Distance(&Umkreismittelpunkt) << endl;
1900 cout << "Dist Candidate to UmkreisMittelpunkt " << Candidate->x.Distance(&Umkreismittelpunkt) << endl;
1901 cout << "Dist a to Mittelpunkt " << a->x.Distance(&Mittelpunkt) << endl;
1902 cout << "Dist b to Mittelpunkt " << b->x.Distance(&Mittelpunkt) << endl;
1903 cout << "Dist Candidate to Mittelpunkt " << Candidate->x.Distance(&Mittelpunkt) << endl;
1904
1905
1906
1907 }
1908 else
1909 {
1910 if (DEBUG)
1911 cout << "Looses to better candidate" << endl;
1912 }
1913 }
1914 */
1915 }
1916 }
1917 else
1918 {
1919 if (DEBUG)
1920 {
1921 cout << "Doesn't satisfy requirements for circumscribing circle" << endl;
1922 }
1923 }
1924 }
1925
1926 else
1927 {
1928 if (DEBUG)
1929 cout << "identisch mit Ursprungslinie" << endl;
1930 }
1931
1932 if (RecursionLevel < 9) // Five is the recursion level threshold.
1933 {
1934 for (int i = 0; i < mol->NumberOfBondsPerAtom[Candidate->nr]; i++) // go through all bond
1935 {
1936 Walker = mol->ListOfBondsPerAtom[Candidate->nr][i]->GetOtherAtom(
1937 Candidate);
1938 if (Walker == Parent)
1939 { // don't go back the same bond
1940 continue;
1941 }
1942 else
1943 {
1944 Find_next_suitable_point(a, b, Walker, Candidate, RecursionLevel
1945 + 1, Chord, d1, OldNormal, Opt_Candidate, Opt_Mittelpunkt, Storage, RADIUS,
1946 mol); //call function again
1947
1948 }
1949 }
1950 }
1951}
1952;
1953
1954/** This function finds a triangle to a line, adjacent to an existing one.
1955 * @param out output stream for debugging
1956 * @param tecplot output stream for writing found triangles in TecPlot format
1957 * @param mol molecule structure with all atoms and bonds
1958 * @param Line current baseline to search from
1959 * @param T current triangle which \a Line is edge of
1960 * @param RADIUS radius of the rolling ball
1961 * @param N number of found triangles
1962 */
1963void Tesselation::Find_next_suitable_triangle(ofstream *out, ofstream *tecplot,
1964 molecule* mol, BoundaryLineSet &Line, BoundaryTriangleSet &T,
1965 const double& RADIUS, int N)
1966{
1967 cout << Verbose(1) << "Begin of Find_next_suitable_triangle\n";
1968 Vector direction1;
1969 Vector helper;
1970 Vector Chord;
1971 ofstream *tempstream = NULL;
1972 char filename[255];
1973 double tmp;
1974 //atom* Walker;
1975 atom* OldThirdPoint;
1976
1977 double Storage[3];
1978 Storage[0] = -2.; // This direction is either +1 or -1 one, so any result will take precedence over initial values
1979 Storage[1] = -2.; // This is also lower then any value produced by an eligible atom, which are all positive
1980 Storage[2] = 9999999.;
1981 atom* Opt_Candidate = NULL;
1982 Vector Opt_Mittelpunkt;
1983
1984 cout << Verbose(1) << "Current baseline is " << Line << " of triangle " << T << "." << endl;
1985
1986 helper.CopyVector(&(Line.endpoints[0]->node->x));
1987 for (int i = 0; i < 3; i++)
1988 {
1989 if (T.endpoints[i]->node->nr != Line.endpoints[0]->node->nr
1990 && T.endpoints[i]->node->nr != Line.endpoints[1]->node->nr)
1991 {
1992 OldThirdPoint = T.endpoints[i]->node;
1993 helper.SubtractVector(&T.endpoints[i]->node->x);
1994 break;
1995 }
1996 }
1997
1998 direction1.CopyVector(&Line.endpoints[0]->node->x);
1999 direction1.SubtractVector(&Line.endpoints[1]->node->x);
2000 direction1.VectorProduct(&(T.NormalVector));
2001
2002 if (direction1.ScalarProduct(&helper) < 0)
2003 {
2004 direction1.Scale(-1);
2005 }
2006 cout << Verbose(2) << "Looking in direction " << direction1 << " for candidates.\n";
2007
2008 Chord.CopyVector(&(Line.endpoints[0]->node->x)); // bring into calling function
2009 Chord.SubtractVector(&(Line.endpoints[1]->node->x));
2010 cout << Verbose(2) << "Baseline vector is " << Chord << ".\n";
2011
2012
2013 Vector Umkreismittelpunkt, a, b, c;
2014 double alpha, beta, gamma;
2015 a.CopyVector(&(T.endpoints[0]->node->x));
2016 b.CopyVector(&(T.endpoints[1]->node->x));
2017 c.CopyVector(&(T.endpoints[2]->node->x));
2018 a.SubtractVector(&(T.endpoints[1]->node->x));
2019 b.SubtractVector(&(T.endpoints[2]->node->x));
2020 c.SubtractVector(&(T.endpoints[0]->node->x));
2021
2022// alpha = a.Angle(&c) - M_PI/2.;
2023// beta = b.Angle(&a);
2024// gamma = c.Angle(&b) - M_PI/2.;
2025 alpha = M_PI - a.Angle(&c);
2026 beta = M_PI - b.Angle(&a);
2027 gamma = M_PI - c.Angle(&b);
2028 if (fabs(M_PI - alpha - beta - gamma) > MYEPSILON)
2029 cerr << Verbose(0) << "WARNING: sum of angles for candidate triangle " << (alpha + beta + gamma)/M_PI*180. << " != 180.\n";
2030
2031 Umkreismittelpunkt = (T.endpoints[0]->node->x) * sin(2.*alpha) + T.endpoints[1]->node->x * sin(2.*beta) + (T.endpoints[2]->node->x) * sin(2.*gamma) ;
2032 //cout << "UmkreisMittelpunkt is " << Umkreismittelpunkt.x[0] << " "<< Umkreismittelpunkt.x[1] << " "<< Umkreismittelpunkt.x[2] << " "<< endl;
2033 Umkreismittelpunkt.Scale(1/(sin(2*alpha) + sin(2*beta) + sin(2*gamma)));
2034 cout << "UmkreisMittelpunkt is " << Umkreismittelpunkt.x[0] << " "<< Umkreismittelpunkt.x[1] << " "<< Umkreismittelpunkt.x[2] << " "<< endl;
2035 cout << " We look over line " << Line << " in direction " << direction1.x[0] << " " << direction1.x[1] << " " << direction1.x[2] << " " << endl;
2036 cout << " Old Normal is " << (T.NormalVector.x)[0] << " " << T.NormalVector.x[1] << " " << (T.NormalVector.x)[2] << " " << endl;
2037
2038 cout << Verbose(2) << "Base triangle has sides " << a << ", " << b << ", " << c << " with angles " << alpha/M_PI*180. << ", " << beta/M_PI*180. << ", " << gamma/M_PI*180. << "." << endl;
2039 Umkreismittelpunkt = (T.endpoints[0]->node->x) * sin(2.*alpha) + T.endpoints[1]->node->x * sin(2.*beta) + (T.endpoints[2]->node->x) * sin(2.*gamma) ;
2040 Umkreismittelpunkt.Scale(1/(sin(2*alpha) + sin(2*beta) + sin(2*gamma)));
2041 cout << Verbose(2) << "Center of circumference is " << Umkreismittelpunkt << "." << endl;
2042 if (DEBUG)
2043 cout << Verbose(3) << "Check of relative endpoints (same distance, equally spreaded): "<< endl;
2044 tmp = 0;
2045 for (int i=0;i<NDIM;i++) {
2046 helper.CopyVector(&T.endpoints[i]->node->x);
2047 helper.SubtractVector(&Umkreismittelpunkt);
2048 if (DEBUG)
2049 cout << Verbose(3) << "Endpoint[" << i << "]: " << helper << " with length " << helper.Norm() << "." << endl;
2050 if (tmp == 0) // set on first time for comparison against next ones
2051 tmp = helper.Norm();
2052 if (fabs(helper.Norm() - tmp) > MYEPSILON)
2053 cerr << Verbose(1) << "WARNING: center of circumference is wrong!" << endl;
2054 }
2055
2056 cout << Verbose(1) << "Looking for third point candidates for triangle ... " << endl;
2057
2058 Find_next_suitable_point_via_Angle_of_Sphere(Line.endpoints[0]->node, Line.endpoints[1]->node, OldThirdPoint,
2059 Line.endpoints[0]->node, Line.endpoints[1]->node, 0, &Chord, &direction1,
2060 &(T.NormalVector), Umkreismittelpunkt, Opt_Candidate, Storage, RADIUS, mol);
2061 Find_next_suitable_point_via_Angle_of_Sphere(Line.endpoints[0]->node, Line.endpoints[1]->node, OldThirdPoint,
2062 Line.endpoints[1]->node, Line.endpoints[0]->node, 0, &Chord, &direction1,
2063 &(T.NormalVector), Umkreismittelpunkt, Opt_Candidate, Storage, RADIUS, mol);
2064
2065
2066 cout << "Letzter Winkel bei " << TrianglesOnBoundaryCount << " Winkel ist " << Storage[2] << endl;
2067
2068
2069 if ((TrianglesOnBoundaryCount % 1) == 0)
2070 {
2071 cout << Verbose(1) << "Writing temporary non convex hull to file testEnvelope-" << TriangleFilesWritten << "d.dat.\n";
2072 sprintf(filename, "testEnvelope-%d.dat", TriangleFilesWritten);
2073 tempstream = new ofstream(filename, ios::trunc);
2074 write_tecplot_file(out, tempstream, this, mol, TriangleFilesWritten++);
2075 tempstream->close();
2076 tempstream->flush();
2077 delete(tempstream);
2078 }
2079
2080 if (TrianglesOnBoundaryCount >189 and TrianglesOnBoundaryCount < 200 )
2081 {
2082 cerr << Verbose(0)
2083 << "WARNING: Already more than " << TrianglesOnBoundaryCount-1 << "triangles, construction probably has crashed." << endl;
2084 write_tecplot_file(out, tecplot, this, mol, TriangleFilesWritten);
2085 cout << Verbose(2) << "This is currently added candidate" << Opt_Candidate << endl;
2086 }
2087 // Konstruiere nun neues Dreieck am Ende der Liste der Dreiecke
2088
2089 cout << Verbose(2) << " Optimal candidate is " << *Opt_Candidate << endl;
2090
2091 // check whether all edges of the new triangle still have space for one more triangle (i.e. TriangleCount <2)
2092
2093 AddTrianglePoint(Opt_Candidate, 0);
2094 LineMap::iterator TryAndError;
2095 TryAndError = TPS[0]->lines.find(Line.endpoints[0]->node->nr);
2096 bool flag = true;
2097 if ((TryAndError != TPS[0]->lines.end()) && (TryAndError->second->TrianglesCount > 1))
2098 flag = false;
2099 TryAndError = TPS[0]->lines.find(Line.endpoints[1]->node->nr);
2100 if ((TryAndError != TPS[0]->lines.end()) && (TryAndError->second->TrianglesCount > 1))
2101 flag = false;
2102
2103 if (flag) { // if so, add
2104 AddTrianglePoint(Line.endpoints[0]->node, 1);
2105 AddTrianglePoint(Line.endpoints[1]->node, 2);
2106
2107 AddTriangleLine(TPS[0], TPS[1], 0);
2108 AddTriangleLine(TPS[0], TPS[2], 1);
2109 AddTriangleLine(TPS[1], TPS[2], 2);
2110
2111 BTS = new class BoundaryTriangleSet(BLS, TrianglesOnBoundaryCount);
2112 AddTriangleToLines();
2113
2114 BTS->GetNormalVector(BTS->NormalVector);
2115
2116 if ((BTS->NormalVector.ScalarProduct(&(T.NormalVector)) < 0 && Storage[0] > 0) ||
2117 (BTS->NormalVector.ScalarProduct(&(T.NormalVector)) > 0 && Storage[0] < 0) ||
2118 (fabs(Storage[0]) < MYEPSILON && Storage[1]*BTS->NormalVector.ScalarProduct(&direction1) < 0) )
2119
2120 {
2121 BTS->NormalVector.Scale(-1);
2122 };
2123 cout << Verbose(2) << "New triangle with " << *BTS << "and normal vector " << BTS->NormalVector << " for this triangle ... " << endl;
2124 cout << Verbose(2) << "We have "<< TrianglesOnBoundaryCount << " for line " << Line << "." << endl;
2125 } else { // else, yell and do nothing
2126 cout << Verbose(2) << "This triangle consisting of ";
2127 for (int i=0;i<NDIM;i++)
2128 cout << BLS[i] << "(" << BLS[i]->TrianglesCount << "), ";
2129 cout << " is invalid!" << endl;
2130 }
2131 cout << Verbose(1) << "End of Find_next_suitable_triangle\n";
2132}
2133;
2134
2135void Find_second_point_for_Tesselation(atom* a, atom* Candidate, atom* Parent,
2136 int RecursionLevel, Vector Oben, atom*& Opt_Candidate, double Storage[3],
2137 molecule* mol, double RADIUS)
2138{
2139 cout << Verbose(2)
2140 << "Begin of Find_second_point_for_Tesselation, recursive level "
2141 << RecursionLevel << endl;
2142 int i;
2143 Vector AngleCheck;
2144 atom* Walker;
2145 double norm = -1., angle;
2146
2147 // check if we only have one unique point yet ...
2148 if (a != Candidate)
2149 {
2150 cout << Verbose(3) << "Current candidate is " << *Candidate << ": ";
2151 AngleCheck.CopyVector(&(Candidate->x));
2152 AngleCheck.SubtractVector(&(a->x));
2153 norm = AngleCheck.Norm();
2154 // second point shall have smallest angle with respect to Oben vector
2155 if (norm < RADIUS)
2156 {
2157 angle = AngleCheck.Angle(&Oben);
2158 if (angle < Storage[0])
2159 {
2160 //cout << Verbose(1) << "Old values of Storage: %lf %lf \n", Storage[0], Storage[1]);
2161 cout << "Is a better candidate with distance " << norm << " and " << angle << ".\n";
2162 Opt_Candidate = Candidate;
2163 Storage[0] = AngleCheck.Angle(&Oben);
2164 //cout << Verbose(1) << "Changing something in Storage: %lf %lf. \n", Storage[0], Storage[2]);
2165 }
2166 else
2167 {
2168 cout << "Looses with angle " << angle << " to a better candidate "
2169 << *Opt_Candidate << endl;
2170 }
2171 }
2172 else
2173 {
2174 cout << "Refused due to Radius " << norm
2175 << endl;
2176 }
2177 }
2178
2179 // if not recursed to deeply, look at all its bonds
2180 if (RecursionLevel < 7)
2181 {
2182 for (i = 0; i < mol->NumberOfBondsPerAtom[Candidate->nr]; i++)
2183 {
2184 Walker = mol->ListOfBondsPerAtom[Candidate->nr][i]->GetOtherAtom(
2185 Candidate);
2186 if (Walker == Parent) // don't go back along the bond we came from
2187 continue;
2188 else
2189 Find_second_point_for_Tesselation(a, Walker, Candidate,
2190 RecursionLevel + 1, Oben, Opt_Candidate, Storage, mol, RADIUS);
2191 };
2192 };
2193 cout << Verbose(2) << "End of Find_second_point_for_Tesselation, recursive level "
2194 << RecursionLevel << endl;
2195}
2196;
2197
2198void Tesselation::Find_starting_triangle(molecule* mol, const double RADIUS)
2199{
2200 cout << Verbose(1) << "Begin of Find_starting_triangle\n";
2201 int i = 0;
2202 atom* Walker;
2203 atom* FirstPoint;
2204 atom* SecondPoint;
2205 atom* max_index[NDIM];
2206 double max_coordinate[NDIM];
2207 Vector Oben;
2208 Vector helper;
2209 Vector Chord;
2210 Vector CenterOfFirstLine;
2211
2212 Oben.Zero();
2213
2214 for (i = 0; i < 3; i++)
2215 {
2216 max_index[i] = NULL;
2217 max_coordinate[i] = -1;
2218 }
2219 cout << Verbose(2) << "Molecule mol is there and has " << mol->AtomCount
2220 << " Atoms \n";
2221
2222 // 1. searching topmost atom with respect to each axis
2223 Walker = mol->start;
2224 while (Walker->next != mol->end)
2225 {
2226 Walker = Walker->next;
2227 for (i = 0; i < 3; i++)
2228 {
2229 if (Walker->x.x[i] > max_coordinate[i])
2230 {
2231 max_coordinate[i] = Walker->x.x[i];
2232 max_index[i] = Walker;
2233 }
2234 }
2235 }
2236
2237 cout << Verbose(2) << "Found maximum coordinates: ";
2238 for (int i=0;i<NDIM;i++)
2239 cout << i << ": " << *max_index[i] << "\t";
2240 cout << endl;
2241 //Koennen dies fuer alle Richtungen, legen hier erstmal Richtung auf k=0
2242 const int k = 1;
2243 Oben.x[k] = 1.;
2244 FirstPoint = max_index[k];
2245
2246 cout << Verbose(1) << "Coordinates of start atom " << *FirstPoint << " at " << FirstPoint->x << " with " << mol->NumberOfBondsPerAtom[FirstPoint->nr] << " bonds." << endl;
2247 double Storage[3];
2248 atom* Opt_Candidate = NULL;
2249 Storage[0] = 999999.; // This will contain the angle, which will be always positive (when looking for second point), when looking for third point this will be the quadrant.
2250 Storage[1] = 999999.; // This will be an angle looking for the third point.
2251 Storage[2] = 999999.;
2252
2253 Find_second_point_for_Tesselation(FirstPoint, FirstPoint, FirstPoint, 0,
2254 Oben, Opt_Candidate, Storage, mol, RADIUS); // we give same point as next candidate as its bonds are looked into in find_second_...
2255 SecondPoint = Opt_Candidate;
2256 cout << Verbose(1) << "Found second point is " << *SecondPoint << " at " << SecondPoint->x << ".\n";
2257
2258 helper.CopyVector(&(FirstPoint->x));
2259 helper.SubtractVector(&(SecondPoint->x));
2260 helper.Normalize();
2261 Oben.ProjectOntoPlane(&helper);
2262 Oben.Normalize();
2263 helper.VectorProduct(&Oben);
2264 Storage[0] = -2.; // This will indicate the quadrant.
2265 Storage[1] = 9999999.; // This will be an angle looking for the third point.
2266 Storage[2] = 9999999.;
2267
2268 Chord.CopyVector(&(FirstPoint->x)); // bring into calling function
2269 Chord.SubtractVector(&(SecondPoint->x));
2270 // Now, oben and helper are two orthonormalized vectors in the plane defined by Chord (not normalized)
2271
2272 cout << Verbose(2) << "Looking for third point candidates \n";
2273 // look in one direction of baseline for initial candidate
2274 Opt_Candidate = NULL;
2275 CenterOfFirstLine.CopyVector(&Chord);
2276 CenterOfFirstLine.Scale(0.5);
2277 CenterOfFirstLine.AddVector(&(SecondPoint->x));
2278
2279 cout << Verbose(1) << "Looking for third point candidates from " << *FirstPoint << " onward ...\n";
2280 Find_next_suitable_point_via_Angle_of_Sphere(FirstPoint, SecondPoint, SecondPoint, SecondPoint, FirstPoint, 0,
2281 &Chord, &helper, &Oben, CenterOfFirstLine, Opt_Candidate, Storage, RADIUS, mol);
2282 // look in other direction of baseline for possible better candidate
2283 cout << Verbose(1) << "Looking for third point candidates from " << *SecondPoint << " onward ...\n";
2284 Find_next_suitable_point_via_Angle_of_Sphere(FirstPoint, SecondPoint, SecondPoint, FirstPoint, SecondPoint, 0,
2285 &Chord, &helper, &Oben, CenterOfFirstLine, Opt_Candidate, Storage, RADIUS, mol);
2286 cout << Verbose(1) << "Third Point is " << *Opt_Candidate << endl;
2287
2288 // FOUND Starting Triangle: FirstPoint, SecondPoint, Opt_Candidate
2289
2290 // Finally, we only have to add the found points
2291 AddTrianglePoint(FirstPoint, 0);
2292 AddTrianglePoint(SecondPoint, 1);
2293 AddTrianglePoint(Opt_Candidate, 2);
2294 // ... and respective lines
2295 AddTriangleLine(TPS[0], TPS[1], 0);
2296 AddTriangleLine(TPS[1], TPS[2], 1);
2297 AddTriangleLine(TPS[0], TPS[2], 2);
2298 // ... and triangles to the Maps of the Tesselation class
2299 BTS = new class BoundaryTriangleSet(BLS, TrianglesOnBoundaryCount);
2300 AddTriangleToLines();
2301 // ... and calculate its normal vector (with correct orientation)
2302 Oben.Scale(-1.);
2303 BTS->GetNormalVector(Oben);
2304 cout << Verbose(0) << "==> The found starting triangle consists of "
2305 << *FirstPoint << ", " << *SecondPoint << " and " << *Opt_Candidate
2306 << " with normal vector " << BTS->NormalVector << ".\n";
2307 cout << Verbose(1) << "End of Find_starting_triangle\n";
2308}
2309;
2310
2311void Find_non_convex_border(ofstream *out, ofstream *tecplot, molecule* mol)
2312{
2313 int N = 0;
2314 struct Tesselation *Tess = new Tesselation;
2315 cout << Verbose(1) << "Entering search for non convex hull. " << endl;
2316 cout << flush;
2317 const double RADIUS = 6.;
2318 LineMap::iterator baseline;
2319 cout << Verbose(0) << "Begin of Find_non_convex_border\n";
2320 bool flag = false; // marks whether we went once through all baselines without finding any without two triangles
2321
2322 Tess->Find_starting_triangle(mol, RADIUS);
2323
2324 baseline = Tess->LinesOnBoundary.begin();
2325 while ((baseline != Tess->LinesOnBoundary.end()) || (flag))
2326 {
2327 if (baseline->second->TrianglesCount == 1)
2328 {
2329 Tess->Find_next_suitable_triangle(out, tecplot, mol,
2330 *(baseline->second),
2331 *(((baseline->second->triangles.begin()))->second), RADIUS, N); //the line is there, so there is a triangle, but only one.
2332 flag = true;
2333 }
2334 else
2335 {
2336 cout << Verbose(1) << "Line " << baseline->second << " has "
2337 << baseline->second->TrianglesCount << " triangles adjacent"
2338 << endl;
2339 }
2340 N++;
2341 baseline++;
2342 if ((baseline == Tess->LinesOnBoundary.end()) && (flag)) {
2343 baseline = Tess->LinesOnBoundary.begin(); // restart if we reach end due to newly inserted lines
2344 flag = false;
2345 }
2346 }
2347 cout << Verbose(1) << "Writing final tecplot file\n";
2348 write_tecplot_file(out, tecplot, Tess, mol, -1);
2349
2350 cout << Verbose(0) << "End of Find_non_convex_border\n";
2351}
2352;
2353
Note: See TracBrowser for help on using the repository browser.