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