Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/boundary.cpp

    redb93c r8c54a3  
    1 /** \file boundary.hpp
    2  *
    3  * Implementations and super-function for envelopes
    4  */
    5 
    6 
    71#include "boundary.hpp"
    8 
    9 #include<gsl/gsl_poly.h>
     2#include "linkedcell.hpp"
     3#include "molecules.hpp"
     4#include <gsl/gsl_matrix.h>
     5#include <gsl/gsl_linalg.h>
     6#include <gsl/gsl_multimin.h>
     7#include <gsl/gsl_permutation.h>
     8
     9#define DEBUG 1
     10#define DoSingleStepOutput 0
     11#define DoTecplotOutput 1
     12#define DoRaster3DOutput 0
     13#define DoVRMLOutput 1
     14#define TecplotSuffix ".dat"
     15#define Raster3DSuffix ".r3d"
     16#define VRMLSUffix ".wrl"
     17#define HULLEPSILON 1e-7
     18
     19// ======================================== Points on Boundary =================================
     20
     21BoundaryPointSet::BoundaryPointSet()
     22{
     23  LinesCount = 0;
     24  Nr = -1;
     25}
     26;
     27
     28BoundaryPointSet::BoundaryPointSet(atom *Walker)
     29{
     30  node = Walker;
     31  LinesCount = 0;
     32  Nr = Walker->nr;
     33}
     34;
     35
     36BoundaryPointSet::~BoundaryPointSet()
     37{
     38  cout << Verbose(5) << "Erasing point nr. " << Nr << "." << endl;
     39  if (!lines.empty())
     40    cerr << "WARNING: Memory Leak! I " << *this << " am still connected to some lines." << endl;
     41  node = NULL;
     42}
     43;
     44
     45void BoundaryPointSet::AddLine(class BoundaryLineSet *line)
     46{
     47  cout << Verbose(6) << "Adding line " << *line << " to " << *this << "." << endl;
     48  if (line->endpoints[0] == this)
     49    {
     50      lines.insert(LinePair(line->endpoints[1]->Nr, line));
     51    }
     52  else
     53    {
     54      lines.insert(LinePair(line->endpoints[0]->Nr, line));
     55    }
     56  LinesCount++;
     57}
     58;
     59
     60ostream &
     61operator <<(ostream &ost, BoundaryPointSet &a)
     62{
     63  ost << "[" << a.Nr << "|" << a.node->Name << "]";
     64  return ost;
     65}
     66;
     67
     68// ======================================== Lines on Boundary =================================
     69
     70BoundaryLineSet::BoundaryLineSet()
     71{
     72  for (int i = 0; i < 2; i++)
     73    endpoints[i] = NULL;
     74  TrianglesCount = 0;
     75  Nr = -1;
     76}
     77;
     78
     79BoundaryLineSet::BoundaryLineSet(class BoundaryPointSet *Point[2], int number)
     80{
     81  // set number
     82  Nr = number;
     83  // set endpoints in ascending order
     84  SetEndpointsOrdered(endpoints, Point[0], Point[1]);
     85  // add this line to the hash maps of both endpoints
     86  Point[0]->AddLine(this); //Taken out, to check whether we can avoid unwanted double adding.
     87  Point[1]->AddLine(this); //
     88  // clear triangles list
     89  TrianglesCount = 0;
     90  cout << Verbose(5) << "New Line with endpoints " << *this << "." << endl;
     91}
     92;
     93
     94BoundaryLineSet::~BoundaryLineSet()
     95{
     96  int Numbers[2];
     97  Numbers[0] = endpoints[1]->Nr;
     98  Numbers[1] = endpoints[0]->Nr;
     99  for (int i = 0; i < 2; i++) {
     100    cout << Verbose(5) << "Erasing Line Nr. " << Nr << " in boundary point " << *endpoints[i] << "." << endl;
     101    // as there may be multiple lines with same endpoints, we have to go through each and find in the endpoint's line list this line set
     102    pair<LineMap::iterator, LineMap::iterator> erasor = endpoints[i]->lines.equal_range(Numbers[i]);
     103    for (LineMap::iterator Runner = erasor.first; Runner != erasor.second; Runner++)
     104      if ((*Runner).second == this) {
     105        endpoints[i]->lines.erase(Runner);
     106        break;
     107      }
     108    if (endpoints[i]->lines.empty()) {
     109      cout << Verbose(5) << *endpoints[i] << " has no more lines it's attached to, erasing." << endl;
     110      if (endpoints[i] != NULL) {
     111        delete(endpoints[i]);
     112        endpoints[i] = NULL;
     113      } else
     114        cerr << "ERROR: Endpoint " << i << " has already been free'd." << endl;
     115    } else
     116      cout << Verbose(5) << *endpoints[i] << " has still lines it's attached to." << endl;
     117  }
     118  if (!triangles.empty())
     119    cerr << "WARNING: Memory Leak! I " << *this << " am still connected to some triangles." << endl;
     120}
     121;
     122
     123void
     124BoundaryLineSet::AddTriangle(class BoundaryTriangleSet *triangle)
     125{
     126  cout << Verbose(6) << "Add " << triangle->Nr << " to line " << *this << "."
     127      << endl;
     128  triangles.insert(TrianglePair(triangle->Nr, triangle));
     129  TrianglesCount++;
     130}
     131;
     132
     133ostream &
     134operator <<(ostream &ost, BoundaryLineSet &a)
     135{
     136  ost << "[" << a.Nr << "|" << a.endpoints[0]->node->Name << ","
     137      << a.endpoints[1]->node->Name << "]";
     138  return ost;
     139}
     140;
     141
     142// ======================================== Triangles on Boundary =================================
     143
     144
     145BoundaryTriangleSet::BoundaryTriangleSet()
     146{
     147  for (int i = 0; i < 3; i++)
     148    {
     149      endpoints[i] = NULL;
     150      lines[i] = NULL;
     151    }
     152  Nr = -1;
     153}
     154;
     155
     156BoundaryTriangleSet::BoundaryTriangleSet(class BoundaryLineSet *line[3], int number)
     157{
     158  // set number
     159  Nr = number;
     160  // set lines
     161  cout << Verbose(5) << "New triangle " << Nr << ":" << endl;
     162  for (int i = 0; i < 3; i++)
     163    {
     164      lines[i] = line[i];
     165      lines[i]->AddTriangle(this);
     166    }
     167  // get ascending order of endpoints
     168  map<int, class BoundaryPointSet *> OrderMap;
     169  for (int i = 0; i < 3; i++)
     170    // for all three lines
     171    for (int j = 0; j < 2; j++)
     172      { // for both endpoints
     173        OrderMap.insert(pair<int, class BoundaryPointSet *> (
     174            line[i]->endpoints[j]->Nr, line[i]->endpoints[j]));
     175        // and we don't care whether insertion fails
     176      }
     177  // set endpoints
     178  int Counter = 0;
     179  cout << Verbose(6) << " with end points ";
     180  for (map<int, class BoundaryPointSet *>::iterator runner = OrderMap.begin(); runner
     181      != OrderMap.end(); runner++)
     182    {
     183      endpoints[Counter] = runner->second;
     184      cout << " " << *endpoints[Counter];
     185      Counter++;
     186    }
     187  if (Counter < 3)
     188    {
     189      cerr << "ERROR! We have a triangle with only two distinct endpoints!"
     190          << endl;
     191      //exit(1);
     192    }
     193  cout << "." << endl;
     194}
     195;
     196
     197BoundaryTriangleSet::~BoundaryTriangleSet()
     198{
     199  for (int i = 0; i < 3; i++) {
     200    cout << Verbose(5) << "Erasing triangle Nr." << Nr << endl;
     201    lines[i]->triangles.erase(Nr);
     202    if (lines[i]->triangles.empty()) {
     203      if (lines[i] != NULL) {
     204        cout << Verbose(5) << *lines[i] << " is no more attached to any triangle, erasing." << endl;
     205        delete (lines[i]);
     206        lines[i] = NULL;
     207      } else
     208        cerr << "ERROR: This line " << i << " has already been free'd." << endl;
     209    } else
     210      cout << Verbose(5) << *lines[i] << " is still attached to another triangle." << endl;
     211  }
     212}
     213;
     214
     215void
     216BoundaryTriangleSet::GetNormalVector(Vector &OtherVector)
     217{
     218  // get normal vector
     219  NormalVector.MakeNormalVector(&endpoints[0]->node->x, &endpoints[1]->node->x,
     220      &endpoints[2]->node->x);
     221
     222  // make it always point inward (any offset vector onto plane projected onto normal vector suffices)
     223  if (NormalVector.Projection(&OtherVector) > 0)
     224    NormalVector.Scale(-1.);
     225}
     226;
     227
     228ostream &
     229operator <<(ostream &ost, BoundaryTriangleSet &a)
     230{
     231  ost << "[" << a.Nr << "|" << a.endpoints[0]->node->Name << ","
     232      << a.endpoints[1]->node->Name << "," << a.endpoints[2]->node->Name << "]";
     233  return ost;
     234}
     235;
     236
     237
     238// ============================ CandidateForTesselation =============================
     239
     240CandidateForTesselation::CandidateForTesselation(
     241        atom *candidate, BoundaryLineSet* line, Vector OptCandidateCenter, Vector OtherOptCandidateCenter
     242) {
     243        point = candidate;
     244        BaseLine = line;
     245        OptCenter.CopyVector(&OptCandidateCenter);
     246        OtherOptCenter.CopyVector(&OtherOptCandidateCenter);
     247}
     248
     249CandidateForTesselation::~CandidateForTesselation() {
     250        point = NULL;
     251        BaseLine = NULL;
     252}
    10253
    11254// ========================================== F U N C T I O N S =================================
    12255
     256/** Finds the endpoint two lines are sharing.
     257 * \param *line1 first line
     258 * \param *line2 second line
     259 * \return point which is shared or NULL if none
     260 */
     261class BoundaryPointSet *
     262GetCommonEndpoint(class BoundaryLineSet * line1, class BoundaryLineSet * line2)
     263{
     264  class BoundaryLineSet * lines[2] =
     265    { line1, line2 };
     266  class BoundaryPointSet *node = NULL;
     267  map<int, class BoundaryPointSet *> OrderMap;
     268  pair<map<int, class BoundaryPointSet *>::iterator, bool> OrderTest;
     269  for (int i = 0; i < 2; i++)
     270    // for both lines
     271    for (int j = 0; j < 2; j++)
     272      { // for both endpoints
     273        OrderTest = OrderMap.insert(pair<int, class BoundaryPointSet *> (
     274            lines[i]->endpoints[j]->Nr, lines[i]->endpoints[j]));
     275        if (!OrderTest.second)
     276          { // if insertion fails, we have common endpoint
     277            node = OrderTest.first->second;
     278            cout << Verbose(5) << "Common endpoint of lines " << *line1
     279                << " and " << *line2 << " is: " << *node << "." << endl;
     280            j = 2;
     281            i = 2;
     282            break;
     283          }
     284      }
     285  return node;
     286}
     287;
     288
     289/** Determines the boundary points of a cluster.
     290 * Does a projection per axis onto the orthogonal plane, transforms into spherical coordinates, sorts them by the angle
     291 * and looks at triples: if the middle has less a distance than the allowed maximum height of the triangle formed by the plane's
     292 * center and first and last point in the triple, it is thrown out.
     293 * \param *out output stream for debugging
     294 * \param *mol molecule structure representing the cluster
     295 */
     296Boundaries *
     297GetBoundaryPoints(ofstream *out, molecule *mol)
     298{
     299  atom *Walker = NULL;
     300  PointMap PointsOnBoundary;
     301  LineMap LinesOnBoundary;
     302  TriangleMap TrianglesOnBoundary;
     303
     304  *out << Verbose(1) << "Finding all boundary points." << endl;
     305  Boundaries *BoundaryPoints = new Boundaries[NDIM]; // first is alpha, second is (r, nr)
     306  BoundariesTestPair BoundaryTestPair;
     307  Vector AxisVector, AngleReferenceVector, AngleReferenceNormalVector;
     308  double radius, angle;
     309  // 3a. Go through every axis
     310  for (int axis = 0; axis < NDIM; axis++)
     311    {
     312      AxisVector.Zero();
     313      AngleReferenceVector.Zero();
     314      AngleReferenceNormalVector.Zero();
     315      AxisVector.x[axis] = 1.;
     316      AngleReferenceVector.x[(axis + 1) % NDIM] = 1.;
     317      AngleReferenceNormalVector.x[(axis + 2) % NDIM] = 1.;
     318      //    *out << Verbose(1) << "Axisvector is ";
     319      //    AxisVector.Output(out);
     320      //    *out << " and AngleReferenceVector is ";
     321      //    AngleReferenceVector.Output(out);
     322      //    *out << "." << endl;
     323      //    *out << " and AngleReferenceNormalVector is ";
     324      //    AngleReferenceNormalVector.Output(out);
     325      //    *out << "." << endl;
     326      // 3b. construct set of all points, transformed into cylindrical system and with left and right neighbours
     327      Walker = mol->start;
     328      while (Walker->next != mol->end)
     329        {
     330          Walker = Walker->next;
     331          Vector ProjectedVector;
     332          ProjectedVector.CopyVector(&Walker->x);
     333          ProjectedVector.ProjectOntoPlane(&AxisVector);
     334          // correct for negative side
     335          //if (Projection(y) < 0)
     336          //angle = 2.*M_PI - angle;
     337          radius = ProjectedVector.Norm();
     338          if (fabs(radius) > MYEPSILON)
     339            angle = ProjectedVector.Angle(&AngleReferenceVector);
     340          else
     341            angle = 0.; // otherwise it's a vector in Axis Direction and unimportant for boundary issues
     342
     343          //*out << "Checking sign in quadrant : " << ProjectedVector.Projection(&AngleReferenceNormalVector) << "." << endl;
     344          if (ProjectedVector.Projection(&AngleReferenceNormalVector) > 0)
     345            {
     346              angle = 2. * M_PI - angle;
     347            }
     348          //*out << Verbose(2) << "Inserting " << *Walker << ": (r, alpha) = (" << radius << "," << angle << "): ";
     349          //ProjectedVector.Output(out);
     350          //*out << endl;
     351          BoundaryTestPair = BoundaryPoints[axis].insert(BoundariesPair(angle,
     352              DistancePair (radius, Walker)));
     353          if (BoundaryTestPair.second)
     354            { // successfully inserted
     355            }
     356          else
     357            { // same point exists, check first r, then distance of original vectors to center of gravity
     358              *out << Verbose(2)
     359                  << "Encountered two vectors whose projection onto axis "
     360                  << axis << " is equal: " << endl;
     361              *out << Verbose(2) << "Present vector: ";
     362              BoundaryTestPair.first->second.second->x.Output(out);
     363              *out << endl;
     364              *out << Verbose(2) << "New vector: ";
     365              Walker->x.Output(out);
     366              *out << endl;
     367              double tmp = ProjectedVector.Norm();
     368              if (tmp > BoundaryTestPair.first->second.first)
     369                {
     370                  BoundaryTestPair.first->second.first = tmp;
     371                  BoundaryTestPair.first->second.second = Walker;
     372                  *out << Verbose(2) << "Keeping new vector." << endl;
     373                }
     374              else if (tmp == BoundaryTestPair.first->second.first)
     375                {
     376                  if (BoundaryTestPair.first->second.second->x.ScalarProduct(
     377                      &BoundaryTestPair.first->second.second->x)
     378                      < Walker->x.ScalarProduct(&Walker->x))
     379                    { // Norm() does a sqrt, which makes it a lot slower
     380                      BoundaryTestPair.first->second.second = Walker;
     381                      *out << Verbose(2) << "Keeping new vector." << endl;
     382                    }
     383                  else
     384                    {
     385                      *out << Verbose(2) << "Keeping present vector." << endl;
     386                    }
     387                }
     388              else
     389                {
     390                  *out << Verbose(2) << "Keeping present vector." << endl;
     391                }
     392            }
     393        }
     394      // printing all inserted for debugging
     395      //    {
     396      //      *out << Verbose(2) << "Printing list of candidates for axis " << axis << " which we have inserted so far." << endl;
     397      //      int i=0;
     398      //      for(Boundaries::iterator runner = BoundaryPoints[axis].begin(); runner != BoundaryPoints[axis].end(); runner++) {
     399      //        if (runner != BoundaryPoints[axis].begin())
     400      //          *out << ", " << i << ": " << *runner->second.second;
     401      //        else
     402      //          *out << i << ": " << *runner->second.second;
     403      //        i++;
     404      //      }
     405      //      *out << endl;
     406      //    }
     407      // 3c. throw out points whose distance is less than the mean of left and right neighbours
     408      bool flag = false;
     409      do
     410        { // do as long as we still throw one out per round
     411          *out << Verbose(1)
     412              << "Looking for candidates to kick out by convex condition ... "
     413              << endl;
     414          flag = false;
     415          Boundaries::iterator left = BoundaryPoints[axis].end();
     416          Boundaries::iterator right = BoundaryPoints[axis].end();
     417          for (Boundaries::iterator runner = BoundaryPoints[axis].begin(); runner
     418              != BoundaryPoints[axis].end(); runner++)
     419            {
     420              // set neighbours correctly
     421              if (runner == BoundaryPoints[axis].begin())
     422                {
     423                  left = BoundaryPoints[axis].end();
     424                }
     425              else
     426                {
     427                  left = runner;
     428                }
     429              left--;
     430              right = runner;
     431              right++;
     432              if (right == BoundaryPoints[axis].end())
     433                {
     434                  right = BoundaryPoints[axis].begin();
     435                }
     436              // check distance
     437
     438              // construct the vector of each side of the triangle on the projected plane (defined by normal vector AxisVector)
     439                {
     440                  Vector SideA, SideB, SideC, SideH;
     441                  SideA.CopyVector(&left->second.second->x);
     442                  SideA.ProjectOntoPlane(&AxisVector);
     443                  //          *out << "SideA: ";
     444                  //          SideA.Output(out);
     445                  //          *out << endl;
     446
     447                  SideB.CopyVector(&right->second.second->x);
     448                  SideB.ProjectOntoPlane(&AxisVector);
     449                  //          *out << "SideB: ";
     450                  //          SideB.Output(out);
     451                  //          *out << endl;
     452
     453                  SideC.CopyVector(&left->second.second->x);
     454                  SideC.SubtractVector(&right->second.second->x);
     455                  SideC.ProjectOntoPlane(&AxisVector);
     456                  //          *out << "SideC: ";
     457                  //          SideC.Output(out);
     458                  //          *out << endl;
     459
     460                  SideH.CopyVector(&runner->second.second->x);
     461                  SideH.ProjectOntoPlane(&AxisVector);
     462                  //          *out << "SideH: ";
     463                  //          SideH.Output(out);
     464                  //          *out << endl;
     465
     466                  // calculate each length
     467                  double a = SideA.Norm();
     468                  //double b = SideB.Norm();
     469                  //double c = SideC.Norm();
     470                  double h = SideH.Norm();
     471                  // calculate the angles
     472                  double alpha = SideA.Angle(&SideH);
     473                  double beta = SideA.Angle(&SideC);
     474                  double gamma = SideB.Angle(&SideH);
     475                  double delta = SideC.Angle(&SideH);
     476                  double MinDistance = a * sin(beta) / (sin(delta)) * (((alpha
     477                      < M_PI / 2.) || (gamma < M_PI / 2.)) ? 1. : -1.);
     478                  //          *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;
     479                  //*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;
     480                  if ((fabs(h / fabs(h) - MinDistance / fabs(MinDistance))
     481                      < MYEPSILON) && (h < MinDistance))
     482                    {
     483                      // throw out point
     484                      //*out << Verbose(1) << "Throwing out " << *runner->second.second << "." << endl;
     485                      BoundaryPoints[axis].erase(runner);
     486                      flag = true;
     487                    }
     488                }
     489            }
     490        }
     491      while (flag);
     492    }
     493  return BoundaryPoints;
     494}
     495;
    13496
    14497/** Determines greatest diameters of a cluster defined by its convex envelope.
     
    27510  bool BoundaryFreeFlag = false;
    28511  Boundaries *BoundaryPoints = BoundaryPtr;
    29   if (BoundaryPoints == NULL) {
    30     BoundaryFreeFlag = true;
    31     BoundaryPoints = GetBoundaryPoints(out, mol);
    32   } else {
    33     *out << Verbose(1) << "Using given boundary points set." << endl;
    34   }
     512  if (BoundaryPoints == NULL)
     513    {
     514      BoundaryFreeFlag = true;
     515      BoundaryPoints = GetBoundaryPoints(out, mol);
     516    }
     517  else
     518    {
     519      *out << Verbose(1) << "Using given boundary points set." << endl;
     520    }
    35521  // determine biggest "diameter" of cluster for each axis
    36522  Boundaries::iterator Neighbour, OtherNeighbour;
     
    133619      *vrmlfile << "Sphere {" << endl << "  "; // 2 is sphere type
    134620      for (i=0;i<NDIM;i++)
    135         *vrmlfile << Walker->x.x[i]-center->x[i] << " ";
     621        *vrmlfile << Walker->x.x[i]+center->x[i] << " ";
    136622      *vrmlfile << "\t0.1\t1. 1. 1." << endl; // radius 0.05 and white as colour
    137623    }
     
    142628      *vrmlfile << "3" << endl << "  "; // 2 is round-ended cylinder type
    143629      for (i=0;i<NDIM;i++)
    144         *vrmlfile << Binder->leftatom->x.x[i]-center->x[i] << " ";
     630        *vrmlfile << Binder->leftatom->x.x[i]+center->x[i] << " ";
    145631      *vrmlfile << "\t0.03\t";
    146632      for (i=0;i<NDIM;i++)
    147         *vrmlfile << Binder->rightatom->x.x[i]-center->x[i] << " ";
     633        *vrmlfile << Binder->rightatom->x.x[i]+center->x[i] << " ";
    148634      *vrmlfile << "\t0.03\t0. 0. 1." << endl; // radius 0.05 and blue as colour
    149635    }
     
    154640      for (i=0;i<3;i++) { // print each node
    155641        for (int j=0;j<NDIM;j++)  // and for each node all NDIM coordinates
    156           *vrmlfile << TriangleRunner->second->endpoints[i]->node->node->x[j]-center->x[j] << " ";
     642          *vrmlfile << TriangleRunner->second->endpoints[i]->node->x.x[j]+center->x[j] << " ";
    157643        *vrmlfile << "\t";
    158644      }
     
    187673      *rasterfile << "2" << endl << "  ";  // 2 is sphere type
    188674      for (i=0;i<NDIM;i++)
    189         *rasterfile << Walker->x.x[i]-center->x[i] << " ";
     675        *rasterfile << Walker->x.x[i]+center->x[i] << " ";
    190676      *rasterfile << "\t0.1\t1. 1. 1." << endl; // radius 0.05 and white as colour
    191677    }
     
    196682      *rasterfile << "3" << endl << "  ";  // 2 is round-ended cylinder type
    197683      for (i=0;i<NDIM;i++)
    198         *rasterfile << Binder->leftatom->x.x[i]-center->x[i] << " ";
     684        *rasterfile << Binder->leftatom->x.x[i]+center->x[i] << " ";
    199685      *rasterfile << "\t0.03\t";
    200686      for (i=0;i<NDIM;i++)
    201         *rasterfile << Binder->rightatom->x.x[i]-center->x[i] << " ";
     687        *rasterfile << Binder->rightatom->x.x[i]+center->x[i] << " ";
    202688      *rasterfile << "\t0.03\t0. 0. 1." << endl; // radius 0.05 and blue as colour
    203689    }
     
    209695      for (i=0;i<3;i++) {  // print each node
    210696        for (int j=0;j<NDIM;j++)  // and for each node all NDIM coordinates
    211           *rasterfile << TriangleRunner->second->endpoints[i]->node->node->x[j]-center->x[j] << " ";
     697          *rasterfile << TriangleRunner->second->endpoints[i]->node->x.x[j]+center->x[j] << " ";
    212698        *rasterfile << "\t";
    213699      }
     
    227713 * \param N arbitrary number to differentiate various zones in the tecplot format
    228714 */
    229 void write_tecplot_file(ofstream *out, ofstream *tecplot, class Tesselation *TesselStruct, class molecule *mol, int N)
    230 {
    231   if (tecplot != NULL) {
    232     *tecplot << "TITLE = \"3D CONVEX SHELL\"" << endl;
    233     *tecplot << "VARIABLES = \"X\" \"Y\" \"Z\"" << endl;
    234     *tecplot << "ZONE T=\"TRIANGLES" << N << "\", N=" << TesselStruct->PointsOnBoundaryCount << ", E=" << TesselStruct->TrianglesOnBoundaryCount << ", DATAPACKING=POINT, ZONETYPE=FETRIANGLE" << endl;
    235     int *LookupList = new int[mol->AtomCount];
    236     for (int i = 0; i < mol->AtomCount; i++)
    237       LookupList[i] = -1;
    238 
    239     // print atom coordinates
    240     *out << Verbose(2) << "The following triangles were created:";
    241     int Counter = 1;
    242     TesselPoint *Walker = NULL;
    243     for (PointMap::iterator target = TesselStruct->PointsOnBoundary.begin(); target != TesselStruct->PointsOnBoundary.end(); target++) {
    244       Walker = target->second->node;
    245       LookupList[Walker->nr] = Counter++;
    246       *tecplot << Walker->node->x[0] << " " << Walker->node->x[1] << " " << Walker->node->x[2] << " " << endl;
    247     }
    248     *tecplot << endl;
    249     // print connectivity
    250     for (TriangleMap::iterator runner = TesselStruct->TrianglesOnBoundary.begin(); runner != TesselStruct->TrianglesOnBoundary.end(); runner++) {
    251       *out << " " << runner->second->endpoints[0]->node->Name << "<->" << runner->second->endpoints[1]->node->Name << "<->" << runner->second->endpoints[2]->node->Name;
    252       *tecplot << LookupList[runner->second->endpoints[0]->node->nr] << " " << LookupList[runner->second->endpoints[1]->node->nr] << " " << LookupList[runner->second->endpoints[2]->node->nr] << endl;
    253     }
    254     delete[] (LookupList);
    255     *out << endl;
    256   }
    257 }
    258 
    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.
     715void
     716write_tecplot_file(ofstream *out, ofstream *tecplot,
     717    class Tesselation *TesselStruct, class molecule *mol, int N)
     718{
     719  if (tecplot != NULL)
     720    {
     721      *tecplot << "TITLE = \"3D CONVEX SHELL\"" << endl;
     722      *tecplot << "VARIABLES = \"X\" \"Y\" \"Z\"" << endl;
     723      *tecplot << "ZONE T=\"TRIANGLES" << N << "\", N="
     724          << TesselStruct->PointsOnBoundaryCount << ", E="
     725          << TesselStruct->TrianglesOnBoundaryCount
     726          << ", DATAPACKING=POINT, ZONETYPE=FETRIANGLE" << endl;
     727      int *LookupList = new int[mol->AtomCount];
     728      for (int i = 0; i < mol->AtomCount; i++)
     729        LookupList[i] = -1;
     730
     731      // print atom coordinates
     732      *out << Verbose(2) << "The following triangles were created:";
     733      int Counter = 1;
     734      atom *Walker = NULL;
     735      for (PointMap::iterator target = TesselStruct->PointsOnBoundary.begin(); target
     736          != TesselStruct->PointsOnBoundary.end(); target++)
     737        {
     738          Walker = target->second->node;
     739          LookupList[Walker->nr] = Counter++;
     740          *tecplot << Walker->x.x[0] << " " << Walker->x.x[1] << " "
     741              << Walker->x.x[2] << " " << endl;
     742        }
     743      *tecplot << endl;
     744      // print connectivity
     745      for (TriangleMap::iterator runner =
     746          TesselStruct->TrianglesOnBoundary.begin(); runner
     747          != TesselStruct->TrianglesOnBoundary.end(); runner++)
     748        {
     749          *out << " " << runner->second->endpoints[0]->node->Name << "<->"
     750              << runner->second->endpoints[1]->node->Name << "<->"
     751              << runner->second->endpoints[2]->node->Name;
     752          *tecplot << LookupList[runner->second->endpoints[0]->node->nr] << " "
     753              << LookupList[runner->second->endpoints[1]->node->nr] << " "
     754              << LookupList[runner->second->endpoints[2]->node->nr] << endl;
     755        }
     756      delete[] (LookupList);
     757      *out << endl;
     758    }
     759}
     760
     761/** Determines the volume of a cluster.
     762 * Determines first the convex envelope, then tesselates it and calculates its volume.
    264763 * \param *out output stream for debugging
     764 * \param *filename filename prefix for output of vertex data
     765 * \param *configuration needed for path to store convex envelope file
     766 * \param *BoundaryPoints NDIM set of boundary points on the projected plane per axis, on return if desired
    265767 * \param *mol molecule structure representing the cluster
    266  */
    267 Boundaries *GetBoundaryPoints(ofstream *out, molecule *mol)
    268 {
     768 * \return determined volume of the cluster in cubed config:GetIsAngstroem()
     769 */
     770double
     771VolumeOfConvexEnvelope(ofstream *out, const char *filename, config *configuration,
     772    Boundaries *BoundaryPtr, molecule *mol)
     773{
     774  bool IsAngstroem = configuration->GetIsAngstroem();
    269775  atom *Walker = NULL;
    270   PointMap PointsOnBoundary;
    271   LineMap LinesOnBoundary;
    272   TriangleMap TrianglesOnBoundary;
    273   Vector *MolCenter = mol->DetermineCenterOfAll(out);
    274   Vector helper;
    275 
    276   *out << Verbose(1) << "Finding all boundary points." << endl;
    277   Boundaries *BoundaryPoints = new Boundaries[NDIM]; // first is alpha, second is (r, nr)
    278   BoundariesTestPair BoundaryTestPair;
    279   Vector AxisVector, AngleReferenceVector, AngleReferenceNormalVector;
    280   double radius, angle;
    281   // 3a. Go through every axis
    282   for (int axis = 0; axis < NDIM; axis++) {
    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 
    290     *out << Verbose(1) << "Axisvector is " << AxisVector << " and AngleReferenceVector is " << AngleReferenceVector << ", and AngleReferenceNormalVector is " << AngleReferenceNormalVector << "." << endl;
    291 
    292     // 3b. construct set of all points, transformed into cylindrical system and with left and right neighbours
    293     Walker = mol->start;
    294     while (Walker->next != mol->end) {
     776  struct Tesselation *TesselStruct = new Tesselation;
     777  bool BoundaryFreeFlag = false;
     778  Boundaries *BoundaryPoints = BoundaryPtr;
     779  double volume = 0.;
     780  double PyramidVolume = 0.;
     781  double G, h;
     782  Vector x, y;
     783  double a, b, c;
     784
     785  //Find_non_convex_border(out, tecplot, *TesselStruct, mol); // Is now called from command line.
     786
     787  // 1. calculate center of gravity
     788  *out << endl;
     789  Vector *CenterOfGravity = mol->DetermineCenterOfGravity(out);
     790
     791  // 2. translate all points into CoG
     792  *out << Verbose(1) << "Translating system to Center of Gravity." << endl;
     793  Walker = mol->start;
     794  while (Walker->next != mol->end)
     795    {
    295796      Walker = Walker->next;
    296       Vector ProjectedVector;
    297       ProjectedVector.CopyVector(&Walker->x);
    298       ProjectedVector.SubtractVector(MolCenter);
    299       ProjectedVector.ProjectOntoPlane(&AxisVector);
    300 
    301       // correct for negative side
    302       radius = ProjectedVector.NormSquared();
    303       if (fabs(radius) > MYEPSILON)
    304         angle = ProjectedVector.Angle(&AngleReferenceVector);
    305       else
    306         angle = 0.; // otherwise it's a vector in Axis Direction and unimportant for boundary issues
    307 
    308       //*out << "Checking sign in quadrant : " << ProjectedVector.Projection(&AngleReferenceNormalVector) << "." << endl;
    309       if (ProjectedVector.Projection(&AngleReferenceNormalVector) > 0) {
    310         angle = 2. * M_PI - angle;
    311       }
    312       *out << Verbose(2) << "Inserting " << *Walker << ": (r, alpha) = (" << radius << "," << angle << "): " << ProjectedVector << endl;
    313       BoundaryTestPair = BoundaryPoints[axis].insert(BoundariesPair(angle, DistancePair (radius, Walker)));
    314       if (!BoundaryTestPair.second) { // same point exists, check first r, then distance of original vectors to center of gravity
    315         *out << Verbose(2) << "Encountered two vectors whose projection onto axis " << axis << " is equal: " << endl;
    316         *out << Verbose(2) << "Present vector: " << *BoundaryTestPair.first->second.second << endl;
    317         *out << Verbose(2) << "New vector: " << *Walker << endl;
    318         double tmp = ProjectedVector.NormSquared();
    319         if ((tmp - BoundaryTestPair.first->second.first) > MYEPSILON) {
    320           BoundaryTestPair.first->second.first = tmp;
    321           BoundaryTestPair.first->second.second = Walker;
    322           *out << Verbose(2) << "Keeping new vector due to larger projected distance " << tmp << "." << endl;
    323         } else if (fabs(tmp - BoundaryTestPair.first->second.first) < MYEPSILON) {
    324           helper.CopyVector(&Walker->x);
    325           helper.SubtractVector(MolCenter);
    326           tmp = helper.NormSquared();
    327           helper.CopyVector(&BoundaryTestPair.first->second.second->x);
    328           helper.SubtractVector(MolCenter);
    329           if (helper.NormSquared() < tmp) {
    330             BoundaryTestPair.first->second.second = Walker;
    331             *out << Verbose(2) << "Keeping new vector due to larger distance to molecule center " << helper.NormSquared() << "." << endl;
    332           } else {
    333             *out << Verbose(2) << "Keeping present vector due to larger distance to molecule center " << tmp << "." << endl;
    334           }
    335         } else {
    336           *out << Verbose(2) << "Keeping present vector due to larger projected distance " << tmp << "." << endl;
    337         }
    338       }
    339     }
    340     // printing all inserted for debugging
    341     //    {
    342     //      *out << Verbose(2) << "Printing list of candidates for axis " << axis << " which we have inserted so far." << endl;
    343     //      int i=0;
    344     //      for(Boundaries::iterator runner = BoundaryPoints[axis].begin(); runner != BoundaryPoints[axis].end(); runner++) {
    345     //        if (runner != BoundaryPoints[axis].begin())
    346     //          *out << ", " << i << ": " << *runner->second.second;
    347     //        else
    348     //          *out << i << ": " << *runner->second.second;
    349     //        i++;
    350     //      }
    351     //      *out << endl;
    352     //    }
    353     // 3c. throw out points whose distance is less than the mean of left and right neighbours
    354     bool flag = false;
    355     *out << Verbose(1) << "Looking for candidates to kick out by convex condition ... " << endl;
    356     do { // do as long as we still throw one out per round
    357       flag = false;
    358       Boundaries::iterator left = BoundaryPoints[axis].end();
    359       Boundaries::iterator right = BoundaryPoints[axis].end();
    360       for (Boundaries::iterator runner = BoundaryPoints[axis].begin(); runner != BoundaryPoints[axis].end(); runner++) {
    361         // set neighbours correctly
    362         if (runner == BoundaryPoints[axis].begin()) {
    363           left = BoundaryPoints[axis].end();
    364         } else {
    365           left = runner;
    366         }
    367         left--;
    368         right = runner;
    369         right++;
    370         if (right == BoundaryPoints[axis].end()) {
    371           right = BoundaryPoints[axis].begin();
    372         }
    373         // check distance
    374 
    375         // construct the vector of each side of the triangle on the projected plane (defined by normal vector AxisVector)
    376         {
    377           Vector SideA, SideB, SideC, SideH;
    378           SideA.CopyVector(&left->second.second->x);
    379           SideA.SubtractVector(MolCenter);
    380           SideA.ProjectOntoPlane(&AxisVector);
    381           //          *out << "SideA: ";
    382           //          SideA.Output(out);
    383           //          *out << endl;
    384 
    385           SideB.CopyVector(&right->second.second->x);
    386           SideB.SubtractVector(MolCenter);
    387           SideB.ProjectOntoPlane(&AxisVector);
    388           //          *out << "SideB: ";
    389           //          SideB.Output(out);
    390           //          *out << endl;
    391 
    392           SideC.CopyVector(&left->second.second->x);
    393           SideC.SubtractVector(&right->second.second->x);
    394           SideC.ProjectOntoPlane(&AxisVector);
    395           //          *out << "SideC: ";
    396           //          SideC.Output(out);
    397           //          *out << endl;
    398 
    399           SideH.CopyVector(&runner->second.second->x);
    400           SideH.SubtractVector(MolCenter);
    401           SideH.ProjectOntoPlane(&AxisVector);
    402           //          *out << "SideH: ";
    403           //          SideH.Output(out);
    404           //          *out << endl;
    405 
    406           // calculate each length
    407           double a = SideA.Norm();
    408           //double b = SideB.Norm();
    409           //double c = SideC.Norm();
    410           double h = SideH.Norm();
    411           // calculate the angles
    412           double alpha = SideA.Angle(&SideH);
    413           double beta = SideA.Angle(&SideC);
    414           double gamma = SideB.Angle(&SideH);
    415           double delta = SideC.Angle(&SideH);
    416           double MinDistance = a * sin(beta) / (sin(delta)) * (((alpha < M_PI / 2.) || (gamma < M_PI / 2.)) ? 1. : -1.);
    417           //*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;
    418           *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;
    419           if ((fabs(h / fabs(h) - MinDistance / fabs(MinDistance)) < MYEPSILON) && ((h - MinDistance)) < -MYEPSILON) {
    420             // throw out point
    421             *out << Verbose(1) << "Throwing out " << *runner->second.second << "." << endl;
    422             BoundaryPoints[axis].erase(runner);
    423             flag = true;
    424           }
    425         }
    426       }
    427     } while (flag);
    428   }
    429   delete(MolCenter);
    430   return BoundaryPoints;
    431 };
    432 
    433 /** Tesselates the convex boundary by finding all boundary points.
    434  * \param *out output stream for debugging
    435  * \param *mol molecule structure with Atom's and Bond's
    436  * \param *TesselStruct Tesselation filled with points, lines and triangles on boundary on return
    437  * \param *LCList atoms in LinkedCell list
    438  * \param *filename filename prefix for output of vertex data
    439  * \return *TesselStruct is filled with convex boundary and tesselation is stored under \a *filename.
    440  */
    441 void Find_convex_border(ofstream *out, molecule* mol, class Tesselation *&TesselStruct, class LinkedCell *LCList, const char *filename)
    442 {
    443   bool BoundaryFreeFlag = false;
    444   Boundaries *BoundaryPoints = NULL;
    445 
    446   cout << Verbose(1) << "Begin of find_convex_border" << endl;
    447 
    448   if (TesselStruct != NULL) // free if allocated
    449     delete(TesselStruct);
    450   TesselStruct = new class Tesselation;
    451 
    452   // 1. Find all points on the boundary
    453   if (BoundaryPoints == NULL) {
     797      Walker->x.Translate(CenterOfGravity);
     798    }
     799
     800  // 3. Find all points on the boundary
     801  if (BoundaryPoints == NULL)
     802    {
    454803      BoundaryFreeFlag = true;
    455804      BoundaryPoints = GetBoundaryPoints(out, mol);
    456   } else {
     805    }
     806  else
     807    {
    457808      *out << Verbose(1) << "Using given boundary points set." << endl;
    458   }
    459 
    460 // printing all inserted for debugging
    461   for (int axis=0; axis < NDIM; axis++)
    462     {
    463       *out << Verbose(2) << "Printing list of candidates for axis " << axis << " which we have inserted so far." << endl;
    464       int i=0;
    465       for(Boundaries::iterator runner = BoundaryPoints[axis].begin(); runner != BoundaryPoints[axis].end(); runner++) {
    466         if (runner != BoundaryPoints[axis].begin())
    467           *out << ", " << i << ": " << *runner->second.second;
    468         else
    469           *out << i << ": " << *runner->second.second;
    470         i++;
     809    }
     810
     811  // 4. fill the boundary point list
     812  for (int axis = 0; axis < NDIM; axis++)
     813    for (Boundaries::iterator runner = BoundaryPoints[axis].begin(); runner
     814        != BoundaryPoints[axis].end(); runner++)
     815      {
     816        TesselStruct->AddPoint(runner->second.second);
    471817      }
    472       *out << endl;
    473     }
    474 
    475   // 2. fill the boundary point list
    476   for (int axis = 0; axis < NDIM; axis++)
    477     for (Boundaries::iterator runner = BoundaryPoints[axis].begin(); runner != BoundaryPoints[axis].end(); runner++)
    478         TesselStruct->AddPoint(runner->second.second);
    479 
    480   *out << Verbose(2) << "I found " << TesselStruct->PointsOnBoundaryCount << " points on the convex boundary." << endl;
     818
     819  *out << Verbose(2) << "I found " << TesselStruct->PointsOnBoundaryCount
     820      << " points on the convex boundary." << endl;
    481821  // now we have the whole set of edge points in the BoundaryList
    482822
     
    488828  //  *out << endl;
    489829
    490   // 3a. guess starting triangle
     830  // 5a. guess starting triangle
    491831  TesselStruct->GuessStartingTriangle(out);
    492832
    493   // 3b. go through all lines, that are not yet part of two triangles (only of one so far)
    494   TesselStruct->TesselateOnBoundary(out, mol);
    495 
    496   // 3c. check whether all atoms lay inside the boundary, if not, add to boundary points, segment triangle into three with the new point
    497   if (!TesselStruct->InsertStraddlingPoints(out, mol))
    498     *out << Verbose(1) << "Insertion of straddling points failed!" << endl;
    499 
    500   // 3d. check all baselines whether the peaks of the two adjacent triangles with respect to center of baseline are convex, if not, make the baseline between the two peaks and baseline endpoints become the new peaks
    501   if (!TesselStruct->CorrectConcaveBaselines(out))
    502     *out << Verbose(1) << "Correction of concave baselines failed!" << endl;
    503 
    504   *out << Verbose(2) << "I created " << TesselStruct->TrianglesOnBoundary.size() << " triangles with " << TesselStruct->LinesOnBoundary.size() << " lines and " << TesselStruct->PointsOnBoundary.size() << " points." << endl;
    505 
    506   // 4. Store triangles in tecplot file
    507   if (filename != NULL) {
    508     if (DoTecplotOutput) {
    509       string OutputName(filename);
    510       OutputName.append(TecplotSuffix);
    511       ofstream *tecplot = new ofstream(OutputName.c_str());
    512       write_tecplot_file(out, tecplot, TesselStruct, mol, 0);
    513       tecplot->close();
    514       delete(tecplot);
    515     }
    516     if (DoRaster3DOutput) {
    517       string OutputName(filename);
    518       OutputName.append(Raster3DSuffix);
    519       ofstream *rasterplot = new ofstream(OutputName.c_str());
    520       write_raster3d_file(out, rasterplot, TesselStruct, mol);
    521       rasterplot->close();
    522       delete(rasterplot);
    523     }
    524   }
    525 
    526   // free reference lists
    527   if (BoundaryFreeFlag)
    528     delete[] (BoundaryPoints);
    529 
    530   cout << Verbose(1) << "End of find_convex_border" << endl;
    531 };
    532 
    533 
    534 /** Determines the volume of a cluster.
    535  * Determines first the convex envelope, then tesselates it and calculates its volume.
    536  * \param *out output stream for debugging
    537  * \param *TesselStruct Tesselation filled with points, lines and triangles on boundary on return
    538  * \param *configuration needed for path to store convex envelope file
    539  * \return determined volume of the cluster in cubed config:GetIsAngstroem()
    540  */
    541 double VolumeOfConvexEnvelope(ofstream *out, class Tesselation *TesselStruct, class config *configuration)
    542 {
    543   bool IsAngstroem = configuration->GetIsAngstroem();
    544   double volume = 0.;
    545   double PyramidVolume = 0.;
    546   double G, h;
    547   Vector x, y;
    548   double a, b, c;
     833  // 5b. go through all lines, that are not yet part of two triangles (only of one so far)
     834  TesselStruct->TesselateOnBoundary(out, configuration, mol);
     835
     836  *out << Verbose(2) << "I created " << TesselStruct->TrianglesOnBoundaryCount
     837      << " triangles with " << TesselStruct->LinesOnBoundaryCount
     838      << " lines and " << TesselStruct->PointsOnBoundaryCount << " points."
     839      << endl;
    549840
    550841  // 6a. Every triangle forms a pyramid with the center of gravity as its peak, sum up the volumes
     
    552843      << "Calculating the volume of the pyramids formed out of triangles and center of gravity."
    553844      << endl;
    554   for (TriangleMap::iterator runner = TesselStruct->TrianglesOnBoundary.begin(); runner != TesselStruct->TrianglesOnBoundary.end(); runner++)
     845  for (TriangleMap::iterator runner = TesselStruct->TrianglesOnBoundary.begin(); runner
     846      != TesselStruct->TrianglesOnBoundary.end(); runner++)
    555847    { // go through every triangle, calculate volume of its pyramid with CoG as peak
    556       x.CopyVector(runner->second->endpoints[0]->node->node);
    557       x.SubtractVector(runner->second->endpoints[1]->node->node);
    558       y.CopyVector(runner->second->endpoints[0]->node->node);
    559       y.SubtractVector(runner->second->endpoints[2]->node->node);
    560       a = sqrt(runner->second->endpoints[0]->node->node->DistanceSquared(runner->second->endpoints[1]->node->node));
    561       b = sqrt(runner->second->endpoints[0]->node->node->DistanceSquared(runner->second->endpoints[2]->node->node));
    562       c = sqrt(runner->second->endpoints[2]->node->node->DistanceSquared(runner->second->endpoints[1]->node->node));
     848      x.CopyVector(&runner->second->endpoints[0]->node->x);
     849      x.SubtractVector(&runner->second->endpoints[1]->node->x);
     850      y.CopyVector(&runner->second->endpoints[0]->node->x);
     851      y.SubtractVector(&runner->second->endpoints[2]->node->x);
     852      a = sqrt(runner->second->endpoints[0]->node->x.DistanceSquared(
     853          &runner->second->endpoints[1]->node->x));
     854      b = sqrt(runner->second->endpoints[0]->node->x.DistanceSquared(
     855          &runner->second->endpoints[2]->node->x));
     856      c = sqrt(runner->second->endpoints[2]->node->x.DistanceSquared(
     857          &runner->second->endpoints[1]->node->x));
    563858      G = sqrt(((a + b + c) * (a + b + c) - 2 * (a * a + b * b + c * c)) / 16.); // area of tesselated triangle
    564       x.MakeNormalVector(runner->second->endpoints[0]->node->node, runner->second->endpoints[1]->node->node, runner->second->endpoints[2]->node->node);
    565       x.Scale(runner->second->endpoints[1]->node->node->Projection(&x));
     859      x.MakeNormalVector(&runner->second->endpoints[0]->node->x,
     860          &runner->second->endpoints[1]->node->x,
     861          &runner->second->endpoints[2]->node->x);
     862      x.Scale(runner->second->endpoints[1]->node->x.Projection(&x));
    566863      h = x.Norm(); // distance of CoG to triangle
    567864      PyramidVolume = (1. / 3.) * G * h; // this formula holds for _all_ pyramids (independent of n-edge base or (not) centered peak)
     
    576873      << endl;
    577874
     875  // 7. translate all points back from CoG
     876  *out << Verbose(1) << "Translating system back from Center of Gravity."
     877      << endl;
     878  CenterOfGravity->Scale(-1);
     879  Walker = mol->start;
     880  while (Walker->next != mol->end)
     881    {
     882      Walker = Walker->next;
     883      Walker->x.Translate(CenterOfGravity);
     884    }
     885
     886  // 8. Store triangles in tecplot file
     887  string OutputName(filename);
     888  OutputName.append(TecplotSuffix);
     889  ofstream *tecplot = new ofstream(OutputName.c_str());
     890  write_tecplot_file(out, tecplot, TesselStruct, mol, 0);
     891  tecplot->close();
     892  delete(tecplot);
     893
     894  // free reference lists
     895  if (BoundaryFreeFlag)
     896    delete[] (BoundaryPoints);
     897
    578898  return volume;
    579899}
     
    598918  bool IsAngstroem = configuration->GetIsAngstroem();
    599919  Boundaries *BoundaryPoints = GetBoundaryPoints(out, mol);
    600   class Tesselation *TesselStruct = NULL;
    601   LinkedCell LCList(mol, 10.);
    602   Find_convex_border(out, mol, TesselStruct, &LCList, NULL);
    603920  double clustervolume;
    604921  if (ClusterVolume == 0)
    605     clustervolume = VolumeOfConvexEnvelope(out, TesselStruct, configuration);
     922    clustervolume = VolumeOfConvexEnvelope(out, NULL, configuration,
     923        BoundaryPoints, mol);
    606924  else
    607925    clustervolume = ClusterVolume;
    608   double *GreatestDiameter = GetDiametersOfCluster(out, BoundaryPoints, mol, IsAngstroem);
     926  double *GreatestDiameter = GetDiametersOfCluster(out, BoundaryPoints, mol,
     927      IsAngstroem);
    609928  Vector BoxLengths;
    610929  int repetition[NDIM] =
     
    6911010      // set new box dimensions
    6921011      *out << Verbose(0) << "Translating to box with these boundaries." << endl;
    693       mol->SetBoxDimension(&BoxLengths);
    694       mol->CenterInBox((ofstream *) &cout);
     1012      mol->CenterInBox((ofstream *) &cout, &BoxLengths);
    6951013    }
    6961014  // update Box of atoms by boundary
     
    7031021;
    7041022
    705 
    706 /** Fills the empty space of the simulation box with water/
     1023// =========================================================== class TESSELATION ===========================================
     1024
     1025/** Constructor of class Tesselation.
     1026 */
     1027Tesselation::Tesselation()
     1028{
     1029  PointsOnBoundaryCount = 0;
     1030  LinesOnBoundaryCount = 0;
     1031  TrianglesOnBoundaryCount = 0;
     1032  TriangleFilesWritten = 0;
     1033}
     1034;
     1035
     1036/** Constructor of class Tesselation.
     1037 * We have to free all points, lines and triangles.
     1038 */
     1039Tesselation::~Tesselation()
     1040{
     1041  cout << Verbose(1) << "Free'ing TesselStruct ... " << endl;
     1042  for (TriangleMap::iterator runner = TrianglesOnBoundary.begin(); runner != TrianglesOnBoundary.end(); runner++) {
     1043    if (runner->second != NULL) {
     1044      delete (runner->second);
     1045      runner->second = NULL;
     1046    } else
     1047      cerr << "ERROR: The triangle " << runner->first << " has already been free'd." << endl;
     1048  }
     1049}
     1050;
     1051
     1052/** Gueses first starting triangle of the convex envelope.
     1053 * We guess the starting triangle by taking the smallest distance between two points and looking for a fitting third.
    7071054 * \param *out output stream for debugging
    708  * \param *List list of molecules already present in box
    709  * \param *TesselStruct contains tesselated surface
    710  * \param *filler molecule which the box is to be filled with
    711  * \param configuration contains box dimensions
    712  * \param distance[NDIM] distance between filling molecules in each direction
    713  * \param RandAtomDisplacement maximum distance for random displacement per atom
    714  * \param RandMolDisplacement maximum distance for random displacement per filler molecule
    715  * \param DoRandomRotation true - do random rotiations, false - don't
    716  * \return *mol pointer to new molecule with filled atoms
    717  */
    718 molecule * FillBoxWithMolecule(ofstream *out, MoleculeListClass *List, molecule *filler, config &configuration, double distance[NDIM], double RandomAtomDisplacement, double RandomMolDisplacement, bool DoRandomRotation)
    719 {
    720   molecule *Filling = new molecule(filler->elemente);
    721   Vector CurrentPosition;
    722   int N[NDIM];
    723   int n[NDIM];
    724   double *M =  filler->ReturnFullMatrixforSymmetric(filler->cell_size);
    725   double Rotations[NDIM*NDIM];
    726   Vector AtomTranslations;
    727   Vector FillerTranslations;
    728   Vector FillerDistance;
    729   double FillIt = false;
    730   atom *Walker = NULL, *Runner = NULL;
    731   bond *Binder = NULL;
    732 
    733   // Center filler at origin
    734   filler->CenterOrigin(out);
    735   filler->Center.Zero();
    736 
    737   // calculate filler grid in [0,1]^3
    738   FillerDistance.Init(distance[0], distance[1], distance[2]);
    739   FillerDistance.InverseMatrixMultiplication(M);
    740   for(int i=0;i<NDIM;i++)
    741     N[i] = ceil(1./FillerDistance.x[i]);
    742 
    743   // go over [0,1]^3 filler grid
    744   for (n[0] = 0; n[0] < N[0]; n[0]++)
    745     for (n[1] = 0; n[1] < N[1]; n[1]++)
    746       for (n[2] = 0; n[2] < N[2]; n[2]++) {
    747         // calculate position of current grid vector in untransformed box
    748         CurrentPosition.Init(n[0], n[1], n[2]);
    749         CurrentPosition.MatrixMultiplication(M);
    750         // Check whether point is in- or outside
    751         FillIt = true;
    752         for (MoleculeList::iterator ListRunner = List->ListOfMolecules.begin(); ListRunner != List->ListOfMolecules.end(); ListRunner++) {
    753           FillIt = FillIt && (!(*ListRunner)->TesselStruct->IsInside(&CurrentPosition));
     1055 * \param PointsOnBoundary set of boundary points defining the convex envelope of the cluster
     1056 */
     1057void
     1058Tesselation::GuessStartingTriangle(ofstream *out)
     1059{
     1060  // 4b. create a starting triangle
     1061  // 4b1. create all distances
     1062  DistanceMultiMap DistanceMMap;
     1063  double distance, tmp;
     1064  Vector PlaneVector, TrialVector;
     1065  PointMap::iterator A, B, C; // three nodes of the first triangle
     1066  A = PointsOnBoundary.begin(); // the first may be chosen arbitrarily
     1067
     1068  // with A chosen, take each pair B,C and sort
     1069  if (A != PointsOnBoundary.end())
     1070    {
     1071      B = A;
     1072      B++;
     1073      for (; B != PointsOnBoundary.end(); B++)
     1074        {
     1075          C = B;
     1076          C++;
     1077          for (; C != PointsOnBoundary.end(); C++)
     1078            {
     1079              tmp = A->second->node->x.DistanceSquared(&B->second->node->x);
     1080              distance = tmp * tmp;
     1081              tmp = A->second->node->x.DistanceSquared(&C->second->node->x);
     1082              distance += tmp * tmp;
     1083              tmp = B->second->node->x.DistanceSquared(&C->second->node->x);
     1084              distance += tmp * tmp;
     1085              DistanceMMap.insert(DistanceMultiMapPair(distance, pair<
     1086                  PointMap::iterator, PointMap::iterator> (B, C)));
     1087            }
    7541088        }
    755 
    756         if (FillIt) {
    757           // fill in Filler
    758           *out << Verbose(2) << "Space at " << CurrentPosition << " is unoccupied by any molecule, filling in." << endl;
    759 
    760           // create molecule random translation vector ...
    761           for (int i=0;i<NDIM;i++)
    762             FillerTranslations.x[i] = RandomMolDisplacement*(rand()/(RAND_MAX/2.) - 1.);
    763 
    764           // go through all atoms
    765           Walker = filler->start;
    766           while (Walker != filler->end) {
    767             Walker = Walker->next;
    768             // copy atom ...
    769             *Runner = new atom(Walker);
    770 
    771             // create atomic random translation vector ...
    772             for (int i=0;i<NDIM;i++)
    773               AtomTranslations.x[i] = RandomAtomDisplacement*(rand()/(RAND_MAX/2.) - 1.);
    774 
    775             // ... and rotation matrix
    776             if (DoRandomRotation) {
    777               double phi[NDIM];
    778               for (int i=0;i<NDIM;i++) {
    779                 phi[i] = rand()/(RAND_MAX/(2.*M_PI));
     1089    }
     1090  //    // listing distances
     1091  //    *out << Verbose(1) << "Listing DistanceMMap:";
     1092  //    for(DistanceMultiMap::iterator runner = DistanceMMap.begin(); runner != DistanceMMap.end(); runner++) {
     1093  //      *out << " " << runner->first << "(" << *runner->second.first->second << ", " << *runner->second.second->second << ")";
     1094  //    }
     1095  //    *out << endl;
     1096  // 4b2. pick three baselines forming a triangle
     1097  // 1. we take from the smallest sum of squared distance as the base line BC (with peak A) onward as the triangle candidate
     1098  DistanceMultiMap::iterator baseline = DistanceMMap.begin();
     1099  for (; baseline != DistanceMMap.end(); baseline++)
     1100    {
     1101      // we take from the smallest sum of squared distance as the base line BC (with peak A) onward as the triangle candidate
     1102      // 2. next, we have to check whether all points reside on only one side of the triangle
     1103      // 3. construct plane vector
     1104      PlaneVector.MakeNormalVector(&A->second->node->x,
     1105          &baseline->second.first->second->node->x,
     1106          &baseline->second.second->second->node->x);
     1107      *out << Verbose(2) << "Plane vector of candidate triangle is ";
     1108      PlaneVector.Output(out);
     1109      *out << endl;
     1110      // 4. loop over all points
     1111      double sign = 0.;
     1112      PointMap::iterator checker = PointsOnBoundary.begin();
     1113      for (; checker != PointsOnBoundary.end(); checker++)
     1114        {
     1115          // (neglecting A,B,C)
     1116          if ((checker == A) || (checker == baseline->second.first) || (checker
     1117              == baseline->second.second))
     1118            continue;
     1119          // 4a. project onto plane vector
     1120          TrialVector.CopyVector(&checker->second->node->x);
     1121          TrialVector.SubtractVector(&A->second->node->x);
     1122          distance = TrialVector.Projection(&PlaneVector);
     1123          if (fabs(distance) < 1e-4) // we need to have a small epsilon around 0 which is still ok
     1124            continue;
     1125          *out << Verbose(3) << "Projection of " << checker->second->node->Name
     1126              << " yields distance of " << distance << "." << endl;
     1127          tmp = distance / fabs(distance);
     1128          // 4b. Any have different sign to than before? (i.e. would lie outside convex hull with this starting triangle)
     1129          if ((sign != 0) && (tmp != sign))
     1130            {
     1131              // 4c. If so, break 4. loop and continue with next candidate in 1. loop
     1132              *out << Verbose(2) << "Current candidates: "
     1133                  << A->second->node->Name << ","
     1134                  << baseline->second.first->second->node->Name << ","
     1135                  << baseline->second.second->second->node->Name << " leave "
     1136                  << checker->second->node->Name << " outside the convex hull."
     1137                  << endl;
     1138              break;
     1139            }
     1140          else
     1141            { // note the sign for later
     1142              *out << Verbose(2) << "Current candidates: "
     1143                  << A->second->node->Name << ","
     1144                  << baseline->second.first->second->node->Name << ","
     1145                  << baseline->second.second->second->node->Name << " leave "
     1146                  << checker->second->node->Name << " inside the convex hull."
     1147                  << endl;
     1148              sign = tmp;
     1149            }
     1150          // 4d. Check whether the point is inside the triangle (check distance to each node
     1151          tmp = checker->second->node->x.DistanceSquared(&A->second->node->x);
     1152          int innerpoint = 0;
     1153          if ((tmp < A->second->node->x.DistanceSquared(
     1154              &baseline->second.first->second->node->x)) && (tmp
     1155              < A->second->node->x.DistanceSquared(
     1156                  &baseline->second.second->second->node->x)))
     1157            innerpoint++;
     1158          tmp = checker->second->node->x.DistanceSquared(
     1159              &baseline->second.first->second->node->x);
     1160          if ((tmp < baseline->second.first->second->node->x.DistanceSquared(
     1161              &A->second->node->x)) && (tmp
     1162              < baseline->second.first->second->node->x.DistanceSquared(
     1163                  &baseline->second.second->second->node->x)))
     1164            innerpoint++;
     1165          tmp = checker->second->node->x.DistanceSquared(
     1166              &baseline->second.second->second->node->x);
     1167          if ((tmp < baseline->second.second->second->node->x.DistanceSquared(
     1168              &baseline->second.first->second->node->x)) && (tmp
     1169              < baseline->second.second->second->node->x.DistanceSquared(
     1170                  &A->second->node->x)))
     1171            innerpoint++;
     1172          // 4e. If so, break 4. loop and continue with next candidate in 1. loop
     1173          if (innerpoint == 3)
     1174            break;
     1175        }
     1176      // 5. come this far, all on same side? Then break 1. loop and construct triangle
     1177      if (checker == PointsOnBoundary.end())
     1178        {
     1179          *out << "Looks like we have a candidate!" << endl;
     1180          break;
     1181        }
     1182    }
     1183  if (baseline != DistanceMMap.end())
     1184    {
     1185      BPS[0] = baseline->second.first->second;
     1186      BPS[1] = baseline->second.second->second;
     1187      BLS[0] = new class BoundaryLineSet(BPS, LinesOnBoundaryCount);
     1188      BPS[0] = A->second;
     1189      BPS[1] = baseline->second.second->second;
     1190      BLS[1] = new class BoundaryLineSet(BPS, LinesOnBoundaryCount);
     1191      BPS[0] = baseline->second.first->second;
     1192      BPS[1] = A->second;
     1193      BLS[2] = new class BoundaryLineSet(BPS, LinesOnBoundaryCount);
     1194
     1195      // 4b3. insert created triangle
     1196      BTS = new class BoundaryTriangleSet(BLS, TrianglesOnBoundaryCount);
     1197      TrianglesOnBoundary.insert(TrianglePair(TrianglesOnBoundaryCount, BTS));
     1198      TrianglesOnBoundaryCount++;
     1199      for (int i = 0; i < NDIM; i++)
     1200        {
     1201          LinesOnBoundary.insert(LinePair(LinesOnBoundaryCount, BTS->lines[i]));
     1202          LinesOnBoundaryCount++;
     1203        }
     1204
     1205      *out << Verbose(1) << "Starting triangle is " << *BTS << "." << endl;
     1206    }
     1207  else
     1208    {
     1209      *out << Verbose(1) << "No starting triangle found." << endl;
     1210      exit(255);
     1211    }
     1212}
     1213;
     1214
     1215/** Tesselates the convex envelope of a cluster from a single starting triangle.
     1216 * The starting triangle is made out of three baselines. Each line in the final tesselated cluster may belong to at most
     1217 * 2 triangles. Hence, we go through all current lines:
     1218 * -# if the lines contains to only one triangle
     1219 * -# We search all points in the boundary
     1220 *    -# if the triangle with the baseline and the current point has the smallest of angles (comparison between normal vectors
     1221 *    -# if the triangle is in forward direction of the baseline (at most 90 degrees angle between vector orthogonal to
     1222 *       baseline in triangle plane pointing out of the triangle and normal vector of new triangle)
     1223 *    -# then we have a new triangle, whose baselines we again add (or increase their TriangleCount)
     1224 * \param *out output stream for debugging
     1225 * \param *configuration for IsAngstroem
     1226 * \param *mol the cluster as a molecule structure
     1227 */
     1228void
     1229Tesselation::TesselateOnBoundary(ofstream *out, config *configuration,
     1230    molecule *mol)
     1231{
     1232  bool flag;
     1233  PointMap::iterator winner;
     1234  class BoundaryPointSet *peak = NULL;
     1235  double SmallestAngle, TempAngle;
     1236  Vector NormalVector, VirtualNormalVector, CenterVector, TempVector,
     1237      PropagationVector;
     1238  LineMap::iterator LineChecker[2];
     1239  do
     1240    {
     1241      flag = false;
     1242      for (LineMap::iterator baseline = LinesOnBoundary.begin(); baseline
     1243          != LinesOnBoundary.end(); baseline++)
     1244        if (baseline->second->TrianglesCount == 1)
     1245          {
     1246            *out << Verbose(2) << "Current baseline is between "
     1247                << *(baseline->second) << "." << endl;
     1248            // 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)
     1249            SmallestAngle = M_PI;
     1250            BTS = baseline->second->triangles.begin()->second; // there is only one triangle so far
     1251            // get peak point with respect to this base line's only triangle
     1252            for (int i = 0; i < 3; i++)
     1253              if ((BTS->endpoints[i] != baseline->second->endpoints[0])
     1254                  && (BTS->endpoints[i] != baseline->second->endpoints[1]))
     1255                peak = BTS->endpoints[i];
     1256            *out << Verbose(3) << " and has peak " << *peak << "." << endl;
     1257            // normal vector of triangle
     1258            BTS->GetNormalVector(NormalVector);
     1259            *out << Verbose(4) << "NormalVector of base triangle is ";
     1260            NormalVector.Output(out);
     1261            *out << endl;
     1262            // offset to center of triangle
     1263            CenterVector.Zero();
     1264            for (int i = 0; i < 3; i++)
     1265              CenterVector.AddVector(&BTS->endpoints[i]->node->x);
     1266            CenterVector.Scale(1. / 3.);
     1267            *out << Verbose(4) << "CenterVector of base triangle is ";
     1268            CenterVector.Output(out);
     1269            *out << endl;
     1270            // vector in propagation direction (out of triangle)
     1271            // project center vector onto triangle plane (points from intersection plane-NormalVector to plane-CenterVector intersection)
     1272            TempVector.CopyVector(&baseline->second->endpoints[0]->node->x);
     1273            TempVector.SubtractVector(&baseline->second->endpoints[1]->node->x);
     1274            PropagationVector.MakeNormalVector(&TempVector, &NormalVector);
     1275            TempVector.CopyVector(&CenterVector);
     1276            TempVector.SubtractVector(&baseline->second->endpoints[0]->node->x); // TempVector is vector on triangle plane pointing from one baseline egde towards center!
     1277            //*out << Verbose(2) << "Projection of propagation onto temp: " << PropagationVector.Projection(&TempVector) << "." << endl;
     1278            if (PropagationVector.Projection(&TempVector) > 0) // make sure normal propagation vector points outward from baseline
     1279              PropagationVector.Scale(-1.);
     1280            *out << Verbose(4) << "PropagationVector of base triangle is ";
     1281            PropagationVector.Output(out);
     1282            *out << endl;
     1283            winner = PointsOnBoundary.end();
     1284            for (PointMap::iterator target = PointsOnBoundary.begin(); target
     1285                != PointsOnBoundary.end(); target++)
     1286              if ((target->second != baseline->second->endpoints[0])
     1287                  && (target->second != baseline->second->endpoints[1]))
     1288                { // don't take the same endpoints
     1289                  *out << Verbose(3) << "Target point is " << *(target->second)
     1290                      << ":";
     1291                  bool continueflag = true;
     1292
     1293                  VirtualNormalVector.CopyVector(
     1294                      &baseline->second->endpoints[0]->node->x);
     1295                  VirtualNormalVector.AddVector(
     1296                      &baseline->second->endpoints[0]->node->x);
     1297                  VirtualNormalVector.Scale(-1. / 2.); // points now to center of base line
     1298                  VirtualNormalVector.AddVector(&target->second->node->x); // points from center of base line to target
     1299                  TempAngle = VirtualNormalVector.Angle(&PropagationVector);
     1300                  continueflag = continueflag && (TempAngle < (M_PI/2.)); // no bends bigger than Pi/2 (90 degrees)
     1301                  if (!continueflag)
     1302                    {
     1303                      *out << Verbose(4)
     1304                          << "Angle between propagation direction and base line to "
     1305                          << *(target->second) << " is " << TempAngle
     1306                          << ", bad direction!" << endl;
     1307                      continue;
     1308                    }
     1309                  else
     1310                    *out << Verbose(4)
     1311                        << "Angle between propagation direction and base line to "
     1312                        << *(target->second) << " is " << TempAngle
     1313                        << ", good direction!" << endl;
     1314                  LineChecker[0] = baseline->second->endpoints[0]->lines.find(
     1315                      target->first);
     1316                  LineChecker[1] = baseline->second->endpoints[1]->lines.find(
     1317                      target->first);
     1318                  //            if (LineChecker[0] != baseline->second->endpoints[0]->lines.end())
     1319                  //              *out << Verbose(4) << *(baseline->second->endpoints[0]) << " has line " << *(LineChecker[0]->second) << " to " << *(target->second) << " as endpoint with " << LineChecker[0]->second->TrianglesCount << " triangles." << endl;
     1320                  //            else
     1321                  //              *out << Verbose(4) << *(baseline->second->endpoints[0]) << " has no line to " << *(target->second) << " as endpoint." << endl;
     1322                  //            if (LineChecker[1] != baseline->second->endpoints[1]->lines.end())
     1323                  //              *out << Verbose(4) << *(baseline->second->endpoints[1]) << " has line " << *(LineChecker[1]->second) << " to " << *(target->second) << " as endpoint with " << LineChecker[1]->second->TrianglesCount << " triangles." << endl;
     1324                  //            else
     1325                  //              *out << Verbose(4) << *(baseline->second->endpoints[1]) << " has no line to " << *(target->second) << " as endpoint." << endl;
     1326                  // check first endpoint (if any connecting line goes to target or at least not more than 1)
     1327                  continueflag = continueflag && (((LineChecker[0]
     1328                      == baseline->second->endpoints[0]->lines.end())
     1329                      || (LineChecker[0]->second->TrianglesCount == 1)));
     1330                  if (!continueflag)
     1331                    {
     1332                      *out << Verbose(4) << *(baseline->second->endpoints[0])
     1333                          << " has line " << *(LineChecker[0]->second)
     1334                          << " to " << *(target->second)
     1335                          << " as endpoint with "
     1336                          << LineChecker[0]->second->TrianglesCount
     1337                          << " triangles." << endl;
     1338                      continue;
     1339                    }
     1340                  // check second endpoint (if any connecting line goes to target or at least not more than 1)
     1341                  continueflag = continueflag && (((LineChecker[1]
     1342                      == baseline->second->endpoints[1]->lines.end())
     1343                      || (LineChecker[1]->second->TrianglesCount == 1)));
     1344                  if (!continueflag)
     1345                    {
     1346                      *out << Verbose(4) << *(baseline->second->endpoints[1])
     1347                          << " has line " << *(LineChecker[1]->second)
     1348                          << " to " << *(target->second)
     1349                          << " as endpoint with "
     1350                          << LineChecker[1]->second->TrianglesCount
     1351                          << " triangles." << endl;
     1352                      continue;
     1353                    }
     1354                  // check whether the envisaged triangle does not already exist (if both lines exist and have same endpoint)
     1355                  continueflag = continueflag && (!(((LineChecker[0]
     1356                      != baseline->second->endpoints[0]->lines.end())
     1357                      && (LineChecker[1]
     1358                          != baseline->second->endpoints[1]->lines.end())
     1359                      && (GetCommonEndpoint(LineChecker[0]->second,
     1360                          LineChecker[1]->second) == peak))));
     1361                  if (!continueflag)
     1362                    {
     1363                      *out << Verbose(4) << "Current target is peak!" << endl;
     1364                      continue;
     1365                    }
     1366                  // in case NOT both were found
     1367                  if (continueflag)
     1368                    { // create virtually this triangle, get its normal vector, calculate angle
     1369                      flag = true;
     1370                      VirtualNormalVector.MakeNormalVector(
     1371                          &baseline->second->endpoints[0]->node->x,
     1372                          &baseline->second->endpoints[1]->node->x,
     1373                          &target->second->node->x);
     1374                      // make it always point inward
     1375                      if (baseline->second->endpoints[0]->node->x.Projection(
     1376                          &VirtualNormalVector) > 0)
     1377                        VirtualNormalVector.Scale(-1.);
     1378                      // calculate angle
     1379                      TempAngle = NormalVector.Angle(&VirtualNormalVector);
     1380                      *out << Verbose(4) << "NormalVector is ";
     1381                      VirtualNormalVector.Output(out);
     1382                      *out << " and the angle is " << TempAngle << "." << endl;
     1383                      if (SmallestAngle > TempAngle)
     1384                        { // set to new possible winner
     1385                          SmallestAngle = TempAngle;
     1386                          winner = target;
     1387                        }
     1388                    }
     1389                }
     1390            // 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
     1391            if (winner != PointsOnBoundary.end())
     1392              {
     1393                *out << Verbose(2) << "Winning target point is "
     1394                    << *(winner->second) << " with angle " << SmallestAngle
     1395                    << "." << endl;
     1396                // create the lins of not yet present
     1397                BLS[0] = baseline->second;
     1398                // 5c. add lines to the line set if those were new (not yet part of a triangle), delete lines that belong to two triangles)
     1399                LineChecker[0] = baseline->second->endpoints[0]->lines.find(
     1400                    winner->first);
     1401                LineChecker[1] = baseline->second->endpoints[1]->lines.find(
     1402                    winner->first);
     1403                if (LineChecker[0]
     1404                    == baseline->second->endpoints[0]->lines.end())
     1405                  { // create
     1406                    BPS[0] = baseline->second->endpoints[0];
     1407                    BPS[1] = winner->second;
     1408                    BLS[1] = new class BoundaryLineSet(BPS,
     1409                        LinesOnBoundaryCount);
     1410                    LinesOnBoundary.insert(LinePair(LinesOnBoundaryCount,
     1411                        BLS[1]));
     1412                    LinesOnBoundaryCount++;
     1413                  }
     1414                else
     1415                  BLS[1] = LineChecker[0]->second;
     1416                if (LineChecker[1]
     1417                    == baseline->second->endpoints[1]->lines.end())
     1418                  { // create
     1419                    BPS[0] = baseline->second->endpoints[1];
     1420                    BPS[1] = winner->second;
     1421                    BLS[2] = new class BoundaryLineSet(BPS,
     1422                        LinesOnBoundaryCount);
     1423                    LinesOnBoundary.insert(LinePair(LinesOnBoundaryCount,
     1424                        BLS[2]));
     1425                    LinesOnBoundaryCount++;
     1426                  }
     1427                else
     1428                  BLS[2] = LineChecker[1]->second;
     1429                BTS = new class BoundaryTriangleSet(BLS,
     1430                    TrianglesOnBoundaryCount);
     1431                TrianglesOnBoundary.insert(TrianglePair(
     1432                    TrianglesOnBoundaryCount, BTS));
     1433                TrianglesOnBoundaryCount++;
    7801434              }
    781 
    782               Rotations[0] =   cos(phi[0])            *cos(phi[2]) + (sin(phi[0])*sin(phi[1])*sin(phi[2]));
    783               Rotations[3] =   sin(phi[0])            *cos(phi[2]) - (cos(phi[0])*sin(phi[1])*sin(phi[2]));
    784               Rotations[6] =               cos(phi[1])*sin(phi[2])                                     ;
    785               Rotations[1] = - sin(phi[0])*cos(phi[1])                                                ;
    786               Rotations[4] =   cos(phi[0])*cos(phi[1])                                                ;
    787               Rotations[7] =               sin(phi[1])                                                ;
    788               Rotations[3] = - cos(phi[0])            *sin(phi[2]) + (sin(phi[0])*sin(phi[1])*cos(phi[2]));
    789               Rotations[5] = - sin(phi[0])            *sin(phi[2]) - (cos(phi[0])*sin(phi[1])*cos(phi[2]));
    790               Rotations[8] =               cos(phi[1])*cos(phi[2])                                     ;
     1435            else
     1436              {
     1437                *out << Verbose(1)
     1438                    << "I could not determine a winner for this baseline "
     1439                    << *(baseline->second) << "." << endl;
     1440              }
     1441
     1442            // 5d. If the set of lines is not yet empty, go to 5. and continue
     1443          }
     1444        else
     1445          *out << Verbose(2) << "Baseline candidate " << *(baseline->second)
     1446              << " has a triangle count of "
     1447              << baseline->second->TrianglesCount << "." << endl;
     1448    }
     1449  while (flag);
     1450
     1451}
     1452;
     1453
     1454/** Adds an atom to the tesselation::PointsOnBoundary list.
     1455 * \param *Walker atom to add
     1456 */
     1457void
     1458Tesselation::AddPoint(atom *Walker)
     1459{
     1460  PointTestPair InsertUnique;
     1461  BPS[0] = new class BoundaryPointSet(Walker);
     1462  InsertUnique = PointsOnBoundary.insert(PointPair(Walker->nr, BPS[0]));
     1463  if (InsertUnique.second) // if new point was not present before, increase counter
     1464    PointsOnBoundaryCount++;
     1465}
     1466;
     1467
     1468/** Adds point to Tesselation::PointsOnBoundary if not yet present.
     1469 * Tesselation::TPS is set to either this new BoundaryPointSet or to the existing one of not unique.
     1470 * @param Candidate point to add
     1471 * @param n index for this point in Tesselation::TPS array
     1472 */
     1473void
     1474Tesselation::AddTrianglePoint(atom* Candidate, int n)
     1475{
     1476  PointTestPair InsertUnique;
     1477  TPS[n] = new class BoundaryPointSet(Candidate);
     1478  InsertUnique = PointsOnBoundary.insert(PointPair(Candidate->nr, TPS[n]));
     1479  if (InsertUnique.second) { // if new point was not present before, increase counter
     1480    PointsOnBoundaryCount++;
     1481  } else {
     1482    delete TPS[n];
     1483    cout << Verbose(3) << "Atom " << *((InsertUnique.first)->second->node) << " is already present in PointsOnBoundary." << endl;
     1484    TPS[n] = (InsertUnique.first)->second;
     1485  }
     1486}
     1487;
     1488
     1489/** Function tries to add line from current Points in BPS to BoundaryLineSet.
     1490 * If successful it raises the line count and inserts the new line into the BLS,
     1491 * if unsuccessful, it writes the line which had been present into the BLS, deleting the new constructed one.
     1492 * @param *a first endpoint
     1493 * @param *b second endpoint
     1494 * @param n index of Tesselation::BLS giving the line with both endpoints
     1495 */
     1496void Tesselation::AddTriangleLine(class BoundaryPointSet *a, class BoundaryPointSet *b, int n) {
     1497  bool insertNewLine = true;
     1498
     1499  if (a->lines.find(b->node->nr) != a->lines.end()) {
     1500    LineMap::iterator FindLine;
     1501    pair<LineMap::iterator,LineMap::iterator> FindPair;
     1502    FindPair = a->lines.equal_range(b->node->nr);
     1503
     1504    for (FindLine = FindPair.first; FindLine != FindPair.second; ++FindLine) {
     1505      // If there is a line with less than two attached triangles, we don't need a new line.
     1506      if (FindLine->second->TrianglesCount < 2) {
     1507        insertNewLine = false;
     1508        cout << Verbose(3) << "Using existing line " << *FindLine->second << endl;
     1509
     1510        BPS[0] = FindLine->second->endpoints[0];
     1511        BPS[1] = FindLine->second->endpoints[1];
     1512        BLS[n] = FindLine->second;
     1513
     1514        break;
     1515      }
     1516    }
     1517  }
     1518
     1519  if (insertNewLine) {
     1520    AlwaysAddTriangleLine(a, b, n);
     1521  }
     1522}
     1523;
     1524
     1525/**
     1526 * Adds lines from each of the current points in the BPS to BoundaryLineSet.
     1527 * Raises the line count and inserts the new line into the BLS.
     1528 *
     1529 * @param *a first endpoint
     1530 * @param *b second endpoint
     1531 * @param n index of Tesselation::BLS giving the line with both endpoints
     1532 */
     1533void Tesselation::AlwaysAddTriangleLine(class BoundaryPointSet *a, class BoundaryPointSet *b, int n)
     1534{
     1535  cout << Verbose(3) << "Adding line between " << *(a->node) << " and " << *(b->node) << "." << endl;
     1536  BPS[0] = a;
     1537  BPS[1] = b;
     1538  BLS[n] = new class BoundaryLineSet(BPS, LinesOnBoundaryCount);  // this also adds the line to the local maps
     1539  // add line to global map
     1540  LinesOnBoundary.insert(LinePair(LinesOnBoundaryCount, BLS[n]));
     1541  // increase counter
     1542  LinesOnBoundaryCount++;
     1543};
     1544
     1545/** Function tries to add Triangle just created to Triangle and remarks if already existent (Failure of algorithm).
     1546 * Furthermore it adds the triangle to all of its lines, in order to recognize those which are saturated later.
     1547 */
     1548void
     1549Tesselation::AddTriangle()
     1550{
     1551  cout << Verbose(1) << "Adding triangle to global TrianglesOnBoundary map." << endl;
     1552
     1553  // add triangle to global map
     1554  TrianglesOnBoundary.insert(TrianglePair(TrianglesOnBoundaryCount, BTS));
     1555  TrianglesOnBoundaryCount++;
     1556
     1557  // NOTE: add triangle to local maps is done in constructor of BoundaryTriangleSet
     1558}
     1559;
     1560
     1561
     1562double det_get(gsl_matrix *A, int inPlace) {
     1563  /*
     1564  inPlace = 1 => A is replaced with the LU decomposed copy.
     1565  inPlace = 0 => A is retained, and a copy is used for LU.
     1566  */
     1567
     1568  double det;
     1569  int signum;
     1570  gsl_permutation *p = gsl_permutation_alloc(A->size1);
     1571  gsl_matrix *tmpA;
     1572
     1573  if (inPlace)
     1574  tmpA = A;
     1575  else {
     1576  gsl_matrix *tmpA = gsl_matrix_alloc(A->size1, A->size2);
     1577  gsl_matrix_memcpy(tmpA , A);
     1578  }
     1579
     1580
     1581  gsl_linalg_LU_decomp(tmpA , p , &signum);
     1582  det = gsl_linalg_LU_det(tmpA , signum);
     1583  gsl_permutation_free(p);
     1584  if (! inPlace)
     1585  gsl_matrix_free(tmpA);
     1586
     1587  return det;
     1588};
     1589
     1590void get_sphere(Vector *center, Vector &a, Vector &b, Vector &c, double RADIUS)
     1591{
     1592  gsl_matrix *A = gsl_matrix_calloc(3,3);
     1593  double m11, m12, m13, m14;
     1594
     1595  for(int i=0;i<3;i++) {
     1596    gsl_matrix_set(A, i, 0, a.x[i]);
     1597    gsl_matrix_set(A, i, 1, b.x[i]);
     1598    gsl_matrix_set(A, i, 2, c.x[i]);
     1599  }
     1600  m11 = det_get(A, 1);
     1601
     1602  for(int i=0;i<3;i++) {
     1603    gsl_matrix_set(A, i, 0, a.x[i]*a.x[i] + b.x[i]*b.x[i] + c.x[i]*c.x[i]);
     1604    gsl_matrix_set(A, i, 1, b.x[i]);
     1605    gsl_matrix_set(A, i, 2, c.x[i]);
     1606  }
     1607  m12 = det_get(A, 1);
     1608
     1609  for(int i=0;i<3;i++) {
     1610    gsl_matrix_set(A, i, 0, a.x[i]*a.x[i] + b.x[i]*b.x[i] + c.x[i]*c.x[i]);
     1611    gsl_matrix_set(A, i, 1, a.x[i]);
     1612    gsl_matrix_set(A, i, 2, c.x[i]);
     1613  }
     1614  m13 = det_get(A, 1);
     1615
     1616  for(int i=0;i<3;i++) {
     1617    gsl_matrix_set(A, i, 0, a.x[i]*a.x[i] + b.x[i]*b.x[i] + c.x[i]*c.x[i]);
     1618    gsl_matrix_set(A, i, 1, a.x[i]);
     1619    gsl_matrix_set(A, i, 2, b.x[i]);
     1620  }
     1621  m14 = det_get(A, 1);
     1622
     1623  if (fabs(m11) < MYEPSILON)
     1624    cerr << "ERROR: three points are colinear." << endl;
     1625
     1626  center->x[0] =  0.5 * m12/ m11;
     1627  center->x[1] = -0.5 * m13/ m11;
     1628  center->x[2] =  0.5 * m14/ m11;
     1629
     1630  if (fabs(a.Distance(center) - RADIUS) > MYEPSILON)
     1631    cerr << "ERROR: The given center is further way by " << fabs(a.Distance(center) - RADIUS) << " from a than RADIUS." << endl;
     1632
     1633  gsl_matrix_free(A);
     1634};
     1635
     1636
     1637
     1638/**
     1639 * Function returns center of sphere with RADIUS, which rests on points a, b, c
     1640 * @param Center this vector will be used for return
     1641 * @param a vector first point of triangle
     1642 * @param b vector second point of triangle
     1643 * @param c vector third point of triangle
     1644 * @param *Umkreismittelpunkt new cneter point of circumference
     1645 * @param Direction vector indicates up/down
     1646 * @param AlternativeDirection vecotr, needed in case the triangles have 90 deg angle
     1647 * @param Halfplaneindicator double indicates whether Direction is up or down
     1648 * @param AlternativeIndicator doube indicates in case of orthogonal triangles which direction of AlternativeDirection is suitable
     1649 * @param alpha double angle at a
     1650 * @param beta double, angle at b
     1651 * @param gamma, double, angle at c
     1652 * @param Radius, double
     1653 * @param Umkreisradius double radius of circumscribing circle
     1654 */
     1655void Get_center_of_sphere(Vector* Center, Vector a, Vector b, Vector c, Vector *NewUmkreismittelpunkt, Vector* Direction, Vector* AlternativeDirection,
     1656    double HalfplaneIndicator, double AlternativeIndicator, double alpha, double beta, double gamma, double RADIUS, double Umkreisradius)
     1657{
     1658  Vector TempNormal, helper;
     1659  double Restradius;
     1660  Vector OtherCenter;
     1661  cout << Verbose(3) << "Begin of Get_center_of_sphere.\n";
     1662  Center->Zero();
     1663  helper.CopyVector(&a);
     1664  helper.Scale(sin(2.*alpha));
     1665  Center->AddVector(&helper);
     1666  helper.CopyVector(&b);
     1667  helper.Scale(sin(2.*beta));
     1668  Center->AddVector(&helper);
     1669  helper.CopyVector(&c);
     1670  helper.Scale(sin(2.*gamma));
     1671  Center->AddVector(&helper);
     1672  //*Center = a * sin(2.*alpha) + b * sin(2.*beta) + c * sin(2.*gamma) ;
     1673  Center->Scale(1./(sin(2.*alpha) + sin(2.*beta) + sin(2.*gamma)));
     1674  NewUmkreismittelpunkt->CopyVector(Center);
     1675  cout << Verbose(4) << "Center of new circumference is " << *NewUmkreismittelpunkt << ".\n";
     1676  // Here we calculated center of circumscribing circle, using barycentric coordinates
     1677  cout << Verbose(4) << "Center of circumference is " << *Center << " in direction " << *Direction << ".\n";
     1678
     1679  TempNormal.CopyVector(&a);
     1680  TempNormal.SubtractVector(&b);
     1681  helper.CopyVector(&a);
     1682  helper.SubtractVector(&c);
     1683  TempNormal.VectorProduct(&helper);
     1684  if (fabs(HalfplaneIndicator) < MYEPSILON)
     1685    {
     1686      if ((TempNormal.ScalarProduct(AlternativeDirection) <0 and AlternativeIndicator >0) or (TempNormal.ScalarProduct(AlternativeDirection) >0 and AlternativeIndicator <0))
     1687        {
     1688          TempNormal.Scale(-1);
     1689        }
     1690    }
     1691  else
     1692    {
     1693      if (TempNormal.ScalarProduct(Direction)<0 && HalfplaneIndicator >0 || TempNormal.ScalarProduct(Direction)>0 && HalfplaneIndicator<0)
     1694        {
     1695          TempNormal.Scale(-1);
     1696        }
     1697    }
     1698
     1699  TempNormal.Normalize();
     1700  Restradius = sqrt(RADIUS*RADIUS - Umkreisradius*Umkreisradius);
     1701  cout << Verbose(4) << "Height of center of circumference to center of sphere is " << Restradius << ".\n";
     1702  TempNormal.Scale(Restradius);
     1703  cout << Verbose(4) << "Shift vector to sphere of circumference is " << TempNormal << ".\n";
     1704
     1705  Center->AddVector(&TempNormal);
     1706  cout << Verbose(0) << "Center of sphere of circumference is " << *Center << ".\n";
     1707  get_sphere(&OtherCenter, a, b, c, RADIUS);
     1708  cout << Verbose(0) << "OtherCenter of sphere of circumference is " << OtherCenter << ".\n";
     1709  cout << Verbose(3) << "End of Get_center_of_sphere.\n";
     1710};
     1711
     1712
     1713/** Constructs the center of the circumcircle defined by three points \a *a, \a *b and \a *c.
     1714 * \param *Center new center on return
     1715 * \param *a first point
     1716 * \param *b second point
     1717 * \param *c third point
     1718 */
     1719void GetCenterofCircumcircle(Vector *Center, Vector *a, Vector *b, Vector *c)
     1720{
     1721  Vector helper;
     1722  double alpha, beta, gamma;
     1723  Vector SideA, SideB, SideC;
     1724  SideA.CopyVector(b);
     1725  SideA.SubtractVector(c);
     1726  SideB.CopyVector(c);
     1727  SideB.SubtractVector(a);
     1728  SideC.CopyVector(a);
     1729  SideC.SubtractVector(b);
     1730  alpha = M_PI - SideB.Angle(&SideC);
     1731  beta = M_PI - SideC.Angle(&SideA);
     1732  gamma = M_PI - SideA.Angle(&SideB);
     1733  //cout << Verbose(3) << "INFO: alpha = " << alpha/M_PI*180. << ", beta = " << beta/M_PI*180. << ", gamma = " << gamma/M_PI*180. << "." << endl;
     1734  if (fabs(M_PI - alpha - beta - gamma) > HULLEPSILON)
     1735    cerr << "GetCenterofCircumcircle: Sum of angles " << (alpha+beta+gamma)/M_PI*180. << " > 180 degrees by " << fabs(M_PI - alpha - beta - gamma)/M_PI*180. << "!" << endl;
     1736
     1737  Center->Zero();
     1738  helper.CopyVector(a);
     1739  helper.Scale(sin(2.*alpha));
     1740  Center->AddVector(&helper);
     1741  helper.CopyVector(b);
     1742  helper.Scale(sin(2.*beta));
     1743  Center->AddVector(&helper);
     1744  helper.CopyVector(c);
     1745  helper.Scale(sin(2.*gamma));
     1746  Center->AddVector(&helper);
     1747  Center->Scale(1./(sin(2.*alpha) + sin(2.*beta) + sin(2.*gamma)));
     1748};
     1749
     1750/** Returns the parameter "path length" for a given \a NewSphereCenter relative to \a OldSphereCenter on a circle on the plane \a CirclePlaneNormal with center \a CircleCenter and radius \a CircleRadius.
     1751 * Test whether the \a NewSphereCenter is really on the given plane and in distance \a CircleRadius from \a CircleCenter.
     1752 * It calculates the angle, making it unique on [0,2.*M_PI) by comparing to SearchDirection.
     1753 * Also the new center is invalid if it the same as the old one and does not lie right above (\a NormalVector) the base line (\a CircleCenter).
     1754 * \param CircleCenter Center of the parameter circle
     1755 * \param CirclePlaneNormal normal vector to plane of the parameter circle
     1756 * \param CircleRadius radius of the parameter circle
     1757 * \param NewSphereCenter new center of a circumcircle
     1758 * \param OldSphereCenter old center of a circumcircle, defining the zero "path length" on the parameter circle
     1759 * \param NormalVector normal vector
     1760 * \param SearchDirection search direction to make angle unique on return.
     1761 * \return Angle between \a NewSphereCenter and \a OldSphereCenter relative to \a CircleCenter, 2.*M_PI if one test fails
     1762 */
     1763double GetPathLengthonCircumCircle(Vector &CircleCenter, Vector &CirclePlaneNormal, double CircleRadius, Vector &NewSphereCenter, Vector &OldSphereCenter, Vector &NormalVector, Vector &SearchDirection)
     1764{
     1765  Vector helper;
     1766  double radius, alpha;
     1767
     1768  helper.CopyVector(&NewSphereCenter);
     1769  // test whether new center is on the parameter circle's plane
     1770  if (fabs(helper.ScalarProduct(&CirclePlaneNormal)) > HULLEPSILON) {
     1771    cerr << "ERROR: Something's very wrong here: NewSphereCenter is not on the band's plane as desired by " <<fabs(helper.ScalarProduct(&CirclePlaneNormal))  << "!" << endl;
     1772    helper.ProjectOntoPlane(&CirclePlaneNormal);
     1773  }
     1774  radius = helper.ScalarProduct(&helper);
     1775  // test whether the new center vector has length of CircleRadius
     1776  if (fabs(radius - CircleRadius) > HULLEPSILON)
     1777    cerr << Verbose(1) << "ERROR: The projected center of the new sphere has radius " << radius << " instead of " << CircleRadius << "." << endl;
     1778  alpha = helper.Angle(&OldSphereCenter);
     1779  // make the angle unique by checking the halfplanes/search direction
     1780  if (helper.ScalarProduct(&SearchDirection) < -HULLEPSILON)  // acos is not unique on [0, 2.*M_PI), hence extra check to decide between two half intervals
     1781    alpha = 2.*M_PI - alpha;
     1782  //cout << Verbose(2) << "INFO: RelativeNewSphereCenter is " << helper << ", RelativeOldSphereCenter is " << OldSphereCenter << " and resulting angle is " << alpha << "." << endl;
     1783  radius = helper.Distance(&OldSphereCenter);
     1784  helper.ProjectOntoPlane(&NormalVector);
     1785  // check whether new center is somewhat away or at least right over the current baseline to prevent intersecting triangles
     1786  if ((radius > HULLEPSILON) || (helper.Norm() < HULLEPSILON)) {
     1787    //cout << Verbose(2) << "INFO: Distance between old and new center is " << radius << " and between new center and baseline center is " << helper.Norm() << "." << endl;
     1788    return alpha;
     1789  } else {
     1790    //cout << Verbose(1) << "INFO: NewSphereCenter " << helper << " is too close to OldSphereCenter" << OldSphereCenter << "." << endl;
     1791    return 2.*M_PI;
     1792  }
     1793};
     1794
     1795
     1796/** Checks whether the triangle consisting of the three atoms is already present.
     1797 * Searches for the points in Tesselation::PointsOnBoundary and checks their
     1798 * lines. If any of the three edges already has two triangles attached, false is
     1799 * returned.
     1800 * \param *out output stream for debugging
     1801 * \param *Candidates endpoints of the triangle candidate
     1802 * \return integer 0 if no triangle exists, 1 if one triangle exists, 2 if two
     1803 *                 triangles exist which is the maximum for three points
     1804 */
     1805int Tesselation::CheckPresenceOfTriangle(ofstream *out, atom *Candidates[3]) {
     1806// TODO: use findTriangles here and return result.size();
     1807  LineMap::iterator FindLine;
     1808  PointMap::iterator FindPoint;
     1809  TriangleMap::iterator FindTriangle;
     1810  int adjacentTriangleCount = 0;
     1811  class BoundaryPointSet *Points[3];
     1812
     1813  //*out << Verbose(2) << "Begin of CheckPresenceOfTriangle" << endl;
     1814  // builds a triangle point set (Points) of the end points
     1815  for (int i = 0; i < 3; i++) {
     1816    FindPoint = PointsOnBoundary.find(Candidates[i]->nr);
     1817    if (FindPoint != PointsOnBoundary.end()) {
     1818      Points[i] = FindPoint->second;
     1819    } else {
     1820      Points[i] = NULL;
     1821    }
     1822  }
     1823
     1824  // checks lines between the points in the Points for their adjacent triangles
     1825  for (int i = 0; i < 3; i++) {
     1826    if (Points[i] != NULL) {
     1827      for (int j = i; j < 3; j++) {
     1828        if (Points[j] != NULL) {
     1829          FindLine = Points[i]->lines.find(Points[j]->node->nr);
     1830          if (FindLine != Points[i]->lines.end()) {
     1831            for (; FindLine->first == Points[j]->node->nr; FindLine++) {
     1832              FindTriangle = FindLine->second->triangles.begin();
     1833              for (; FindTriangle != FindLine->second->triangles.end(); FindTriangle++) {
     1834                if ((
     1835                  (FindTriangle->second->endpoints[0] == Points[0])
     1836                    || (FindTriangle->second->endpoints[0] == Points[1])
     1837                    || (FindTriangle->second->endpoints[0] == Points[2])
     1838                  ) && (
     1839                    (FindTriangle->second->endpoints[1] == Points[0])
     1840                    || (FindTriangle->second->endpoints[1] == Points[1])
     1841                    || (FindTriangle->second->endpoints[1] == Points[2])
     1842                  ) && (
     1843                    (FindTriangle->second->endpoints[2] == Points[0])
     1844                    || (FindTriangle->second->endpoints[2] == Points[1])
     1845                    || (FindTriangle->second->endpoints[2] == Points[2])
     1846                  )
     1847                ) {
     1848                  adjacentTriangleCount++;
     1849                }
     1850              }
    7911851            }
    792 
    793             // ... and put at new position
    794             if (DoRandomRotation)
    795               Runner->x.MatrixMultiplication(Rotations);
    796             Runner->x.AddVector(&AtomTranslations);
    797             Runner->x.AddVector(&FillerTranslations);
    798             Runner->x.AddVector(&CurrentPosition);
    799             // insert into Filling
    800             Filling->AddAtom(Runner);
     1852            // Only one of the triangle lines must be considered for the triangle count.
     1853            *out << Verbose(2) << "Found " << adjacentTriangleCount << " adjacent triangles for the point set." << endl;
     1854            return adjacentTriangleCount;
     1855
    8011856          }
    802 
    803           // go through all bonds and add as well
    804           Binder = filler->first;
    805           while(Binder != filler->last) {
    806             Binder = Binder->next;
     1857        }
     1858      }
     1859    }
     1860  }
     1861
     1862  *out << Verbose(2) << "Found " << adjacentTriangleCount << " adjacent triangles for the point set." << endl;
     1863  return adjacentTriangleCount;
     1864};
     1865
     1866/** This recursive function finds a third point, to form a triangle with two given ones.
     1867 * Note that this function is for the starting triangle.
     1868 * The idea is as follows: A sphere with fixed radius is (almost) uniquely defined in space by three points
     1869 * that sit on its boundary. Hence, when two points are given and we look for the (next) third point, then
     1870 * the center of the sphere is still fixed up to a single parameter. The band of possible values
     1871 * describes a circle in 3D-space. The old center of the sphere for the current base triangle gives
     1872 * us the "null" on this circle, the new center of the candidate point will be some way along this
     1873 * circle. The shorter the way the better is the candidate. Note that the direction is clearly given
     1874 * by the normal vector of the base triangle that always points outwards by construction.
     1875 * Hence, we construct a Center of this circle which sits right in the middle of the current base line.
     1876 * We construct the normal vector that defines the plane this circle lies in, it is just in the
     1877 * direction of the baseline. And finally, we need the radius of the circle, which is given by the rest
     1878 * with respect to the length of the baseline and the sphere's fixed \a RADIUS.
     1879 * Note that there is one difficulty: The circumcircle is uniquely defined, but for the circumsphere's center
     1880 * there are two possibilities which becomes clear from the construction as seen below. Hence, we must check
     1881 * both.
     1882 * Note also that the acos() function is not unique on [0, 2.*M_PI). Hence, we need an additional check
     1883 * to decide for one of the two possible angles. Therefore we need a SearchDirection and to make this check
     1884 * sensible we need OldSphereCenter to be orthogonal to it. Either we construct SearchDirection orthogonal
     1885 * right away, or -- what we do here -- we rotate the relative sphere centers such that this orthogonality
     1886 * holds. Then, the normalized projection onto the SearchDirection is either +1 or -1 and thus states whether
     1887 * the angle is uniquely in either (0,M_PI] or [M_PI, 2.*M_PI).
     1888 * @param NormalVector normal direction of the base triangle (here the unit axis vector, \sa Find_starting_triangle())
     1889 * @param SearchDirection general direction where to search for the next point, relative to center of BaseLine
     1890 * @param OldSphereCenter center of sphere for base triangle, relative to center of BaseLine, giving null angle for the parameter circle
     1891 * @param BaseLine BoundaryLineSet with the current base line
     1892 * @param ThirdNode third atom to avoid in search
     1893 * @param candidates list of equally good candidates to return
     1894 * @param ShortestAngle the current path length on this circle band for the current Opt_Candidate
     1895 * @param RADIUS radius of sphere
     1896 * @param *LC LinkedCell structure with neighbouring atoms
     1897 */
     1898void Find_third_point_for_Tesselation(
     1899  Vector NormalVector, Vector SearchDirection, Vector OldSphereCenter,
     1900  class BoundaryLineSet *BaseLine, atom *ThirdNode, CandidateList* &candidates,
     1901  double *ShortestAngle, const double RADIUS, LinkedCell *LC
     1902) {
     1903  Vector CircleCenter;  // center of the circle, i.e. of the band of sphere's centers
     1904  Vector CirclePlaneNormal; // normal vector defining the plane this circle lives in
     1905  Vector SphereCenter;
     1906  Vector NewSphereCenter;        // center of the sphere defined by the two points of BaseLine and the one of Candidate, first possibility
     1907  Vector OtherNewSphereCenter;   // center of the sphere defined by the two points of BaseLine and the one of Candidate, second possibility
     1908  Vector NewNormalVector;   // normal vector of the Candidate's triangle
     1909  Vector helper, OptCandidateCenter, OtherOptCandidateCenter;
     1910  LinkedAtoms *List = NULL;
     1911  double CircleRadius; // radius of this circle
     1912  double radius;
     1913  double alpha, Otheralpha; // angles (i.e. parameter for the circle).
     1914  int N[NDIM], Nlower[NDIM], Nupper[NDIM];
     1915  atom *Candidate = NULL;
     1916  CandidateForTesselation *optCandidate = NULL;
     1917
     1918  cout << Verbose(1) << "Begin of Find_third_point_for_Tesselation" << endl;
     1919
     1920  //cout << Verbose(2) << "INFO: NormalVector of BaseTriangle is " << NormalVector << "." << endl;
     1921
     1922  // construct center of circle
     1923  CircleCenter.CopyVector(&(BaseLine->endpoints[0]->node->x));
     1924  CircleCenter.AddVector(&BaseLine->endpoints[1]->node->x);
     1925  CircleCenter.Scale(0.5);
     1926
     1927  // construct normal vector of circle
     1928  CirclePlaneNormal.CopyVector(&BaseLine->endpoints[0]->node->x);
     1929  CirclePlaneNormal.SubtractVector(&BaseLine->endpoints[1]->node->x);
     1930
     1931  // calculate squared radius atom *ThirdNode,f circle
     1932  radius = CirclePlaneNormal.ScalarProduct(&CirclePlaneNormal);
     1933  if (radius/4. < RADIUS*RADIUS) {
     1934    CircleRadius = RADIUS*RADIUS - radius/4.;
     1935    CirclePlaneNormal.Normalize();
     1936    //cout << Verbose(2) << "INFO: CircleCenter is at " << CircleCenter << ", CirclePlaneNormal is " << CirclePlaneNormal << " with circle radius " << sqrt(CircleRadius) << "." << endl;
     1937
     1938    // test whether old center is on the band's plane
     1939    if (fabs(OldSphereCenter.ScalarProduct(&CirclePlaneNormal)) > HULLEPSILON) {
     1940      cerr << "ERROR: Something's very wrong here: OldSphereCenter is not on the band's plane as desired by " << fabs(OldSphereCenter.ScalarProduct(&CirclePlaneNormal)) << "!" << endl;
     1941      OldSphereCenter.ProjectOntoPlane(&CirclePlaneNormal);
     1942    }
     1943    radius = OldSphereCenter.ScalarProduct(&OldSphereCenter);
     1944    if (fabs(radius - CircleRadius) < HULLEPSILON) {
     1945
     1946      // check SearchDirection
     1947      //cout << Verbose(2) << "INFO: SearchDirection is " << SearchDirection << "." << endl;
     1948      if (fabs(OldSphereCenter.ScalarProduct(&SearchDirection)) > HULLEPSILON) {  // rotated the wrong way!
     1949        cerr << "ERROR: SearchDirection and RelativeOldSphereCenter are not orthogonal!" << endl;
     1950      }
     1951
     1952      // get cell for the starting atom
     1953      if (LC->SetIndexToVector(&CircleCenter)) {
     1954        for(int i=0;i<NDIM;i++) // store indices of this cell
     1955        N[i] = LC->n[i];
     1956        //cout << Verbose(2) << "INFO: Center cell is " << N[0] << ", " << N[1] << ", " << N[2] << " with No. " << LC->index << "." << endl;
     1957      } else {
     1958        cerr << "ERROR: Vector " << CircleCenter << " is outside of LinkedCell's bounding box." << endl;
     1959        return;
     1960      }
     1961      // then go through the current and all neighbouring cells and check the contained atoms for possible candidates
     1962      //cout << Verbose(2) << "LC Intervals:";
     1963      for (int i=0;i<NDIM;i++) {
     1964        Nlower[i] = ((N[i]-1) >= 0) ? N[i]-1 : 0;
     1965        Nupper[i] = ((N[i]+1) < LC->N[i]) ? N[i]+1 : LC->N[i]-1;
     1966        //cout << " [" << Nlower[i] << "," << Nupper[i] << "] ";
     1967      }
     1968      //cout << endl;
     1969      for (LC->n[0] = Nlower[0]; LC->n[0] <= Nupper[0]; LC->n[0]++)
     1970        for (LC->n[1] = Nlower[1]; LC->n[1] <= Nupper[1]; LC->n[1]++)
     1971          for (LC->n[2] = Nlower[2]; LC->n[2] <= Nupper[2]; LC->n[2]++) {
     1972            List = LC->GetCurrentCell();
     1973            //cout << Verbose(2) << "Current cell is " << LC->n[0] << ", " << LC->n[1] << ", " << LC->n[2] << " with No. " << LC->index << "." << endl;
     1974            if (List != NULL) {
     1975              for (LinkedAtoms::iterator Runner = List->begin(); Runner != List->end(); Runner++) {
     1976                Candidate = (*Runner);
     1977
     1978                // check for three unique points
     1979                //cout << Verbose(2) << "INFO: Current Candidate is " << *Candidate << " at " << Candidate->x << "." << endl;
     1980                if ((Candidate != BaseLine->endpoints[0]->node) && (Candidate != BaseLine->endpoints[1]->node) ){
     1981
     1982                  // construct both new centers
     1983                  GetCenterofCircumcircle(&NewSphereCenter, &(BaseLine->endpoints[0]->node->x), &(BaseLine->endpoints[1]->node->x), &(Candidate->x));
     1984                  OtherNewSphereCenter.CopyVector(&NewSphereCenter);
     1985
     1986                  if ((NewNormalVector.MakeNormalVector(&(BaseLine->endpoints[0]->node->x), &(BaseLine->endpoints[1]->node->x), &(Candidate->x)))
     1987                        && (fabs(NewNormalVector.ScalarProduct(&NewNormalVector)) > HULLEPSILON)
     1988                  ) {
     1989                    helper.CopyVector(&NewNormalVector);
     1990                    //cout << Verbose(2) << "INFO: NewNormalVector is " << NewNormalVector << "." << endl;
     1991                    radius = BaseLine->endpoints[0]->node->x.DistanceSquared(&NewSphereCenter);
     1992                    if (radius < RADIUS*RADIUS) {
     1993                      helper.Scale(sqrt(RADIUS*RADIUS - radius));
     1994                      //cout << Verbose(2) << "INFO: Distance of NewCircleCenter to NewSphereCenter is " << helper.Norm() << " with sphere radius " << RADIUS << "." << endl;
     1995                      NewSphereCenter.AddVector(&helper);
     1996                      NewSphereCenter.SubtractVector(&CircleCenter);
     1997                      //cout << Verbose(2) << "INFO: NewSphereCenter is at " << NewSphereCenter << "." << endl;
     1998
     1999                      // OtherNewSphereCenter is created by the same vector just in the other direction
     2000                      helper.Scale(-1.);
     2001                      OtherNewSphereCenter.AddVector(&helper);
     2002                      OtherNewSphereCenter.SubtractVector(&CircleCenter);
     2003                      //cout << Verbose(2) << "INFO: OtherNewSphereCenter is at " << OtherNewSphereCenter << "." << endl;
     2004
     2005                      alpha = GetPathLengthonCircumCircle(CircleCenter, CirclePlaneNormal, CircleRadius, NewSphereCenter, OldSphereCenter, NormalVector, SearchDirection);
     2006                      Otheralpha = GetPathLengthonCircumCircle(CircleCenter, CirclePlaneNormal, CircleRadius, OtherNewSphereCenter, OldSphereCenter, NormalVector, SearchDirection);
     2007                      alpha = min(alpha, Otheralpha);
     2008                      // if there is a better candidate, drop the current list and add the new candidate
     2009                      // otherwise ignore the new candidate and keep the list
     2010                      if (*ShortestAngle > (alpha - HULLEPSILON)) {
     2011                        optCandidate = new CandidateForTesselation(Candidate, BaseLine, OptCandidateCenter, OtherOptCandidateCenter);
     2012                        if (fabs(alpha - Otheralpha) > MYEPSILON) {
     2013                          optCandidate->OptCenter.CopyVector(&NewSphereCenter);
     2014                          optCandidate->OtherOptCenter.CopyVector(&OtherNewSphereCenter);
     2015                        } else {
     2016                          optCandidate->OptCenter.CopyVector(&OtherNewSphereCenter);
     2017                          optCandidate->OtherOptCenter.CopyVector(&NewSphereCenter);
     2018                        }
     2019                        // if there is an equal candidate, add it to the list without clearing the list
     2020                        if ((*ShortestAngle - HULLEPSILON) < alpha) {
     2021                          candidates->push_back(optCandidate);
     2022                          cout << Verbose(2) << "ACCEPT: We have found an equally good candidate: " << *(optCandidate->point) << " with "
     2023                            << alpha << " and circumsphere's center at " << optCandidate->OptCenter << "." << endl;
     2024                        } else {
     2025                          // remove all candidates from the list and then the list itself
     2026                          class CandidateForTesselation *remover = NULL;
     2027                          for (CandidateList::iterator it = candidates->begin(); it != candidates->end(); ++it) {
     2028                            remover = *it;
     2029                            delete(remover);
     2030                          }
     2031                          candidates->clear();
     2032                          candidates->push_back(optCandidate);
     2033                          cout << Verbose(2) << "ACCEPT: We have found a better candidate: " << *(optCandidate->point) << " with "
     2034                            << alpha << " and circumsphere's center at " << optCandidate->OptCenter << "." << endl;
     2035                        }
     2036                        *ShortestAngle = alpha;
     2037                        //cout << Verbose(2) << "INFO: There are " << candidates->size() << " candidates in the list now." << endl;
     2038                      } else {
     2039                        if ((optCandidate != NULL) && (optCandidate->point != NULL)) {
     2040                          //cout << Verbose(2) << "REJECT: Old candidate: " << *(optCandidate->point) << " is better than " << alpha << " with " << *ShortestAngle << "." << endl;
     2041                        } else {
     2042                          //cout << Verbose(2) << "REJECT: Candidate " << *Candidate << " with " << alpha << " was rejected." << endl;
     2043                        }
     2044                      }
     2045
     2046                    } else {
     2047                      //cout << Verbose(2) << "REJECT: NewSphereCenter " << NewSphereCenter << " is too far away: " << radius << "." << endl;
     2048                    }
     2049                  } else {
     2050                    //cout << Verbose(2) << "REJECT: Three points from " << *BaseLine << " and Candidate " << *Candidate << " are linear-dependent." << endl;
     2051                  }
     2052                } else {
     2053                  if (ThirdNode != NULL) {
     2054                    //cout << Verbose(2) << "REJECT: Base triangle " << *BaseLine << " and " << *ThirdNode << " contains Candidate " << *Candidate << "." << endl;
     2055                  } else {
     2056                    //cout << Verbose(2) << "REJECT: Base triangle " << *BaseLine << " contains Candidate " << *Candidate << "." << endl;
     2057                  }
     2058                }
     2059              }
     2060            }
     2061          }
     2062    } else {
     2063      cerr << Verbose(2) << "ERROR: The projected center of the old sphere has radius " << radius << " instead of " << CircleRadius << "." << endl;
     2064    }
     2065  } else {
     2066    if (ThirdNode != NULL)
     2067      cout << Verbose(2) << "Circumcircle for base line " << *BaseLine << " and third node " << *ThirdNode << " is too big!" << endl;
     2068    else
     2069      cout << Verbose(2) << "Circumcircle for base line " << *BaseLine << " is too big!" << endl;
     2070  }
     2071
     2072  //cout << Verbose(2) << "INFO: Sorting candidate list ..." << endl;
     2073  if (candidates->size() > 1) {
     2074          candidates->unique();
     2075          candidates->sort(sortCandidates);
     2076  }
     2077
     2078  cout << Verbose(1) << "End of Find_third_point_for_Tesselation" << endl;
     2079};
     2080
     2081struct Intersection {
     2082        Vector x1;
     2083        Vector x2;
     2084        Vector x3;
     2085        Vector x4;
     2086};
     2087
     2088/**
     2089 * Intersection calculation function.
     2090 *
     2091 * @param x to find the result for
     2092 * @param function parameter
     2093 */
     2094double MinIntersectDistance(const gsl_vector * x, void *params) {
     2095        double retval = 0;
     2096        struct Intersection *I = (struct Intersection *)params;
     2097        Vector intersection;
     2098        Vector SideA,SideB,HeightA, HeightB;
     2099        for (int i=0;i<NDIM;i++)
     2100                intersection.x[i] = gsl_vector_get(x, i);
     2101
     2102        SideA.CopyVector(&(I->x1));
     2103        SideA.SubtractVector(&I->x2);
     2104        HeightA.CopyVector(&intersection);
     2105        HeightA.SubtractVector(&I->x1);
     2106        HeightA.ProjectOntoPlane(&SideA);
     2107
     2108        SideB.CopyVector(&I->x3);
     2109        SideB.SubtractVector(&I->x4);
     2110        HeightB.CopyVector(&intersection);
     2111        HeightB.SubtractVector(&I->x3);
     2112        HeightB.ProjectOntoPlane(&SideB);
     2113
     2114        retval = HeightA.ScalarProduct(&HeightA) + HeightB.ScalarProduct(&HeightB);
     2115        //cout << Verbose(2) << "MinIntersectDistance called, result: " << retval << endl;
     2116
     2117        return retval;
     2118};
     2119
     2120
     2121/**
     2122 * Calculates whether there is an intersection between two lines. The first line
     2123 * always goes through point 1 and point 2 and the second line is given by the
     2124 * connection between point 4 and point 5.
     2125 *
     2126 * @param point 1 of line 1
     2127 * @param point 2 of line 1
     2128 * @param point 1 of line 2
     2129 * @param point 2 of line 2
     2130 *
     2131 * @return true if there is an intersection between the given lines, false otherwise
     2132 */
     2133bool existsIntersection(Vector point1, Vector point2, Vector point3, Vector point4) {
     2134        bool result;
     2135
     2136        struct Intersection par;
     2137                par.x1.CopyVector(&point1);
     2138                par.x2.CopyVector(&point2);
     2139                par.x3.CopyVector(&point3);
     2140                par.x4.CopyVector(&point4);
     2141
     2142    const gsl_multimin_fminimizer_type *T = gsl_multimin_fminimizer_nmsimplex;
     2143    gsl_multimin_fminimizer *s = NULL;
     2144    gsl_vector *ss, *x;
     2145    gsl_multimin_function minex_func;
     2146
     2147    size_t iter = 0;
     2148    int status;
     2149    double size;
     2150
     2151    /* Starting point */
     2152    x = gsl_vector_alloc(NDIM);
     2153    gsl_vector_set(x, 0, point1.x[0]);
     2154    gsl_vector_set(x, 1, point1.x[1]);
     2155    gsl_vector_set(x, 2, point1.x[2]);
     2156
     2157    /* Set initial step sizes to 1 */
     2158    ss = gsl_vector_alloc(NDIM);
     2159    gsl_vector_set_all(ss, 1.0);
     2160
     2161    /* Initialize method and iterate */
     2162    minex_func.n = NDIM;
     2163    minex_func.f = &MinIntersectDistance;
     2164    minex_func.params = (void *)&par;
     2165
     2166    s = gsl_multimin_fminimizer_alloc(T, NDIM);
     2167    gsl_multimin_fminimizer_set(s, &minex_func, x, ss);
     2168
     2169    do {
     2170        iter++;
     2171        status = gsl_multimin_fminimizer_iterate(s);
     2172
     2173        if (status) {
     2174          break;
     2175        }
     2176
     2177        size = gsl_multimin_fminimizer_size(s);
     2178        status = gsl_multimin_test_size(size, 1e-2);
     2179
     2180        if (status == GSL_SUCCESS) {
     2181                cout << Verbose(2) << "converged to minimum" <<  endl;
     2182        }
     2183    } while (status == GSL_CONTINUE && iter < 100);
     2184
     2185    // check whether intersection is in between or not
     2186        Vector intersection, SideA, SideB, HeightA, HeightB;
     2187        double t1, t2;
     2188        for (int i = 0; i < NDIM; i++) {
     2189                intersection.x[i] = gsl_vector_get(s->x, i);
     2190        }
     2191
     2192        SideA.CopyVector(&par.x2);
     2193        SideA.SubtractVector(&par.x1);
     2194        HeightA.CopyVector(&intersection);
     2195        HeightA.SubtractVector(&par.x1);
     2196
     2197        t1 = HeightA.Projection(&SideA)/SideA.ScalarProduct(&SideA);
     2198
     2199        SideB.CopyVector(&par.x4);
     2200        SideB.SubtractVector(&par.x3);
     2201        HeightB.CopyVector(&intersection);
     2202        HeightB.SubtractVector(&par.x3);
     2203
     2204        t2 = HeightB.Projection(&SideB)/SideB.ScalarProduct(&SideB);
     2205
     2206        cout << Verbose(2) << "Intersection " << intersection << " is at "
     2207                << t1 << " for (" << point1 << "," << point2 << ") and at "
     2208                << t2 << " for (" << point3 << "," << point4 << "): ";
     2209
     2210        if (((t1 >= 0) && (t1 <= 1)) && ((t2 >= 0) && (t2 <= 1))) {
     2211                cout << "true intersection." << endl;
     2212                result = true;
     2213        } else {
     2214                cout << "intersection out of region of interest." << endl;
     2215                result = false;
     2216        }
     2217
     2218        // free minimizer stuff
     2219    gsl_vector_free(x);
     2220    gsl_vector_free(ss);
     2221    gsl_multimin_fminimizer_free(s);
     2222
     2223        return result;
     2224}
     2225
     2226/** Finds the second point of starting triangle.
     2227 * \param *a first atom
     2228 * \param *Candidate pointer to candidate atom on return
     2229 * \param Oben vector indicating the outside
     2230 * \param Opt_Candidate reference to recommended candidate on return
     2231 * \param Storage[3] array storing angles and other candidate information
     2232 * \param RADIUS radius of virtual sphere
     2233 * \param *LC LinkedCell structure with neighbouring atoms
     2234 */
     2235void Find_second_point_for_Tesselation(atom* a, atom* Candidate, Vector Oben, atom*& Opt_Candidate, double Storage[3], double RADIUS, LinkedCell *LC)
     2236{
     2237  cout << Verbose(2) << "Begin of Find_second_point_for_Tesselation" << endl;
     2238  Vector AngleCheck;
     2239  double norm = -1., angle;
     2240  LinkedAtoms *List = NULL;
     2241  int N[NDIM], Nlower[NDIM], Nupper[NDIM];
     2242
     2243  if (LC->SetIndexToAtom(*a)) {  // get cell for the starting atom
     2244    for(int i=0;i<NDIM;i++) // store indices of this cell
     2245      N[i] = LC->n[i];
     2246  } else {
     2247    cerr << "ERROR: Atom " << *a << " is not found in cell " << LC->index << "." << endl;
     2248    return;
     2249  }
     2250  // then go through the current and all neighbouring cells and check the contained atoms for possible candidates
     2251  cout << Verbose(3) << "LC Intervals from [";
     2252  for (int i=0;i<NDIM;i++) {
     2253  cout << " " << N[i] << "<->" << LC->N[i];
     2254  }
     2255  cout << "] :";
     2256  for (int i=0;i<NDIM;i++) {
     2257    Nlower[i] = ((N[i]-1) >= 0) ? N[i]-1 : 0;
     2258    Nupper[i] = ((N[i]+1) < LC->N[i]) ? N[i]+1 : LC->N[i]-1;
     2259    cout << " [" << Nlower[i] << "," << Nupper[i] << "] ";
     2260  }
     2261  cout << endl;
     2262
     2263
     2264  for (LC->n[0] = Nlower[0]; LC->n[0] <= Nupper[0]; LC->n[0]++)
     2265    for (LC->n[1] = Nlower[1]; LC->n[1] <= Nupper[1]; LC->n[1]++)
     2266      for (LC->n[2] = Nlower[2]; LC->n[2] <= Nupper[2]; LC->n[2]++) {
     2267        List = LC->GetCurrentCell();
     2268        //cout << Verbose(2) << "Current cell is " << LC->n[0] << ", " << LC->n[1] << ", " << LC->n[2] << " with No. " << LC->index << "." << endl;
     2269        if (List != NULL) {
     2270          for (LinkedAtoms::iterator Runner = List->begin(); Runner != List->end(); Runner++) {
     2271            Candidate = (*Runner);
     2272            // check if we only have one unique point yet ...
     2273            if (a != Candidate) {
     2274              // Calculate center of the circle with radius RADIUS through points a and Candidate
     2275              Vector OrthogonalizedOben, a_Candidate, Center;
     2276              double distance, scaleFactor;
     2277
     2278              OrthogonalizedOben.CopyVector(&Oben);
     2279              a_Candidate.CopyVector(&(a->x));
     2280              a_Candidate.SubtractVector(&(Candidate->x));
     2281              OrthogonalizedOben.ProjectOntoPlane(&a_Candidate);
     2282              OrthogonalizedOben.Normalize();
     2283              distance = 0.5 * a_Candidate.Norm();
     2284              scaleFactor = sqrt(((RADIUS * RADIUS) - (distance * distance)));
     2285              OrthogonalizedOben.Scale(scaleFactor);
     2286
     2287              Center.CopyVector(&(Candidate->x));
     2288              Center.AddVector(&(a->x));
     2289              Center.Scale(0.5);
     2290              Center.AddVector(&OrthogonalizedOben);
     2291
     2292              AngleCheck.CopyVector(&Center);
     2293              AngleCheck.SubtractVector(&(a->x));
     2294              norm = a_Candidate.Norm();
     2295              // second point shall have smallest angle with respect to Oben vector
     2296              if (norm < RADIUS*2.) {
     2297                angle = AngleCheck.Angle(&Oben);
     2298                if (angle < Storage[0]) {
     2299                  //cout << Verbose(3) << "Old values of Storage: %lf %lf \n", Storage[0], Storage[1]);
     2300                  cout << Verbose(3) << "Current candidate is " << *Candidate << ": Is a better candidate with distance " << norm << " and angle " << angle << " to oben " << Oben << ".\n";
     2301                  Opt_Candidate = Candidate;
     2302                  Storage[0] = angle;
     2303                  //cout << Verbose(3) << "Changing something in Storage: %lf %lf. \n", Storage[0], Storage[2]);
     2304                } else {
     2305                  //cout << Verbose(3) << "Current candidate is " << *Candidate << ": Looses with angle " << angle << " to a better candidate " << *Opt_Candidate << endl;
     2306                }
     2307              } else {
     2308                //cout << Verbose(3) << "Current candidate is " << *Candidate << ": Refused due to Radius " << norm << endl;
     2309              }
     2310            } else {
     2311              //cout << Verbose(3) << "Current candidate is " << *Candidate << ": Candidate is equal to first endpoint." << *a << "." << endl;
     2312            }
    8072313          }
    8082314        } else {
    809           // leave empty
    810           *out << Verbose(2) << "Space at " << CurrentPosition << " is occupied." << endl;
     2315          cout << Verbose(3) << "Linked cell list is empty." << endl;
    8112316        }
    8122317      }
    813   return Filling;
     2318  cout << Verbose(2) << "End of Find_second_point_for_Tesselation" << endl;
    8142319};
     2320
     2321/** Finds the starting triangle for find_non_convex_border().
     2322 * Looks at the outermost atom per axis, then Find_second_point_for_Tesselation()
     2323 * for the second and Find_next_suitable_point_via_Angle_of_Sphere() for the third
     2324 * point are called.
     2325 * \param RADIUS radius of virtual rolling sphere
     2326 * \param *LC LinkedCell structure with neighbouring atoms
     2327 */
     2328void Tesselation::Find_starting_triangle(ofstream *out, molecule *mol, const double RADIUS, LinkedCell *LC)
     2329{
     2330  cout << Verbose(1) << "Begin of Find_starting_triangle\n";
     2331  int i = 0;
     2332  LinkedAtoms *List = NULL;
     2333  atom* FirstPoint = NULL;
     2334  atom* SecondPoint = NULL;
     2335  atom* MaxAtom[NDIM];
     2336  double max_coordinate[NDIM];
     2337  Vector Oben;
     2338  Vector helper;
     2339  Vector Chord;
     2340  Vector SearchDirection;
     2341
     2342  Oben.Zero();
     2343
     2344  for (i = 0; i < 3; i++) {
     2345    MaxAtom[i] = NULL;
     2346    max_coordinate[i] = -1;
     2347  }
     2348
     2349  // 1. searching topmost atom with respect to each axis
     2350  for (int i=0;i<NDIM;i++) { // each axis
     2351    LC->n[i] = LC->N[i]-1; // current axis is topmost cell
     2352    for (LC->n[(i+1)%NDIM]=0;LC->n[(i+1)%NDIM]<LC->N[(i+1)%NDIM];LC->n[(i+1)%NDIM]++)
     2353      for (LC->n[(i+2)%NDIM]=0;LC->n[(i+2)%NDIM]<LC->N[(i+2)%NDIM];LC->n[(i+2)%NDIM]++) {
     2354        List = LC->GetCurrentCell();
     2355        //cout << Verbose(2) << "Current cell is " << LC->n[0] << ", " << LC->n[1] << ", " << LC->n[2] << " with No. " << LC->index << "." << endl;
     2356        if (List != NULL) {
     2357          for (LinkedAtoms::iterator Runner = List->begin();Runner != List->end();Runner++) {
     2358            if ((*Runner)->x.x[i] > max_coordinate[i]) {
     2359              cout << Verbose(2) << "New maximal for axis " << i << " atom is " << *(*Runner) << " at " << (*Runner)->x << "." << endl;
     2360              max_coordinate[i] = (*Runner)->x.x[i];
     2361              MaxAtom[i] = (*Runner);
     2362            }
     2363          }
     2364        } else {
     2365          cerr << "ERROR: The current cell " << LC->n[0] << "," << LC->n[1] << "," << LC->n[2] << " is invalid!" << endl;
     2366        }
     2367      }
     2368  }
     2369
     2370  cout << Verbose(2) << "Found maximum coordinates: ";
     2371  for (int i=0;i<NDIM;i++)
     2372    cout << i << ": " << *MaxAtom[i] << "\t";
     2373  cout << endl;
     2374
     2375  BTS = NULL;
     2376  CandidateList *Opt_Candidates = new CandidateList();
     2377  for (int k=0;k<NDIM;k++) {
     2378    Oben.x[k] = 1.;
     2379    FirstPoint = MaxAtom[k];
     2380    cout << Verbose(1) << "Coordinates of start atom " << *FirstPoint << " at " << FirstPoint->x << "." << endl;
     2381
     2382    double ShortestAngle;
     2383    atom* Opt_Candidate = NULL;
     2384    ShortestAngle = 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.
     2385
     2386    Find_second_point_for_Tesselation(FirstPoint, NULL, Oben, Opt_Candidate, &ShortestAngle, RADIUS, LC); // we give same point as next candidate as its bonds are looked into in find_second_...
     2387    SecondPoint = Opt_Candidate;
     2388    if (SecondPoint == NULL)  // have we found a second point?
     2389      continue;
     2390    else
     2391      cout << Verbose(1) << "Found second point is " << *SecondPoint << " at " << SecondPoint->x << ".\n";
     2392
     2393    helper.CopyVector(&(FirstPoint->x));
     2394    helper.SubtractVector(&(SecondPoint->x));
     2395    helper.Normalize();
     2396    Oben.ProjectOntoPlane(&helper);
     2397    Oben.Normalize();
     2398    helper.VectorProduct(&Oben);
     2399    ShortestAngle = 2.*M_PI; // This will indicate the quadrant.
     2400
     2401    Chord.CopyVector(&(FirstPoint->x)); // bring into calling function
     2402    Chord.SubtractVector(&(SecondPoint->x));
     2403    double radius = Chord.ScalarProduct(&Chord);
     2404    double CircleRadius = sqrt(RADIUS*RADIUS - radius/4.);
     2405    helper.CopyVector(&Oben);
     2406    helper.Scale(CircleRadius);
     2407    // Now, oben and helper are two orthonormalized vectors in the plane defined by Chord (not normalized)
     2408
     2409    // look in one direction of baseline for initial candidate
     2410    SearchDirection.MakeNormalVector(&Chord, &Oben);  // whether we look "left" first or "right" first is not important ...
     2411
     2412    // adding point 1 and point 2 and the line between them
     2413    AddTrianglePoint(FirstPoint, 0);
     2414    AddTrianglePoint(SecondPoint, 1);
     2415    AddTriangleLine(TPS[0], TPS[1], 0);
     2416
     2417    //cout << Verbose(2) << "INFO: OldSphereCenter is at " << helper << ".\n";
     2418    Find_third_point_for_Tesselation(
     2419      Oben, SearchDirection, helper, BLS[0], NULL, *&Opt_Candidates, &ShortestAngle, RADIUS, LC
     2420    );
     2421    cout << Verbose(1) << "List of third Points is ";
     2422    for (CandidateList::iterator it = Opt_Candidates->begin(); it != Opt_Candidates->end(); ++it) {
     2423        cout << " " << *(*it)->point;
     2424    }
     2425    cout << endl;
     2426
     2427    for (CandidateList::iterator it = Opt_Candidates->begin(); it != Opt_Candidates->end(); ++it) {
     2428      // add third triangle point
     2429      AddTrianglePoint((*it)->point, 2);
     2430      // add the second and third line
     2431      AddTriangleLine(TPS[1], TPS[2], 1);
     2432      AddTriangleLine(TPS[0], TPS[2], 2);
     2433      // ... and triangles to the Maps of the Tesselation class
     2434      BTS = new class BoundaryTriangleSet(BLS, TrianglesOnBoundaryCount);
     2435      AddTriangle();
     2436      // ... and calculate its normal vector (with correct orientation)
     2437      (*it)->OptCenter.Scale(-1.);
     2438      cout << Verbose(2) << "Anti-Oben is currently " << (*it)->OptCenter << "." << endl;
     2439      BTS->GetNormalVector((*it)->OptCenter);  // vector to compare with should point inwards
     2440      cout << Verbose(0) << "==> Found starting triangle consists of " << *FirstPoint << ", " << *SecondPoint << " and "
     2441      << *(*it)->point << " with normal vector " << BTS->NormalVector << ".\n";
     2442
     2443      // if we do not reach the end with the next step of iteration, we need to setup a new first line
     2444      if (it != Opt_Candidates->end()--) {
     2445        FirstPoint = (*it)->BaseLine->endpoints[0]->node;
     2446        SecondPoint = (*it)->point;
     2447        // adding point 1 and point 2 and the line between them
     2448        AddTrianglePoint(FirstPoint, 0);
     2449        AddTrianglePoint(SecondPoint, 1);
     2450        AddTriangleLine(TPS[0], TPS[1], 0);
     2451      }
     2452      cout << Verbose(2) << "Projection is " << BTS->NormalVector.Projection(&Oben) << "." << endl;
     2453    }
     2454    if (BTS != NULL) // we have created one starting triangle
     2455      break;
     2456    else {
     2457      // remove all candidates from the list and then the list itself
     2458      class CandidateForTesselation *remover = NULL;
     2459      for (CandidateList::iterator it = Opt_Candidates->begin(); it != Opt_Candidates->end(); ++it) {
     2460        remover = *it;
     2461        delete(remover);
     2462      }
     2463      Opt_Candidates->clear();
     2464    }
     2465  }
     2466
     2467  // remove all candidates from the list and then the list itself
     2468  class CandidateForTesselation *remover = NULL;
     2469  for (CandidateList::iterator it = Opt_Candidates->begin(); it != Opt_Candidates->end(); ++it) {
     2470    remover = *it;
     2471    delete(remover);
     2472  }
     2473  delete(Opt_Candidates);
     2474  cout << Verbose(1) << "End of Find_starting_triangle\n";
     2475};
     2476
     2477/** Checks for a new special triangle whether one of its edges is already present with one one triangle connected.
     2478 * This enforces that special triangles (i.e. degenerated ones) should at last close the open-edge frontier and not
     2479 * make it bigger (i.e. closing one (the baseline) and opening two new ones).
     2480 * \param TPS[3] nodes of the triangle
     2481 * \return true - there is such a line (i.e. creation of degenerated triangle is valid), false - no such line (don't create)
     2482 */
     2483bool CheckLineCriteriaforDegeneratedTriangle(class BoundaryPointSet *nodes[3])
     2484{
     2485  bool result = false;
     2486  int counter = 0;
     2487
     2488  // check all three points
     2489  for (int i=0;i<3;i++)
     2490    for (int j=i+1; j<3; j++) {
     2491      if (nodes[i]->lines.find(nodes[j]->node->nr) != nodes[i]->lines.end()) {  // there already is a line
     2492        LineMap::iterator FindLine;
     2493        pair<LineMap::iterator,LineMap::iterator> FindPair;
     2494        FindPair = nodes[i]->lines.equal_range(nodes[j]->node->nr);
     2495        for (FindLine = FindPair.first; FindLine != FindPair.second; ++FindLine) {
     2496          // If there is a line with less than two attached triangles, we don't need a new line.
     2497          if (FindLine->second->TrianglesCount < 2) {
     2498            counter++;
     2499            break;  // increase counter only once per edge
     2500          }
     2501        }
     2502      } else { // no line
     2503        cout << Verbose(1) << "ERROR: The line between " << nodes[i] << " and " << nodes[j] << " is not yet present, hence no need for a degenerate triangle!" << endl;
     2504        result = true;
     2505      }
     2506    }
     2507  if (counter > 1) {
     2508    cout << Verbose(2) << "INFO: Degenerate triangle is ok, at least two, here " << counter << ", existing lines are used." << endl;
     2509    result = true;
     2510  }
     2511  return result;
     2512};
     2513
     2514
     2515/** This function finds a triangle to a line, adjacent to an existing one.
     2516 * @param out output stream for debugging
     2517 * @param *mol molecule with Atom's and Bond's
     2518 * @param Line current baseline to search from
     2519 * @param T current triangle which \a Line is edge of
     2520 * @param RADIUS radius of the rolling ball
     2521 * @param N number of found triangles
     2522 * @param *filename filename base for intermediate envelopes
     2523 * @param *LC LinkedCell structure with neighbouring atoms
     2524 */
     2525bool Tesselation::Find_next_suitable_triangle(ofstream *out,
     2526    molecule *mol, BoundaryLineSet &Line, BoundaryTriangleSet &T,
     2527    const double& RADIUS, int N, const char *tempbasename, LinkedCell *LC)
     2528{
     2529  cout << Verbose(0) << "Begin of Find_next_suitable_triangle\n";
     2530  ofstream *tempstream = NULL;
     2531  char NumberName[255];
     2532  bool result = true;
     2533  CandidateList *Opt_Candidates = new CandidateList();
     2534
     2535  Vector CircleCenter;
     2536  Vector CirclePlaneNormal;
     2537  Vector OldSphereCenter;
     2538  Vector SearchDirection;
     2539  Vector helper;
     2540  atom *ThirdNode = NULL;
     2541  LineMap::iterator testline;
     2542  double ShortestAngle = 2.*M_PI; // This will indicate the quadrant.
     2543  double radius, CircleRadius;
     2544
     2545  cout << Verbose(1) << "Current baseline is " << Line << " of triangle " << T << "." << endl;
     2546  for (int i=0;i<3;i++)
     2547    if ((T.endpoints[i]->node != Line.endpoints[0]->node) && (T.endpoints[i]->node != Line.endpoints[1]->node))
     2548      ThirdNode = T.endpoints[i]->node;
     2549
     2550  // construct center of circle
     2551  CircleCenter.CopyVector(&Line.endpoints[0]->node->x);
     2552  CircleCenter.AddVector(&Line.endpoints[1]->node->x);
     2553  CircleCenter.Scale(0.5);
     2554
     2555  // construct normal vector of circle
     2556  CirclePlaneNormal.CopyVector(&Line.endpoints[0]->node->x);
     2557  CirclePlaneNormal.SubtractVector(&Line.endpoints[1]->node->x);
     2558
     2559  // calculate squared radius of circle
     2560  radius = CirclePlaneNormal.ScalarProduct(&CirclePlaneNormal);
     2561  if (radius/4. < RADIUS*RADIUS) {
     2562    CircleRadius = RADIUS*RADIUS - radius/4.;
     2563    CirclePlaneNormal.Normalize();
     2564    cout << Verbose(2) << "INFO: CircleCenter is at " << CircleCenter << ", CirclePlaneNormal is " << CirclePlaneNormal << " with circle radius " << sqrt(CircleRadius) << "." << endl;
     2565
     2566    // construct old center
     2567    GetCenterofCircumcircle(&OldSphereCenter, &(T.endpoints[0]->node->x), &(T.endpoints[1]->node->x), &(T.endpoints[2]->node->x));
     2568    helper.CopyVector(&T.NormalVector);  // normal vector ensures that this is correct center of the two possible ones
     2569    radius = Line.endpoints[0]->node->x.DistanceSquared(&OldSphereCenter);
     2570    helper.Scale(sqrt(RADIUS*RADIUS - radius));
     2571    OldSphereCenter.AddVector(&helper);
     2572    OldSphereCenter.SubtractVector(&CircleCenter);
     2573    //cout << Verbose(2) << "INFO: OldSphereCenter is at " << OldSphereCenter << "." << endl;
     2574
     2575    // construct SearchDirection
     2576    SearchDirection.MakeNormalVector(&T.NormalVector, &CirclePlaneNormal);
     2577    helper.CopyVector(&Line.endpoints[0]->node->x);
     2578    helper.SubtractVector(&ThirdNode->x);
     2579    if (helper.ScalarProduct(&SearchDirection) < -HULLEPSILON)// ohoh, SearchDirection points inwards!
     2580      SearchDirection.Scale(-1.);
     2581    SearchDirection.ProjectOntoPlane(&OldSphereCenter);
     2582    SearchDirection.Normalize();
     2583    cout << Verbose(2) << "INFO: SearchDirection is " << SearchDirection << "." << endl;
     2584    if (fabs(OldSphereCenter.ScalarProduct(&SearchDirection)) > HULLEPSILON) {
     2585      // rotated the wrong way!
     2586      cerr << "ERROR: SearchDirection and RelativeOldSphereCenter are still not orthogonal!" << endl;
     2587    }
     2588
     2589    // add third point
     2590    Find_third_point_for_Tesselation(
     2591      T.NormalVector, SearchDirection, OldSphereCenter, &Line, ThirdNode, Opt_Candidates,
     2592      &ShortestAngle, RADIUS, LC
     2593    );
     2594
     2595  } else {
     2596    cout << Verbose(1) << "Circumcircle for base line " << Line << " and base triangle " << T << " is too big!" << endl;
     2597  }
     2598
     2599  if (Opt_Candidates->begin() == Opt_Candidates->end()) {
     2600    cerr << "WARNING: Could not find a suitable candidate." << endl;
     2601    return false;
     2602  }
     2603  cout << Verbose(1) << "Third Points are ";
     2604  for (CandidateList::iterator it = Opt_Candidates->begin(); it != Opt_Candidates->end(); ++it) {
     2605          cout << " " << *(*it)->point;
     2606  }
     2607  cout << endl;
     2608
     2609  BoundaryLineSet *BaseRay = &Line;
     2610  for (CandidateList::iterator it = Opt_Candidates->begin(); it != Opt_Candidates->end(); ++it) {
     2611          cout << Verbose(1) << " Third point candidate is " << *(*it)->point
     2612                << " with circumsphere's center at " << (*it)->OptCenter << "." << endl;
     2613          cout << Verbose(1) << " Baseline is " << *BaseRay << endl;
     2614
     2615          // check whether all edges of the new triangle still have space for one more triangle (i.e. TriangleCount <2)
     2616          atom *AtomCandidates[3];
     2617          AtomCandidates[0] = (*it)->point;
     2618          AtomCandidates[1] = BaseRay->endpoints[0]->node;
     2619          AtomCandidates[2] = BaseRay->endpoints[1]->node;
     2620          int existentTrianglesCount = CheckPresenceOfTriangle(out, AtomCandidates);
     2621
     2622          BTS = NULL;
     2623          // If there is no triangle, add it regularly.
     2624          if (existentTrianglesCount == 0) {
     2625      AddTrianglePoint((*it)->point, 0);
     2626      AddTrianglePoint(BaseRay->endpoints[0]->node, 1);
     2627      AddTrianglePoint(BaseRay->endpoints[1]->node, 2);
     2628
     2629      AddTriangleLine(TPS[0], TPS[1], 0);
     2630      AddTriangleLine(TPS[0], TPS[2], 1);
     2631      AddTriangleLine(TPS[1], TPS[2], 2);
     2632
     2633      BTS = new class BoundaryTriangleSet(BLS, TrianglesOnBoundaryCount);
     2634      AddTriangle();
     2635      (*it)->OptCenter.Scale(-1.);
     2636      BTS->GetNormalVector((*it)->OptCenter);
     2637      (*it)->OptCenter.Scale(-1.);
     2638
     2639      cout << "--> New triangle with " << *BTS << " and normal vector " << BTS->NormalVector
     2640        << " for this triangle ... " << endl;
     2641      //cout << Verbose(1) << "We have "<< TrianglesOnBoundaryCount << " for line " << *BaseRay << "." << endl;
     2642          } else if (existentTrianglesCount == 1) { // If there is a planar region within the structure, we need this triangle a second time.
     2643        AddTrianglePoint((*it)->point, 0);
     2644        AddTrianglePoint(BaseRay->endpoints[0]->node, 1);
     2645        AddTrianglePoint(BaseRay->endpoints[1]->node, 2);
     2646
     2647        // We demand that at most one new degenerate line is created and that this line also already exists (which has to be the case due to existentTrianglesCount == 1)
     2648        // i.e. at least one of the three lines must be present with TriangleCount <= 1
     2649        if (CheckLineCriteriaforDegeneratedTriangle(TPS)) {
     2650          AddTriangleLine(TPS[0], TPS[1], 0);
     2651          AddTriangleLine(TPS[0], TPS[2], 1);
     2652          AddTriangleLine(TPS[1], TPS[2], 2);
     2653
     2654          BTS = new class BoundaryTriangleSet(BLS, TrianglesOnBoundaryCount);
     2655          AddTriangle();
     2656
     2657          (*it)->OtherOptCenter.Scale(-1.);
     2658          BTS->GetNormalVector((*it)->OtherOptCenter);
     2659          (*it)->OtherOptCenter.Scale(-1.);
     2660
     2661          cout << "--> WARNING: Special new triangle with " << *BTS << " and normal vector " << BTS->NormalVector
     2662          << " for this triangle ... " << endl;
     2663          cout << Verbose(1) << "We have "<< BaseRay->TrianglesCount << " for line " << BaseRay << "." << endl;
     2664        } else {
     2665          cout << Verbose(1) << "WARNING: This triangle consisting of ";
     2666          cout << *(*it)->point << ", ";
     2667          cout << *BaseRay->endpoints[0]->node << " and ";
     2668          cout << *BaseRay->endpoints[1]->node << " ";
     2669          cout << "exists and is not added, as it does not seem helpful!" << endl;
     2670          result = false;
     2671        }
     2672    } else {
     2673      cout << Verbose(1) << "This triangle consisting of ";
     2674      cout << *(*it)->point << ", ";
     2675      cout << *BaseRay->endpoints[0]->node << " and ";
     2676      cout << *BaseRay->endpoints[1]->node << " ";
     2677      cout << "is invalid!" << endl;
     2678      result = false;
     2679    }
     2680
     2681          if ((result) && (existentTrianglesCount < 2) && (DoSingleStepOutput && (TrianglesOnBoundaryCount % 1 == 0))) { // if we have a new triangle and want to output each new triangle configuration
     2682      sprintf(NumberName, "-%04d-%s_%s_%s", TriangleFilesWritten, BTS->endpoints[0]->node->Name, BTS->endpoints[1]->node->Name, BTS->endpoints[2]->node->Name);
     2683      if (DoTecplotOutput) {
     2684        string NameofTempFile(tempbasename);
     2685        NameofTempFile.append(NumberName);
     2686        for(size_t npos = NameofTempFile.find_first_of(' '); npos != string::npos; npos = NameofTempFile.find(' ', npos))
     2687        NameofTempFile.erase(npos, 1);
     2688        NameofTempFile.append(TecplotSuffix);
     2689        cout << Verbose(1) << "Writing temporary non convex hull to file " << NameofTempFile << ".\n";
     2690        tempstream = new ofstream(NameofTempFile.c_str(), ios::trunc);
     2691        write_tecplot_file(out, tempstream, this, mol, TriangleFilesWritten);
     2692        tempstream->close();
     2693        tempstream->flush();
     2694        delete(tempstream);
     2695      }
     2696
     2697      if (DoRaster3DOutput) {
     2698        string NameofTempFile(tempbasename);
     2699        NameofTempFile.append(NumberName);
     2700        for(size_t npos = NameofTempFile.find_first_of(' '); npos != string::npos; npos = NameofTempFile.find(' ', npos))
     2701        NameofTempFile.erase(npos, 1);
     2702        NameofTempFile.append(Raster3DSuffix);
     2703        cout << Verbose(1) << "Writing temporary non convex hull to file " << NameofTempFile << ".\n";
     2704        tempstream = new ofstream(NameofTempFile.c_str(), ios::trunc);
     2705        write_raster3d_file(out, tempstream, this, mol);
     2706        // include the current position of the virtual sphere in the temporary raster3d file
     2707        // make the circumsphere's center absolute again
     2708        helper.CopyVector(&BaseRay->endpoints[0]->node->x);
     2709        helper.AddVector(&BaseRay->endpoints[1]->node->x);
     2710        helper.Scale(0.5);
     2711        (*it)->OptCenter.AddVector(&helper);
     2712        Vector *center = mol->DetermineCenterOfAll(out);
     2713        (*it)->OptCenter.AddVector(center);
     2714        delete(center);
     2715        // and add to file plus translucency object
     2716        *tempstream << "# current virtual sphere\n";
     2717        *tempstream << "8\n  25.0    0.6     -1.0 -1.0 -1.0     0.2        0 0 0 0\n";
     2718        *tempstream << "2\n  " << (*it)->OptCenter.x[0] << " "
     2719          << (*it)->OptCenter.x[1] << " " << (*it)->OptCenter.x[2]
     2720          << "\t" << RADIUS << "\t1 0 0\n";
     2721        *tempstream << "9\n  terminating special property\n";
     2722        tempstream->close();
     2723        tempstream->flush();
     2724        delete(tempstream);
     2725      }
     2726      if (DoTecplotOutput || DoRaster3DOutput)
     2727        TriangleFilesWritten++;
     2728          }
     2729
     2730    // set baseline to new ray from ref point (here endpoints[0]->node) to current candidate (here (*it)->point))
     2731          BaseRay = BLS[0];
     2732  }
     2733
     2734  // remove all candidates from the list and then the list itself
     2735  class CandidateForTesselation *remover = NULL;
     2736  for (CandidateList::iterator it = Opt_Candidates->begin(); it != Opt_Candidates->end(); ++it) {
     2737    remover = *it;
     2738    delete(remover);
     2739  }
     2740  delete(Opt_Candidates);
     2741  cout << Verbose(0) << "End of Find_next_suitable_triangle\n";
     2742  return result;
     2743};
     2744
     2745/**
     2746 * Sort function for the candidate list.
     2747 */
     2748bool sortCandidates(CandidateForTesselation* candidate1, CandidateForTesselation* candidate2) {
     2749  // TODO: use get angle and remove duplicate code
     2750  Vector BaseLineVector, OrthogonalVector, helper;
     2751        if (candidate1->BaseLine != candidate2->BaseLine) {  // sanity check
     2752          cout << Verbose(0) << "ERROR: sortCandidates was called for two different baselines: " << candidate1->BaseLine << " and " << candidate2->BaseLine << "." << endl;
     2753          //return false;
     2754          exit(1);
     2755        }
     2756        // create baseline vector
     2757        BaseLineVector.CopyVector(&(candidate1->BaseLine->endpoints[1]->node->x));
     2758        BaseLineVector.SubtractVector(&(candidate1->BaseLine->endpoints[0]->node->x));
     2759        BaseLineVector.Normalize();
     2760
     2761  // create normal in-plane vector to cope with acos() non-uniqueness on [0,2pi] (note that is pointing in the "right" direction already, hence ">0" test!)
     2762        helper.CopyVector(&(candidate1->BaseLine->endpoints[0]->node->x));
     2763        helper.SubtractVector(&(candidate1->point->x));
     2764        OrthogonalVector.CopyVector(&helper);
     2765        helper.VectorProduct(&BaseLineVector);
     2766        OrthogonalVector.SubtractVector(&helper);
     2767        OrthogonalVector.Normalize();
     2768
     2769  // calculate both angles and correct with in-plane vector
     2770        helper.CopyVector(&(candidate1->point->x));
     2771        helper.SubtractVector(&(candidate1->BaseLine->endpoints[0]->node->x));
     2772        double phi = BaseLineVector.Angle(&helper);
     2773  if (OrthogonalVector.ScalarProduct(&helper) > 0) {
     2774    phi = 2.*M_PI - phi;
     2775  }
     2776  helper.CopyVector(&(candidate2->point->x));
     2777        helper.SubtractVector(&(candidate1->BaseLine->endpoints[0]->node->x));
     2778        double psi = BaseLineVector.Angle(&helper);
     2779  if (OrthogonalVector.ScalarProduct(&helper) > 0) {
     2780                psi = 2.*M_PI - psi;
     2781        }
     2782
     2783        cout << Verbose(2) << *candidate1->point << " has angle " << phi << endl;
     2784        cout << Verbose(2) << *candidate2->point << " has angle " << psi << endl;
     2785
     2786        // return comparison
     2787        return phi < psi;
     2788}
     2789
     2790/**
     2791 * Checks whether the provided atom is within the tesselation structure.
     2792 *
     2793 * @param atom of which to check the position
     2794 * @param tesselation structure
     2795 *
     2796 * @return true if the atom is inside the tesselation structure, false otherwise
     2797 */
     2798bool IsInnerAtom(atom *Atom, class Tesselation *Tess, LinkedCell* LC) {
     2799  if (Tess->LinesOnBoundary.begin() == Tess->LinesOnBoundary.end()) {
     2800    cout << Verbose(0) << "Error: There is no tesselation structure to compare the atom with, "
     2801        << "please create one first.";
     2802    exit(1);
     2803  }
     2804
     2805  class atom *trianglePoints[3];
     2806  trianglePoints[0] = findClosestAtom(Atom, LC);
     2807  // check whether closest atom is "too close" :), then it's inside
     2808  if (trianglePoints[0]->x.DistanceSquared(&Atom->x) < MYEPSILON)
     2809    return true;
     2810  list<atom*> *connectedClosestAtoms = Tess->getClosestConnectedAtoms(trianglePoints[0], Atom);
     2811  trianglePoints[1] = connectedClosestAtoms->front();
     2812  trianglePoints[2] = connectedClosestAtoms->back();
     2813  for (int i=0;i<3;i++) {
     2814    if (trianglePoints[i] == NULL) {
     2815      cout << Verbose(1) << "IsInnerAtom encounters serious error, point " << i << " not found." << endl;
     2816    }
     2817
     2818    cout << Verbose(1) << "List of possible atoms:" << endl;
     2819    cout << *trianglePoints[i] << endl;
     2820
     2821//    for(list<atom*>::iterator runner = connectedClosestAtoms->begin(); runner != connectedClosestAtoms->end(); runner++)
     2822//      cout << Verbose(2) << *(*runner) << endl;
     2823  }
     2824  delete(connectedClosestAtoms);
     2825
     2826  list<BoundaryTriangleSet*> *triangles = Tess->FindTriangles(trianglePoints);
     2827
     2828  if (triangles->empty()) {
     2829    cout << Verbose(0) << "Error: There is no nearest triangle. Please check the tesselation structure.";
     2830    exit(1);
     2831  }
     2832
     2833  Vector helper;
     2834  helper.CopyVector(&Atom->x);
     2835
     2836  // Only in case of degeneration, there will be two different scalar products.
     2837  // If at least one scalar product is positive, the point is considered to be outside.
     2838  bool status = (helper.ScalarProduct(&triangles->front()->NormalVector) < 0)
     2839      && (helper.ScalarProduct(&triangles->back()->NormalVector) < 0);
     2840  delete(triangles);
     2841  return status;
     2842}
     2843
     2844/**
     2845 * Finds the atom which is closest to the provided one.
     2846 *
     2847 * @param atom to which to find the closest other atom
     2848 * @param linked cell structure
     2849 *
     2850 * @return atom which is closest to the provided one
     2851 */
     2852atom* findClosestAtom(const atom* Atom, LinkedCell* LC) {
     2853  LinkedAtoms *List = NULL;
     2854  atom* closestAtom = NULL;
     2855  double distance = 1e16;
     2856  Vector helper;
     2857  int N[NDIM], Nlower[NDIM], Nupper[NDIM];
     2858
     2859  LC->SetIndexToVector(&Atom->x); // ignore status as we calculate bounds below sensibly
     2860  for(int i=0;i<NDIM;i++) // store indices of this cell
     2861    N[i] = LC->n[i];
     2862  //cout << Verbose(2) << "INFO: Center cell is " << N[0] << ", " << N[1] << ", " << N[2] << " with No. " << LC->index << "." << endl;
     2863
     2864  LC->GetNeighbourBounds(Nlower, Nupper);
     2865  //cout << endl;
     2866  for (LC->n[0] = Nlower[0]; LC->n[0] <= Nupper[0]; LC->n[0]++)
     2867    for (LC->n[1] = Nlower[1]; LC->n[1] <= Nupper[1]; LC->n[1]++)
     2868      for (LC->n[2] = Nlower[2]; LC->n[2] <= Nupper[2]; LC->n[2]++) {
     2869        List = LC->GetCurrentCell();
     2870        //cout << "The current cell " << LC->n[0] << "," << LC->n[1] << "," << LC->n[2] << endl;
     2871        if (List != NULL) {
     2872          for (LinkedAtoms::iterator Runner = List->begin(); Runner != List->end(); Runner++) {
     2873            helper.CopyVector(&Atom->x);
     2874            helper.SubtractVector(&(*Runner)->x);
     2875            double currentNorm = helper. Norm();
     2876            if (currentNorm < distance) {
     2877              distance = currentNorm;
     2878              closestAtom = (*Runner);
     2879            }
     2880          }
     2881        } else {
     2882          cerr << "ERROR: The current cell " << LC->n[0] << "," << LC->n[1] << ","
     2883            << LC->n[2] << " is invalid!" << endl;
     2884        }
     2885      }
     2886
     2887  return closestAtom;
     2888}
     2889
     2890/**
     2891 * Gets all atoms connected to the provided atom by triangulation lines.
     2892 *
     2893 * @param atom of which get all connected atoms
     2894 * @param atom to be checked whether it is an inner atom
     2895 *
     2896 * @return list of the two atoms linked to the provided one and closest to the atom to be checked,
     2897 */
     2898list<atom*> * Tesselation::getClosestConnectedAtoms(atom* Atom, atom* AtomToCheck) {
     2899  list<atom*> connectedAtoms;
     2900  map<double, atom*> anglesOfAtoms;
     2901  map<double, atom*>::iterator runner;
     2902  LineMap::iterator findLines = LinesOnBoundary.begin();
     2903  list<atom*>::iterator listRunner;
     2904  Vector center, planeNorm, currentPoint, OrthogonalVector, helper;
     2905  atom* current;
     2906  bool takeAtom = false;
     2907
     2908  planeNorm.CopyVector(&Atom->x);
     2909  planeNorm.SubtractVector(&AtomToCheck->x);
     2910  planeNorm.Normalize();
     2911
     2912  while (findLines != LinesOnBoundary.end()) {
     2913    takeAtom = false;
     2914
     2915    if (findLines->second->endpoints[0]->Nr == Atom->nr) {
     2916      takeAtom = true;
     2917      current = findLines->second->endpoints[1]->node;
     2918    } else if (findLines->second->endpoints[1]->Nr == Atom->nr) {
     2919      takeAtom = true;
     2920      current = findLines->second->endpoints[0]->node;
     2921    }
     2922
     2923    if (takeAtom) {
     2924      connectedAtoms.push_back(current);
     2925      currentPoint.CopyVector(&current->x);
     2926      currentPoint.ProjectOntoPlane(&planeNorm);
     2927      center.AddVector(&currentPoint);
     2928    }
     2929
     2930    findLines++;
     2931  }
     2932
     2933  cout << "Summed vectors " << center << "; number of atoms " << connectedAtoms.size()
     2934    << "; scale factor " << 1.0/connectedAtoms.size();
     2935
     2936  center.Scale(1.0/connectedAtoms.size());
     2937  listRunner = connectedAtoms.begin();
     2938
     2939  cout << " calculated center " << center <<  endl;
     2940
     2941  // construct one orthogonal vector
     2942  helper.CopyVector(&AtomToCheck->x);
     2943  helper.ProjectOntoPlane(&planeNorm);
     2944  OrthogonalVector.MakeNormalVector(&center, &helper, &(*listRunner)->x);
     2945  while (listRunner != connectedAtoms.end()) {
     2946    double angle = getAngle((*listRunner)->x, AtomToCheck->x, center, OrthogonalVector);
     2947    cout << "Calculated angle " << angle << " for atom " << **listRunner << endl;
     2948    anglesOfAtoms.insert(pair<double, atom*>(angle, (*listRunner)));
     2949    listRunner++;
     2950  }
     2951
     2952  list<atom*> *result = new list<atom*>;
     2953  runner = anglesOfAtoms.begin();
     2954  cout << "First value is " << *runner->second << endl;
     2955  result->push_back(runner->second);
     2956  runner = anglesOfAtoms.end();
     2957  runner--;
     2958  cout << "Second value is " << *runner->second << endl;
     2959  result->push_back(runner->second);
     2960
     2961  cout << "List of closest atoms has " << result->size() << " elements, which are "
     2962    << *(result->front()) << " and " << *(result->back()) << endl;
     2963
     2964  return result;
     2965}
     2966
     2967/**
     2968 * Finds triangles belonging to the three provided atoms.
     2969 *
     2970 * @param atom list, is expected to contain three atoms
     2971 *
     2972 * @return triangles which belong to the provided atoms, will be empty if there are none,
     2973 *         will usually be one, in case of degeneration, there will be two
     2974 */
     2975list<BoundaryTriangleSet*> *Tesselation::FindTriangles(atom* Points[3]) {
     2976  list<BoundaryTriangleSet*> *result = new list<BoundaryTriangleSet*>;
     2977  LineMap::iterator FindLine;
     2978  PointMap::iterator FindPoint;
     2979  TriangleMap::iterator FindTriangle;
     2980  class BoundaryPointSet *TrianglePoints[3];
     2981
     2982  for (int i = 0; i < 3; i++) {
     2983    FindPoint = PointsOnBoundary.find(Points[i]->nr);
     2984    if (FindPoint != PointsOnBoundary.end()) {
     2985      TrianglePoints[i] = FindPoint->second;
     2986    } else {
     2987      TrianglePoints[i] = NULL;
     2988    }
     2989  }
     2990
     2991  // checks lines between the points in the Points for their adjacent triangles
     2992  for (int i = 0; i < 3; i++) {
     2993    if (TrianglePoints[i] != NULL) {
     2994      for (int j = i; j < 3; j++) {
     2995        if (TrianglePoints[j] != NULL) {
     2996          FindLine = TrianglePoints[i]->lines.find(TrianglePoints[j]->node->nr);
     2997          if (FindLine != TrianglePoints[i]->lines.end()) {
     2998            for (; FindLine->first == TrianglePoints[j]->node->nr; FindLine++) {
     2999              FindTriangle = FindLine->second->triangles.begin();
     3000              for (; FindTriangle != FindLine->second->triangles.end(); FindTriangle++) {
     3001                if ((
     3002                  (FindTriangle->second->endpoints[0] == TrianglePoints[0])
     3003                    || (FindTriangle->second->endpoints[0] == TrianglePoints[1])
     3004                    || (FindTriangle->second->endpoints[0] == TrianglePoints[2])
     3005                  ) && (
     3006                    (FindTriangle->second->endpoints[1] == TrianglePoints[0])
     3007                    || (FindTriangle->second->endpoints[1] == TrianglePoints[1])
     3008                    || (FindTriangle->second->endpoints[1] == TrianglePoints[2])
     3009                  ) && (
     3010                    (FindTriangle->second->endpoints[2] == TrianglePoints[0])
     3011                    || (FindTriangle->second->endpoints[2] == TrianglePoints[1])
     3012                    || (FindTriangle->second->endpoints[2] == TrianglePoints[2])
     3013                  )
     3014                ) {
     3015                  result->push_back(FindTriangle->second);
     3016                }
     3017              }
     3018            }
     3019            // Is it sufficient to consider one of the triangle lines for this.
     3020            return result;
     3021
     3022          }
     3023        }
     3024      }
     3025    }
     3026  }
     3027
     3028  return result;
     3029}
     3030
     3031/**
     3032 * Gets the angle between a point and a reference relative to the provided center.
     3033 *
     3034 * @param point to calculate the angle for
     3035 * @param reference to which to calculate the angle
     3036 * @param center for which to calculate the angle between the vectors
     3037 * @param OrthogonalVector helps discern between [0,pi] and [pi,2pi] in acos()
     3038 *
     3039 * @return angle between point and reference
     3040 */
     3041double getAngle(Vector point, Vector reference, Vector center, Vector OrthogonalVector) {
     3042  Vector ReferenceVector, helper;
     3043  cout << Verbose(2) << reference << " is our reference " << endl;
     3044  cout << Verbose(2) << center << " is our center " << endl;
     3045  // create baseline vector
     3046  ReferenceVector.CopyVector(&reference);
     3047  ReferenceVector.SubtractVector(&center);
     3048  if (ReferenceVector.IsNull())
     3049    return M_PI;
     3050
     3051  // calculate both angles and correct with in-plane vector
     3052  helper.CopyVector(&point);
     3053  helper.SubtractVector(&center);
     3054  if (helper.IsNull())
     3055    return M_PI;
     3056  double phi = ReferenceVector.Angle(&helper);
     3057  if (OrthogonalVector.ScalarProduct(&helper) > 0) {
     3058    phi = 2.*M_PI - phi;
     3059  }
     3060
     3061  cout << Verbose(2) << point << " has angle " << phi << endl;
     3062
     3063  return phi;
     3064}
     3065
     3066/**
     3067 * Checks whether the provided point is within the tesselation structure.
     3068 *
     3069 * This is a wrapper function for IsInnerAtom, so it can be used with a simple
     3070 * vector, too.
     3071 *
     3072 * @param point of which to check the position
     3073 * @param tesselation structure
     3074 *
     3075 * @return true if the point is inside the tesselation structure, false otherwise
     3076 */
     3077bool IsInnerPoint(Vector Point, class Tesselation *Tess, LinkedCell* LC) {
     3078  atom *temp_atom = new atom;
     3079  bool status = false;
     3080  temp_atom->x.CopyVector(&Point);
     3081
     3082  status = IsInnerAtom(temp_atom, Tess, LC);
     3083  delete(temp_atom);
     3084
     3085  return status;
     3086}
    8153087
    8163088/** Tesselates the non convex boundary by rolling a virtual sphere along the surface of the molecule.
     
    8183090 * \param *mol molecule structure with Atom's and Bond's
    8193091 * \param *Tess Tesselation filled with points, lines and triangles on boundary on return
    820  * \param *LCList atoms in LinkedCell list
    8213092 * \param *filename filename prefix for output of vertex data
    8223093 * \para RADIUS radius of the virtual sphere
     
    8273098  bool freeTess = false;
    8283099  bool freeLC = false;
    829   ofstream *tempstream = NULL;
    830   char NumberName[255];
    831   int TriangleFilesWritten = 0;
    832 
    8333100  *out << Verbose(1) << "Entering search for non convex hull. " << endl;
    8343101  if (Tess == NULL) {
     
    8483115  }
    8493116
    850   Tess->Find_starting_triangle(out, RADIUS, LCList);
     3117  Tess->Find_starting_triangle(out, mol, RADIUS, LCList);
    8513118
    8523119  baseline = Tess->LinesOnBoundary.begin();
    8533120  while ((baseline != Tess->LinesOnBoundary.end()) || (flag)) {
    8543121    if (baseline->second->TrianglesCount == 1) {
    855       failflag = Tess->Find_next_suitable_triangle(out, *(baseline->second), *(((baseline->second->triangles.begin()))->second), RADIUS, N, LCList); //the line is there, so there is a triangle, but only one.
     3122      failflag = Tess->Find_next_suitable_triangle(out, mol, *(baseline->second), *(((baseline->second->triangles.begin()))->second), RADIUS, N, filename, LCList); //the line is there, so there is a triangle, but only one.
    8563123      flag = flag || failflag;
    8573124      if (!failflag)
     
    8693136      flag = false;
    8703137    }
    871 
    872     // write temporary envelope
    873     if ((DoSingleStepOutput && (Tess->TrianglesOnBoundaryCount % 1 == 0))) { // if we have a new triangle and want to output each new triangle configuration
    874       class BoundaryTriangleSet *triangle = (Tess->TrianglesOnBoundary.end()--)->second;
    875       sprintf(NumberName, "-%04d-%s_%s_%s", TriangleFilesWritten, triangle->endpoints[0]->node->Name, triangle->endpoints[1]->node->Name, triangle->endpoints[2]->node->Name);
    876       if (DoTecplotOutput) {
    877         string NameofTempFile(filename);
    878         NameofTempFile.append(NumberName);
    879         for(size_t npos = NameofTempFile.find_first_of(' '); npos != string::npos; npos = NameofTempFile.find(' ', npos))
    880         NameofTempFile.erase(npos, 1);
    881         NameofTempFile.append(TecplotSuffix);
    882         cout << Verbose(1) << "Writing temporary non convex hull to file " << NameofTempFile << ".\n";
    883         tempstream = new ofstream(NameofTempFile.c_str(), ios::trunc);
    884         write_tecplot_file(out, tempstream, Tess, mol, TriangleFilesWritten);
    885         tempstream->close();
    886         tempstream->flush();
    887         delete(tempstream);
    888       }
    889 
    890       if (DoRaster3DOutput) {
    891         string NameofTempFile(filename);
    892         NameofTempFile.append(NumberName);
    893         for(size_t npos = NameofTempFile.find_first_of(' '); npos != string::npos; npos = NameofTempFile.find(' ', npos))
    894         NameofTempFile.erase(npos, 1);
    895         NameofTempFile.append(Raster3DSuffix);
    896         cout << Verbose(1) << "Writing temporary non convex hull to file " << NameofTempFile << ".\n";
    897         tempstream = new ofstream(NameofTempFile.c_str(), ios::trunc);
    898         write_raster3d_file(out, tempstream, Tess, mol);
    899 //        // include the current position of the virtual sphere in the temporary raster3d file
    900 //        // make the circumsphere's center absolute again
    901 //        helper.CopyVector(BaseRay->endpoints[0]->node->node);
    902 //        helper.AddVector(BaseRay->endpoints[1]->node->node);
    903 //        helper.Scale(0.5);
    904 //        (*it)->OptCenter.AddVector(&helper);
    905 //        Vector *center = mol->DetermineCenterOfAll(out);
    906 //        (*it)->OptCenter.SubtractVector(center);
    907 //        delete(center);
    908 //        // and add to file plus translucency object
    909 //        *tempstream << "# current virtual sphere\n";
    910 //        *tempstream << "8\n  25.0    0.6     -1.0 -1.0 -1.0     0.2        0 0 0 0\n";
    911 //        *tempstream << "2\n  " << (*it)->OptCenter.x[0] << " "
    912 //          << (*it)->OptCenter.x[1] << " " << (*it)->OptCenter.x[2]
    913 //          << "\t" << RADIUS << "\t1 0 0\n";
    914 //        *tempstream << "9\n  terminating special property\n";
    915         tempstream->close();
    916         tempstream->flush();
    917         delete(tempstream);
    918       }
    919       if (DoTecplotOutput || DoRaster3DOutput)
    920         TriangleFilesWritten++;
    921     }
    922   }
    923 
    924   // write final envelope
    925   if (filename != 0) {
     3138  }
     3139  if (1) { //failflag) {
    9263140    *out << Verbose(1) << "Writing final tecplot file\n";
    9273141    if (DoTecplotOutput) {
     
    9563170    cout << Verbose(2) << "None." << endl;
    9573171
     3172  // Tests the IsInnerAtom() function.
     3173  Vector x (0, 0, 0);
     3174  cout << Verbose(0) << "Point to check: " << x << endl;
     3175  cout << Verbose(0) << "Check: IsInnerPoint() returns " << IsInnerPoint(x, Tess, LCList)
     3176    << "for vector " << x << "." << endl;
     3177  atom* a = Tess->PointsOnBoundary.begin()->second->node;
     3178  cout << Verbose(0) << "Point to check: " << *a << " (on boundary)." << endl;
     3179  cout << Verbose(0) << "Check: IsInnerAtom() returns " << IsInnerAtom(a, Tess, LCList)
     3180    << "for atom " << a << " (on boundary)." << endl;
     3181  LinkedAtoms *List = NULL;
     3182  for (int i=0;i<NDIM;i++) { // each axis
     3183    LCList->n[i] = LCList->N[i]-1; // current axis is topmost cell
     3184    for (LCList->n[(i+1)%NDIM]=0;LCList->n[(i+1)%NDIM]<LCList->N[(i+1)%NDIM];LCList->n[(i+1)%NDIM]++)
     3185      for (LCList->n[(i+2)%NDIM]=0;LCList->n[(i+2)%NDIM]<LCList->N[(i+2)%NDIM];LCList->n[(i+2)%NDIM]++) {
     3186        List = LCList->GetCurrentCell();
     3187        //cout << Verbose(2) << "Current cell is " << LC->n[0] << ", " << LC->n[1] << ", " << LC->n[2] << " with No. " << LC->index << "." << endl;
     3188        if (List != NULL) {
     3189          for (LinkedAtoms::iterator Runner = List->begin();Runner != List->end();Runner++) {
     3190            if (Tess->PointsOnBoundary.find((*Runner)->nr) == Tess->PointsOnBoundary.end()) {
     3191              a = *Runner;
     3192              i=3;
     3193              for (int j=0;j<NDIM;j++)
     3194                LCList->n[j] = LCList->N[j];
     3195              break;
     3196            }
     3197          }
     3198        }
     3199      }
     3200  }
     3201  cout << Verbose(0) << "Check: IsInnerAtom() returns " << IsInnerAtom(a, Tess, LCList)
     3202    << "for atom " << a << " (inside)." << endl;
     3203
     3204
    9583205  if (freeTess)
    9593206    delete(Tess);
Note: See TracChangeset for help on using the changeset viewer.