Changes in src/boundary.cpp [8c54a3:2319ed]
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
src/boundary.cpp
r8c54a3 r2319ed 10 10 #define DoSingleStepOutput 0 11 11 #define DoTecplotOutput 1 12 #define DoRaster3DOutput 012 #define DoRaster3DOutput 1 13 13 #define DoVRMLOutput 1 14 14 #define TecplotSuffix ".dat" … … 45 45 void BoundaryPointSet::AddLine(class BoundaryLineSet *line) 46 46 { 47 cout << Verbose(6) << "Adding line " << *line << " to " << *this << "." << endl; 47 cout << Verbose(6) << "Adding " << *this << " to line " << *line << "." 48 << endl; 48 49 if (line->endpoints[0] == this) 49 50 { … … 131 132 ; 132 133 134 /** Checks whether we have a common endpoint with given \a *line. 135 * \param *line other line to test 136 * \return true - common endpoint present, false - not connected 137 */ 138 bool BoundaryLineSet::IsConnectedTo(class BoundaryLineSet *line) 139 { 140 if ((endpoints[0] == line->endpoints[0]) || (endpoints[1] == line->endpoints[0]) || (endpoints[0] == line->endpoints[1]) || (endpoints[1] == line->endpoints[1])) 141 return true; 142 else 143 return false; 144 }; 145 146 /** Checks whether the adjacent triangles of a baseline are convex or not. 147 * We sum the two angles of each normal vector with a ficticious normnal vector from this baselinbe pointing outwards. 148 * If greater/equal M_PI than we are convex. 149 * \param *out output stream for debugging 150 * \return true - triangles are convex, false - concave or less than two triangles connected 151 */ 152 bool BoundaryLineSet::CheckConvexityCriterion(ofstream *out) 153 { 154 Vector BaseLineNormal; 155 double angle = 0; 156 // get the two triangles 157 if (TrianglesCount != 2) { 158 *out << Verbose(1) << "ERROR: Baseline " << this << " is connect to less than two triangles, Tesselation incomplete!" << endl; 159 return false; 160 } 161 // have a normal vector on the base line pointing outwards 162 BaseLineNormal.Zero(); 163 for(TriangleMap::iterator runner = triangles.begin(); runner != triangles.end(); runner++) 164 BaseLineNormal.AddVector(&runner->second->NormalVector); 165 BaseLineNormal.Normalize(); 166 // and calculate the sum of the angles with this normal vector and each of the triangle ones' 167 for(TriangleMap::iterator runner = triangles.begin(); runner != triangles.end(); runner++) 168 angle += BaseLineNormal.Angle(&runner->second->NormalVector); 169 170 if ((angle - M_PI) > -MYEPSILON) 171 return true; 172 else 173 return false; 174 } 175 176 /** Checks whether point is any of the two endpoints this line contains. 177 * \param *point point to test 178 * \return true - point is of the line, false - is not 179 */ 180 bool BoundaryLineSet::ContainsBoundaryPoint(class BoundaryPointSet *point) 181 { 182 for(int i=0;i<2;i++) 183 if (point == endpoints[i]) 184 return true; 185 return false; 186 }; 187 133 188 ostream & 134 189 operator <<(ostream &ost, BoundaryLineSet &a) … … 213 268 ; 214 269 215 void 216 BoundaryTriangleSet::GetNormalVector(Vector &OtherVector) 270 /** Calculates the normal vector for this triangle. 271 * Is made unique by comparison with \a OtherVector to point in the other direction. 272 * \param &OtherVector direction vector to make normal vector unique. 273 */ 274 void BoundaryTriangleSet::GetNormalVector(Vector &OtherVector) 217 275 { 218 276 // get normal vector … … 223 281 if (NormalVector.Projection(&OtherVector) > 0) 224 282 NormalVector.Scale(-1.); 225 } 226 ; 283 }; 284 285 /** Finds the point on the triangle \a *BTS the line defined by \a *MolCenter and \a *x crosses through. 286 * We call Vector::GetIntersectionWithPlane() to receive the intersection point with the plane 287 * This we test if it's really on the plane and whether it's inside the triangle on the plane or not. 288 * The latter is done as follows: if it's really outside, then for any endpoint of the triangle and it's opposite 289 * base line, the intersection between the line from endpoint to intersection and the base line will have a Vector::NormSquared() 290 * smaller than the first line. 291 * \param *out output stream for debugging 292 * \param *MolCenter offset vector of line 293 * \param *x second endpoint of line, minus \a *MolCenter is directional vector of line 294 * \param *Intersection intersection on plane on return 295 * \return true - \a *Intersection contains intersection on plane defined by triangle, false - zero vector if outside of triangle. 296 */ 297 bool BoundaryTriangleSet::GetIntersectionInsideTriangle(ofstream *out, Vector *MolCenter, Vector *x, Vector *Intersection) 298 { 299 Vector CrossPoint; 300 Vector helper; 301 int i=0; 302 303 if (Intersection->GetIntersectionWithPlane(out, &NormalVector, &endpoints[0]->node->x, MolCenter, x)) { 304 *out << Verbose(1) << "Alas! [Bronstein] failed - at least numerically - the intersection is not on the plane!" << endl; 305 return false; 306 } 307 308 // Calculate cross point between one baseline and the line from the third endpoint to intersection 309 do { 310 CrossPoint.GetIntersectionOfTwoLinesOnPlane(out, &endpoints[i%3]->node->x, &endpoints[(i+1)%3]->node->x, &endpoints[(i+2)%3]->node->x, Intersection); 311 helper.CopyVector(&endpoints[(i+1)%3]->node->x); 312 helper.SubtractVector(&endpoints[i%3]->node->x); 313 i++; 314 if (i>3) 315 break; 316 } while (CrossPoint.NormSquared() < MYEPSILON); 317 if (i>3) { 318 *out << Verbose(1) << "ERROR: Could not find any cross points, something's utterly wrong here!" << endl; 319 exit(255); 320 } 321 CrossPoint.SubtractVector(&endpoints[i%3]->node->x); 322 323 // check whether intersection is inside or not by comparing length of intersection and length of cross point 324 if ((CrossPoint.NormSquared() - helper.NormSquared()) > -MYEPSILON) { // inside 325 return true; 326 } else { // outside! 327 Intersection->Zero(); 328 return false; 329 } 330 }; 331 332 /** Checks whether lines is any of the three boundary lines this triangle contains. 333 * \param *line line to test 334 * \return true - line is of the triangle, false - is not 335 */ 336 bool BoundaryTriangleSet::ContainsBoundaryLine(class BoundaryLineSet *line) 337 { 338 for(int i=0;i<3;i++) 339 if (line == lines[i]) 340 return true; 341 return false; 342 }; 343 344 /** Checks whether point is any of the three endpoints this triangle contains. 345 * \param *point point to test 346 * \return true - point is of the triangle, false - is not 347 */ 348 bool BoundaryTriangleSet::ContainsBoundaryPoint(class BoundaryPointSet *point) 349 { 350 for(int i=0;i<3;i++) 351 if (point == endpoints[i]) 352 return true; 353 return false; 354 }; 227 355 228 356 ostream & … … 239 367 240 368 CandidateForTesselation::CandidateForTesselation( 241 369 atom *candidate, BoundaryLineSet* line, Vector OptCandidateCenter, Vector OtherOptCandidateCenter 242 370 ) { 243 244 245 246 371 point = candidate; 372 BaseLine = line; 373 OptCenter.CopyVector(&OptCandidateCenter); 374 OtherOptCenter.CopyVector(&OtherOptCandidateCenter); 247 375 } 248 376 249 377 CandidateForTesselation::~CandidateForTesselation() { 250 251 378 point = NULL; 379 BaseLine = NULL; 252 380 } 253 381 … … 301 429 LineMap LinesOnBoundary; 302 430 TriangleMap TrianglesOnBoundary; 431 Vector *MolCenter = mol->DetermineCenterOfAll(out); 432 Vector helper; 303 433 304 434 *out << Verbose(1) << "Finding all boundary points." << endl; … … 308 438 double radius, angle; 309 439 // 3a. Go through every axis 310 for (int axis = 0; axis < NDIM; axis++) 311 { 312 AxisVector.Zero(); 313 AngleReferenceVector.Zero(); 314 AngleReferenceNormalVector.Zero(); 315 AxisVector.x[axis] = 1.; 316 AngleReferenceVector.x[(axis + 1) % NDIM] = 1.; 317 AngleReferenceNormalVector.x[(axis + 2) % NDIM] = 1.; 318 // *out << Verbose(1) << "Axisvector is "; 319 // AxisVector.Output(out); 320 // *out << " and AngleReferenceVector is "; 321 // AngleReferenceVector.Output(out); 322 // *out << "." << endl; 323 // *out << " and AngleReferenceNormalVector is "; 324 // AngleReferenceNormalVector.Output(out); 325 // *out << "." << endl; 326 // 3b. construct set of all points, transformed into cylindrical system and with left and right neighbours 327 Walker = mol->start; 328 while (Walker->next != mol->end) 440 for (int axis = 0; axis < NDIM; axis++) { 441 AxisVector.Zero(); 442 AngleReferenceVector.Zero(); 443 AngleReferenceNormalVector.Zero(); 444 AxisVector.x[axis] = 1.; 445 AngleReferenceVector.x[(axis + 1) % NDIM] = 1.; 446 AngleReferenceNormalVector.x[(axis + 2) % NDIM] = 1.; 447 448 *out << Verbose(1) << "Axisvector is " << AxisVector << " and AngleReferenceVector is " << AngleReferenceVector << ", and AngleReferenceNormalVector is " << AngleReferenceNormalVector << "." << endl; 449 450 // 3b. construct set of all points, transformed into cylindrical system and with left and right neighbours 451 Walker = mol->start; 452 while (Walker->next != mol->end) { 453 Walker = Walker->next; 454 Vector ProjectedVector; 455 ProjectedVector.CopyVector(&Walker->x); 456 ProjectedVector.SubtractVector(MolCenter); 457 ProjectedVector.ProjectOntoPlane(&AxisVector); 458 459 // correct for negative side 460 radius = ProjectedVector.NormSquared(); 461 if (fabs(radius) > MYEPSILON) 462 angle = ProjectedVector.Angle(&AngleReferenceVector); 463 else 464 angle = 0.; // otherwise it's a vector in Axis Direction and unimportant for boundary issues 465 466 //*out << "Checking sign in quadrant : " << ProjectedVector.Projection(&AngleReferenceNormalVector) << "." << endl; 467 if (ProjectedVector.Projection(&AngleReferenceNormalVector) > 0) { 468 angle = 2. * M_PI - angle; 469 } 470 *out << Verbose(2) << "Inserting " << *Walker << ": (r, alpha) = (" << radius << "," << angle << "): " << ProjectedVector << endl; 471 BoundaryTestPair = BoundaryPoints[axis].insert(BoundariesPair(angle, DistancePair (radius, Walker))); 472 if (!BoundaryTestPair.second) { // same point exists, check first r, then distance of original vectors to center of gravity 473 *out << Verbose(2) << "Encountered two vectors whose projection onto axis " << axis << " is equal: " << endl; 474 *out << Verbose(2) << "Present vector: " << *BoundaryTestPair.first->second.second << endl; 475 *out << Verbose(2) << "New vector: " << *Walker << endl; 476 double tmp = ProjectedVector.NormSquared(); 477 if ((tmp - BoundaryTestPair.first->second.first) > MYEPSILON) { 478 BoundaryTestPair.first->second.first = tmp; 479 BoundaryTestPair.first->second.second = Walker; 480 *out << Verbose(2) << "Keeping new vector due to larger projected distance " << tmp << "." << endl; 481 } else if (fabs(tmp - BoundaryTestPair.first->second.first) < MYEPSILON) { 482 helper.CopyVector(&Walker->x); 483 helper.SubtractVector(MolCenter); 484 tmp = helper.NormSquared(); 485 helper.CopyVector(&BoundaryTestPair.first->second.second->x); 486 helper.SubtractVector(MolCenter); 487 if (helper.NormSquared() < tmp) { 488 BoundaryTestPair.first->second.second = Walker; 489 *out << Verbose(2) << "Keeping new vector due to larger distance to molecule center " << helper.NormSquared() << "." << endl; 490 } else { 491 *out << Verbose(2) << "Keeping present vector due to larger distance to molecule center " << tmp << "." << endl; 492 } 493 } else { 494 *out << Verbose(2) << "Keeping present vector due to larger projected distance " << tmp << "." << endl; 495 } 496 } 497 } 498 // printing all inserted for debugging 499 // { 500 // *out << Verbose(2) << "Printing list of candidates for axis " << axis << " which we have inserted so far." << endl; 501 // int i=0; 502 // for(Boundaries::iterator runner = BoundaryPoints[axis].begin(); runner != BoundaryPoints[axis].end(); runner++) { 503 // if (runner != BoundaryPoints[axis].begin()) 504 // *out << ", " << i << ": " << *runner->second.second; 505 // else 506 // *out << i << ": " << *runner->second.second; 507 // i++; 508 // } 509 // *out << endl; 510 // } 511 // 3c. throw out points whose distance is less than the mean of left and right neighbours 512 bool flag = false; 513 *out << Verbose(1) << "Looking for candidates to kick out by convex condition ... " << endl; 514 do { // do as long as we still throw one out per round 515 flag = false; 516 Boundaries::iterator left = BoundaryPoints[axis].end(); 517 Boundaries::iterator right = BoundaryPoints[axis].end(); 518 for (Boundaries::iterator runner = BoundaryPoints[axis].begin(); runner != BoundaryPoints[axis].end(); runner++) { 519 // set neighbours correctly 520 if (runner == BoundaryPoints[axis].begin()) { 521 left = BoundaryPoints[axis].end(); 522 } else { 523 left = runner; 524 } 525 left--; 526 right = runner; 527 right++; 528 if (right == BoundaryPoints[axis].end()) { 529 right = BoundaryPoints[axis].begin(); 530 } 531 // check distance 532 533 // construct the vector of each side of the triangle on the projected plane (defined by normal vector AxisVector) 329 534 { 330 Walker = Walker->next; 331 Vector ProjectedVector; 332 ProjectedVector.CopyVector(&Walker->x); 333 ProjectedVector.ProjectOntoPlane(&AxisVector); 334 // correct for negative side 335 //if (Projection(y) < 0) 336 //angle = 2.*M_PI - angle; 337 radius = ProjectedVector.Norm(); 338 if (fabs(radius) > MYEPSILON) 339 angle = ProjectedVector.Angle(&AngleReferenceVector); 340 else 341 angle = 0.; // otherwise it's a vector in Axis Direction and unimportant for boundary issues 342 343 //*out << "Checking sign in quadrant : " << ProjectedVector.Projection(&AngleReferenceNormalVector) << "." << endl; 344 if (ProjectedVector.Projection(&AngleReferenceNormalVector) > 0) 345 { 346 angle = 2. * M_PI - angle; 347 } 348 //*out << Verbose(2) << "Inserting " << *Walker << ": (r, alpha) = (" << radius << "," << angle << "): "; 349 //ProjectedVector.Output(out); 350 //*out << endl; 351 BoundaryTestPair = BoundaryPoints[axis].insert(BoundariesPair(angle, 352 DistancePair (radius, Walker))); 353 if (BoundaryTestPair.second) 354 { // successfully inserted 355 } 356 else 357 { // same point exists, check first r, then distance of original vectors to center of gravity 358 *out << Verbose(2) 359 << "Encountered two vectors whose projection onto axis " 360 << axis << " is equal: " << endl; 361 *out << Verbose(2) << "Present vector: "; 362 BoundaryTestPair.first->second.second->x.Output(out); 363 *out << endl; 364 *out << Verbose(2) << "New vector: "; 365 Walker->x.Output(out); 366 *out << endl; 367 double tmp = ProjectedVector.Norm(); 368 if (tmp > BoundaryTestPair.first->second.first) 369 { 370 BoundaryTestPair.first->second.first = tmp; 371 BoundaryTestPair.first->second.second = Walker; 372 *out << Verbose(2) << "Keeping new vector." << endl; 373 } 374 else if (tmp == BoundaryTestPair.first->second.first) 375 { 376 if (BoundaryTestPair.first->second.second->x.ScalarProduct( 377 &BoundaryTestPair.first->second.second->x) 378 < Walker->x.ScalarProduct(&Walker->x)) 379 { // Norm() does a sqrt, which makes it a lot slower 380 BoundaryTestPair.first->second.second = Walker; 381 *out << Verbose(2) << "Keeping new vector." << endl; 382 } 383 else 384 { 385 *out << Verbose(2) << "Keeping present vector." << endl; 386 } 387 } 388 else 389 { 390 *out << Verbose(2) << "Keeping present vector." << endl; 391 } 392 } 535 Vector SideA, SideB, SideC, SideH; 536 SideA.CopyVector(&left->second.second->x); 537 SideA.SubtractVector(MolCenter); 538 SideA.ProjectOntoPlane(&AxisVector); 539 // *out << "SideA: "; 540 // SideA.Output(out); 541 // *out << endl; 542 543 SideB.CopyVector(&right->second.second->x); 544 SideB.SubtractVector(MolCenter); 545 SideB.ProjectOntoPlane(&AxisVector); 546 // *out << "SideB: "; 547 // SideB.Output(out); 548 // *out << endl; 549 550 SideC.CopyVector(&left->second.second->x); 551 SideC.SubtractVector(&right->second.second->x); 552 SideC.ProjectOntoPlane(&AxisVector); 553 // *out << "SideC: "; 554 // SideC.Output(out); 555 // *out << endl; 556 557 SideH.CopyVector(&runner->second.second->x); 558 SideH.SubtractVector(MolCenter); 559 SideH.ProjectOntoPlane(&AxisVector); 560 // *out << "SideH: "; 561 // SideH.Output(out); 562 // *out << endl; 563 564 // calculate each length 565 double a = SideA.Norm(); 566 //double b = SideB.Norm(); 567 //double c = SideC.Norm(); 568 double h = SideH.Norm(); 569 // calculate the angles 570 double alpha = SideA.Angle(&SideH); 571 double beta = SideA.Angle(&SideC); 572 double gamma = SideB.Angle(&SideH); 573 double delta = SideC.Angle(&SideH); 574 double MinDistance = a * sin(beta) / (sin(delta)) * (((alpha < M_PI / 2.) || (gamma < M_PI / 2.)) ? 1. : -1.); 575 //*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; 576 *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; 577 if ((fabs(h / fabs(h) - MinDistance / fabs(MinDistance)) < MYEPSILON) && ((h - MinDistance)) < -MYEPSILON) { 578 // throw out point 579 *out << Verbose(1) << "Throwing out " << *runner->second.second << "." << endl; 580 BoundaryPoints[axis].erase(runner); 581 flag = true; 582 } 393 583 } 394 // printing all inserted for debugging 395 // { 396 // *out << Verbose(2) << "Printing list of candidates for axis " << axis << " which we have inserted so far." << endl; 397 // int i=0; 398 // for(Boundaries::iterator runner = BoundaryPoints[axis].begin(); runner != BoundaryPoints[axis].end(); runner++) { 399 // if (runner != BoundaryPoints[axis].begin()) 400 // *out << ", " << i << ": " << *runner->second.second; 401 // else 402 // *out << i << ": " << *runner->second.second; 403 // i++; 404 // } 405 // *out << endl; 406 // } 407 // 3c. throw out points whose distance is less than the mean of left and right neighbours 408 bool flag = false; 409 do 410 { // do as long as we still throw one out per round 411 *out << Verbose(1) 412 << "Looking for candidates to kick out by convex condition ... " 413 << endl; 414 flag = false; 415 Boundaries::iterator left = BoundaryPoints[axis].end(); 416 Boundaries::iterator right = BoundaryPoints[axis].end(); 417 for (Boundaries::iterator runner = BoundaryPoints[axis].begin(); runner 418 != BoundaryPoints[axis].end(); runner++) 419 { 420 // set neighbours correctly 421 if (runner == BoundaryPoints[axis].begin()) 422 { 423 left = BoundaryPoints[axis].end(); 424 } 425 else 426 { 427 left = runner; 428 } 429 left--; 430 right = runner; 431 right++; 432 if (right == BoundaryPoints[axis].end()) 433 { 434 right = BoundaryPoints[axis].begin(); 435 } 436 // check distance 437 438 // construct the vector of each side of the triangle on the projected plane (defined by normal vector AxisVector) 439 { 440 Vector SideA, SideB, SideC, SideH; 441 SideA.CopyVector(&left->second.second->x); 442 SideA.ProjectOntoPlane(&AxisVector); 443 // *out << "SideA: "; 444 // SideA.Output(out); 445 // *out << endl; 446 447 SideB.CopyVector(&right->second.second->x); 448 SideB.ProjectOntoPlane(&AxisVector); 449 // *out << "SideB: "; 450 // SideB.Output(out); 451 // *out << endl; 452 453 SideC.CopyVector(&left->second.second->x); 454 SideC.SubtractVector(&right->second.second->x); 455 SideC.ProjectOntoPlane(&AxisVector); 456 // *out << "SideC: "; 457 // SideC.Output(out); 458 // *out << endl; 459 460 SideH.CopyVector(&runner->second.second->x); 461 SideH.ProjectOntoPlane(&AxisVector); 462 // *out << "SideH: "; 463 // SideH.Output(out); 464 // *out << endl; 465 466 // calculate each length 467 double a = SideA.Norm(); 468 //double b = SideB.Norm(); 469 //double c = SideC.Norm(); 470 double h = SideH.Norm(); 471 // calculate the angles 472 double alpha = SideA.Angle(&SideH); 473 double beta = SideA.Angle(&SideC); 474 double gamma = SideB.Angle(&SideH); 475 double delta = SideC.Angle(&SideH); 476 double MinDistance = a * sin(beta) / (sin(delta)) * (((alpha 477 < M_PI / 2.) || (gamma < M_PI / 2.)) ? 1. : -1.); 478 // *out << Verbose(2) << " I calculated: a = " << a << ", h = " << h << ", beta(" << left->second.second->Name << "," << left->second.second->Name << "-" << right->second.second->Name << ") = " << beta << ", delta(" << left->second.second->Name << "," << runner->second.second->Name << ") = " << delta << ", Min = " << MinDistance << "." << endl; 479 //*out << Verbose(1) << "Checking CoG distance of runner " << *runner->second.second << " " << h << " against triangle's side length spanned by (" << *left->second.second << "," << *right->second.second << ") of " << MinDistance << "." << endl; 480 if ((fabs(h / fabs(h) - MinDistance / fabs(MinDistance)) 481 < MYEPSILON) && (h < MinDistance)) 482 { 483 // throw out point 484 //*out << Verbose(1) << "Throwing out " << *runner->second.second << "." << endl; 485 BoundaryPoints[axis].erase(runner); 486 flag = true; 487 } 488 } 489 } 490 } 491 while (flag); 492 } 584 } 585 } while (flag); 586 } 587 delete(MolCenter); 493 588 return BoundaryPoints; 494 589 } … … 619 714 *vrmlfile << "Sphere {" << endl << " "; // 2 is sphere type 620 715 for (i=0;i<NDIM;i++) 621 *vrmlfile << Walker->x.x[i] +center->x[i] << " ";716 *vrmlfile << Walker->x.x[i]-center->x[i] << " "; 622 717 *vrmlfile << "\t0.1\t1. 1. 1." << endl; // radius 0.05 and white as colour 623 718 } … … 628 723 *vrmlfile << "3" << endl << " "; // 2 is round-ended cylinder type 629 724 for (i=0;i<NDIM;i++) 630 *vrmlfile << Binder->leftatom->x.x[i] +center->x[i] << " ";725 *vrmlfile << Binder->leftatom->x.x[i]-center->x[i] << " "; 631 726 *vrmlfile << "\t0.03\t"; 632 727 for (i=0;i<NDIM;i++) 633 *vrmlfile << Binder->rightatom->x.x[i] +center->x[i] << " ";728 *vrmlfile << Binder->rightatom->x.x[i]-center->x[i] << " "; 634 729 *vrmlfile << "\t0.03\t0. 0. 1." << endl; // radius 0.05 and blue as colour 635 730 } … … 640 735 for (i=0;i<3;i++) { // print each node 641 736 for (int j=0;j<NDIM;j++) // and for each node all NDIM coordinates 642 *vrmlfile << TriangleRunner->second->endpoints[i]->node->x.x[j] +center->x[j] << " ";737 *vrmlfile << TriangleRunner->second->endpoints[i]->node->x.x[j]-center->x[j] << " "; 643 738 *vrmlfile << "\t"; 644 739 } … … 673 768 *rasterfile << "2" << endl << " "; // 2 is sphere type 674 769 for (i=0;i<NDIM;i++) 675 *rasterfile << Walker->x.x[i] +center->x[i] << " ";770 *rasterfile << Walker->x.x[i]-center->x[i] << " "; 676 771 *rasterfile << "\t0.1\t1. 1. 1." << endl; // radius 0.05 and white as colour 677 772 } … … 682 777 *rasterfile << "3" << endl << " "; // 2 is round-ended cylinder type 683 778 for (i=0;i<NDIM;i++) 684 *rasterfile << Binder->leftatom->x.x[i] +center->x[i] << " ";779 *rasterfile << Binder->leftatom->x.x[i]-center->x[i] << " "; 685 780 *rasterfile << "\t0.03\t"; 686 781 for (i=0;i<NDIM;i++) 687 *rasterfile << Binder->rightatom->x.x[i] +center->x[i] << " ";782 *rasterfile << Binder->rightatom->x.x[i]-center->x[i] << " "; 688 783 *rasterfile << "\t0.03\t0. 0. 1." << endl; // radius 0.05 and blue as colour 689 784 } … … 695 790 for (i=0;i<3;i++) { // print each node 696 791 for (int j=0;j<NDIM;j++) // and for each node all NDIM coordinates 697 *rasterfile << TriangleRunner->second->endpoints[i]->node->x.x[j] +center->x[j] << " ";792 *rasterfile << TriangleRunner->second->endpoints[i]->node->x.x[j]-center->x[j] << " "; 698 793 *rasterfile << "\t"; 699 794 } … … 713 808 * \param N arbitrary number to differentiate various zones in the tecplot format 714 809 */ 715 void 716 write_tecplot_file(ofstream *out, ofstream *tecplot, 717 class Tesselation *TesselStruct, class molecule *mol, int N) 718 { 719 if (tecplot != NULL) 720 { 721 *tecplot << "TITLE = \"3D CONVEX SHELL\"" << endl; 722 *tecplot << "VARIABLES = \"X\" \"Y\" \"Z\"" << endl; 723 *tecplot << "ZONE T=\"TRIANGLES" << N << "\", N=" 724 << TesselStruct->PointsOnBoundaryCount << ", E=" 725 << TesselStruct->TrianglesOnBoundaryCount 726 << ", DATAPACKING=POINT, ZONETYPE=FETRIANGLE" << endl; 727 int *LookupList = new int[mol->AtomCount]; 728 for (int i = 0; i < mol->AtomCount; i++) 729 LookupList[i] = -1; 730 731 // print atom coordinates 732 *out << Verbose(2) << "The following triangles were created:"; 733 int Counter = 1; 734 atom *Walker = NULL; 735 for (PointMap::iterator target = TesselStruct->PointsOnBoundary.begin(); target 736 != TesselStruct->PointsOnBoundary.end(); target++) 737 { 738 Walker = target->second->node; 739 LookupList[Walker->nr] = Counter++; 740 *tecplot << Walker->x.x[0] << " " << Walker->x.x[1] << " " 741 << Walker->x.x[2] << " " << endl; 742 } 743 *tecplot << endl; 744 // print connectivity 745 for (TriangleMap::iterator runner = 746 TesselStruct->TrianglesOnBoundary.begin(); runner 747 != TesselStruct->TrianglesOnBoundary.end(); runner++) 748 { 749 *out << " " << runner->second->endpoints[0]->node->Name << "<->" 750 << runner->second->endpoints[1]->node->Name << "<->" 751 << runner->second->endpoints[2]->node->Name; 752 *tecplot << LookupList[runner->second->endpoints[0]->node->nr] << " " 753 << LookupList[runner->second->endpoints[1]->node->nr] << " " 754 << LookupList[runner->second->endpoints[2]->node->nr] << endl; 755 } 756 delete[] (LookupList); 757 *out << endl; 758 } 810 void write_tecplot_file(ofstream *out, ofstream *tecplot, class Tesselation *TesselStruct, class molecule *mol, int N) 811 { 812 if (tecplot != NULL) { 813 *tecplot << "TITLE = \"3D CONVEX SHELL\"" << endl; 814 *tecplot << "VARIABLES = \"X\" \"Y\" \"Z\"" << endl; 815 *tecplot << "ZONE T=\"TRIANGLES" << N << "\", N=" << TesselStruct->PointsOnBoundaryCount << ", E=" << TesselStruct->TrianglesOnBoundaryCount << ", DATAPACKING=POINT, ZONETYPE=FETRIANGLE" << endl; 816 int *LookupList = new int[mol->AtomCount]; 817 for (int i = 0; i < mol->AtomCount; i++) 818 LookupList[i] = -1; 819 820 // print atom coordinates 821 *out << Verbose(2) << "The following triangles were created:"; 822 int Counter = 1; 823 atom *Walker = NULL; 824 for (PointMap::iterator target = TesselStruct->PointsOnBoundary.begin(); target != TesselStruct->PointsOnBoundary.end(); target++) { 825 Walker = target->second->node; 826 LookupList[Walker->nr] = Counter++; 827 *tecplot << Walker->x.x[0] << " " << Walker->x.x[1] << " " << Walker->x.x[2] << " " << endl; 828 } 829 *tecplot << endl; 830 // print connectivity 831 for (TriangleMap::iterator runner = TesselStruct->TrianglesOnBoundary.begin(); runner != TesselStruct->TrianglesOnBoundary.end(); runner++) { 832 *out << " " << runner->second->endpoints[0]->node->Name << "<->" << runner->second->endpoints[1]->node->Name << "<->" << runner->second->endpoints[2]->node->Name; 833 *tecplot << LookupList[runner->second->endpoints[0]->node->nr] << " " << LookupList[runner->second->endpoints[1]->node->nr] << " " << LookupList[runner->second->endpoints[2]->node->nr] << endl; 834 } 835 delete[] (LookupList); 836 *out << endl; 837 } 759 838 } 760 839 761 /** Determines the volume of a cluster. 762 * Determines first the convex envelope, then tesselates it and calculates its volume. 840 /** Tesselates the convex boundary by finding all boundary points. 763 841 * \param *out output stream for debugging 842 * \param *mol molecule structure with Atom's and Bond's 843 * \param *TesselStruct Tesselation filled with points, lines and triangles on boundary on return 844 * \param *LCList atoms in LinkedCell list 764 845 * \param *filename filename prefix for output of vertex data 765 * \param *configuration needed for path to store convex envelope file 766 * \param *BoundaryPoints NDIM set of boundary points on the projected plane per axis, on return if desired 767 * \param *mol molecule structure representing the cluster 768 * \return determined volume of the cluster in cubed config:GetIsAngstroem() 769 */ 770 double 771 VolumeOfConvexEnvelope(ofstream *out, const char *filename, config *configuration, 772 Boundaries *BoundaryPtr, molecule *mol) 773 { 774 bool IsAngstroem = configuration->GetIsAngstroem(); 775 atom *Walker = NULL; 776 struct Tesselation *TesselStruct = new Tesselation; 846 * \return *TesselStruct is filled with convex boundary and tesselation is stored under \a *filename. 847 */ 848 void Find_convex_border(ofstream *out, molecule* mol, class Tesselation *&TesselStruct, class LinkedCell *LCList, const char *filename) 849 { 777 850 bool BoundaryFreeFlag = false; 778 Boundaries *BoundaryPoints = BoundaryPtr; 779 double volume = 0.; 780 double PyramidVolume = 0.; 781 double G, h; 782 Vector x, y; 783 double a, b, c; 784 785 //Find_non_convex_border(out, tecplot, *TesselStruct, mol); // Is now called from command line. 786 787 // 1. calculate center of gravity 788 *out << endl; 789 Vector *CenterOfGravity = mol->DetermineCenterOfGravity(out); 790 791 // 2. translate all points into CoG 792 *out << Verbose(1) << "Translating system to Center of Gravity." << endl; 793 Walker = mol->start; 794 while (Walker->next != mol->end) 795 { 796 Walker = Walker->next; 797 Walker->x.Translate(CenterOfGravity); 798 } 799 800 // 3. Find all points on the boundary 801 if (BoundaryPoints == NULL) 802 { 851 Boundaries *BoundaryPoints = NULL; 852 853 cout << Verbose(1) << "Begin of find_convex_border" << endl; 854 855 if (TesselStruct != NULL) // free if allocated 856 delete(TesselStruct); 857 TesselStruct = new class Tesselation; 858 859 // 1. Find all points on the boundary 860 if (BoundaryPoints == NULL) { 803 861 BoundaryFreeFlag = true; 804 862 BoundaryPoints = GetBoundaryPoints(out, mol); 805 } 806 else 863 } else { 864 *out << Verbose(1) << "Using given boundary points set." << endl; 865 } 866 867 // printing all inserted for debugging 868 for (int axis=0; axis < NDIM; axis++) 807 869 { 808 *out << Verbose(1) << "Using given boundary points set." << endl; 809 } 810 811 // 4. fill the boundary point list 870 *out << Verbose(2) << "Printing list of candidates for axis " << axis << " which we have inserted so far." << endl; 871 int i=0; 872 for(Boundaries::iterator runner = BoundaryPoints[axis].begin(); runner != BoundaryPoints[axis].end(); runner++) { 873 if (runner != BoundaryPoints[axis].begin()) 874 *out << ", " << i << ": " << *runner->second.second; 875 else 876 *out << i << ": " << *runner->second.second; 877 i++; 878 } 879 *out << endl; 880 } 881 882 // 2. fill the boundary point list 812 883 for (int axis = 0; axis < NDIM; axis++) 813 for (Boundaries::iterator runner = BoundaryPoints[axis].begin(); runner 814 != BoundaryPoints[axis].end(); runner++) 815 { 884 for (Boundaries::iterator runner = BoundaryPoints[axis].begin(); runner != BoundaryPoints[axis].end(); runner++) 816 885 TesselStruct->AddPoint(runner->second.second); 817 } 818 819 *out << Verbose(2) << "I found " << TesselStruct->PointsOnBoundaryCount 820 << " points on the convex boundary." << endl; 886 887 *out << Verbose(2) << "I found " << TesselStruct->PointsOnBoundaryCount << " points on the convex boundary." << endl; 821 888 // now we have the whole set of edge points in the BoundaryList 822 889 … … 828 895 // *out << endl; 829 896 830 // 5a. guess starting triangle897 // 3a. guess starting triangle 831 898 TesselStruct->GuessStartingTriangle(out); 832 899 833 // 5b. go through all lines, that are not yet part of two triangles (only of one so far) 834 TesselStruct->TesselateOnBoundary(out, configuration, mol); 835 836 *out << Verbose(2) << "I created " << TesselStruct->TrianglesOnBoundaryCount 837 << " triangles with " << TesselStruct->LinesOnBoundaryCount 838 << " lines and " << TesselStruct->PointsOnBoundaryCount << " points." 839 << endl; 900 // 3b. go through all lines, that are not yet part of two triangles (only of one so far) 901 TesselStruct->TesselateOnBoundary(out, mol); 902 903 // 3c. check whether all atoms lay inside the boundary, if not, add to boundary points, segment triangle into three with the new point 904 if (!TesselStruct->InsertStraddlingPoints(out, mol)) 905 *out << Verbose(1) << "Insertion of straddling points failed!" << endl; 906 907 // 3d. check all baselines whether the peaks of the two adjacent triangles with respect to center of baseline are convex, if not, make the baseline between the two peaks and baseline endpoints become the new peaks 908 if (!TesselStruct->CorrectConcaveBaselines(out)) 909 *out << Verbose(1) << "Correction of concave baselines failed!" << endl; 910 911 *out << Verbose(2) << "I created " << TesselStruct->TrianglesOnBoundary.size() << " triangles with " << TesselStruct->LinesOnBoundary.size() << " lines and " << TesselStruct->PointsOnBoundary.size() << " points." << endl; 912 913 // 4. Store triangles in tecplot file 914 if (filename != NULL) { 915 if (DoTecplotOutput) { 916 string OutputName(filename); 917 OutputName.append(TecplotSuffix); 918 ofstream *tecplot = new ofstream(OutputName.c_str()); 919 write_tecplot_file(out, tecplot, TesselStruct, mol, 0); 920 tecplot->close(); 921 delete(tecplot); 922 } 923 if (DoRaster3DOutput) { 924 string OutputName(filename); 925 OutputName.append(Raster3DSuffix); 926 ofstream *rasterplot = new ofstream(OutputName.c_str()); 927 write_raster3d_file(out, rasterplot, TesselStruct, mol); 928 rasterplot->close(); 929 delete(rasterplot); 930 } 931 } 932 933 // free reference lists 934 if (BoundaryFreeFlag) 935 delete[] (BoundaryPoints); 936 937 cout << Verbose(1) << "End of find_convex_border" << endl; 938 }; 939 940 941 /** Determines the volume of a cluster. 942 * Determines first the convex envelope, then tesselates it and calculates its volume. 943 * \param *out output stream for debugging 944 * \param *TesselStruct Tesselation filled with points, lines and triangles on boundary on return 945 * \param *configuration needed for path to store convex envelope file 946 * \return determined volume of the cluster in cubed config:GetIsAngstroem() 947 */ 948 double VolumeOfConvexEnvelope(ofstream *out, class Tesselation *TesselStruct, class config *configuration) 949 { 950 bool IsAngstroem = configuration->GetIsAngstroem(); 951 double volume = 0.; 952 double PyramidVolume = 0.; 953 double G, h; 954 Vector x, y; 955 double a, b, c; 840 956 841 957 // 6a. Every triangle forms a pyramid with the center of gravity as its peak, sum up the volumes … … 873 989 << endl; 874 990 875 // 7. translate all points back from CoG876 *out << Verbose(1) << "Translating system back from Center of Gravity."877 << endl;878 CenterOfGravity->Scale(-1);879 Walker = mol->start;880 while (Walker->next != mol->end)881 {882 Walker = Walker->next;883 Walker->x.Translate(CenterOfGravity);884 }885 886 // 8. Store triangles in tecplot file887 string OutputName(filename);888 OutputName.append(TecplotSuffix);889 ofstream *tecplot = new ofstream(OutputName.c_str());890 write_tecplot_file(out, tecplot, TesselStruct, mol, 0);891 tecplot->close();892 delete(tecplot);893 894 // free reference lists895 if (BoundaryFreeFlag)896 delete[] (BoundaryPoints);897 898 991 return volume; 899 992 } … … 918 1011 bool IsAngstroem = configuration->GetIsAngstroem(); 919 1012 Boundaries *BoundaryPoints = GetBoundaryPoints(out, mol); 1013 class Tesselation *TesselStruct = NULL; 1014 LinkedCell LCList(mol, 10.); 1015 Find_convex_border(out, mol, TesselStruct, &LCList, NULL); 920 1016 double clustervolume; 921 1017 if (ClusterVolume == 0) 922 clustervolume = VolumeOfConvexEnvelope(out, NULL, configuration, 923 BoundaryPoints, mol); 1018 clustervolume = VolumeOfConvexEnvelope(out, TesselStruct, configuration); 924 1019 else 925 1020 clustervolume = ClusterVolume; 926 double *GreatestDiameter = GetDiametersOfCluster(out, BoundaryPoints, mol, 927 IsAngstroem); 1021 double *GreatestDiameter = GetDiametersOfCluster(out, BoundaryPoints, mol, IsAngstroem); 928 1022 Vector BoxLengths; 929 1023 int repetition[NDIM] = … … 1010 1104 // set new box dimensions 1011 1105 *out << Verbose(0) << "Translating to box with these boundaries." << endl; 1012 mol->CenterInBox((ofstream *) &cout, &BoxLengths); 1106 mol->SetBoxDimension(&BoxLengths); 1107 mol->CenterInBox((ofstream *) &cout); 1013 1108 } 1014 1109 // update Box of atoms by boundary … … 1020 1115 } 1021 1116 ; 1117 1118 1119 /** Fills the empty space of the simulation box with water/ 1120 * \param *out output stream for debugging 1121 * \param *List list of molecules already present in box 1122 * \param *TesselStruct contains tesselated surface 1123 * \param *filler molecule which the box is to be filled with 1124 * \param configuration contains box dimensions 1125 * \param distance[NDIM] distance between filling molecules in each direction 1126 * \param RandAtomDisplacement maximum distance for random displacement per atom 1127 * \param RandMolDisplacement maximum distance for random displacement per filler molecule 1128 * \param DoRandomRotation true - do random rotiations, false - don't 1129 * \return *mol pointer to new molecule with filled atoms 1130 */ 1131 molecule * FillBoxWithMolecule(ofstream *out, MoleculeListClass *List, molecule *filler, config &configuration, double distance[NDIM], double RandomAtomDisplacement, double RandomMolDisplacement, bool DoRandomRotation) 1132 { 1133 molecule *Filling = new molecule(filler->elemente); 1134 Vector CurrentPosition; 1135 int N[NDIM]; 1136 int n[NDIM]; 1137 double *M = filler->ReturnFullMatrixforSymmetric(filler->cell_size); 1138 double Rotations[NDIM*NDIM]; 1139 Vector AtomTranslations; 1140 Vector FillerTranslations; 1141 Vector FillerDistance; 1142 double FillIt = false; 1143 atom *Walker = NULL, *Runner = NULL; 1144 bond *Binder = NULL; 1145 1146 // Center filler at origin 1147 filler->CenterOrigin(out); 1148 filler->Center.Zero(); 1149 1150 // calculate filler grid in [0,1]^3 1151 FillerDistance.Init(distance[0], distance[1], distance[2]); 1152 FillerDistance.InverseMatrixMultiplication(M); 1153 for(int i=0;i<NDIM;i++) 1154 N[i] = ceil(1./FillerDistance.x[i]); 1155 1156 // go over [0,1]^3 filler grid 1157 for (n[0] = 0; n[0] < N[0]; n[0]++) 1158 for (n[1] = 0; n[1] < N[1]; n[1]++) 1159 for (n[2] = 0; n[2] < N[2]; n[2]++) { 1160 // calculate position of current grid vector in untransformed box 1161 CurrentPosition.Init(n[0], n[1], n[2]); 1162 CurrentPosition.MatrixMultiplication(M); 1163 // Check whether point is in- or outside 1164 FillIt = true; 1165 for (MoleculeList::iterator ListRunner = List->ListOfMolecules.begin(); ListRunner != List->ListOfMolecules.end(); ListRunner++) { 1166 FillIt = FillIt && (!(*ListRunner)->TesselStruct->IsInside(&CurrentPosition)); 1167 } 1168 1169 if (FillIt) { 1170 // fill in Filler 1171 *out << Verbose(2) << "Space at " << CurrentPosition << " is unoccupied by any molecule, filling in." << endl; 1172 1173 // create molecule random translation vector ... 1174 for (int i=0;i<NDIM;i++) 1175 FillerTranslations.x[i] = RandomMolDisplacement*(rand()/(RAND_MAX/2.) - 1.); 1176 1177 // go through all atoms 1178 Walker = filler->start; 1179 while (Walker != filler->end) { 1180 Walker = Walker->next; 1181 // copy atom ... 1182 *Runner = new atom(Walker); 1183 1184 // create atomic random translation vector ... 1185 for (int i=0;i<NDIM;i++) 1186 AtomTranslations.x[i] = RandomAtomDisplacement*(rand()/(RAND_MAX/2.) - 1.); 1187 1188 // ... and rotation matrix 1189 if (DoRandomRotation) { 1190 double phi[NDIM]; 1191 for (int i=0;i<NDIM;i++) { 1192 phi[i] = rand()/(RAND_MAX/(2.*M_PI)); 1193 } 1194 1195 Rotations[0] = cos(phi[0]) *cos(phi[2]) + (sin(phi[0])*sin(phi[1])*sin(phi[2])); 1196 Rotations[3] = sin(phi[0]) *cos(phi[2]) - (cos(phi[0])*sin(phi[1])*sin(phi[2])); 1197 Rotations[6] = cos(phi[1])*sin(phi[2]) ; 1198 Rotations[1] = - sin(phi[0])*cos(phi[1]) ; 1199 Rotations[4] = cos(phi[0])*cos(phi[1]) ; 1200 Rotations[7] = sin(phi[1]) ; 1201 Rotations[3] = - cos(phi[0]) *sin(phi[2]) + (sin(phi[0])*sin(phi[1])*cos(phi[2])); 1202 Rotations[5] = - sin(phi[0]) *sin(phi[2]) - (cos(phi[0])*sin(phi[1])*cos(phi[2])); 1203 Rotations[8] = cos(phi[1])*cos(phi[2]) ; 1204 } 1205 1206 // ... and put at new position 1207 if (DoRandomRotation) 1208 Runner->x.MatrixMultiplication(Rotations); 1209 Runner->x.AddVector(&AtomTranslations); 1210 Runner->x.AddVector(&FillerTranslations); 1211 Runner->x.AddVector(&CurrentPosition); 1212 // insert into Filling 1213 Filling->AddAtom(Runner); 1214 } 1215 1216 // go through all bonds and add as well 1217 Binder = filler->first; 1218 while(Binder != filler->last) { 1219 Binder = Binder->next; 1220 } 1221 } else { 1222 // leave empty 1223 *out << Verbose(2) << "Space at " << CurrentPosition << " is occupied." << endl; 1224 } 1225 } 1226 return Filling; 1227 }; 1228 1022 1229 1023 1230 // =========================================================== class TESSELATION =========================================== … … 1133 1340 << A->second->node->Name << "," 1134 1341 << baseline->second.first->second->node->Name << "," 1135 << baseline->second.second->second->node->Name << " leave "1342 << baseline->second.second->second->node->Name << " leaves " 1136 1343 << checker->second->node->Name << " outside the convex hull." 1137 1344 << endl; … … 1218 1425 * -# if the lines contains to only one triangle 1219 1426 * -# We search all points in the boundary 1220 * -# if the triangle with the baseline and the current point has the smallest of angles (comparison between normal vectors1221 1427 * -# if the triangle is in forward direction of the baseline (at most 90 degrees angle between vector orthogonal to 1222 1428 * baseline in triangle plane pointing out of the triangle and normal vector of new triangle) 1429 * -# if the triangle with the baseline and the current point has the smallest of angles (comparison between normal vectors) 1223 1430 * -# then we have a new triangle, whose baselines we again add (or increase their TriangleCount) 1224 1431 * \param *out output stream for debugging … … 1226 1433 * \param *mol the cluster as a molecule structure 1227 1434 */ 1228 void 1229 Tesselation::TesselateOnBoundary(ofstream *out, config *configuration, 1230 molecule *mol) 1435 void Tesselation::TesselateOnBoundary(ofstream *out, molecule *mol) 1231 1436 { 1232 1437 bool flag; … … 1234 1439 class BoundaryPointSet *peak = NULL; 1235 1440 double SmallestAngle, TempAngle; 1236 Vector NormalVector, VirtualNormalVector, CenterVector, TempVector, 1237 PropagationVector; 1441 Vector NormalVector, VirtualNormalVector, CenterVector, TempVector, helper, PropagationVector, *MolCenter = NULL; 1238 1442 LineMap::iterator LineChecker[2]; 1239 do 1240 { 1241 flag = false; 1242 for (LineMap::iterator baseline = LinesOnBoundary.begin(); baseline 1243 != LinesOnBoundary.end(); baseline++) 1244 if (baseline->second->TrianglesCount == 1) 1245 { 1246 *out << Verbose(2) << "Current baseline is between " 1247 << *(baseline->second) << "." << endl; 1248 // 5a. go through each boundary point if not _both_ edges between either endpoint of the current line and this point exist (and belong to 2 triangles) 1249 SmallestAngle = M_PI; 1250 BTS = baseline->second->triangles.begin()->second; // there is only one triangle so far 1251 // get peak point with respect to this base line's only triangle 1252 for (int i = 0; i < 3; i++) 1253 if ((BTS->endpoints[i] != baseline->second->endpoints[0]) 1254 && (BTS->endpoints[i] != baseline->second->endpoints[1])) 1255 peak = BTS->endpoints[i]; 1256 *out << Verbose(3) << " and has peak " << *peak << "." << endl; 1257 // normal vector of triangle 1258 BTS->GetNormalVector(NormalVector); 1259 *out << Verbose(4) << "NormalVector of base triangle is "; 1260 NormalVector.Output(out); 1261 *out << endl; 1262 // offset to center of triangle 1263 CenterVector.Zero(); 1264 for (int i = 0; i < 3; i++) 1265 CenterVector.AddVector(&BTS->endpoints[i]->node->x); 1266 CenterVector.Scale(1. / 3.); 1267 *out << Verbose(4) << "CenterVector of base triangle is "; 1268 CenterVector.Output(out); 1269 *out << endl; 1270 // vector in propagation direction (out of triangle) 1271 // project center vector onto triangle plane (points from intersection plane-NormalVector to plane-CenterVector intersection) 1443 1444 MolCenter = mol->DetermineCenterOfAll(out); 1445 // create a first tesselation with the given BoundaryPoints 1446 do { 1447 flag = false; 1448 for (LineMap::iterator baseline = LinesOnBoundary.begin(); baseline != LinesOnBoundary.end(); baseline++) 1449 if (baseline->second->TrianglesCount == 1) { 1450 // 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) 1451 SmallestAngle = M_PI; 1452 1453 // get peak point with respect to this base line's only triangle 1454 BTS = baseline->second->triangles.begin()->second; // there is only one triangle so far 1455 *out << Verbose(2) << "Current baseline is between " << *(baseline->second) << "." << endl; 1456 for (int i = 0; i < 3; i++) 1457 if ((BTS->endpoints[i] != baseline->second->endpoints[0]) && (BTS->endpoints[i] != baseline->second->endpoints[1])) 1458 peak = BTS->endpoints[i]; 1459 *out << Verbose(3) << " and has peak " << *peak << "." << endl; 1460 1461 // prepare some auxiliary vectors 1462 Vector BaseLineCenter, BaseLine; 1463 BaseLineCenter.CopyVector(&baseline->second->endpoints[0]->node->x); 1464 BaseLineCenter.AddVector(&baseline->second->endpoints[1]->node->x); 1465 BaseLineCenter.Scale(1. / 2.); // points now to center of base line 1466 BaseLine.CopyVector(&baseline->second->endpoints[0]->node->x); 1467 BaseLine.SubtractVector(&baseline->second->endpoints[1]->node->x); 1468 1469 // offset to center of triangle 1470 CenterVector.Zero(); 1471 for (int i = 0; i < 3; i++) 1472 CenterVector.AddVector(&BTS->endpoints[i]->node->x); 1473 CenterVector.Scale(1. / 3.); 1474 *out << Verbose(4) << "CenterVector of base triangle is " << CenterVector << endl; 1475 1476 // normal vector of triangle 1477 NormalVector.CopyVector(MolCenter); 1478 NormalVector.SubtractVector(&CenterVector); 1479 BTS->GetNormalVector(NormalVector); 1480 NormalVector.CopyVector(&BTS->NormalVector); 1481 *out << Verbose(4) << "NormalVector of base triangle is " << NormalVector << endl; 1482 1483 // vector in propagation direction (out of triangle) 1484 // project center vector onto triangle plane (points from intersection plane-NormalVector to plane-CenterVector intersection) 1485 PropagationVector.MakeNormalVector(&BaseLine, &NormalVector); 1486 TempVector.CopyVector(&CenterVector); 1487 TempVector.SubtractVector(&baseline->second->endpoints[0]->node->x); // TempVector is vector on triangle plane pointing from one baseline egde towards center! 1488 //*out << Verbose(2) << "Projection of propagation onto temp: " << PropagationVector.Projection(&TempVector) << "." << endl; 1489 if (PropagationVector.Projection(&TempVector) > 0) // make sure normal propagation vector points outward from baseline 1490 PropagationVector.Scale(-1.); 1491 *out << Verbose(4) << "PropagationVector of base triangle is " << PropagationVector << endl; 1492 winner = PointsOnBoundary.end(); 1493 1494 // loop over all points and calculate angle between normal vector of new and present triangle 1495 for (PointMap::iterator target = PointsOnBoundary.begin(); target != PointsOnBoundary.end(); target++) { 1496 if ((target->second != baseline->second->endpoints[0]) && (target->second != baseline->second->endpoints[1])) { // don't take the same endpoints 1497 *out << Verbose(3) << "Target point is " << *(target->second) << ":" << endl; 1498 1499 // first check direction, so that triangles don't intersect 1500 VirtualNormalVector.CopyVector(&target->second->node->x); 1501 VirtualNormalVector.SubtractVector(&BaseLineCenter); // points from center of base line to target 1502 VirtualNormalVector.ProjectOntoPlane(&NormalVector); 1503 TempAngle = VirtualNormalVector.Angle(&PropagationVector); 1504 *out << Verbose(4) << "VirtualNormalVector is " << VirtualNormalVector << " and PropagationVector is " << PropagationVector << "." << endl; 1505 if (TempAngle > (M_PI/2.)) { // no bends bigger than Pi/2 (90 degrees) 1506 *out << Verbose(4) << "Angle on triangle plane between propagation direction and base line to " << *(target->second) << " is " << TempAngle << ", bad direction!" << endl; 1507 continue; 1508 } else 1509 *out << Verbose(4) << "Angle on triangle plane between propagation direction and base line to " << *(target->second) << " is " << TempAngle << ", good direction!" << endl; 1510 1511 // check first and second endpoint (if any connecting line goes to target has at least not more than 1 triangle) 1512 LineChecker[0] = baseline->second->endpoints[0]->lines.find(target->first); 1513 LineChecker[1] = baseline->second->endpoints[1]->lines.find(target->first); 1514 if (((LineChecker[0] != baseline->second->endpoints[0]->lines.end()) && (LineChecker[0]->second->TrianglesCount == 2))) { 1515 *out << Verbose(4) << *(baseline->second->endpoints[0]) << " has line " << *(LineChecker[0]->second) << " to " << *(target->second) << " as endpoint with " << LineChecker[0]->second->TrianglesCount << " triangles." << endl; 1516 continue; 1517 } 1518 if (((LineChecker[1] != baseline->second->endpoints[1]->lines.end()) && (LineChecker[1]->second->TrianglesCount == 2))) { 1519 *out << Verbose(4) << *(baseline->second->endpoints[1]) << " has line " << *(LineChecker[1]->second) << " to " << *(target->second) << " as endpoint with " << LineChecker[1]->second->TrianglesCount << " triangles." << endl; 1520 continue; 1521 } 1522 1523 // check whether the envisaged triangle does not already exist (if both lines exist and have same endpoint) 1524 if ((((LineChecker[0] != baseline->second->endpoints[0]->lines.end()) && (LineChecker[1] != baseline->second->endpoints[1]->lines.end()) && (GetCommonEndpoint(LineChecker[0]->second, LineChecker[1]->second) == peak)))) { 1525 *out << Verbose(4) << "Current target is peak!" << endl; 1526 continue; 1527 } 1528 1529 // check for linear dependence 1272 1530 TempVector.CopyVector(&baseline->second->endpoints[0]->node->x); 1273 TempVector.SubtractVector(&baseline->second->endpoints[1]->node->x); 1274 PropagationVector.MakeNormalVector(&TempVector, &NormalVector); 1275 TempVector.CopyVector(&CenterVector); 1276 TempVector.SubtractVector(&baseline->second->endpoints[0]->node->x); // TempVector is vector on triangle plane pointing from one baseline egde towards center! 1277 //*out << Verbose(2) << "Projection of propagation onto temp: " << PropagationVector.Projection(&TempVector) << "." << endl; 1278 if (PropagationVector.Projection(&TempVector) > 0) // make sure normal propagation vector points outward from baseline 1279 PropagationVector.Scale(-1.); 1280 *out << Verbose(4) << "PropagationVector of base triangle is "; 1281 PropagationVector.Output(out); 1282 *out << endl; 1283 winner = PointsOnBoundary.end(); 1284 for (PointMap::iterator target = PointsOnBoundary.begin(); target 1285 != PointsOnBoundary.end(); target++) 1286 if ((target->second != baseline->second->endpoints[0]) 1287 && (target->second != baseline->second->endpoints[1])) 1288 { // don't take the same endpoints 1289 *out << Verbose(3) << "Target point is " << *(target->second) 1290 << ":"; 1291 bool continueflag = true; 1292 1293 VirtualNormalVector.CopyVector( 1294 &baseline->second->endpoints[0]->node->x); 1295 VirtualNormalVector.AddVector( 1296 &baseline->second->endpoints[0]->node->x); 1297 VirtualNormalVector.Scale(-1. / 2.); // points now to center of base line 1298 VirtualNormalVector.AddVector(&target->second->node->x); // points from center of base line to target 1299 TempAngle = VirtualNormalVector.Angle(&PropagationVector); 1300 continueflag = continueflag && (TempAngle < (M_PI/2.)); // no bends bigger than Pi/2 (90 degrees) 1301 if (!continueflag) 1302 { 1303 *out << Verbose(4) 1304 << "Angle between propagation direction and base line to " 1305 << *(target->second) << " is " << TempAngle 1306 << ", bad direction!" << endl; 1307 continue; 1308 } 1309 else 1310 *out << Verbose(4) 1311 << "Angle between propagation direction and base line to " 1312 << *(target->second) << " is " << TempAngle 1313 << ", good direction!" << endl; 1314 LineChecker[0] = baseline->second->endpoints[0]->lines.find( 1315 target->first); 1316 LineChecker[1] = baseline->second->endpoints[1]->lines.find( 1317 target->first); 1318 // if (LineChecker[0] != baseline->second->endpoints[0]->lines.end()) 1319 // *out << Verbose(4) << *(baseline->second->endpoints[0]) << " has line " << *(LineChecker[0]->second) << " to " << *(target->second) << " as endpoint with " << LineChecker[0]->second->TrianglesCount << " triangles." << endl; 1320 // else 1321 // *out << Verbose(4) << *(baseline->second->endpoints[0]) << " has no line to " << *(target->second) << " as endpoint." << endl; 1322 // if (LineChecker[1] != baseline->second->endpoints[1]->lines.end()) 1323 // *out << Verbose(4) << *(baseline->second->endpoints[1]) << " has line " << *(LineChecker[1]->second) << " to " << *(target->second) << " as endpoint with " << LineChecker[1]->second->TrianglesCount << " triangles." << endl; 1324 // else 1325 // *out << Verbose(4) << *(baseline->second->endpoints[1]) << " has no line to " << *(target->second) << " as endpoint." << endl; 1326 // check first endpoint (if any connecting line goes to target or at least not more than 1) 1327 continueflag = continueflag && (((LineChecker[0] 1328 == baseline->second->endpoints[0]->lines.end()) 1329 || (LineChecker[0]->second->TrianglesCount == 1))); 1330 if (!continueflag) 1331 { 1332 *out << Verbose(4) << *(baseline->second->endpoints[0]) 1333 << " has line " << *(LineChecker[0]->second) 1334 << " to " << *(target->second) 1335 << " as endpoint with " 1336 << LineChecker[0]->second->TrianglesCount 1337 << " triangles." << endl; 1338 continue; 1339 } 1340 // check second endpoint (if any connecting line goes to target or at least not more than 1) 1341 continueflag = continueflag && (((LineChecker[1] 1342 == baseline->second->endpoints[1]->lines.end()) 1343 || (LineChecker[1]->second->TrianglesCount == 1))); 1344 if (!continueflag) 1345 { 1346 *out << Verbose(4) << *(baseline->second->endpoints[1]) 1347 << " has line " << *(LineChecker[1]->second) 1348 << " to " << *(target->second) 1349 << " as endpoint with " 1350 << LineChecker[1]->second->TrianglesCount 1351 << " triangles." << endl; 1352 continue; 1353 } 1354 // check whether the envisaged triangle does not already exist (if both lines exist and have same endpoint) 1355 continueflag = continueflag && (!(((LineChecker[0] 1356 != baseline->second->endpoints[0]->lines.end()) 1357 && (LineChecker[1] 1358 != baseline->second->endpoints[1]->lines.end()) 1359 && (GetCommonEndpoint(LineChecker[0]->second, 1360 LineChecker[1]->second) == peak)))); 1361 if (!continueflag) 1362 { 1363 *out << Verbose(4) << "Current target is peak!" << endl; 1364 continue; 1365 } 1366 // in case NOT both were found 1367 if (continueflag) 1368 { // create virtually this triangle, get its normal vector, calculate angle 1369 flag = true; 1370 VirtualNormalVector.MakeNormalVector( 1371 &baseline->second->endpoints[0]->node->x, 1372 &baseline->second->endpoints[1]->node->x, 1373 &target->second->node->x); 1374 // make it always point inward 1375 if (baseline->second->endpoints[0]->node->x.Projection( 1376 &VirtualNormalVector) > 0) 1377 VirtualNormalVector.Scale(-1.); 1378 // calculate angle 1379 TempAngle = NormalVector.Angle(&VirtualNormalVector); 1380 *out << Verbose(4) << "NormalVector is "; 1381 VirtualNormalVector.Output(out); 1382 *out << " and the angle is " << TempAngle << "." << endl; 1383 if (SmallestAngle > TempAngle) 1384 { // set to new possible winner 1385 SmallestAngle = TempAngle; 1386 winner = target; 1387 } 1388 } 1389 } 1390 // 5b. The point of the above whose triangle has the greatest angle with the triangle the current line belongs to (it only belongs to one, remember!): New triangle 1391 if (winner != PointsOnBoundary.end()) 1392 { 1393 *out << Verbose(2) << "Winning target point is " 1394 << *(winner->second) << " with angle " << SmallestAngle 1395 << "." << endl; 1396 // create the lins of not yet present 1397 BLS[0] = baseline->second; 1398 // 5c. add lines to the line set if those were new (not yet part of a triangle), delete lines that belong to two triangles) 1399 LineChecker[0] = baseline->second->endpoints[0]->lines.find( 1400 winner->first); 1401 LineChecker[1] = baseline->second->endpoints[1]->lines.find( 1402 winner->first); 1403 if (LineChecker[0] 1404 == baseline->second->endpoints[0]->lines.end()) 1405 { // create 1406 BPS[0] = baseline->second->endpoints[0]; 1407 BPS[1] = winner->second; 1408 BLS[1] = new class BoundaryLineSet(BPS, 1409 LinesOnBoundaryCount); 1410 LinesOnBoundary.insert(LinePair(LinesOnBoundaryCount, 1411 BLS[1])); 1412 LinesOnBoundaryCount++; 1413 } 1414 else 1415 BLS[1] = LineChecker[0]->second; 1416 if (LineChecker[1] 1417 == baseline->second->endpoints[1]->lines.end()) 1418 { // create 1419 BPS[0] = baseline->second->endpoints[1]; 1420 BPS[1] = winner->second; 1421 BLS[2] = new class BoundaryLineSet(BPS, 1422 LinesOnBoundaryCount); 1423 LinesOnBoundary.insert(LinePair(LinesOnBoundaryCount, 1424 BLS[2])); 1425 LinesOnBoundaryCount++; 1426 } 1427 else 1428 BLS[2] = LineChecker[1]->second; 1429 BTS = new class BoundaryTriangleSet(BLS, 1430 TrianglesOnBoundaryCount); 1431 TrianglesOnBoundary.insert(TrianglePair( 1432 TrianglesOnBoundaryCount, BTS)); 1433 TrianglesOnBoundaryCount++; 1434 } 1435 else 1436 { 1437 *out << Verbose(1) 1438 << "I could not determine a winner for this baseline " 1439 << *(baseline->second) << "." << endl; 1440 } 1441 1442 // 5d. If the set of lines is not yet empty, go to 5. and continue 1531 TempVector.SubtractVector(&target->second->node->x); 1532 helper.CopyVector(&baseline->second->endpoints[1]->node->x); 1533 helper.SubtractVector(&target->second->node->x); 1534 helper.ProjectOntoPlane(&TempVector); 1535 if (fabs(helper.NormSquared()) < MYEPSILON) { 1536 *out << Verbose(4) << "Chosen set of vectors is linear dependent." << endl; 1537 continue; 1538 } 1539 1540 // in case NOT both were found, create virtually this triangle, get its normal vector, calculate angle 1541 flag = true; 1542 VirtualNormalVector.MakeNormalVector(&baseline->second->endpoints[0]->node->x, &baseline->second->endpoints[1]->node->x, &target->second->node->x); 1543 TempVector.CopyVector(&baseline->second->endpoints[0]->node->x); 1544 TempVector.AddVector(&baseline->second->endpoints[1]->node->x); 1545 TempVector.AddVector(&target->second->node->x); 1546 TempVector.Scale(1./3.); 1547 TempVector.SubtractVector(MolCenter); 1548 // make it always point outward 1549 if (VirtualNormalVector.Projection(&TempVector) < 0) 1550 VirtualNormalVector.Scale(-1.); 1551 // calculate angle 1552 TempAngle = NormalVector.Angle(&VirtualNormalVector); 1553 *out << Verbose(4) << "NormalVector is " << VirtualNormalVector << " and the angle is " << TempAngle << "." << endl; 1554 if ((SmallestAngle - TempAngle) > MYEPSILON) { // set to new possible winner 1555 SmallestAngle = TempAngle; 1556 winner = target; 1557 *out << Verbose(4) << "New winner " << *winner->second->node << " due to smaller angle between normal vectors." << endl; 1558 } else if (fabs(SmallestAngle - TempAngle) < MYEPSILON) { // check the angle to propagation, both possible targets are in one plane! (their normals have same angle) 1559 // hence, check the angles to some normal direction from our base line but in this common plane of both targets... 1560 helper.CopyVector(&target->second->node->x); 1561 helper.SubtractVector(&BaseLineCenter); 1562 helper.ProjectOntoPlane(&BaseLine); 1563 // ...the one with the smaller angle is the better candidate 1564 TempVector.CopyVector(&target->second->node->x); 1565 TempVector.SubtractVector(&BaseLineCenter); 1566 TempVector.ProjectOntoPlane(&VirtualNormalVector); 1567 TempAngle = TempVector.Angle(&helper); 1568 TempVector.CopyVector(&winner->second->node->x); 1569 TempVector.SubtractVector(&BaseLineCenter); 1570 TempVector.ProjectOntoPlane(&VirtualNormalVector); 1571 if (TempAngle < TempVector.Angle(&helper)) { 1572 TempAngle = NormalVector.Angle(&VirtualNormalVector); 1573 SmallestAngle = TempAngle; 1574 winner = target; 1575 *out << Verbose(4) << "New winner " << *winner->second->node << " due to smaller angle " << TempAngle << " to propagation direction." << endl; 1576 } else 1577 *out << Verbose(4) << "Keeping old winner " << *winner->second->node << " due to smaller angle to propagation direction." << endl; 1578 } else 1579 *out << Verbose(4) << "Keeping old winner " << *winner->second->node << " due to smaller angle between normal vectors." << endl; 1443 1580 } 1581 } // end of loop over all boundary points 1582 1583 // 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 1584 if (winner != PointsOnBoundary.end()) { 1585 *out << Verbose(2) << "Winning target point is " << *(winner->second) << " with angle " << SmallestAngle << "." << endl; 1586 // create the lins of not yet present 1587 BLS[0] = baseline->second; 1588 // 5c. add lines to the line set if those were new (not yet part of a triangle), delete lines that belong to two triangles) 1589 LineChecker[0] = baseline->second->endpoints[0]->lines.find(winner->first); 1590 LineChecker[1] = baseline->second->endpoints[1]->lines.find(winner->first); 1591 if (LineChecker[0] == baseline->second->endpoints[0]->lines.end()) { // create 1592 BPS[0] = baseline->second->endpoints[0]; 1593 BPS[1] = winner->second; 1594 BLS[1] = new class BoundaryLineSet(BPS, LinesOnBoundaryCount); 1595 LinesOnBoundary.insert(LinePair(LinesOnBoundaryCount, BLS[1])); 1596 LinesOnBoundaryCount++; 1597 } else 1598 BLS[1] = LineChecker[0]->second; 1599 if (LineChecker[1] == baseline->second->endpoints[1]->lines.end()) { // create 1600 BPS[0] = baseline->second->endpoints[1]; 1601 BPS[1] = winner->second; 1602 BLS[2] = new class BoundaryLineSet(BPS, LinesOnBoundaryCount); 1603 LinesOnBoundary.insert(LinePair(LinesOnBoundaryCount, BLS[2])); 1604 LinesOnBoundaryCount++; 1605 } else 1606 BLS[2] = LineChecker[1]->second; 1607 BTS = new class BoundaryTriangleSet(BLS, TrianglesOnBoundaryCount); 1608 TrianglesOnBoundary.insert(TrianglePair(TrianglesOnBoundaryCount, BTS)); 1609 TrianglesOnBoundaryCount++; 1610 } else { 1611 *out << Verbose(1) << "I could not determine a winner for this baseline " << *(baseline->second) << "." << endl; 1612 } 1613 1614 // 5d. If the set of lines is not yet empty, go to 5. and continue 1615 } else 1616 *out << Verbose(2) << "Baseline candidate " << *(baseline->second) << " has a triangle count of " << baseline->second->TrianglesCount << "." << endl; 1617 } while (flag); 1618 1619 // exit 1620 delete(MolCenter); 1621 }; 1622 1623 /** Inserts all atoms outside of the tesselated surface into it by adding new triangles. 1624 * \param *out output stream for debugging 1625 * \param *mol molecule structure with atoms 1626 * \return true - all straddling points insert, false - something went wrong 1627 */ 1628 bool Tesselation::InsertStraddlingPoints(ofstream *out, molecule *mol) 1629 { 1630 Vector Intersection; 1631 atom *Walker = mol->start; 1632 Vector *MolCenter = mol->DetermineCenterOfAll(out); 1633 while (Walker->next != mol->end) { // we only have to go once through all points, as boundary can become only bigger 1634 // get the next triangle 1635 BTS = FindClosestTriangleToPoint(out, &Walker->x); 1636 if (BTS == NULL) { 1637 *out << Verbose(1) << "ERROR: No triangle closest to " << Walker << " was found." << endl; 1638 return false; 1639 } 1640 // get the intersection point 1641 if (BTS->GetIntersectionInsideTriangle(out, MolCenter, &Walker->x, &Intersection)) { 1642 // we have the intersection, check whether in- or outside of boundary 1643 if ((MolCenter->DistanceSquared(&Walker->x) - MolCenter->DistanceSquared(&Intersection)) < -MYEPSILON) { 1644 // inside, next! 1645 *out << Verbose(4) << Walker << " is inside wrt triangle " << BTS << "." << endl; 1646 } else { 1647 // outside! 1648 *out << Verbose(3) << Walker << " is outside wrt triangle " << BTS << "." << endl; 1649 class BoundaryLineSet *OldLines[3], *NewLines[3]; 1650 class BoundaryPointSet *OldPoints[3], *NewPoint; 1651 // store the three old lines and old points 1652 for (int i=0;i<3;i++) { 1653 OldLines[i] = BTS->lines[i]; 1654 OldPoints[i] = BTS->endpoints[i]; 1655 } 1656 // add Walker to boundary points 1657 AddPoint(Walker); 1658 if (BPS[0] == NULL) 1659 NewPoint = BPS[0]; 1444 1660 else 1445 *out << Verbose(2) << "Baseline candidate " << *(baseline->second) 1446 << " has a triangle count of " 1447 << baseline->second->TrianglesCount << "." << endl; 1448 } 1449 while (flag); 1450 1451 } 1452 ; 1661 continue; 1662 // remove triangle 1663 TrianglesOnBoundary.erase(BTS->Nr); 1664 // create three new boundary lines 1665 for (int i=0;i<3;i++) { 1666 BPS[0] = NewPoint; 1667 BPS[1] = OldPoints[i]; 1668 NewLines[i] = new class BoundaryLineSet(BPS, LinesOnBoundaryCount); 1669 LinesOnBoundary.insert(LinePair(LinesOnBoundaryCount, NewLines[i])); // no need for check for unique insertion as BPS[0] is definitely a new one 1670 LinesOnBoundaryCount++; 1671 } 1672 // create three new triangle with new point 1673 for (int i=0;i<3;i++) { // find all baselines 1674 BLS[0] = OldLines[i]; 1675 int n = 1; 1676 for (int j=0;j<3;j++) { 1677 if (NewLines[j]->IsConnectedTo(BLS[0])) { 1678 if (n>2) { 1679 *out << Verbose(1) << "ERROR: " << BLS[0] << " connects to all of the new lines?!" << endl; 1680 return false; 1681 } else 1682 BLS[n++] = NewLines[j]; 1683 } 1684 } 1685 // create the triangle 1686 BTS = new class BoundaryTriangleSet(BLS, TrianglesOnBoundaryCount); 1687 TrianglesOnBoundary.insert(TrianglePair(TrianglesOnBoundaryCount, BTS)); 1688 TrianglesOnBoundaryCount++; 1689 } 1690 } 1691 } else { // something is wrong with FindClosestTriangleToPoint! 1692 *out << Verbose(1) << "ERROR: The closest triangle did not produce an intersection!" << endl; 1693 return false; 1694 } 1695 } 1696 1697 // exit 1698 delete(MolCenter); 1699 return true; 1700 }; 1701 1702 /** Goes over all baselines and checks whether adjacent triangles and convex to each other. 1703 * \param *out output stream for debugging 1704 * \return true - all baselines were corrected, false - there are still concave pieces 1705 */ 1706 bool Tesselation::CorrectConcaveBaselines(ofstream *out) 1707 { 1708 class BoundaryTriangleSet *triangle[2]; 1709 class BoundaryLineSet *OldLines[4], *NewLine; 1710 class BoundaryPointSet *OldPoints[2]; 1711 Vector BaseLineNormal; 1712 class BoundaryLineSet *Base = NULL; 1713 int OldTriangles[2], OldBaseLine; 1714 int i; 1715 for (LineMap::iterator baseline = LinesOnBoundary.begin(); baseline != LinesOnBoundary.end(); baseline++) { 1716 Base = baseline->second; 1717 1718 // check convexity 1719 if (Base->CheckConvexityCriterion(out)) { // triangles are convex 1720 *out << Verbose(3) << Base << " has two convex triangles." << endl; 1721 } else { // not convex! 1722 // get the two triangles 1723 i=0; 1724 for(TriangleMap::iterator runner = Base->triangles.begin(); runner != Base->triangles.end(); runner++) 1725 triangle[i++] = runner->second; 1726 // gather four endpoints and four lines 1727 for (int j=0;j<4;j++) 1728 OldLines[j] = NULL; 1729 for (int j=0;j<2;j++) 1730 OldPoints[j] = NULL; 1731 i=0; 1732 for (int m=0;m<2;m++) { // go over both triangles 1733 for (int j=0;j<3;j++) { // all of their endpoints and baselines 1734 if (triangle[m]->lines[j] != Base) // pick not the central baseline 1735 OldLines[i++] = triangle[m]->lines[j]; 1736 if (!Base->ContainsBoundaryPoint(triangle[m]->endpoints[j])) // and neither of its endpoints 1737 OldPoints[m] = triangle[m]->endpoints[j]; 1738 } 1739 } 1740 if (i<4) { 1741 *out << Verbose(1) << "ERROR: We have not gathered enough baselines!" << endl; 1742 return false; 1743 } 1744 for (int j=0;j<4;j++) 1745 if (OldLines[j] == NULL) { 1746 *out << Verbose(1) << "ERROR: We have not gathered enough baselines!" << endl; 1747 return false; 1748 } 1749 for (int j=0;j<2;j++) 1750 if (OldPoints[j] == NULL) { 1751 *out << Verbose(1) << "ERROR: We have not gathered enough endpoints!" << endl; 1752 return false; 1753 } 1754 1755 // remove triangles 1756 for (int j=0;j<2;j++) { 1757 OldTriangles[j] = triangle[j]->Nr; 1758 TrianglesOnBoundary.erase(OldTriangles[j]); 1759 triangle[j] = NULL; 1760 } 1761 1762 // remove baseline 1763 OldBaseLine = Base->Nr; 1764 LinesOnBoundary.erase(OldBaseLine); 1765 Base = NULL; 1766 1767 // construct new baseline (with same number as old one) 1768 BPS[0] = OldPoints[0]; 1769 BPS[1] = OldPoints[1]; 1770 NewLine = new class BoundaryLineSet(BPS, OldBaseLine); 1771 LinesOnBoundary.insert(LinePair(OldBaseLine, NewLine)); // no need for check for unique insertion as NewLine is definitely a new one 1772 1773 // construct new triangles with flipped baseline 1774 i=-1; 1775 if (BLS[0]->IsConnectedTo(OldLines[2])) 1776 i=2; 1777 if (BLS[0]->IsConnectedTo(OldLines[2])) 1778 i=3; 1779 if (i!=-1) { 1780 BLS[0] = OldLines[0]; 1781 BLS[1] = OldLines[i]; 1782 BLS[2] = NewLine; 1783 BTS = new class BoundaryTriangleSet(BLS, OldTriangles[0]); 1784 TrianglesOnBoundary.insert(TrianglePair(OldTriangles[0], BTS)); 1785 1786 BLS[0] = (i==2 ? OldLines[3] : OldLines[2]); 1787 BLS[1] = OldLines[1]; 1788 BLS[2] = NewLine; 1789 BTS = new class BoundaryTriangleSet(BLS, OldTriangles[1]); 1790 TrianglesOnBoundary.insert(TrianglePair(OldTriangles[1], BTS)); 1791 } else { 1792 *out << Verbose(1) << "The four old lines do not connect, something's utterly wrong here!" << endl; 1793 return false; 1794 } 1795 } 1796 } 1797 return true; 1798 }; 1799 1800 1801 /** States whether point is in- or outside of a tesselated surface. 1802 * \param *pointer point to be checked 1803 * \return true - is inside, false - is outside 1804 */ 1805 bool Tesselation::IsInside(Vector *pointer) 1806 { 1807 1808 // hier kommt dann Saskias Routine hin... 1809 1810 return true; 1811 }; 1812 1813 /** Finds the closest triangle to a given point. 1814 * \param *out output stream for debugging 1815 * \param *x second endpoint of line 1816 * \return pointer triangle that is closest, NULL if none was found 1817 */ 1818 class BoundaryTriangleSet * Tesselation::FindClosestTriangleToPoint(ofstream *out, Vector *x) 1819 { 1820 class BoundaryTriangleSet *triangle = NULL; 1821 1822 // hier kommt dann Saskias Routine hin... 1823 1824 return triangle; 1825 }; 1453 1826 1454 1827 /** Adds an atom to the tesselation::PointsOnBoundary list. … … 1463 1836 if (InsertUnique.second) // if new point was not present before, increase counter 1464 1837 PointsOnBoundaryCount++; 1838 else { 1839 delete(BPS[0]); 1840 BPS[0] = NULL; 1841 } 1465 1842 } 1466 1843 ; … … 1804 2181 */ 1805 2182 int Tesselation::CheckPresenceOfTriangle(ofstream *out, atom *Candidates[3]) { 1806 // TODO: use findTriangles here and return result.size();1807 2183 LineMap::iterator FindLine; 1808 2184 PointMap::iterator FindPoint; … … 1904 2280 Vector CirclePlaneNormal; // normal vector defining the plane this circle lives in 1905 2281 Vector SphereCenter; 1906 Vector NewSphereCenter; 1907 Vector OtherNewSphereCenter; 2282 Vector NewSphereCenter; // center of the sphere defined by the two points of BaseLine and the one of Candidate, first possibility 2283 Vector OtherNewSphereCenter; // center of the sphere defined by the two points of BaseLine and the one of Candidate, second possibility 1908 2284 Vector NewNormalVector; // normal vector of the Candidate's triangle 1909 2285 Vector helper, OptCandidateCenter, OtherOptCandidateCenter; … … 1985 2361 1986 2362 if ((NewNormalVector.MakeNormalVector(&(BaseLine->endpoints[0]->node->x), &(BaseLine->endpoints[1]->node->x), &(Candidate->x))) 1987 2363 && (fabs(NewNormalVector.ScalarProduct(&NewNormalVector)) > HULLEPSILON) 1988 2364 ) { 1989 2365 helper.CopyVector(&NewNormalVector); … … 2072 2448 //cout << Verbose(2) << "INFO: Sorting candidate list ..." << endl; 2073 2449 if (candidates->size() > 1) { 2074 2075 2450 candidates->unique(); 2451 candidates->sort(sortCandidates); 2076 2452 } 2077 2453 … … 2080 2456 2081 2457 struct Intersection { 2082 2083 2084 2085 2458 Vector x1; 2459 Vector x2; 2460 Vector x3; 2461 Vector x4; 2086 2462 }; 2087 2463 … … 2093 2469 */ 2094 2470 double MinIntersectDistance(const gsl_vector * x, void *params) { 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2471 double retval = 0; 2472 struct Intersection *I = (struct Intersection *)params; 2473 Vector intersection; 2474 Vector SideA,SideB,HeightA, HeightB; 2475 for (int i=0;i<NDIM;i++) 2476 intersection.x[i] = gsl_vector_get(x, i); 2477 2478 SideA.CopyVector(&(I->x1)); 2479 SideA.SubtractVector(&I->x2); 2480 HeightA.CopyVector(&intersection); 2481 HeightA.SubtractVector(&I->x1); 2482 HeightA.ProjectOntoPlane(&SideA); 2483 2484 SideB.CopyVector(&I->x3); 2485 SideB.SubtractVector(&I->x4); 2486 HeightB.CopyVector(&intersection); 2487 HeightB.SubtractVector(&I->x3); 2488 HeightB.ProjectOntoPlane(&SideB); 2489 2490 retval = HeightA.ScalarProduct(&HeightA) + HeightB.ScalarProduct(&HeightB); 2491 //cout << Verbose(2) << "MinIntersectDistance called, result: " << retval << endl; 2492 2493 return retval; 2118 2494 }; 2119 2495 … … 2132 2508 */ 2133 2509 bool existsIntersection(Vector point1, Vector point2, Vector point3, Vector point4) { 2134 2135 2136 2137 2138 2139 2140 2510 bool result; 2511 2512 struct Intersection par; 2513 par.x1.CopyVector(&point1); 2514 par.x2.CopyVector(&point2); 2515 par.x3.CopyVector(&point3); 2516 par.x4.CopyVector(&point4); 2141 2517 2142 2518 const gsl_multimin_fminimizer_type *T = gsl_multimin_fminimizer_nmsimplex; … … 2179 2555 2180 2556 if (status == GSL_SUCCESS) { 2181 2557 cout << Verbose(2) << "converged to minimum" << endl; 2182 2558 } 2183 2559 } while (status == GSL_CONTINUE && iter < 100); 2184 2560 2185 2561 // check whether intersection is in between or not 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2562 Vector intersection, SideA, SideB, HeightA, HeightB; 2563 double t1, t2; 2564 for (int i = 0; i < NDIM; i++) { 2565 intersection.x[i] = gsl_vector_get(s->x, i); 2566 } 2567 2568 SideA.CopyVector(&par.x2); 2569 SideA.SubtractVector(&par.x1); 2570 HeightA.CopyVector(&intersection); 2571 HeightA.SubtractVector(&par.x1); 2572 2573 t1 = HeightA.Projection(&SideA)/SideA.ScalarProduct(&SideA); 2574 2575 SideB.CopyVector(&par.x4); 2576 SideB.SubtractVector(&par.x3); 2577 HeightB.CopyVector(&intersection); 2578 HeightB.SubtractVector(&par.x3); 2579 2580 t2 = HeightB.Projection(&SideB)/SideB.ScalarProduct(&SideB); 2581 2582 cout << Verbose(2) << "Intersection " << intersection << " is at " 2583 << t1 << " for (" << point1 << "," << point2 << ") and at " 2584 << t2 << " for (" << point3 << "," << point4 << "): "; 2585 2586 if (((t1 >= 0) && (t1 <= 1)) && ((t2 >= 0) && (t2 <= 1))) { 2587 cout << "true intersection." << endl; 2588 result = true; 2589 } else { 2590 cout << "intersection out of region of interest." << endl; 2591 result = false; 2592 } 2593 2594 // free minimizer stuff 2219 2595 gsl_vector_free(x); 2220 2596 gsl_vector_free(ss); 2221 2597 gsl_multimin_fminimizer_free(s); 2222 2598 2223 2599 return result; 2224 2600 } 2225 2601 … … 2241 2617 int N[NDIM], Nlower[NDIM], Nupper[NDIM]; 2242 2618 2243 if (LC->SetIndexToAtom( *a)) { // get cell for the starting atom2619 if (LC->SetIndexToAtom(a)) { // get cell for the starting atom 2244 2620 for(int i=0;i<NDIM;i++) // store indices of this cell 2245 2621 N[i] = LC->n[i]; … … 2603 2979 cout << Verbose(1) << "Third Points are "; 2604 2980 for (CandidateList::iterator it = Opt_Candidates->begin(); it != Opt_Candidates->end(); ++it) { 2605 2981 cout << " " << *(*it)->point; 2606 2982 } 2607 2983 cout << endl; … … 2609 2985 BoundaryLineSet *BaseRay = &Line; 2610 2986 for (CandidateList::iterator it = Opt_Candidates->begin(); it != Opt_Candidates->end(); ++it) { 2611 2612 2613 2614 2615 2616 2617 2618 2619 2620 2621 2622 2623 2624 2987 cout << Verbose(1) << " Third point candidate is " << *(*it)->point 2988 << " with circumsphere's center at " << (*it)->OptCenter << "." << endl; 2989 cout << Verbose(1) << " Baseline is " << *BaseRay << endl; 2990 2991 // check whether all edges of the new triangle still have space for one more triangle (i.e. TriangleCount <2) 2992 atom *AtomCandidates[3]; 2993 AtomCandidates[0] = (*it)->point; 2994 AtomCandidates[1] = BaseRay->endpoints[0]->node; 2995 AtomCandidates[2] = BaseRay->endpoints[1]->node; 2996 int existentTrianglesCount = CheckPresenceOfTriangle(out, AtomCandidates); 2997 2998 BTS = NULL; 2999 // If there is no triangle, add it regularly. 3000 if (existentTrianglesCount == 0) { 2625 3001 AddTrianglePoint((*it)->point, 0); 2626 3002 AddTrianglePoint(BaseRay->endpoints[0]->node, 1); … … 2640 3016 << " for this triangle ... " << endl; 2641 3017 //cout << Verbose(1) << "We have "<< TrianglesOnBoundaryCount << " for line " << *BaseRay << "." << endl; 2642 3018 } else if (existentTrianglesCount == 1) { // If there is a planar region within the structure, we need this triangle a second time. 2643 3019 AddTrianglePoint((*it)->point, 0); 2644 3020 AddTrianglePoint(BaseRay->endpoints[0]->node, 1); … … 2679 3055 } 2680 3056 2681 3057 if ((result) && (existentTrianglesCount < 2) && (DoSingleStepOutput && (TrianglesOnBoundaryCount % 1 == 0))) { // if we have a new triangle and want to output each new triangle configuration 2682 3058 sprintf(NumberName, "-%04d-%s_%s_%s", TriangleFilesWritten, BTS->endpoints[0]->node->Name, BTS->endpoints[1]->node->Name, BTS->endpoints[2]->node->Name); 2683 3059 if (DoTecplotOutput) { … … 2711 3087 (*it)->OptCenter.AddVector(&helper); 2712 3088 Vector *center = mol->DetermineCenterOfAll(out); 2713 (*it)->OptCenter. AddVector(center);3089 (*it)->OptCenter.SubtractVector(center); 2714 3090 delete(center); 2715 3091 // and add to file plus translucency object … … 2726 3102 if (DoTecplotOutput || DoRaster3DOutput) 2727 3103 TriangleFilesWritten++; 2728 3104 } 2729 3105 2730 3106 // set baseline to new ray from ref point (here endpoints[0]->node) to current candidate (here (*it)->point)) 2731 3107 BaseRay = BLS[0]; 2732 3108 } 2733 3109 … … 2747 3123 */ 2748 3124 bool sortCandidates(CandidateForTesselation* candidate1, CandidateForTesselation* candidate2) { 2749 // TODO: use get angle and remove duplicate code2750 3125 Vector BaseLineVector, OrthogonalVector, helper; 2751 2752 2753 2754 2755 2756 2757 2758 2759 3126 if (candidate1->BaseLine != candidate2->BaseLine) { // sanity check 3127 cout << Verbose(0) << "ERROR: sortCandidates was called for two different baselines: " << candidate1->BaseLine << " and " << candidate2->BaseLine << "." << endl; 3128 //return false; 3129 exit(1); 3130 } 3131 // create baseline vector 3132 BaseLineVector.CopyVector(&(candidate1->BaseLine->endpoints[1]->node->x)); 3133 BaseLineVector.SubtractVector(&(candidate1->BaseLine->endpoints[0]->node->x)); 3134 BaseLineVector.Normalize(); 2760 3135 2761 3136 // create normal in-plane vector to cope with acos() non-uniqueness on [0,2pi] (note that is pointing in the "right" direction already, hence ">0" test!) 2762 2763 2764 2765 2766 2767 3137 helper.CopyVector(&(candidate1->BaseLine->endpoints[0]->node->x)); 3138 helper.SubtractVector(&(candidate1->point->x)); 3139 OrthogonalVector.CopyVector(&helper); 3140 helper.VectorProduct(&BaseLineVector); 3141 OrthogonalVector.SubtractVector(&helper); 3142 OrthogonalVector.Normalize(); 2768 3143 2769 3144 // calculate both angles and correct with in-plane vector 2770 2771 2772 3145 helper.CopyVector(&(candidate1->point->x)); 3146 helper.SubtractVector(&(candidate1->BaseLine->endpoints[0]->node->x)); 3147 double phi = BaseLineVector.Angle(&helper); 2773 3148 if (OrthogonalVector.ScalarProduct(&helper) > 0) { 2774 3149 phi = 2.*M_PI - phi; 2775 3150 } 2776 3151 helper.CopyVector(&(candidate2->point->x)); 2777 2778 3152 helper.SubtractVector(&(candidate1->BaseLine->endpoints[0]->node->x)); 3153 double psi = BaseLineVector.Angle(&helper); 2779 3154 if (OrthogonalVector.ScalarProduct(&helper) > 0) { 2780 psi = 2.*M_PI - psi; 2781 } 2782 2783 cout << Verbose(2) << *candidate1->point << " has angle " << phi << endl; 2784 cout << Verbose(2) << *candidate2->point << " has angle " << psi << endl; 2785 2786 // return comparison 2787 return phi < psi; 2788 } 2789 2790 /** 2791 * Checks whether the provided atom is within the tesselation structure. 2792 * 2793 * @param atom of which to check the position 2794 * @param tesselation structure 2795 * 2796 * @return true if the atom is inside the tesselation structure, false otherwise 2797 */ 2798 bool IsInnerAtom(atom *Atom, class Tesselation *Tess, LinkedCell* LC) { 2799 if (Tess->LinesOnBoundary.begin() == Tess->LinesOnBoundary.end()) { 2800 cout << Verbose(0) << "Error: There is no tesselation structure to compare the atom with, " 2801 << "please create one first."; 2802 exit(1); 2803 } 2804 2805 class atom *trianglePoints[3]; 2806 trianglePoints[0] = findClosestAtom(Atom, LC); 2807 // check whether closest atom is "too close" :), then it's inside 2808 if (trianglePoints[0]->x.DistanceSquared(&Atom->x) < MYEPSILON) 2809 return true; 2810 list<atom*> *connectedClosestAtoms = Tess->getClosestConnectedAtoms(trianglePoints[0], Atom); 2811 trianglePoints[1] = connectedClosestAtoms->front(); 2812 trianglePoints[2] = connectedClosestAtoms->back(); 2813 for (int i=0;i<3;i++) { 2814 if (trianglePoints[i] == NULL) { 2815 cout << Verbose(1) << "IsInnerAtom encounters serious error, point " << i << " not found." << endl; 2816 } 2817 2818 cout << Verbose(1) << "List of possible atoms:" << endl; 2819 cout << *trianglePoints[i] << endl; 2820 2821 // for(list<atom*>::iterator runner = connectedClosestAtoms->begin(); runner != connectedClosestAtoms->end(); runner++) 2822 // cout << Verbose(2) << *(*runner) << endl; 2823 } 2824 delete(connectedClosestAtoms); 2825 2826 list<BoundaryTriangleSet*> *triangles = Tess->FindTriangles(trianglePoints); 2827 2828 if (triangles->empty()) { 2829 cout << Verbose(0) << "Error: There is no nearest triangle. Please check the tesselation structure."; 2830 exit(1); 2831 } 2832 2833 Vector helper; 2834 helper.CopyVector(&Atom->x); 2835 2836 // Only in case of degeneration, there will be two different scalar products. 2837 // If at least one scalar product is positive, the point is considered to be outside. 2838 bool status = (helper.ScalarProduct(&triangles->front()->NormalVector) < 0) 2839 && (helper.ScalarProduct(&triangles->back()->NormalVector) < 0); 2840 delete(triangles); 2841 return status; 2842 } 2843 2844 /** 2845 * Finds the atom which is closest to the provided one. 2846 * 2847 * @param atom to which to find the closest other atom 2848 * @param linked cell structure 2849 * 2850 * @return atom which is closest to the provided one 2851 */ 2852 atom* findClosestAtom(const atom* Atom, LinkedCell* LC) { 2853 LinkedAtoms *List = NULL; 2854 atom* closestAtom = NULL; 2855 double distance = 1e16; 2856 Vector helper; 2857 int N[NDIM], Nlower[NDIM], Nupper[NDIM]; 2858 2859 LC->SetIndexToVector(&Atom->x); // ignore status as we calculate bounds below sensibly 2860 for(int i=0;i<NDIM;i++) // store indices of this cell 2861 N[i] = LC->n[i]; 2862 //cout << Verbose(2) << "INFO: Center cell is " << N[0] << ", " << N[1] << ", " << N[2] << " with No. " << LC->index << "." << endl; 2863 2864 LC->GetNeighbourBounds(Nlower, Nupper); 2865 //cout << endl; 2866 for (LC->n[0] = Nlower[0]; LC->n[0] <= Nupper[0]; LC->n[0]++) 2867 for (LC->n[1] = Nlower[1]; LC->n[1] <= Nupper[1]; LC->n[1]++) 2868 for (LC->n[2] = Nlower[2]; LC->n[2] <= Nupper[2]; LC->n[2]++) { 2869 List = LC->GetCurrentCell(); 2870 //cout << "The current cell " << LC->n[0] << "," << LC->n[1] << "," << LC->n[2] << endl; 2871 if (List != NULL) { 2872 for (LinkedAtoms::iterator Runner = List->begin(); Runner != List->end(); Runner++) { 2873 helper.CopyVector(&Atom->x); 2874 helper.SubtractVector(&(*Runner)->x); 2875 double currentNorm = helper. Norm(); 2876 if (currentNorm < distance) { 2877 distance = currentNorm; 2878 closestAtom = (*Runner); 2879 } 2880 } 2881 } else { 2882 cerr << "ERROR: The current cell " << LC->n[0] << "," << LC->n[1] << "," 2883 << LC->n[2] << " is invalid!" << endl; 2884 } 2885 } 2886 2887 return closestAtom; 2888 } 2889 2890 /** 2891 * Gets all atoms connected to the provided atom by triangulation lines. 2892 * 2893 * @param atom of which get all connected atoms 2894 * @param atom to be checked whether it is an inner atom 2895 * 2896 * @return list of the two atoms linked to the provided one and closest to the atom to be checked, 2897 */ 2898 list<atom*> * Tesselation::getClosestConnectedAtoms(atom* Atom, atom* AtomToCheck) { 2899 list<atom*> connectedAtoms; 2900 map<double, atom*> anglesOfAtoms; 2901 map<double, atom*>::iterator runner; 2902 LineMap::iterator findLines = LinesOnBoundary.begin(); 2903 list<atom*>::iterator listRunner; 2904 Vector center, planeNorm, currentPoint, OrthogonalVector, helper; 2905 atom* current; 2906 bool takeAtom = false; 2907 2908 planeNorm.CopyVector(&Atom->x); 2909 planeNorm.SubtractVector(&AtomToCheck->x); 2910 planeNorm.Normalize(); 2911 2912 while (findLines != LinesOnBoundary.end()) { 2913 takeAtom = false; 2914 2915 if (findLines->second->endpoints[0]->Nr == Atom->nr) { 2916 takeAtom = true; 2917 current = findLines->second->endpoints[1]->node; 2918 } else if (findLines->second->endpoints[1]->Nr == Atom->nr) { 2919 takeAtom = true; 2920 current = findLines->second->endpoints[0]->node; 2921 } 2922 2923 if (takeAtom) { 2924 connectedAtoms.push_back(current); 2925 currentPoint.CopyVector(¤t->x); 2926 currentPoint.ProjectOntoPlane(&planeNorm); 2927 center.AddVector(¤tPoint); 2928 } 2929 2930 findLines++; 2931 } 2932 2933 cout << "Summed vectors " << center << "; number of atoms " << connectedAtoms.size() 2934 << "; scale factor " << 1.0/connectedAtoms.size(); 2935 2936 center.Scale(1.0/connectedAtoms.size()); 2937 listRunner = connectedAtoms.begin(); 2938 2939 cout << " calculated center " << center << endl; 2940 2941 // construct one orthogonal vector 2942 helper.CopyVector(&AtomToCheck->x); 2943 helper.ProjectOntoPlane(&planeNorm); 2944 OrthogonalVector.MakeNormalVector(¢er, &helper, &(*listRunner)->x); 2945 while (listRunner != connectedAtoms.end()) { 2946 double angle = getAngle((*listRunner)->x, AtomToCheck->x, center, OrthogonalVector); 2947 cout << "Calculated angle " << angle << " for atom " << **listRunner << endl; 2948 anglesOfAtoms.insert(pair<double, atom*>(angle, (*listRunner))); 2949 listRunner++; 2950 } 2951 2952 list<atom*> *result = new list<atom*>; 2953 runner = anglesOfAtoms.begin(); 2954 cout << "First value is " << *runner->second << endl; 2955 result->push_back(runner->second); 2956 runner = anglesOfAtoms.end(); 2957 runner--; 2958 cout << "Second value is " << *runner->second << endl; 2959 result->push_back(runner->second); 2960 2961 cout << "List of closest atoms has " << result->size() << " elements, which are " 2962 << *(result->front()) << " and " << *(result->back()) << endl; 2963 2964 return result; 2965 } 2966 2967 /** 2968 * Finds triangles belonging to the three provided atoms. 2969 * 2970 * @param atom list, is expected to contain three atoms 2971 * 2972 * @return triangles which belong to the provided atoms, will be empty if there are none, 2973 * will usually be one, in case of degeneration, there will be two 2974 */ 2975 list<BoundaryTriangleSet*> *Tesselation::FindTriangles(atom* Points[3]) { 2976 list<BoundaryTriangleSet*> *result = new list<BoundaryTriangleSet*>; 2977 LineMap::iterator FindLine; 2978 PointMap::iterator FindPoint; 2979 TriangleMap::iterator FindTriangle; 2980 class BoundaryPointSet *TrianglePoints[3]; 2981 2982 for (int i = 0; i < 3; i++) { 2983 FindPoint = PointsOnBoundary.find(Points[i]->nr); 2984 if (FindPoint != PointsOnBoundary.end()) { 2985 TrianglePoints[i] = FindPoint->second; 2986 } else { 2987 TrianglePoints[i] = NULL; 2988 } 2989 } 2990 2991 // checks lines between the points in the Points for their adjacent triangles 2992 for (int i = 0; i < 3; i++) { 2993 if (TrianglePoints[i] != NULL) { 2994 for (int j = i; j < 3; j++) { 2995 if (TrianglePoints[j] != NULL) { 2996 FindLine = TrianglePoints[i]->lines.find(TrianglePoints[j]->node->nr); 2997 if (FindLine != TrianglePoints[i]->lines.end()) { 2998 for (; FindLine->first == TrianglePoints[j]->node->nr; FindLine++) { 2999 FindTriangle = FindLine->second->triangles.begin(); 3000 for (; FindTriangle != FindLine->second->triangles.end(); FindTriangle++) { 3001 if (( 3002 (FindTriangle->second->endpoints[0] == TrianglePoints[0]) 3003 || (FindTriangle->second->endpoints[0] == TrianglePoints[1]) 3004 || (FindTriangle->second->endpoints[0] == TrianglePoints[2]) 3005 ) && ( 3006 (FindTriangle->second->endpoints[1] == TrianglePoints[0]) 3007 || (FindTriangle->second->endpoints[1] == TrianglePoints[1]) 3008 || (FindTriangle->second->endpoints[1] == TrianglePoints[2]) 3009 ) && ( 3010 (FindTriangle->second->endpoints[2] == TrianglePoints[0]) 3011 || (FindTriangle->second->endpoints[2] == TrianglePoints[1]) 3012 || (FindTriangle->second->endpoints[2] == TrianglePoints[2]) 3013 ) 3014 ) { 3015 result->push_back(FindTriangle->second); 3016 } 3017 } 3018 } 3019 // Is it sufficient to consider one of the triangle lines for this. 3020 return result; 3021 3022 } 3023 } 3024 } 3025 } 3026 } 3027 3028 return result; 3029 } 3030 3031 /** 3032 * Gets the angle between a point and a reference relative to the provided center. 3033 * 3034 * @param point to calculate the angle for 3035 * @param reference to which to calculate the angle 3036 * @param center for which to calculate the angle between the vectors 3037 * @param OrthogonalVector helps discern between [0,pi] and [pi,2pi] in acos() 3038 * 3039 * @return angle between point and reference 3040 */ 3041 double getAngle(Vector point, Vector reference, Vector center, Vector OrthogonalVector) { 3042 Vector ReferenceVector, helper; 3043 cout << Verbose(2) << reference << " is our reference " << endl; 3044 cout << Verbose(2) << center << " is our center " << endl; 3045 // create baseline vector 3046 ReferenceVector.CopyVector(&reference); 3047 ReferenceVector.SubtractVector(¢er); 3048 if (ReferenceVector.IsNull()) 3049 return M_PI; 3050 3051 // calculate both angles and correct with in-plane vector 3052 helper.CopyVector(&point); 3053 helper.SubtractVector(¢er); 3054 if (helper.IsNull()) 3055 return M_PI; 3056 double phi = ReferenceVector.Angle(&helper); 3057 if (OrthogonalVector.ScalarProduct(&helper) > 0) { 3058 phi = 2.*M_PI - phi; 3059 } 3060 3061 cout << Verbose(2) << point << " has angle " << phi << endl; 3062 3063 return phi; 3064 } 3065 3066 /** 3067 * Checks whether the provided point is within the tesselation structure. 3068 * 3069 * This is a wrapper function for IsInnerAtom, so it can be used with a simple 3070 * vector, too. 3071 * 3072 * @param point of which to check the position 3073 * @param tesselation structure 3074 * 3075 * @return true if the point is inside the tesselation structure, false otherwise 3076 */ 3077 bool IsInnerPoint(Vector Point, class Tesselation *Tess, LinkedCell* LC) { 3078 atom *temp_atom = new atom; 3079 bool status = false; 3080 temp_atom->x.CopyVector(&Point); 3081 3082 status = IsInnerAtom(temp_atom, Tess, LC); 3083 delete(temp_atom); 3084 3085 return status; 3155 psi = 2.*M_PI - psi; 3156 } 3157 3158 cout << Verbose(2) << *candidate1->point << " has angle " << phi << endl; 3159 cout << Verbose(2) << *candidate2->point << " has angle " << psi << endl; 3160 3161 // return comparison 3162 return phi < psi; 3086 3163 } 3087 3164 … … 3090 3167 * \param *mol molecule structure with Atom's and Bond's 3091 3168 * \param *Tess Tesselation filled with points, lines and triangles on boundary on return 3169 * \param *LCList atoms in LinkedCell list 3092 3170 * \param *filename filename prefix for output of vertex data 3093 3171 * \para RADIUS radius of the virtual sphere … … 3137 3215 } 3138 3216 } 3139 if ( 1) { //failflag) {3217 if (filename != 0) { 3140 3218 *out << Verbose(1) << "Writing final tecplot file\n"; 3141 3219 if (DoTecplotOutput) { … … 3170 3248 cout << Verbose(2) << "None." << endl; 3171 3249 3172 // Tests the IsInnerAtom() function.3173 Vector x (0, 0, 0);3174 cout << Verbose(0) << "Point to check: " << x << endl;3175 cout << Verbose(0) << "Check: IsInnerPoint() returns " << IsInnerPoint(x, Tess, LCList)3176 << "for vector " << x << "." << endl;3177 atom* a = Tess->PointsOnBoundary.begin()->second->node;3178 cout << Verbose(0) << "Point to check: " << *a << " (on boundary)." << endl;3179 cout << Verbose(0) << "Check: IsInnerAtom() returns " << IsInnerAtom(a, Tess, LCList)3180 << "for atom " << a << " (on boundary)." << endl;3181 LinkedAtoms *List = NULL;3182 for (int i=0;i<NDIM;i++) { // each axis3183 LCList->n[i] = LCList->N[i]-1; // current axis is topmost cell3184 for (LCList->n[(i+1)%NDIM]=0;LCList->n[(i+1)%NDIM]<LCList->N[(i+1)%NDIM];LCList->n[(i+1)%NDIM]++)3185 for (LCList->n[(i+2)%NDIM]=0;LCList->n[(i+2)%NDIM]<LCList->N[(i+2)%NDIM];LCList->n[(i+2)%NDIM]++) {3186 List = LCList->GetCurrentCell();3187 //cout << Verbose(2) << "Current cell is " << LC->n[0] << ", " << LC->n[1] << ", " << LC->n[2] << " with No. " << LC->index << "." << endl;3188 if (List != NULL) {3189 for (LinkedAtoms::iterator Runner = List->begin();Runner != List->end();Runner++) {3190 if (Tess->PointsOnBoundary.find((*Runner)->nr) == Tess->PointsOnBoundary.end()) {3191 a = *Runner;3192 i=3;3193 for (int j=0;j<NDIM;j++)3194 LCList->n[j] = LCList->N[j];3195 break;3196 }3197 }3198 }3199 }3200 }3201 cout << Verbose(0) << "Check: IsInnerAtom() returns " << IsInnerAtom(a, Tess, LCList)3202 << "for atom " << a << " (inside)." << endl;3203 3204 3205 3250 if (freeTess) 3206 3251 delete(Tess);
Note:
See TracChangeset
for help on using the changeset viewer.