| [8eb17a] | 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 |  | 
|---|
| [e9b8bb] | 153 | void BoundaryTriangleSet::GetNormalVector(Vector &NormalVector) | 
|---|
| [8eb17a] | 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 |  | 
|---|
| [6c5812] | 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 | */ | 
|---|
| [8eb17a] | 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; | 
|---|
| [e9b8bb] | 213 | Vector AxisVector, AngleReferenceVector, AngleReferenceNormalVector; | 
|---|
| [8eb17a] | 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; | 
|---|
| [e9b8bb] | 235 | Vector ProjectedVector; | 
|---|
| [8eb17a] | 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; | 
|---|
| [ed060e] | 254 | BoundaryTestPair = BoundaryPoints[axis].insert( BoundariesPair (angle, DistancePair (radius, Walker) ) ); | 
|---|
| [8eb17a] | 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 | { | 
|---|
| [e9b8bb] | 318 | Vector SideA, SideB, SideC, SideH; | 
|---|
| [8eb17a] | 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 | 
|---|
| [318bfd] | 374 | * \param *mol molecule structure representing the cluster | 
|---|
| [8eb17a] | 375 | * \param IsAngstroem whether we have angstroem or atomic units | 
|---|
|  | 376 | * \return NDIM array of the diameters | 
|---|
|  | 377 | */ | 
|---|
| [318bfd] | 378 | double * GetDiametersOfCluster(ofstream *out, Boundaries *BoundaryPtr, molecule *mol, bool IsAngstroem) | 
|---|
| [8eb17a] | 379 | { | 
|---|
| [318bfd] | 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 |  | 
|---|
| [8eb17a] | 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; | 
|---|
| [e9b8bb] | 396 | Vector DistanceVector, OtherVector; | 
|---|
| [8eb17a] | 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 |  | 
|---|
| [318bfd] | 447 | // free reference lists | 
|---|
|  | 448 | if (BoundaryFreeFlag) | 
|---|
|  | 449 | delete[](BoundaryPoints); | 
|---|
|  | 450 |  | 
|---|
| [8eb17a] | 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 | 
|---|
| [450d63] | 458 | * \param *tecplot output stream for tecplot data | 
|---|
| [8eb17a] | 459 | * \param *configuration needed for path to store convex envelope file | 
|---|
| [6c5812] | 460 | * \param *BoundaryPoints NDIM set of boundary points on the projected plane per axis, on return if desired | 
|---|
| [8eb17a] | 461 | * \param *mol molecule structure representing the cluster | 
|---|
| [450d63] | 462 | * \return determined volume of the cluster in cubed config:GetIsAngstroem() | 
|---|
| [8eb17a] | 463 | */ | 
|---|
| [450d63] | 464 | double VolumeOfConvexEnvelope(ofstream *out, ofstream *tecplot, config *configuration, Boundaries *BoundaryPtr, molecule *mol) | 
|---|
| [8eb17a] | 465 | { | 
|---|
|  | 466 | bool IsAngstroem = configuration->GetIsAngstroem(); | 
|---|
|  | 467 | atom *Walker = NULL; | 
|---|
|  | 468 | struct Tesselation *TesselStruct = new Tesselation; | 
|---|
| [6c5812] | 469 | bool BoundaryFreeFlag = false; | 
|---|
|  | 470 | Boundaries *BoundaryPoints = BoundaryPtr; | 
|---|
| [318bfd] | 471 | double volume = 0.; | 
|---|
|  | 472 | double PyramidVolume = 0.; | 
|---|
|  | 473 | double G,h; | 
|---|
| [e9b8bb] | 474 | Vector x,y; | 
|---|
| [318bfd] | 475 | double a,b,c; | 
|---|
|  | 476 |  | 
|---|
| [8eb17a] | 477 | // 1. calculate center of gravity | 
|---|
|  | 478 | *out << endl; | 
|---|
| [e9b8bb] | 479 | Vector *CenterOfGravity = mol->DetermineCenterOfGravity(out); | 
|---|
| [8eb17a] | 480 |  | 
|---|
|  | 481 | // 2. translate all points into CoG | 
|---|
|  | 482 | *out << Verbose(1) << "Translating system to Center of Gravity." << endl; | 
|---|
|  | 483 | Walker = mol->start; | 
|---|
|  | 484 | while (Walker->next != mol->end) { | 
|---|
|  | 485 | Walker = Walker->next; | 
|---|
|  | 486 | Walker->x.Translate(CenterOfGravity); | 
|---|
|  | 487 | } | 
|---|
|  | 488 |  | 
|---|
|  | 489 | // 3. Find all points on the boundary | 
|---|
| [6c5812] | 490 | if (BoundaryPoints == NULL) { | 
|---|
|  | 491 | BoundaryFreeFlag = true; | 
|---|
|  | 492 | BoundaryPoints = GetBoundaryPoints(out, mol); | 
|---|
|  | 493 | } else { | 
|---|
|  | 494 | *out << Verbose(1) << "Using given boundary points set." << endl; | 
|---|
|  | 495 | } | 
|---|
| [8eb17a] | 496 |  | 
|---|
| [318bfd] | 497 | // 4. fill the boundary point list | 
|---|
|  | 498 | for (int axis=0;axis<NDIM;axis++) | 
|---|
| [8eb17a] | 499 | for(Boundaries::iterator runner = BoundaryPoints[axis].begin(); runner != BoundaryPoints[axis].end(); runner++) { | 
|---|
| [318bfd] | 500 | TesselStruct->AddPoint(runner->second.second); | 
|---|
| [8eb17a] | 501 | } | 
|---|
|  | 502 |  | 
|---|
|  | 503 | *out << Verbose(2) << "I found " << TesselStruct->PointsOnBoundaryCount << " points on the convex boundary." << endl; | 
|---|
|  | 504 | // now we have the whole set of edge points in the BoundaryList | 
|---|
|  | 505 |  | 
|---|
|  | 506 | // listing for debugging | 
|---|
|  | 507 | //  *out << Verbose(1) << "Listing PointsOnBoundary:"; | 
|---|
|  | 508 | //  for(PointMap::iterator runner = PointsOnBoundary.begin(); runner != PointsOnBoundary.end(); runner++) { | 
|---|
|  | 509 | //    *out << " " << *runner->second; | 
|---|
|  | 510 | //  } | 
|---|
|  | 511 | //  *out << endl; | 
|---|
|  | 512 |  | 
|---|
| [318bfd] | 513 | // 5a. guess starting triangle | 
|---|
| [8eb17a] | 514 | TesselStruct->GuessStartingTriangle(out); | 
|---|
|  | 515 |  | 
|---|
| [318bfd] | 516 | // 5b. go through all lines, that are not yet part of two triangles (only of one so far) | 
|---|
| [8eb17a] | 517 | TesselStruct->TesselateOnBoundary(out, configuration, mol); | 
|---|
|  | 518 |  | 
|---|
|  | 519 | *out << Verbose(2) << "I created " << TesselStruct->TrianglesOnBoundaryCount << " triangles with " << TesselStruct->LinesOnBoundaryCount << " lines and " << TesselStruct->PointsOnBoundaryCount << " points." << endl; | 
|---|
|  | 520 |  | 
|---|
|  | 521 | // 6a. Every triangle forms a pyramid with the center of gravity as its peak, sum up the volumes | 
|---|
|  | 522 | *out << Verbose(1) << "Calculating the volume of the pyramids formed out of triangles and center of gravity." << endl; | 
|---|
|  | 523 | 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 | 
|---|
|  | 524 | x.CopyVector(&runner->second->endpoints[0]->node->x); | 
|---|
|  | 525 | x.SubtractVector(&runner->second->endpoints[1]->node->x); | 
|---|
|  | 526 | y.CopyVector(&runner->second->endpoints[0]->node->x); | 
|---|
|  | 527 | y.SubtractVector(&runner->second->endpoints[2]->node->x); | 
|---|
|  | 528 | a = sqrt(runner->second->endpoints[0]->node->x.Distance(&runner->second->endpoints[1]->node->x)); | 
|---|
|  | 529 | b = sqrt(runner->second->endpoints[0]->node->x.Distance(&runner->second->endpoints[2]->node->x)); | 
|---|
|  | 530 | c = sqrt(runner->second->endpoints[2]->node->x.Distance(&runner->second->endpoints[1]->node->x)); | 
|---|
|  | 531 | 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 | 
|---|
|  | 532 | x.MakeNormalVector(&runner->second->endpoints[0]->node->x, &runner->second->endpoints[1]->node->x, &runner->second->endpoints[2]->node->x); | 
|---|
|  | 533 | x.Scale(runner->second->endpoints[1]->node->x.Projection(&x)); | 
|---|
|  | 534 | h = x.Norm(); // distance of CoG to triangle | 
|---|
|  | 535 | PyramidVolume = (1./3.) * G * h;    // this formula holds for _all_ pyramids (independent of n-edge base or (not) centered peak) | 
|---|
|  | 536 | *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; | 
|---|
|  | 537 | volume += PyramidVolume; | 
|---|
|  | 538 | } | 
|---|
|  | 539 | *out << Verbose(0) << "RESULT: The summed volume is " << setprecision(10) << volume << " " << (IsAngstroem ? "angstrom" : "atomiclength") << "^3." << endl; | 
|---|
|  | 540 |  | 
|---|
|  | 541 |  | 
|---|
|  | 542 | // 7. translate all points back from CoG | 
|---|
|  | 543 | *out << Verbose(1) << "Translating system back from Center of Gravity." << endl; | 
|---|
|  | 544 | CenterOfGravity->Scale(-1); | 
|---|
|  | 545 | Walker = mol->start; | 
|---|
|  | 546 | while (Walker->next != mol->end) { | 
|---|
|  | 547 | Walker = Walker->next; | 
|---|
|  | 548 | Walker->x.Translate(CenterOfGravity); | 
|---|
|  | 549 | } | 
|---|
| [450d63] | 550 |  | 
|---|
|  | 551 | // 8. Store triangles in tecplot file | 
|---|
|  | 552 | if (tecplot != NULL) { | 
|---|
|  | 553 | *tecplot << "TITLE = \"3D CONVEX SHELL\"" << endl; | 
|---|
|  | 554 | *tecplot << "VARIABLES = \"X\" \"Y\" \"Z\"" << endl; | 
|---|
|  | 555 | *tecplot << "ZONE T=\"TRIANGLES\", N=" <<  TesselStruct->PointsOnBoundaryCount << ", E=" <<  TesselStruct->TrianglesOnBoundaryCount << ", DATAPACKING=POINT, ZONETYPE=FETRIANGLE" << endl; | 
|---|
|  | 556 | int *LookupList = new int[mol->AtomCount]; | 
|---|
|  | 557 | for (int i=0;i<mol->AtomCount;i++) | 
|---|
|  | 558 | LookupList[i] = -1; | 
|---|
|  | 559 |  | 
|---|
|  | 560 | // print atom coordinates | 
|---|
|  | 561 | *out << Verbose(2) << "The following triangles were created:"; | 
|---|
|  | 562 | int Counter = 1; | 
|---|
|  | 563 | atom *Walker = NULL; | 
|---|
|  | 564 | for (PointMap::iterator target =  TesselStruct->PointsOnBoundary.begin(); target !=  TesselStruct->PointsOnBoundary.end(); target++) { | 
|---|
|  | 565 | Walker = target->second->node; | 
|---|
|  | 566 | LookupList[Walker->nr] = Counter++; | 
|---|
|  | 567 | *tecplot << Walker->x.x[0] << " " << Walker->x.x[1] << " " << Walker->x.x[2] << " " << endl; | 
|---|
|  | 568 | } | 
|---|
|  | 569 | *tecplot << endl; | 
|---|
|  | 570 | // print connectivity | 
|---|
|  | 571 | for (TriangleMap::iterator runner =  TesselStruct->TrianglesOnBoundary.begin(); runner !=  TesselStruct->TrianglesOnBoundary.end(); runner++) { | 
|---|
|  | 572 | *out << " " << runner->second->endpoints[0]->node->Name << "<->" << runner->second->endpoints[1]->node->Name << "<->" << runner->second->endpoints[2]->node->Name; | 
|---|
|  | 573 | *tecplot << LookupList[runner->second->endpoints[0]->node->nr] << " " << LookupList[runner->second->endpoints[1]->node->nr] << " " << LookupList[runner->second->endpoints[2]->node->nr] << endl; | 
|---|
|  | 574 | } | 
|---|
|  | 575 | delete[](LookupList); | 
|---|
|  | 576 | *out << endl; | 
|---|
|  | 577 | } | 
|---|
| [8eb17a] | 578 |  | 
|---|
|  | 579 | // free reference lists | 
|---|
| [6c5812] | 580 | if (BoundaryFreeFlag) | 
|---|
|  | 581 | delete[](BoundaryPoints); | 
|---|
|  | 582 |  | 
|---|
| [8eb17a] | 583 | return volume; | 
|---|
|  | 584 | }; | 
|---|
|  | 585 |  | 
|---|
|  | 586 |  | 
|---|
|  | 587 | /** Creates multiples of the by \a *mol given cluster and suspends them in water with a given final density. | 
|---|
| [6c5812] | 588 | * We get cluster volume by VolumeOfConvexEnvelope() and its diameters by GetDiametersOfCluster() | 
|---|
| [8eb17a] | 589 | * \param *out output stream for debugging | 
|---|
|  | 590 | * \param *configuration needed for path to store convex envelope file | 
|---|
|  | 591 | * \param *mol molecule structure representing the cluster | 
|---|
| [edb650] | 592 | * \param ClusterVolume guesstimated cluster volume, if equal 0 we used VolumeOfConvexEnvelope() instead. | 
|---|
| [8eb17a] | 593 | * \param celldensity desired average density in final cell | 
|---|
|  | 594 | */ | 
|---|
| [edb650] | 595 | void PrepareClustersinWater(ofstream *out, config *configuration, molecule *mol, double ClusterVolume, double celldensity) | 
|---|
| [8eb17a] | 596 | { | 
|---|
| [318bfd] | 597 | // transform to PAS | 
|---|
|  | 598 | mol->PrincipalAxisSystem(out, true); | 
|---|
|  | 599 |  | 
|---|
| [6c5812] | 600 | // some preparations beforehand | 
|---|
| [8eb17a] | 601 | bool IsAngstroem = configuration->GetIsAngstroem(); | 
|---|
| [6c5812] | 602 | Boundaries *BoundaryPoints = GetBoundaryPoints(out, mol); | 
|---|
| [edb650] | 603 | double clustervolume; | 
|---|
|  | 604 | if (ClusterVolume == 0) | 
|---|
| [450d63] | 605 | clustervolume = VolumeOfConvexEnvelope(out, NULL, configuration, BoundaryPoints, mol); | 
|---|
| [edb650] | 606 | else | 
|---|
|  | 607 | clustervolume = ClusterVolume; | 
|---|
| [318bfd] | 608 | double *GreatestDiameter = GetDiametersOfCluster(out, BoundaryPoints, mol, IsAngstroem); | 
|---|
| [e9b8bb] | 609 | Vector BoxLengths; | 
|---|
| [318bfd] | 610 | int repetition[NDIM] = {1, 1, 1}; | 
|---|
| [6c5812] | 611 | int TotalNoClusters = 1; | 
|---|
|  | 612 | for (int i=0;i<NDIM;i++) | 
|---|
|  | 613 | TotalNoClusters *= repetition[i]; | 
|---|
|  | 614 |  | 
|---|
| [8eb17a] | 615 | // sum up the atomic masses | 
|---|
|  | 616 | double totalmass = 0.; | 
|---|
|  | 617 | atom *Walker = mol->start; | 
|---|
|  | 618 | while (Walker->next != mol->end) { | 
|---|
|  | 619 | Walker = Walker->next; | 
|---|
|  | 620 | totalmass += Walker->type->mass; | 
|---|
|  | 621 | } | 
|---|
|  | 622 | *out << Verbose(0) << "RESULT: The summed mass is " << setprecision(10) << totalmass << " atomicmassunit." << endl; | 
|---|
|  | 623 |  | 
|---|
|  | 624 | *out << Verbose(0) << "RESULT: The average density is " << setprecision(10) << totalmass/clustervolume << " atomicmassunit/" << (IsAngstroem ? "angstrom" : "atomiclength") << "^3." << endl; | 
|---|
|  | 625 |  | 
|---|
|  | 626 | // solve cubic polynomial | 
|---|
|  | 627 | *out << Verbose(1) << "Solving equidistant suspension in water problem ..." << endl; | 
|---|
|  | 628 | double cellvolume; | 
|---|
|  | 629 | if (IsAngstroem) | 
|---|
| [6c5812] | 630 | cellvolume = (TotalNoClusters*totalmass/SOLVENTDENSITY_A - (totalmass/clustervolume))/(celldensity-1); | 
|---|
| [8eb17a] | 631 | else | 
|---|
| [6c5812] | 632 | cellvolume = (TotalNoClusters*totalmass/SOLVENTDENSITY_a0 - (totalmass/clustervolume))/(celldensity-1); | 
|---|
| [8eb17a] | 633 | *out << Verbose(1) << "Cellvolume needed for a density of " << celldensity << " g/cm^3 is " << cellvolume << " " << (IsAngstroem ? "angstrom" : "atomiclength") << "^3." << endl; | 
|---|
| [318bfd] | 634 |  | 
|---|
| [6c5812] | 635 | double minimumvolume = TotalNoClusters*(GreatestDiameter[0]*GreatestDiameter[1]*GreatestDiameter[2]); | 
|---|
| [8eb17a] | 636 | *out << Verbose(1) << "Minimum volume of the convex envelope contained in a rectangular box is " << minimumvolume << " atomicmassunit/" << (IsAngstroem ? "angstrom" : "atomiclength") << "^3." << endl; | 
|---|
| [edb650] | 637 | if (minimumvolume > cellvolume) { | 
|---|
| [8eb17a] | 638 | cerr << Verbose(0) << "ERROR: the containing box already has a greater volume than the envisaged cell volume!" << endl; | 
|---|
| [edb650] | 639 | cout << Verbose(0) << "Setting Box dimensions to minimum possible, the greatest diameters." << endl; | 
|---|
|  | 640 | for(int i=0;i<NDIM;i++) | 
|---|
|  | 641 | BoxLengths.x[i] = GreatestDiameter[i]; | 
|---|
|  | 642 | mol->CenterEdge(out, &BoxLengths); | 
|---|
|  | 643 | } else { | 
|---|
|  | 644 | BoxLengths.x[0] = (repetition[0]*GreatestDiameter[0] + repetition[1]*GreatestDiameter[1] + repetition[2]*GreatestDiameter[2]); | 
|---|
|  | 645 | BoxLengths.x[1] = (repetition[0]*repetition[1]*GreatestDiameter[0]*GreatestDiameter[1] | 
|---|
|  | 646 | + repetition[0]*repetition[2]*GreatestDiameter[0]*GreatestDiameter[2] | 
|---|
|  | 647 | + repetition[1]*repetition[2]*GreatestDiameter[1]*GreatestDiameter[2]); | 
|---|
|  | 648 | BoxLengths.x[2] = minimumvolume - cellvolume; | 
|---|
|  | 649 | double x0 = 0.,x1 = 0.,x2 = 0.; | 
|---|
|  | 650 | if (gsl_poly_solve_cubic(BoxLengths.x[0],BoxLengths.x[1],BoxLengths.x[2],&x0,&x1,&x2) == 1) // either 1 or 3 on return | 
|---|
|  | 651 | *out << Verbose(0) << "RESULT: The resulting spacing is: " << x0 << " ." << endl; | 
|---|
|  | 652 | else { | 
|---|
|  | 653 | *out << Verbose(0) << "RESULT: The resulting spacings are: " << x0 << " and " << x1 << " and " << x2 << " ." << endl; | 
|---|
|  | 654 | x0 = x2;  // sorted in ascending order | 
|---|
|  | 655 | } | 
|---|
| [6c5812] | 656 |  | 
|---|
| [edb650] | 657 | cellvolume = 1; | 
|---|
|  | 658 | for(int i=0;i<NDIM;i++) { | 
|---|
|  | 659 | BoxLengths.x[i] = repetition[i] * (x0 + GreatestDiameter[i]); | 
|---|
|  | 660 | cellvolume *= BoxLengths.x[i]; | 
|---|
|  | 661 | } | 
|---|
| [318bfd] | 662 |  | 
|---|
| [edb650] | 663 | // set new box dimensions | 
|---|
|  | 664 | *out << Verbose(0) << "Translating to box with these boundaries." << endl; | 
|---|
|  | 665 | mol->CenterInBox((ofstream *)&cout, &BoxLengths); | 
|---|
|  | 666 | } | 
|---|
| [318bfd] | 667 | // update Box of atoms by boundary | 
|---|
|  | 668 | mol->SetBoxDimension(&BoxLengths); | 
|---|
| [edb650] | 669 | *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; | 
|---|
| [8eb17a] | 670 | }; | 
|---|
|  | 671 |  | 
|---|
|  | 672 |  | 
|---|
|  | 673 | // =========================================================== class TESSELATION =========================================== | 
|---|
|  | 674 |  | 
|---|
|  | 675 | /** Constructor of class Tesselation. | 
|---|
|  | 676 | */ | 
|---|
|  | 677 | Tesselation::Tesselation() | 
|---|
|  | 678 | { | 
|---|
|  | 679 | PointsOnBoundaryCount = 0; | 
|---|
|  | 680 | LinesOnBoundaryCount = 0; | 
|---|
|  | 681 | TrianglesOnBoundaryCount = 0; | 
|---|
|  | 682 | }; | 
|---|
|  | 683 |  | 
|---|
|  | 684 | /** Constructor of class Tesselation. | 
|---|
|  | 685 | * We have to free all points, lines and triangles. | 
|---|
|  | 686 | */ | 
|---|
|  | 687 | Tesselation::~Tesselation() | 
|---|
|  | 688 | { | 
|---|
|  | 689 | for (TriangleMap::iterator runner = TrianglesOnBoundary.begin(); runner != TrianglesOnBoundary.end(); runner++) { | 
|---|
|  | 690 | delete(runner->second); | 
|---|
|  | 691 | } | 
|---|
|  | 692 | }; | 
|---|
|  | 693 |  | 
|---|
|  | 694 | /** Gueses first starting triangle of the convex envelope. | 
|---|
|  | 695 | * We guess the starting triangle by taking the smallest distance between two points and looking for a fitting third. | 
|---|
|  | 696 | * \param *out output stream for debugging | 
|---|
|  | 697 | * \param PointsOnBoundary set of boundary points defining the convex envelope of the cluster | 
|---|
|  | 698 | */ | 
|---|
|  | 699 | void Tesselation::GuessStartingTriangle(ofstream *out) | 
|---|
|  | 700 | { | 
|---|
|  | 701 | // 4b. create a starting triangle | 
|---|
|  | 702 | // 4b1. create all distances | 
|---|
|  | 703 | DistanceMultiMap DistanceMMap; | 
|---|
| [2b4a40] | 704 | double distance, tmp; | 
|---|
|  | 705 | Vector PlaneVector, TrialVector; | 
|---|
|  | 706 | PointMap::iterator A, B, C; // three nodes of the first triangle | 
|---|
|  | 707 | A = PointsOnBoundary.begin(); // the first may be chosen arbitrarily | 
|---|
|  | 708 |  | 
|---|
|  | 709 | // with A chosen, take each pair B,C and sort | 
|---|
|  | 710 | if (A != PointsOnBoundary.end()) { | 
|---|
|  | 711 | B = A; | 
|---|
|  | 712 | B++; | 
|---|
|  | 713 | for (; B != PointsOnBoundary.end(); B++) { | 
|---|
|  | 714 | C = B; | 
|---|
|  | 715 | C++; | 
|---|
|  | 716 | for (; C != PointsOnBoundary.end(); C++) { | 
|---|
|  | 717 | tmp = A->second->node->x.Distance(&B->second->node->x); | 
|---|
|  | 718 | distance = tmp*tmp; | 
|---|
|  | 719 | tmp = A->second->node->x.Distance(&C->second->node->x); | 
|---|
|  | 720 | distance += tmp*tmp; | 
|---|
|  | 721 | tmp = B->second->node->x.Distance(&C->second->node->x); | 
|---|
|  | 722 | distance += tmp*tmp; | 
|---|
|  | 723 | DistanceMMap.insert( DistanceMultiMapPair(distance, pair<PointMap::iterator, PointMap::iterator>(B,C) ) ); | 
|---|
| [8eb17a] | 724 | } | 
|---|
|  | 725 | } | 
|---|
|  | 726 | } | 
|---|
|  | 727 | //    // listing distances | 
|---|
|  | 728 | //    *out << Verbose(1) << "Listing DistanceMMap:"; | 
|---|
|  | 729 | //    for(DistanceMultiMap::iterator runner = DistanceMMap.begin(); runner != DistanceMMap.end(); runner++) { | 
|---|
|  | 730 | //      *out << " " << runner->first << "(" << *runner->second.first->second << ", " << *runner->second.second->second << ")"; | 
|---|
|  | 731 | //    } | 
|---|
|  | 732 | //    *out << endl; | 
|---|
|  | 733 |  | 
|---|
| [2b4a40] | 734 | // 4b2. pick three baselines forming a triangle | 
|---|
|  | 735 | // 1. we take from the smallest sum of squared distance as the base line BC (with peak A) onward as the triangle candidate | 
|---|
| [8eb17a] | 736 | DistanceMultiMap::iterator baseline = DistanceMMap.begin(); | 
|---|
| [2b4a40] | 737 | for (; baseline != DistanceMMap.end(); baseline++) { | 
|---|
|  | 738 | // we take from the smallest sum of squared distance as the base line BC (with peak A) onward as the triangle candidate | 
|---|
|  | 739 | // 2. next, we have to check whether all points reside on only one side of the triangle | 
|---|
|  | 740 | // 3. construct plane vector | 
|---|
|  | 741 | PlaneVector.MakeNormalVector(&A->second->node->x, &baseline->second.first->second->node->x, &baseline->second.second->second->node->x); | 
|---|
|  | 742 | *out << Verbose(2) << "Plane vector of candidate triangle is "; | 
|---|
|  | 743 | PlaneVector.Output(out); | 
|---|
|  | 744 | *out << endl; | 
|---|
|  | 745 | // 4. loop over all points | 
|---|
|  | 746 | double sign = 0.; | 
|---|
|  | 747 | PointMap::iterator checker = PointsOnBoundary.begin(); | 
|---|
|  | 748 | for (; checker != PointsOnBoundary.end(); checker++) { | 
|---|
|  | 749 | // (neglecting A,B,C) | 
|---|
|  | 750 | if ((checker == A) || (checker == baseline->second.first) || (checker == baseline->second.second)) | 
|---|
|  | 751 | continue; | 
|---|
|  | 752 | // 4a. project onto plane vector | 
|---|
|  | 753 | TrialVector.CopyVector(&checker->second->node->x); | 
|---|
|  | 754 | TrialVector.SubtractVector(&A->second->node->x); | 
|---|
|  | 755 | distance = TrialVector.Projection(&PlaneVector); | 
|---|
|  | 756 | if (fabs(distance) < 1e-4)  // we need to have a small epsilon around 0 which is still ok | 
|---|
|  | 757 | continue; | 
|---|
|  | 758 | *out << Verbose(3) << "Projection of " << checker->second->node->Name << " yields distance of " << distance << "." << endl; | 
|---|
|  | 759 | tmp = distance/fabs(distance); | 
|---|
|  | 760 | // 4b. Any have different sign to than before? (i.e. would lie outside convex hull with this starting triangle) | 
|---|
|  | 761 | if ((sign != 0) && (tmp != sign)) { | 
|---|
|  | 762 | // 4c. If so, break 4. loop and continue with next candidate in 1. loop | 
|---|
|  | 763 | *out << Verbose(2) << "Current candidates: " << A->second->node->Name << "," << baseline->second.first->second->node->Name  << "," << baseline->second.second->second->node->Name << " leave " << checker->second->node->Name << " outside the convex hull." << endl; | 
|---|
|  | 764 | break; | 
|---|
|  | 765 | } else { // note the sign for later | 
|---|
|  | 766 | *out << Verbose(2) << "Current candidates: " << A->second->node->Name << "," << baseline->second.first->second->node->Name  << "," << baseline->second.second->second->node->Name << " leave " << checker->second->node->Name << " inside the convex hull." << endl; | 
|---|
|  | 767 | sign = tmp; | 
|---|
|  | 768 | } | 
|---|
|  | 769 | // 4d. Check whether the point is inside the triangle (check distance to each node | 
|---|
|  | 770 | tmp = checker->second->node->x.Distance(&A->second->node->x); | 
|---|
|  | 771 | int innerpoint = 0; | 
|---|
|  | 772 | if ((tmp < A->second->node->x.Distance(&baseline->second.first->second->node->x)) | 
|---|
|  | 773 | && (tmp < A->second->node->x.Distance(&baseline->second.second->second->node->x))) | 
|---|
|  | 774 | innerpoint++; | 
|---|
|  | 775 | tmp = checker->second->node->x.Distance(&baseline->second.first->second->node->x); | 
|---|
|  | 776 | if ((tmp < baseline->second.first->second->node->x.Distance(&A->second->node->x)) | 
|---|
|  | 777 | && (tmp < baseline->second.first->second->node->x.Distance(&baseline->second.second->second->node->x))) | 
|---|
|  | 778 | innerpoint++; | 
|---|
|  | 779 | tmp = checker->second->node->x.Distance(&baseline->second.second->second->node->x); | 
|---|
|  | 780 | if ((tmp < baseline->second.second->second->node->x.Distance(&baseline->second.first->second->node->x)) | 
|---|
|  | 781 | && (tmp < baseline->second.second->second->node->x.Distance(&A->second->node->x))) | 
|---|
|  | 782 | innerpoint++; | 
|---|
|  | 783 | // 4e. If so, break 4. loop and continue with next candidate in 1. loop | 
|---|
|  | 784 | if (innerpoint == 3) | 
|---|
|  | 785 | break; | 
|---|
|  | 786 | } | 
|---|
|  | 787 | // 5. come this far, all on same side? Then break 1. loop and construct triangle | 
|---|
|  | 788 | if (checker == PointsOnBoundary.end()) { | 
|---|
|  | 789 | *out << "Looks like we have a candidate!" << endl; | 
|---|
|  | 790 | break; | 
|---|
|  | 791 | } | 
|---|
| [8eb17a] | 792 | } | 
|---|
| [2b4a40] | 793 | if (baseline != DistanceMMap.end()) { | 
|---|
|  | 794 | BPS[0] = baseline->second.first->second; | 
|---|
|  | 795 | BPS[1] = baseline->second.second->second; | 
|---|
|  | 796 | BLS[0] = new class BoundaryLineSet(BPS , LinesOnBoundaryCount); | 
|---|
|  | 797 | BPS[0] = A->second; | 
|---|
|  | 798 | BPS[1] = baseline->second.second->second; | 
|---|
|  | 799 | BLS[1] = new class BoundaryLineSet(BPS , LinesOnBoundaryCount); | 
|---|
|  | 800 | BPS[0] = baseline->second.first->second; | 
|---|
|  | 801 | BPS[1] = A->second; | 
|---|
|  | 802 | BLS[2] = new class BoundaryLineSet(BPS , LinesOnBoundaryCount); | 
|---|
|  | 803 |  | 
|---|
|  | 804 | // 4b3. insert created triangle | 
|---|
|  | 805 | BTS = new class BoundaryTriangleSet(BLS, TrianglesOnBoundaryCount); | 
|---|
|  | 806 | TrianglesOnBoundary.insert( TrianglePair(TrianglesOnBoundaryCount, BTS) ); | 
|---|
|  | 807 | TrianglesOnBoundaryCount++; | 
|---|
|  | 808 | for(int i=0;i<NDIM;i++) { | 
|---|
|  | 809 | LinesOnBoundary.insert( LinePair(LinesOnBoundaryCount, BTS->lines[i]) ); | 
|---|
|  | 810 | LinesOnBoundaryCount++; | 
|---|
|  | 811 | } | 
|---|
| [8eb17a] | 812 |  | 
|---|
| [2b4a40] | 813 | *out << Verbose(1) << "Starting triangle is " << *BTS << "." << endl; | 
|---|
|  | 814 | } else { | 
|---|
|  | 815 | *out << Verbose(1) << "No starting triangle found." << endl; | 
|---|
|  | 816 | exit(255); | 
|---|
| [8eb17a] | 817 | } | 
|---|
|  | 818 | }; | 
|---|
|  | 819 |  | 
|---|
|  | 820 |  | 
|---|
|  | 821 | /** Tesselates the convex envelope of a cluster from a single starting triangle. | 
|---|
|  | 822 | * The starting triangle is made out of three baselines. Each line in the final tesselated cluster may belong to at most | 
|---|
|  | 823 | * 2 triangles. Hence, we go through all current lines: | 
|---|
|  | 824 | * -# if the lines contains to only one triangle | 
|---|
|  | 825 | * -# We search all points in the boundary | 
|---|
|  | 826 | *    -# if the triangle with the baseline and the current point has the smallest of angles (comparison between normal vectors | 
|---|
|  | 827 | *    -# if the triangle is in forward direction of the baseline (at most 90 degrees angle between vector orthogonal to | 
|---|
|  | 828 | *       baseline in triangle plane pointing out of the triangle and normal vector of new triangle) | 
|---|
|  | 829 | *    -# then we have a new triangle, whose baselines we again add (or increase their TriangleCount) | 
|---|
|  | 830 | * \param *out output stream for debugging | 
|---|
|  | 831 | * \param *configuration for IsAngstroem | 
|---|
|  | 832 | * \param *mol the cluster as a molecule structure | 
|---|
|  | 833 | */ | 
|---|
|  | 834 | void Tesselation::TesselateOnBoundary(ofstream *out, config *configuration, molecule *mol) | 
|---|
|  | 835 | { | 
|---|
|  | 836 | bool flag; | 
|---|
|  | 837 | PointMap::iterator winner; | 
|---|
|  | 838 | class BoundaryPointSet *peak = NULL; | 
|---|
|  | 839 | double SmallestAngle, TempAngle; | 
|---|
| [e9b8bb] | 840 | Vector NormalVector, VirtualNormalVector, CenterVector, TempVector, PropagationVector; | 
|---|
| [8eb17a] | 841 | LineMap::iterator LineChecker[2]; | 
|---|
|  | 842 | do { | 
|---|
|  | 843 | flag = false; | 
|---|
|  | 844 | for (LineMap::iterator baseline = LinesOnBoundary.begin(); baseline != LinesOnBoundary.end(); baseline++) | 
|---|
|  | 845 | if (baseline->second->TrianglesCount == 1) { | 
|---|
|  | 846 | *out << Verbose(2) << "Current baseline is between " << *(baseline->second) << "." << endl; | 
|---|
|  | 847 | // 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) | 
|---|
|  | 848 | SmallestAngle = M_PI; | 
|---|
|  | 849 | BTS = baseline->second->triangles.begin()->second; // there is only one triangle so far | 
|---|
|  | 850 | // get peak point with respect to this base line's only triangle | 
|---|
|  | 851 | for(int i=0;i<3;i++) | 
|---|
|  | 852 | if ((BTS->endpoints[i] != baseline->second->endpoints[0]) && (BTS->endpoints[i] != baseline->second->endpoints[1])) | 
|---|
|  | 853 | peak = BTS->endpoints[i]; | 
|---|
|  | 854 | *out << Verbose(3) << " and has peak " << *peak << "." << endl; | 
|---|
|  | 855 | // normal vector of triangle | 
|---|
|  | 856 | BTS->GetNormalVector(NormalVector); | 
|---|
|  | 857 | *out << Verbose(4) << "NormalVector of base triangle is "; | 
|---|
|  | 858 | NormalVector.Output(out); | 
|---|
|  | 859 | *out << endl; | 
|---|
|  | 860 | // offset to center of triangle | 
|---|
|  | 861 | CenterVector.Zero(); | 
|---|
|  | 862 | for(int i=0;i<3;i++) | 
|---|
|  | 863 | CenterVector.AddVector(&BTS->endpoints[i]->node->x); | 
|---|
|  | 864 | CenterVector.Scale(1./3.); | 
|---|
|  | 865 | *out << Verbose(4) << "CenterVector of base triangle is "; | 
|---|
|  | 866 | CenterVector.Output(out); | 
|---|
|  | 867 | *out << endl; | 
|---|
|  | 868 | // vector in propagation direction (out of triangle) | 
|---|
|  | 869 | // project center vector onto triangle plane (points from intersection plane-NormalVector to plane-CenterVector intersection) | 
|---|
|  | 870 | TempVector.CopyVector(&baseline->second->endpoints[0]->node->x); | 
|---|
|  | 871 | TempVector.SubtractVector(&baseline->second->endpoints[1]->node->x); | 
|---|
|  | 872 | PropagationVector.MakeNormalVector(&TempVector, &NormalVector); | 
|---|
|  | 873 | TempVector.CopyVector(&CenterVector); | 
|---|
|  | 874 | TempVector.SubtractVector(&baseline->second->endpoints[0]->node->x);  // TempVector is vector on triangle plane pointing from one baseline egde towards center! | 
|---|
|  | 875 | //*out << Verbose(2) << "Projection of propagation onto temp: " << PropagationVector.Projection(&TempVector) << "." << endl; | 
|---|
|  | 876 | if (PropagationVector.Projection(&TempVector) > 0)  // make sure normal propagation vector points outward from baseline | 
|---|
|  | 877 | PropagationVector.Scale(-1.); | 
|---|
|  | 878 | *out << Verbose(4) << "PropagationVector of base triangle is "; | 
|---|
|  | 879 | PropagationVector.Output(out); | 
|---|
|  | 880 | *out << endl; | 
|---|
|  | 881 | winner = PointsOnBoundary.end(); | 
|---|
|  | 882 | for (PointMap::iterator target = PointsOnBoundary.begin(); target != PointsOnBoundary.end(); target++) | 
|---|
|  | 883 | if ((target->second != baseline->second->endpoints[0]) && (target->second != baseline->second->endpoints[1])) { // don't take the same endpoints | 
|---|
|  | 884 | *out << Verbose(3) << "Target point is " << *(target->second) << ":"; | 
|---|
|  | 885 | bool continueflag = true; | 
|---|
|  | 886 |  | 
|---|
|  | 887 | VirtualNormalVector.CopyVector(&baseline->second->endpoints[0]->node->x); | 
|---|
|  | 888 | VirtualNormalVector.AddVector(&baseline->second->endpoints[0]->node->x); | 
|---|
|  | 889 | VirtualNormalVector.Scale(-1./2.);   // points now to center of base line | 
|---|
|  | 890 | VirtualNormalVector.AddVector(&target->second->node->x); // points from center of base line to target | 
|---|
|  | 891 | TempAngle = VirtualNormalVector.Angle(&PropagationVector); | 
|---|
|  | 892 | continueflag = continueflag && (TempAngle < (M_PI/2.)); // no bends bigger than Pi/2 (90 degrees) | 
|---|
|  | 893 | if (!continueflag) { | 
|---|
|  | 894 | *out << Verbose(4) << "Angle between propagation direction and base line to " << *(target->second) << " is " << TempAngle << ", bad direction!" << endl; | 
|---|
|  | 895 | continue; | 
|---|
|  | 896 | } else | 
|---|
|  | 897 | *out << Verbose(4) << "Angle between propagation direction and base line to " << *(target->second) << " is " << TempAngle << ", good direction!" << endl; | 
|---|
|  | 898 | LineChecker[0] = baseline->second->endpoints[0]->lines.find(target->first); | 
|---|
|  | 899 | LineChecker[1] = baseline->second->endpoints[1]->lines.find(target->first); | 
|---|
|  | 900 | //            if (LineChecker[0] != baseline->second->endpoints[0]->lines.end()) | 
|---|
|  | 901 | //              *out << Verbose(4) << *(baseline->second->endpoints[0]) << " has line " << *(LineChecker[0]->second) << " to " << *(target->second) << " as endpoint with " << LineChecker[0]->second->TrianglesCount << " triangles." << endl; | 
|---|
|  | 902 | //            else | 
|---|
|  | 903 | //              *out << Verbose(4) << *(baseline->second->endpoints[0]) << " has no line to " << *(target->second) << " as endpoint." << endl; | 
|---|
|  | 904 | //            if (LineChecker[1] != baseline->second->endpoints[1]->lines.end()) | 
|---|
|  | 905 | //              *out << Verbose(4) << *(baseline->second->endpoints[1]) << " has line " << *(LineChecker[1]->second) << " to " << *(target->second) << " as endpoint with " << LineChecker[1]->second->TrianglesCount << " triangles." << endl; | 
|---|
|  | 906 | //            else | 
|---|
|  | 907 | //              *out << Verbose(4) << *(baseline->second->endpoints[1]) << " has no line to " << *(target->second) << " as endpoint." << endl; | 
|---|
|  | 908 | // check first endpoint (if any connecting line goes to target or at least not more than 1) | 
|---|
|  | 909 | continueflag = continueflag && (( (LineChecker[0] == baseline->second->endpoints[0]->lines.end()) || (LineChecker[0]->second->TrianglesCount == 1))); | 
|---|
|  | 910 | if (!continueflag) { | 
|---|
|  | 911 | *out << Verbose(4) << *(baseline->second->endpoints[0]) << " has line " << *(LineChecker[0]->second) << " to " << *(target->second) << " as endpoint with " << LineChecker[0]->second->TrianglesCount << " triangles." << endl; | 
|---|
|  | 912 | continue; | 
|---|
|  | 913 | } | 
|---|
|  | 914 | // check second endpoint (if any connecting line goes to target or at least not more than 1) | 
|---|
|  | 915 | continueflag = continueflag && (( (LineChecker[1] == baseline->second->endpoints[1]->lines.end()) || (LineChecker[1]->second->TrianglesCount == 1))); | 
|---|
|  | 916 | if (!continueflag) { | 
|---|
|  | 917 | *out << Verbose(4) << *(baseline->second->endpoints[1]) << " has line " << *(LineChecker[1]->second) << " to " << *(target->second) << " as endpoint with " << LineChecker[1]->second->TrianglesCount << " triangles." << endl; | 
|---|
|  | 918 | continue; | 
|---|
|  | 919 | } | 
|---|
|  | 920 | // check whether the envisaged triangle does not already exist (if both lines exist and have same endpoint) | 
|---|
|  | 921 | continueflag = continueflag && (!( | 
|---|
|  | 922 | ((LineChecker[0] != baseline->second->endpoints[0]->lines.end()) && (LineChecker[1] != baseline->second->endpoints[1]->lines.end()) | 
|---|
|  | 923 | && (GetCommonEndpoint(LineChecker[0]->second, LineChecker[1]->second) == peak)) | 
|---|
|  | 924 | )); | 
|---|
|  | 925 | if (!continueflag) { | 
|---|
|  | 926 | *out << Verbose(4) << "Current target is peak!" << endl; | 
|---|
|  | 927 | continue; | 
|---|
|  | 928 | } | 
|---|
|  | 929 | // in case NOT both were found | 
|---|
|  | 930 | if (continueflag) {  // create virtually this triangle, get its normal vector, calculate angle | 
|---|
|  | 931 | flag = true; | 
|---|
|  | 932 | VirtualNormalVector.MakeNormalVector(&baseline->second->endpoints[0]->node->x, &baseline->second->endpoints[1]->node->x, &target->second->node->x); | 
|---|
|  | 933 | // make it always point inward | 
|---|
|  | 934 | if (baseline->second->endpoints[0]->node->x.Projection(&VirtualNormalVector) > 0) | 
|---|
|  | 935 | VirtualNormalVector.Scale(-1.); | 
|---|
|  | 936 | // calculate angle | 
|---|
|  | 937 | TempAngle = NormalVector.Angle(&VirtualNormalVector); | 
|---|
|  | 938 | *out << Verbose(4) << "NormalVector is "; | 
|---|
|  | 939 | VirtualNormalVector.Output(out); | 
|---|
|  | 940 | *out << " and the angle is " << TempAngle << "." << endl; | 
|---|
|  | 941 | if (SmallestAngle > TempAngle) {  // set to new possible winner | 
|---|
|  | 942 | SmallestAngle = TempAngle; | 
|---|
|  | 943 | winner = target; | 
|---|
|  | 944 | } | 
|---|
|  | 945 | } | 
|---|
|  | 946 | } | 
|---|
|  | 947 | // 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 | 
|---|
|  | 948 | if (winner != PointsOnBoundary.end()) { | 
|---|
|  | 949 | *out << Verbose(2) << "Winning target point is " << *(winner->second) << " with angle " << SmallestAngle << "." << endl; | 
|---|
|  | 950 | // create the lins of not yet present | 
|---|
|  | 951 | BLS[0] = baseline->second; | 
|---|
|  | 952 | // 5c. add lines to the line set if those were new (not yet part of a triangle), delete lines that belong to two triangles) | 
|---|
|  | 953 | LineChecker[0] = baseline->second->endpoints[0]->lines.find(winner->first); | 
|---|
|  | 954 | LineChecker[1] = baseline->second->endpoints[1]->lines.find(winner->first); | 
|---|
|  | 955 | if (LineChecker[0] == baseline->second->endpoints[0]->lines.end()) { // create | 
|---|
|  | 956 | BPS[0] = baseline->second->endpoints[0]; | 
|---|
|  | 957 | BPS[1] = winner->second; | 
|---|
|  | 958 | BLS[1] = new class BoundaryLineSet(BPS , LinesOnBoundaryCount); | 
|---|
|  | 959 | LinesOnBoundary.insert( LinePair(LinesOnBoundaryCount, BLS[1]) ); | 
|---|
|  | 960 | LinesOnBoundaryCount++; | 
|---|
|  | 961 | } else | 
|---|
|  | 962 | BLS[1] = LineChecker[0]->second; | 
|---|
|  | 963 | if (LineChecker[1] == baseline->second->endpoints[1]->lines.end()) { // create | 
|---|
|  | 964 | BPS[0] = baseline->second->endpoints[1]; | 
|---|
|  | 965 | BPS[1] = winner->second; | 
|---|
|  | 966 | BLS[2] = new class BoundaryLineSet(BPS, LinesOnBoundaryCount); | 
|---|
|  | 967 | LinesOnBoundary.insert( LinePair(LinesOnBoundaryCount, BLS[2]) ); | 
|---|
|  | 968 | LinesOnBoundaryCount++; | 
|---|
|  | 969 | } else | 
|---|
|  | 970 | BLS[2] = LineChecker[1]->second; | 
|---|
|  | 971 | BTS = new class BoundaryTriangleSet(BLS, TrianglesOnBoundaryCount); | 
|---|
|  | 972 | TrianglesOnBoundary.insert( TrianglePair(TrianglesOnBoundaryCount, BTS) ); | 
|---|
|  | 973 | TrianglesOnBoundaryCount++; | 
|---|
|  | 974 | } else { | 
|---|
|  | 975 | *out << Verbose(1) << "I could not determine a winner for this baseline " << *(baseline->second) << "." << endl; | 
|---|
|  | 976 | } | 
|---|
|  | 977 |  | 
|---|
|  | 978 | // 5d. If the set of lines is not yet empty, go to 5. and continue | 
|---|
|  | 979 | } else | 
|---|
|  | 980 | *out << Verbose(2) << "Baseline candidate " << *(baseline->second) << " has a triangle count of " << baseline->second->TrianglesCount << "." << endl; | 
|---|
|  | 981 | } while (flag); | 
|---|
|  | 982 |  | 
|---|
|  | 983 | }; | 
|---|
|  | 984 |  | 
|---|
|  | 985 | /** Adds an atom to the tesselation::PointsOnBoundary list. | 
|---|
|  | 986 | * \param *Walker atom to add | 
|---|
|  | 987 | */ | 
|---|
|  | 988 | void Tesselation::AddPoint(atom *Walker) | 
|---|
|  | 989 | { | 
|---|
| [ca8073] | 990 | PointTestPair InsertUnique; | 
|---|
| [8eb17a] | 991 | BPS[0] = new class BoundaryPointSet(Walker); | 
|---|
| [ca8073] | 992 | InsertUnique = PointsOnBoundary.insert( PointPair(Walker->nr, BPS[0]) ); | 
|---|
|  | 993 | if (InsertUnique.second)  // if new point was not present before, increase counter | 
|---|
|  | 994 | PointsOnBoundaryCount++; | 
|---|
| [8eb17a] | 995 | }; | 
|---|