source: molecuilder/src/boundary.cpp@ d3d15c

Last change on this file since d3d15c was d3d15c, checked in by Frederik Heber <heber@…>, 17 years ago

Find_non_convex_border(): calls CreateAdjacencyList() to fill bond list

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