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