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