Changeset 6ac7ee for src/boundary.cpp
- Timestamp:
- Feb 9, 2009, 5:24:10 PM (16 years ago)
- Branches:
- Action_Thermostats, Add_AtomRandomPerturbation, Add_FitFragmentPartialChargesAction, Add_RotateAroundBondAction, Add_SelectAtomByNameAction, Added_ParseSaveFragmentResults, AddingActions_SaveParseParticleParameters, Adding_Graph_to_ChangeBondActions, Adding_MD_integration_tests, Adding_ParticleName_to_Atom, Adding_StructOpt_integration_tests, AtomFragments, Automaking_mpqc_open, AutomationFragmentation_failures, Candidate_v1.5.4, Candidate_v1.6.0, Candidate_v1.6.1, ChangeBugEmailaddress, ChangingTestPorts, ChemicalSpaceEvaluator, CombiningParticlePotentialParsing, Combining_Subpackages, Debian_Package_split, Debian_package_split_molecuildergui_only, Disabling_MemDebug, Docu_Python_wait, EmpiricalPotential_contain_HomologyGraph, EmpiricalPotential_contain_HomologyGraph_documentation, Enable_parallel_make_install, Enhance_userguide, Enhanced_StructuralOptimization, Enhanced_StructuralOptimization_continued, Example_ManyWaysToTranslateAtom, Exclude_Hydrogens_annealWithBondGraph, FitPartialCharges_GlobalError, Fix_BoundInBox_CenterInBox_MoleculeActions, Fix_ChargeSampling_PBC, Fix_ChronosMutex, Fix_FitPartialCharges, Fix_FitPotential_needs_atomicnumbers, Fix_ForceAnnealing, Fix_IndependentFragmentGrids, Fix_ParseParticles, Fix_ParseParticles_split_forward_backward_Actions, Fix_PopActions, Fix_QtFragmentList_sorted_selection, Fix_Restrictedkeyset_FragmentMolecule, Fix_StatusMsg, Fix_StepWorldTime_single_argument, Fix_Verbose_Codepatterns, Fix_fitting_potentials, Fixes, ForceAnnealing_goodresults, ForceAnnealing_oldresults, ForceAnnealing_tocheck, ForceAnnealing_with_BondGraph, ForceAnnealing_with_BondGraph_continued, ForceAnnealing_with_BondGraph_continued_betteresults, ForceAnnealing_with_BondGraph_contraction-expansion, FragmentAction_writes_AtomFragments, FragmentMolecule_checks_bonddegrees, GeometryObjects, Gui_Fixes, Gui_displays_atomic_force_velocity, ImplicitCharges, IndependentFragmentGrids, IndependentFragmentGrids_IndividualZeroInstances, IndependentFragmentGrids_IntegrationTest, IndependentFragmentGrids_Sole_NN_Calculation, JobMarket_RobustOnKillsSegFaults, JobMarket_StableWorkerPool, JobMarket_unresolvable_hostname_fix, MoreRobust_FragmentAutomation, ODR_violation_mpqc_open, PartialCharges_OrthogonalSummation, PdbParser_setsAtomName, PythonUI_with_named_parameters, QtGui_reactivate_TimeChanged_changes, Recreated_GuiChecks, Rewrite_FitPartialCharges, RotateToPrincipalAxisSystem_UndoRedo, SaturateAtoms_findBestMatching, SaturateAtoms_singleDegree, StoppableMakroAction, Subpackage_CodePatterns, Subpackage_JobMarket, Subpackage_LinearAlgebra, Subpackage_levmar, Subpackage_mpqc_open, Subpackage_vmg, Switchable_LogView, ThirdParty_MPQC_rebuilt_buildsystem, TrajectoryDependenant_MaxOrder, TremoloParser_IncreasedPrecision, TremoloParser_MultipleTimesteps, TremoloParser_setsAtomName, Ubuntu_1604_changes, stable
- Children:
- d8b94a
- Parents:
- 124df1
- git-author:
- Frederik Heber <heber@…> (02/09/09 15:55:37)
- git-committer:
- Frederik Heber <heber@…> (02/09/09 17:24:10)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
src/boundary.cpp
-
Property mode
changed from
100644
to100755
r124df1 r6ac7ee 1 #include "molecules.hpp"2 1 #include "boundary.hpp" 3 2 4 3 #define DEBUG 1 5 #define DoTecplotOutput 0 4 #define DoSingleStepOutput 0 5 #define DoTecplotOutput 1 6 6 #define DoRaster3DOutput 1 7 #define DoVRMLOutput 1 7 8 #define TecplotSuffix ".dat" 8 9 #define Raster3DSuffix ".r3d" 10 #define VRMLSUffix ".wrl" 11 #define HULLEPSILON MYEPSILON 9 12 10 13 // ======================================== Points on Boundary ================================= … … 12 15 BoundaryPointSet::BoundaryPointSet() 13 16 { 14 15 17 LinesCount = 0; 18 Nr = -1; 16 19 } 17 20 ; … … 19 22 BoundaryPointSet::BoundaryPointSet(atom *Walker) 20 23 { 21 22 23 24 node = Walker; 25 LinesCount = 0; 26 Nr = Walker->nr; 24 27 } 25 28 ; … … 27 30 BoundaryPointSet::~BoundaryPointSet() 28 31 { 29 cout << Verbose(5) << "Erasing point nr. " << Nr << "." << endl; 30 node = NULL; 31 } 32 ; 33 34 void 35 BoundaryPointSet::AddLine(class BoundaryLineSet *line) 36 { 37 cout << Verbose(6) << "Adding " << *this << " to line " << *line << "." 38 << endl; 39 if (line->endpoints[0] == this) 40 { 41 lines.insert(LinePair(line->endpoints[1]->Nr, line)); 42 } 43 else 44 { 45 lines.insert(LinePair(line->endpoints[0]->Nr, line)); 46 } 47 LinesCount++; 32 cout << Verbose(5) << "Erasing point nr. " << Nr << "." << endl; 33 if (!lines.empty()) 34 cerr << "WARNING: Memory Leak! I " << *this << " am still connected to some lines." << endl; 35 node = NULL; 36 } 37 ; 38 39 void BoundaryPointSet::AddLine(class BoundaryLineSet *line) 40 { 41 cout << Verbose(6) << "Adding " << *this << " to line " << *line << "." 42 << endl; 43 if (line->endpoints[0] == this) 44 { 45 lines.insert(LinePair(line->endpoints[1]->Nr, line)); 46 } 47 else 48 { 49 lines.insert(LinePair(line->endpoints[0]->Nr, line)); 50 } 51 LinesCount++; 48 52 } 49 53 ; … … 52 56 operator <<(ostream &ost, BoundaryPointSet &a) 53 57 { 54 55 58 ost << "[" << a.Nr << "|" << a.node->Name << "]"; 59 return ost; 56 60 } 57 61 ; … … 61 65 BoundaryLineSet::BoundaryLineSet() 62 66 { 63 64 65 66 67 for (int i = 0; i < 2; i++) 68 endpoints[i] = NULL; 69 TrianglesCount = 0; 70 Nr = -1; 67 71 } 68 72 ; … … 70 74 BoundaryLineSet::BoundaryLineSet(class BoundaryPointSet *Point[2], int number) 71 75 { 72 73 74 75 76 77 78 79 80 81 76 // set number 77 Nr = number; 78 // set endpoints in ascending order 79 SetEndpointsOrdered(endpoints, Point[0], Point[1]); 80 // add this line to the hash maps of both endpoints 81 Point[0]->AddLine(this); //Taken out, to check whether we can avoid unwanted double adding. 82 Point[1]->AddLine(this); // 83 // clear triangles list 84 TrianglesCount = 0; 85 cout << Verbose(5) << "New Line with endpoints " << *this << "." << endl; 82 86 } 83 87 ; … … 85 89 BoundaryLineSet::~BoundaryLineSet() 86 90 { 87 for (int i = 0; i < 2; i++) 88 { 89 cout << Verbose(5) << "Erasing Line Nr. " << Nr << " in boundary point " 90 << *endpoints[i] << "." << endl; 91 endpoints[i]->lines.erase(Nr); 92 LineMap::iterator tester = endpoints[i]->lines.begin(); 93 tester++; 94 if (tester == endpoints[i]->lines.end()) 95 { 96 cout << Verbose(5) << *endpoints[i] 97 << " has no more lines it's attached to, erasing." << endl; 98 //delete(endpoints[i]); 99 } 100 else 101 cout << Verbose(5) << *endpoints[i] 102 << " has still lines it's attached to." << endl; 103 } 91 int Numbers[2]; 92 Numbers[0] = endpoints[1]->Nr; 93 Numbers[1] = endpoints[0]->Nr; 94 for (int i = 0; i < 2; i++) { 95 cout << Verbose(5) << "Erasing Line Nr. " << Nr << " in boundary point " << *endpoints[i] << "." << endl; 96 endpoints[i]->lines.erase(Numbers[i]); 97 if (endpoints[i]->lines.empty()) { 98 cout << Verbose(5) << *endpoints[i] << " has no more lines it's attached to, erasing." << endl; 99 if (endpoints[i] != NULL) { 100 delete(endpoints[i]); 101 endpoints[i] = NULL; 102 } else 103 cerr << "ERROR: Endpoint " << i << " has already been free'd." << endl; 104 } else 105 cout << Verbose(5) << *endpoints[i] << " has still lines it's attached to." << endl; 106 } 107 if (!triangles.empty()) 108 cerr << "WARNING: Memory Leak! I " << *this << " am still connected to some triangles." << endl; 104 109 } 105 110 ; … … 108 113 BoundaryLineSet::AddTriangle(class BoundaryTriangleSet *triangle) 109 114 { 110 111 112 triangles.insert(TrianglePair(TrianglesCount, triangle));113 115 cout << Verbose(6) << "Add " << triangle->Nr << " to line " << *this << "." 116 << endl; 117 triangles.insert(TrianglePair(triangle->Nr, triangle)); 118 TrianglesCount++; 114 119 } 115 120 ; … … 118 123 operator <<(ostream &ost, BoundaryLineSet &a) 119 124 { 120 121 122 125 ost << "[" << a.Nr << "|" << a.endpoints[0]->node->Name << "," 126 << a.endpoints[1]->node->Name << "]"; 127 return ost; 123 128 } 124 129 ; … … 129 134 BoundaryTriangleSet::BoundaryTriangleSet() 130 135 { 131 132 133 134 135 136 136 for (int i = 0; i < 3; i++) 137 { 138 endpoints[i] = NULL; 139 lines[i] = NULL; 140 } 141 Nr = -1; 137 142 } 138 143 ; 139 144 140 145 BoundaryTriangleSet::BoundaryTriangleSet(class BoundaryLineSet *line[3], 141 142 { 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 146 int number) 147 { 148 // set number 149 Nr = number; 150 // set lines 151 cout << Verbose(5) << "New triangle " << Nr << ":" << endl; 152 for (int i = 0; i < 3; i++) 153 { 154 lines[i] = line[i]; 155 lines[i]->AddTriangle(this); 156 } 157 // get ascending order of endpoints 158 map<int, class BoundaryPointSet *> OrderMap; 159 for (int i = 0; i < 3; i++) 160 // for all three lines 161 for (int j = 0; j < 2; j++) 162 { // for both endpoints 163 OrderMap.insert(pair<int, class BoundaryPointSet *> ( 164 line[i]->endpoints[j]->Nr, line[i]->endpoints[j])); 165 // and we don't care whether insertion fails 166 } 167 // set endpoints 168 int Counter = 0; 169 cout << Verbose(6) << " with end points "; 170 for (map<int, class BoundaryPointSet *>::iterator runner = OrderMap.begin(); runner 171 != OrderMap.end(); runner++) 172 { 173 endpoints[Counter] = runner->second; 174 cout << " " << *endpoints[Counter]; 175 Counter++; 176 } 177 if (Counter < 3) 178 { 179 cerr << "ERROR! We have a triangle with only two distinct endpoints!" 180 << endl; 181 //exit(1); 182 } 183 cout << "." << endl; 179 184 } 180 185 ; … … 182 187 BoundaryTriangleSet::~BoundaryTriangleSet() 183 188 { 184 for (int i = 0; i < 3; i++) 185 { 186 cout << Verbose(5) << "Erasing triangle Nr." << Nr << endl; 187 lines[i]->triangles.erase(Nr); 188 TriangleMap::iterator tester = lines[i]->triangles.begin(); 189 tester++; 190 if (tester == lines[i]->triangles.end()) 191 { 192 cout << Verbose(5) << *lines[i] 193 << " is no more attached to any triangle, erasing." << endl; 194 delete (lines[i]); 195 } 196 else 197 cout << Verbose(5) << *lines[i] << " is still attached to a triangle." 198 << endl; 199 } 189 for (int i = 0; i < 3; i++) { 190 cout << Verbose(5) << "Erasing triangle Nr." << Nr << endl; 191 lines[i]->triangles.erase(Nr); 192 if (lines[i]->triangles.empty()) { 193 cout << Verbose(5) << *lines[i] << " is no more attached to any triangle, erasing." << endl; 194 if (lines[i] != NULL) { 195 delete (lines[i]); 196 lines[i] = NULL; 197 } else 198 cerr << "ERROR: This line " << i << " has already been free'd." << endl; 199 } else 200 cout << Verbose(5) << *lines[i] << " is still attached to a triangle." << endl; 201 } 200 202 } 201 203 ; … … 204 206 BoundaryTriangleSet::GetNormalVector(Vector &OtherVector) 205 207 { 206 207 208 209 210 211 if (endpoints[0]->node->x.Projection(&OtherVector) > 0)212 208 // get normal vector 209 NormalVector.MakeNormalVector(&endpoints[0]->node->x, &endpoints[1]->node->x, 210 &endpoints[2]->node->x); 211 212 // make it always point inward (any offset vector onto plane projected onto normal vector suffices) 213 if (NormalVector.Projection(&OtherVector) > 0) 214 NormalVector.Scale(-1.); 213 215 } 214 216 ; … … 217 219 operator <<(ostream &ost, BoundaryTriangleSet &a) 218 220 { 219 220 221 221 ost << "[" << a.Nr << "|" << a.endpoints[0]->node->Name << "," 222 << a.endpoints[1]->node->Name << "," << a.endpoints[2]->node->Name << "]"; 223 return ost; 222 224 } 223 225 ; … … 233 235 GetCommonEndpoint(class BoundaryLineSet * line1, class BoundaryLineSet * line2) 234 236 { 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 237 class BoundaryLineSet * lines[2] = 238 { line1, line2 }; 239 class BoundaryPointSet *node = NULL; 240 map<int, class BoundaryPointSet *> OrderMap; 241 pair<map<int, class BoundaryPointSet *>::iterator, bool> OrderTest; 242 for (int i = 0; i < 2; i++) 243 // for both lines 244 for (int j = 0; j < 2; j++) 245 { // for both endpoints 246 OrderTest = OrderMap.insert(pair<int, class BoundaryPointSet *> ( 247 lines[i]->endpoints[j]->Nr, lines[i]->endpoints[j])); 248 if (!OrderTest.second) 249 { // if insertion fails, we have common endpoint 250 node = OrderTest.first->second; 251 cout << Verbose(5) << "Common endpoint of lines " << *line1 252 << " and " << *line2 << " is: " << *node << "." << endl; 253 j = 2; 254 i = 2; 255 break; 256 } 257 } 258 return node; 257 259 } 258 260 ; … … 268 270 GetBoundaryPoints(ofstream *out, molecule *mol) 269 271 { 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 //*out << Verbose(1) << "Axisvector is ";290 //AxisVector.Output(out);291 //*out << " and AngleReferenceVector is ";292 //AngleReferenceVector.Output(out);293 //*out << "." << endl;294 //*out << " and AngleReferenceNormalVector is ";295 //AngleReferenceNormalVector.Output(out);296 //*out << "." << endl;297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 //{367 //*out << Verbose(2) << "Printing list of candidates for axis " << axis << " which we have inserted so far." << endl;368 //int i=0;369 //for(Boundaries::iterator runner = BoundaryPoints[axis].begin(); runner != BoundaryPoints[axis].end(); runner++) {370 //if (runner != BoundaryPoints[axis].begin())371 //*out << ", " << i << ": " << *runner->second.second;372 //else373 //*out << i << ": " << *runner->second.second;374 //i++;375 //}376 //*out << endl;377 //}378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 //*out << "SideA: ";415 //SideA.Output(out);416 //*out << endl;417 418 419 420 //*out << "SideB: ";421 //SideB.Output(out);422 //*out << endl;423 424 425 426 427 //*out << "SideC: ";428 //SideC.Output(out);429 //*out << endl;430 431 432 433 //*out << "SideH: ";434 //SideH.Output(out);435 //*out << endl;436 437 438 439 440 441 442 443 444 445 446 447 448 449 //*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;450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 272 atom *Walker = NULL; 273 PointMap PointsOnBoundary; 274 LineMap LinesOnBoundary; 275 TriangleMap TrianglesOnBoundary; 276 277 *out << Verbose(1) << "Finding all boundary points." << endl; 278 Boundaries *BoundaryPoints = new Boundaries[NDIM]; // first is alpha, second is (r, nr) 279 BoundariesTestPair BoundaryTestPair; 280 Vector AxisVector, AngleReferenceVector, AngleReferenceNormalVector; 281 double radius, angle; 282 // 3a. Go through every axis 283 for (int axis = 0; axis < NDIM; axis++) 284 { 285 AxisVector.Zero(); 286 AngleReferenceVector.Zero(); 287 AngleReferenceNormalVector.Zero(); 288 AxisVector.x[axis] = 1.; 289 AngleReferenceVector.x[(axis + 1) % NDIM] = 1.; 290 AngleReferenceNormalVector.x[(axis + 2) % NDIM] = 1.; 291 // *out << Verbose(1) << "Axisvector is "; 292 // AxisVector.Output(out); 293 // *out << " and AngleReferenceVector is "; 294 // AngleReferenceVector.Output(out); 295 // *out << "." << endl; 296 // *out << " and AngleReferenceNormalVector is "; 297 // AngleReferenceNormalVector.Output(out); 298 // *out << "." << endl; 299 // 3b. construct set of all points, transformed into cylindrical system and with left and right neighbours 300 Walker = mol->start; 301 while (Walker->next != mol->end) 302 { 303 Walker = Walker->next; 304 Vector ProjectedVector; 305 ProjectedVector.CopyVector(&Walker->x); 306 ProjectedVector.ProjectOntoPlane(&AxisVector); 307 // correct for negative side 308 //if (Projection(y) < 0) 309 //angle = 2.*M_PI - angle; 310 radius = ProjectedVector.Norm(); 311 if (fabs(radius) > MYEPSILON) 312 angle = ProjectedVector.Angle(&AngleReferenceVector); 313 else 314 angle = 0.; // otherwise it's a vector in Axis Direction and unimportant for boundary issues 315 316 //*out << "Checking sign in quadrant : " << ProjectedVector.Projection(&AngleReferenceNormalVector) << "." << endl; 317 if (ProjectedVector.Projection(&AngleReferenceNormalVector) > 0) 318 { 319 angle = 2. * M_PI - angle; 320 } 321 //*out << Verbose(2) << "Inserting " << *Walker << ": (r, alpha) = (" << radius << "," << angle << "): "; 322 //ProjectedVector.Output(out); 323 //*out << endl; 324 BoundaryTestPair = BoundaryPoints[axis].insert(BoundariesPair(angle, 325 DistancePair (radius, Walker))); 326 if (BoundaryTestPair.second) 327 { // successfully inserted 328 } 329 else 330 { // same point exists, check first r, then distance of original vectors to center of gravity 331 *out << Verbose(2) 332 << "Encountered two vectors whose projection onto axis " 333 << axis << " is equal: " << endl; 334 *out << Verbose(2) << "Present vector: "; 335 BoundaryTestPair.first->second.second->x.Output(out); 336 *out << endl; 337 *out << Verbose(2) << "New vector: "; 338 Walker->x.Output(out); 339 *out << endl; 340 double tmp = ProjectedVector.Norm(); 341 if (tmp > BoundaryTestPair.first->second.first) 342 { 343 BoundaryTestPair.first->second.first = tmp; 344 BoundaryTestPair.first->second.second = Walker; 345 *out << Verbose(2) << "Keeping new vector." << endl; 346 } 347 else if (tmp == BoundaryTestPair.first->second.first) 348 { 349 if (BoundaryTestPair.first->second.second->x.ScalarProduct( 350 &BoundaryTestPair.first->second.second->x) 351 < Walker->x.ScalarProduct(&Walker->x)) 352 { // Norm() does a sqrt, which makes it a lot slower 353 BoundaryTestPair.first->second.second = Walker; 354 *out << Verbose(2) << "Keeping new vector." << endl; 355 } 356 else 357 { 358 *out << Verbose(2) << "Keeping present vector." << endl; 359 } 360 } 361 else 362 { 363 *out << Verbose(2) << "Keeping present vector." << endl; 364 } 365 } 366 } 367 // printing all inserted for debugging 368 // { 369 // *out << Verbose(2) << "Printing list of candidates for axis " << axis << " which we have inserted so far." << endl; 370 // int i=0; 371 // for(Boundaries::iterator runner = BoundaryPoints[axis].begin(); runner != BoundaryPoints[axis].end(); runner++) { 372 // if (runner != BoundaryPoints[axis].begin()) 373 // *out << ", " << i << ": " << *runner->second.second; 374 // else 375 // *out << i << ": " << *runner->second.second; 376 // i++; 377 // } 378 // *out << endl; 379 // } 380 // 3c. throw out points whose distance is less than the mean of left and right neighbours 381 bool flag = false; 382 do 383 { // do as long as we still throw one out per round 384 *out << Verbose(1) 385 << "Looking for candidates to kick out by convex condition ... " 386 << endl; 387 flag = false; 388 Boundaries::iterator left = BoundaryPoints[axis].end(); 389 Boundaries::iterator right = BoundaryPoints[axis].end(); 390 for (Boundaries::iterator runner = BoundaryPoints[axis].begin(); runner 391 != BoundaryPoints[axis].end(); runner++) 392 { 393 // set neighbours correctly 394 if (runner == BoundaryPoints[axis].begin()) 395 { 396 left = BoundaryPoints[axis].end(); 397 } 398 else 399 { 400 left = runner; 401 } 402 left--; 403 right = runner; 404 right++; 405 if (right == BoundaryPoints[axis].end()) 406 { 407 right = BoundaryPoints[axis].begin(); 408 } 409 // check distance 410 411 // construct the vector of each side of the triangle on the projected plane (defined by normal vector AxisVector) 412 { 413 Vector SideA, SideB, SideC, SideH; 414 SideA.CopyVector(&left->second.second->x); 415 SideA.ProjectOntoPlane(&AxisVector); 416 // *out << "SideA: "; 417 // SideA.Output(out); 418 // *out << endl; 419 420 SideB.CopyVector(&right->second.second->x); 421 SideB.ProjectOntoPlane(&AxisVector); 422 // *out << "SideB: "; 423 // SideB.Output(out); 424 // *out << endl; 425 426 SideC.CopyVector(&left->second.second->x); 427 SideC.SubtractVector(&right->second.second->x); 428 SideC.ProjectOntoPlane(&AxisVector); 429 // *out << "SideC: "; 430 // SideC.Output(out); 431 // *out << endl; 432 433 SideH.CopyVector(&runner->second.second->x); 434 SideH.ProjectOntoPlane(&AxisVector); 435 // *out << "SideH: "; 436 // SideH.Output(out); 437 // *out << endl; 438 439 // calculate each length 440 double a = SideA.Norm(); 441 //double b = SideB.Norm(); 442 //double c = SideC.Norm(); 443 double h = SideH.Norm(); 444 // calculate the angles 445 double alpha = SideA.Angle(&SideH); 446 double beta = SideA.Angle(&SideC); 447 double gamma = SideB.Angle(&SideH); 448 double delta = SideC.Angle(&SideH); 449 double MinDistance = a * sin(beta) / (sin(delta)) * (((alpha 450 < M_PI / 2.) || (gamma < M_PI / 2.)) ? 1. : -1.); 451 // *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; 452 //*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; 453 if ((fabs(h / fabs(h) - MinDistance / fabs(MinDistance)) 454 < MYEPSILON) && (h < MinDistance)) 455 { 456 // throw out point 457 //*out << Verbose(1) << "Throwing out " << *runner->second.second << "." << endl; 458 BoundaryPoints[axis].erase(runner); 459 flag = true; 460 } 461 } 462 } 463 } 464 while (flag); 465 } 466 return BoundaryPoints; 465 467 } 466 468 ; … … 476 478 double * 477 479 GetDiametersOfCluster(ofstream *out, Boundaries *BoundaryPtr, molecule *mol, 478 479 { 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 } 569 ; 570 571 /** Creates the objects in a raster3d file (renderable with a header.r3d)480 bool IsAngstroem) 481 { 482 // get points on boundary of NULL was given as parameter 483 bool BoundaryFreeFlag = false; 484 Boundaries *BoundaryPoints = BoundaryPtr; 485 if (BoundaryPoints == NULL) 486 { 487 BoundaryFreeFlag = true; 488 BoundaryPoints = GetBoundaryPoints(out, mol); 489 } 490 else 491 { 492 *out << Verbose(1) << "Using given boundary points set." << endl; 493 } 494 // determine biggest "diameter" of cluster for each axis 495 Boundaries::iterator Neighbour, OtherNeighbour; 496 double *GreatestDiameter = new double[NDIM]; 497 for (int i = 0; i < NDIM; i++) 498 GreatestDiameter[i] = 0.; 499 double OldComponent, tmp, w1, w2; 500 Vector DistanceVector, OtherVector; 501 int component, Othercomponent; 502 for (int axis = 0; axis < NDIM; axis++) 503 { // regard each projected plane 504 //*out << Verbose(1) << "Current axis is " << axis << "." << endl; 505 for (int j = 0; j < 2; j++) 506 { // and for both axis on the current plane 507 component = (axis + j + 1) % NDIM; 508 Othercomponent = (axis + 1 + ((j + 1) & 1)) % NDIM; 509 //*out << Verbose(1) << "Current component is " << component << ", Othercomponent is " << Othercomponent << "." << endl; 510 for (Boundaries::iterator runner = BoundaryPoints[axis].begin(); runner 511 != BoundaryPoints[axis].end(); runner++) 512 { 513 //*out << Verbose(2) << "Current runner is " << *(runner->second.second) << "." << endl; 514 // seek for the neighbours pair where the Othercomponent sign flips 515 Neighbour = runner; 516 Neighbour++; 517 if (Neighbour == BoundaryPoints[axis].end()) // make it wrap around 518 Neighbour = BoundaryPoints[axis].begin(); 519 DistanceVector.CopyVector(&runner->second.second->x); 520 DistanceVector.SubtractVector(&Neighbour->second.second->x); 521 do 522 { // seek for neighbour pair where it flips 523 OldComponent = DistanceVector.x[Othercomponent]; 524 Neighbour++; 525 if (Neighbour == BoundaryPoints[axis].end()) // make it wrap around 526 Neighbour = BoundaryPoints[axis].begin(); 527 DistanceVector.CopyVector(&runner->second.second->x); 528 DistanceVector.SubtractVector(&Neighbour->second.second->x); 529 //*out << Verbose(3) << "OldComponent is " << OldComponent << ", new one is " << DistanceVector.x[Othercomponent] << "." << endl; 530 } 531 while ((runner != Neighbour) && (fabs(OldComponent / fabs( 532 OldComponent) - DistanceVector.x[Othercomponent] / fabs( 533 DistanceVector.x[Othercomponent])) < MYEPSILON)); // as long as sign does not flip 534 if (runner != Neighbour) 535 { 536 OtherNeighbour = Neighbour; 537 if (OtherNeighbour == BoundaryPoints[axis].begin()) // make it wrap around 538 OtherNeighbour = BoundaryPoints[axis].end(); 539 OtherNeighbour--; 540 //*out << Verbose(2) << "The pair, where the sign of OtherComponent flips, is: " << *(Neighbour->second.second) << " and " << *(OtherNeighbour->second.second) << "." << endl; 541 // now we have found the pair: Neighbour and OtherNeighbour 542 OtherVector.CopyVector(&runner->second.second->x); 543 OtherVector.SubtractVector(&OtherNeighbour->second.second->x); 544 //*out << Verbose(2) << "Distances to Neighbour and OtherNeighbour are " << DistanceVector.x[component] << " and " << OtherVector.x[component] << "." << endl; 545 //*out << Verbose(2) << "OtherComponents to Neighbour and OtherNeighbour are " << DistanceVector.x[Othercomponent] << " and " << OtherVector.x[Othercomponent] << "." << endl; 546 // do linear interpolation between points (is exact) to extract exact intersection between Neighbour and OtherNeighbour 547 w1 = fabs(OtherVector.x[Othercomponent]); 548 w2 = fabs(DistanceVector.x[Othercomponent]); 549 tmp = fabs((w1 * DistanceVector.x[component] + w2 550 * OtherVector.x[component]) / (w1 + w2)); 551 // mark if it has greater diameter 552 //*out << Verbose(2) << "Comparing current greatest " << GreatestDiameter[component] << " to new " << tmp << "." << endl; 553 GreatestDiameter[component] = (GreatestDiameter[component] 554 > tmp) ? GreatestDiameter[component] : tmp; 555 } //else 556 //*out << Verbose(2) << "Saw no sign flip, probably top or bottom node." << endl; 557 } 558 } 559 } 560 *out << Verbose(0) << "RESULT: The biggest diameters are " 561 << GreatestDiameter[0] << " and " << GreatestDiameter[1] << " and " 562 << GreatestDiameter[2] << " " << (IsAngstroem ? "angstrom" 563 : "atomiclength") << "." << endl; 564 565 // free reference lists 566 if (BoundaryFreeFlag) 567 delete[] (BoundaryPoints); 568 569 return GreatestDiameter; 570 } 571 ; 572 573 /** Creates the objects in a VRML file. 572 574 * \param *out output stream for debugging 573 * \param *tecplot output stream for tecplot data 575 * \param *vrmlfile output stream for tecplot data 576 * \param *Tess Tesselation structure with constructed triangles 577 * \param *mol molecule structure with atom positions 578 */ 579 void write_vrml_file(ofstream *out, ofstream *vrmlfile, class Tesselation *Tess, class molecule *mol) 580 { 581 atom *Walker = mol->start; 582 bond *Binder = mol->first; 583 int i; 584 Vector *center = mol->DetermineCenterOfAll(out); 585 if (vrmlfile != NULL) { 586 //cout << Verbose(1) << "Writing Raster3D file ... "; 587 *vrmlfile << "#VRML V2.0 utf8" << endl; 588 *vrmlfile << "#Created by molecuilder" << endl; 589 *vrmlfile << "#All atoms as spheres" << endl; 590 while (Walker->next != mol->end) { 591 Walker = Walker->next; 592 *vrmlfile << "Sphere {" << endl << " "; // 2 is sphere type 593 for (i=0;i<NDIM;i++) 594 *vrmlfile << Walker->x.x[i]+center->x[i] << " "; 595 *vrmlfile << "\t0.1\t1. 1. 1." << endl; // radius 0.05 and white as colour 596 } 597 598 *vrmlfile << "# All bonds as vertices" << endl; 599 while (Binder->next != mol->last) { 600 Binder = Binder->next; 601 *vrmlfile << "3" << endl << " "; // 2 is round-ended cylinder type 602 for (i=0;i<NDIM;i++) 603 *vrmlfile << Binder->leftatom->x.x[i]+center->x[i] << " "; 604 *vrmlfile << "\t0.03\t"; 605 for (i=0;i<NDIM;i++) 606 *vrmlfile << Binder->rightatom->x.x[i]+center->x[i] << " "; 607 *vrmlfile << "\t0.03\t0. 0. 1." << endl; // radius 0.05 and blue as colour 608 } 609 610 *vrmlfile << "# All tesselation triangles" << endl; 611 for (TriangleMap::iterator TriangleRunner = Tess->TrianglesOnBoundary.begin(); TriangleRunner != Tess->TrianglesOnBoundary.end(); TriangleRunner++) { 612 *vrmlfile << "1" << endl << " "; // 1 is triangle type 613 for (i=0;i<3;i++) { // print each node 614 for (int j=0;j<NDIM;j++) // and for each node all NDIM coordinates 615 *vrmlfile << TriangleRunner->second->endpoints[i]->node->x.x[j]+center->x[j] << " "; 616 *vrmlfile << "\t"; 617 } 618 *vrmlfile << "1. 0. 0." << endl; // red as colour 619 *vrmlfile << "18" << endl << " 0.5 0.5 0.5" << endl; // 18 is transparency type for previous object 620 } 621 } else { 622 cerr << "ERROR: Given vrmlfile is " << vrmlfile << "." << endl; 623 } 624 delete(center); 625 }; 626 627 /** Creates the objects in a raster3d file (renderable with a header.r3d). 628 * \param *out output stream for debugging 629 * \param *rasterfile output stream for tecplot data 574 630 * \param *Tess Tesselation structure with constructed triangles 575 631 * \param *mol molecule structure with atom positions … … 577 633 void write_raster3d_file(ofstream *out, ofstream *rasterfile, class Tesselation *Tess, class molecule *mol) 578 634 { 579 atom *Walker = mol->start; 580 bond *Binder = mol->first; 581 int i; 582 Vector *center = mol->DetermineCenterOfAll(out); 583 if (rasterfile != NULL) { 584 //cout << Verbose(1) << "Writing Raster3D file ... "; 585 *rasterfile << "# Raster3D object description, created by MoleCuilder" << endl; 586 *rasterfile << "@header.r3d" << endl; 587 *rasterfile << "# All atoms as spheres" << endl; 588 while (Walker->next != mol->end) { 589 Walker = Walker->next; 590 *rasterfile << "2" << endl << " "; // 2 is sphere type 591 for (i=0;i<NDIM;i++) 592 *rasterfile << Walker->x.x[i]+center->x[i] << " "; 593 *rasterfile << "\t0.1\t1. 1. 1." << endl; // radius 0.05 and white as colour 594 } 595 596 *rasterfile << "# All bonds as vertices" << endl; 597 while (Binder->next != mol->last) { 598 Binder = Binder->next; 599 *rasterfile << "3" << endl << " "; // 2 is round-ended cylinder type 600 for (i=0;i<NDIM;i++) 601 *rasterfile << Binder->leftatom->x.x[i]+center->x[i] << " "; 602 *rasterfile << "\t0.03\t"; 603 for (i=0;i<NDIM;i++) 604 *rasterfile << Binder->rightatom->x.x[i]+center->x[i] << " "; 605 *rasterfile << "\t0.03\t0. 0. 1." << endl; // radius 0.05 and blue as colour 606 } 607 608 *rasterfile << "# All tesselation triangles" << endl; 609 for (TriangleMap::iterator TriangleRunner = Tess->TrianglesOnBoundary.begin(); TriangleRunner != Tess->TrianglesOnBoundary.end(); TriangleRunner++) { 610 *rasterfile << "1" << endl << " "; // 1 is triangle type 611 for (i=0;i<3;i++) { // print each node 612 for (int j=0;j<NDIM;j++) // and for each node all NDIM coordinates 613 *rasterfile << TriangleRunner->second->endpoints[i]->node->x.x[j]+center->x[j] << " "; 614 *rasterfile << "\t"; 615 } 616 *rasterfile << "1. 0. 0." << endl; // red as colour 617 *rasterfile << "18" << endl << " 0.5 0.5 0.5" << endl; // 18 is transparency type for previous object 618 } 619 } else { 620 cerr << "ERROR: Given rasterfile is " << rasterfile << "." << endl; 621 } 622 delete(center); 635 atom *Walker = mol->start; 636 bond *Binder = mol->first; 637 int i; 638 Vector *center = mol->DetermineCenterOfAll(out); 639 if (rasterfile != NULL) { 640 //cout << Verbose(1) << "Writing Raster3D file ... "; 641 *rasterfile << "# Raster3D object description, created by MoleCuilder" << endl; 642 *rasterfile << "@header.r3d" << endl; 643 *rasterfile << "# All atoms as spheres" << endl; 644 while (Walker->next != mol->end) { 645 Walker = Walker->next; 646 *rasterfile << "2" << endl << " "; // 2 is sphere type 647 for (i=0;i<NDIM;i++) 648 *rasterfile << Walker->x.x[i]+center->x[i] << " "; 649 *rasterfile << "\t0.1\t1. 1. 1." << endl; // radius 0.05 and white as colour 650 } 651 652 *rasterfile << "# All bonds as vertices" << endl; 653 while (Binder->next != mol->last) { 654 Binder = Binder->next; 655 *rasterfile << "3" << endl << " "; // 2 is round-ended cylinder type 656 for (i=0;i<NDIM;i++) 657 *rasterfile << Binder->leftatom->x.x[i]+center->x[i] << " "; 658 *rasterfile << "\t0.03\t"; 659 for (i=0;i<NDIM;i++) 660 *rasterfile << Binder->rightatom->x.x[i]+center->x[i] << " "; 661 *rasterfile << "\t0.03\t0. 0. 1." << endl; // radius 0.05 and blue as colour 662 } 663 664 *rasterfile << "# All tesselation triangles" << endl; 665 *rasterfile << "8\n 25. -1. 1. 1. 1. 0.0 0 0 0 2\n SOLID 1.0 0.0 0.0\n BACKFACE 0.3 0.3 1.0 0 0\n"; 666 for (TriangleMap::iterator TriangleRunner = Tess->TrianglesOnBoundary.begin(); TriangleRunner != Tess->TrianglesOnBoundary.end(); TriangleRunner++) { 667 *rasterfile << "1" << endl << " "; // 1 is triangle type 668 for (i=0;i<3;i++) { // print each node 669 for (int j=0;j<NDIM;j++) // and for each node all NDIM coordinates 670 *rasterfile << TriangleRunner->second->endpoints[i]->node->x.x[j]+center->x[j] << " "; 671 *rasterfile << "\t"; 672 } 673 *rasterfile << "1. 0. 0." << endl; // red as colour 674 //*rasterfile << "18" << endl << " 0.5 0.5 0.5" << endl; // 18 is transparency type for previous object 675 } 676 *rasterfile << "9\n terminating special property\n"; 677 } else { 678 cerr << "ERROR: Given rasterfile is " << rasterfile << "." << endl; 679 } 680 delete(center); 623 681 }; 624 682 625 /* 626 * This function creates the tecplot file, displaying the tesselation of the hull. 683 /** This function creates the tecplot file, displaying the tesselation of the hull. 627 684 * \param *out output stream for debugging 628 685 * \param *tecplot output stream for tecplot data … … 631 688 void 632 689 write_tecplot_file(ofstream *out, ofstream *tecplot, 633 634 { 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 690 class Tesselation *TesselStruct, class molecule *mol, int N) 691 { 692 if (tecplot != NULL) 693 { 694 *tecplot << "TITLE = \"3D CONVEX SHELL\"" << endl; 695 *tecplot << "VARIABLES = \"X\" \"Y\" \"Z\"" << endl; 696 *tecplot << "ZONE T=\"TRIANGLES" << N << "\", N=" 697 << TesselStruct->PointsOnBoundaryCount << ", E=" 698 << TesselStruct->TrianglesOnBoundaryCount 699 << ", DATAPACKING=POINT, ZONETYPE=FETRIANGLE" << endl; 700 int *LookupList = new int[mol->AtomCount]; 701 for (int i = 0; i < mol->AtomCount; i++) 702 LookupList[i] = -1; 703 704 // print atom coordinates 705 *out << Verbose(2) << "The following triangles were created:"; 706 int Counter = 1; 707 atom *Walker = NULL; 708 for (PointMap::iterator target = TesselStruct->PointsOnBoundary.begin(); target 709 != TesselStruct->PointsOnBoundary.end(); target++) 710 { 711 Walker = target->second->node; 712 LookupList[Walker->nr] = Counter++; 713 *tecplot << Walker->x.x[0] << " " << Walker->x.x[1] << " " 714 << Walker->x.x[2] << " " << endl; 715 } 716 *tecplot << endl; 717 // print connectivity 718 for (TriangleMap::iterator runner = 719 TesselStruct->TrianglesOnBoundary.begin(); runner 720 != TesselStruct->TrianglesOnBoundary.end(); runner++) 721 { 722 *out << " " << runner->second->endpoints[0]->node->Name << "<->" 723 << runner->second->endpoints[1]->node->Name << "<->" 724 << runner->second->endpoints[2]->node->Name; 725 *tecplot << LookupList[runner->second->endpoints[0]->node->nr] << " " 726 << LookupList[runner->second->endpoints[1]->node->nr] << " " 727 << LookupList[runner->second->endpoints[2]->node->nr] << endl; 728 } 729 delete[] (LookupList); 730 *out << endl; 731 } 675 732 } 676 733 … … 678 735 * Determines first the convex envelope, then tesselates it and calculates its volume. 679 736 * \param *out output stream for debugging 680 * \param * tecplot output stream for tecplotdata737 * \param *filename filename prefix for output of vertex data 681 738 * \param *configuration needed for path to store convex envelope file 682 739 * \param *BoundaryPoints NDIM set of boundary points on the projected plane per axis, on return if desired … … 685 742 */ 686 743 double 687 VolumeOfConvexEnvelope(ofstream *out, ofstream *tecplot, config *configuration, 688 Boundaries *BoundaryPtr, molecule *mol) 689 { 690 bool IsAngstroem = configuration->GetIsAngstroem(); 691 atom *Walker = NULL; 692 struct Tesselation *TesselStruct = new Tesselation; 693 bool BoundaryFreeFlag = false; 694 Boundaries *BoundaryPoints = BoundaryPtr; 695 double volume = 0.; 696 double PyramidVolume = 0.; 697 double G, h; 698 Vector x, y; 699 double a, b, c; 700 701 //Find_non_convex_border(out, tecplot, *TesselStruct, mol); // Is now called from command line. 702 703 // 1. calculate center of gravity 704 *out << endl; 705 Vector *CenterOfGravity = mol->DetermineCenterOfGravity(out); 706 707 // 2. translate all points into CoG 708 *out << Verbose(1) << "Translating system to Center of Gravity." << endl; 709 Walker = mol->start; 710 while (Walker->next != mol->end) 711 { 712 Walker = Walker->next; 713 Walker->x.Translate(CenterOfGravity); 714 } 715 716 // 3. Find all points on the boundary 717 if (BoundaryPoints == NULL) 718 { 719 BoundaryFreeFlag = true; 720 BoundaryPoints = GetBoundaryPoints(out, mol); 721 } 722 else 723 { 724 *out << Verbose(1) << "Using given boundary points set." << endl; 725 } 726 727 // 4. fill the boundary point list 728 for (int axis = 0; axis < NDIM; axis++) 729 for (Boundaries::iterator runner = BoundaryPoints[axis].begin(); runner 730 != BoundaryPoints[axis].end(); runner++) 731 { 732 TesselStruct->AddPoint(runner->second.second); 733 } 734 735 *out << Verbose(2) << "I found " << TesselStruct->PointsOnBoundaryCount 736 << " points on the convex boundary." << endl; 737 // now we have the whole set of edge points in the BoundaryList 738 739 // listing for debugging 740 // *out << Verbose(1) << "Listing PointsOnBoundary:"; 741 // for(PointMap::iterator runner = PointsOnBoundary.begin(); runner != PointsOnBoundary.end(); runner++) { 742 // *out << " " << *runner->second; 743 // } 744 // *out << endl; 745 746 // 5a. guess starting triangle 747 TesselStruct->GuessStartingTriangle(out); 748 749 // 5b. go through all lines, that are not yet part of two triangles (only of one so far) 750 TesselStruct->TesselateOnBoundary(out, configuration, mol); 751 752 *out << Verbose(2) << "I created " << TesselStruct->TrianglesOnBoundaryCount 753 << " triangles with " << TesselStruct->LinesOnBoundaryCount 754 << " lines and " << TesselStruct->PointsOnBoundaryCount << " points." 755 << endl; 756 757 // 6a. Every triangle forms a pyramid with the center of gravity as its peak, sum up the volumes 758 *out << Verbose(1) 759 << "Calculating the volume of the pyramids formed out of triangles and center of gravity." 760 << endl; 761 for (TriangleMap::iterator runner = TesselStruct->TrianglesOnBoundary.begin(); runner 762 != TesselStruct->TrianglesOnBoundary.end(); runner++) 763 { // go through every triangle, calculate volume of its pyramid with CoG as peak 764 x.CopyVector(&runner->second->endpoints[0]->node->x); 765 x.SubtractVector(&runner->second->endpoints[1]->node->x); 766 y.CopyVector(&runner->second->endpoints[0]->node->x); 767 y.SubtractVector(&runner->second->endpoints[2]->node->x); 768 a = sqrt(runner->second->endpoints[0]->node->x.Distance( 769 &runner->second->endpoints[1]->node->x)); 770 b = sqrt(runner->second->endpoints[0]->node->x.Distance( 771 &runner->second->endpoints[2]->node->x)); 772 c = sqrt(runner->second->endpoints[2]->node->x.Distance( 773 &runner->second->endpoints[1]->node->x)); 774 G = sqrt(((a * a + b * b + c * c) * (a * a + b * b + c * c) - 2 * (a * a 775 * a * a + b * b * b * b + c * c * c * c)) / 16.); // area of tesselated triangle 776 x.MakeNormalVector(&runner->second->endpoints[0]->node->x, 777 &runner->second->endpoints[1]->node->x, 778 &runner->second->endpoints[2]->node->x); 779 x.Scale(runner->second->endpoints[1]->node->x.Projection(&x)); 780 h = x.Norm(); // distance of CoG to triangle 781 PyramidVolume = (1. / 3.) * G * h; // this formula holds for _all_ pyramids (independent of n-edge base or (not) centered peak) 782 *out << Verbose(2) << "Area of triangle is " << G << " " 783 << (IsAngstroem ? "angstrom" : "atomiclength") << "^2, height is " 784 << h << " and the volume is " << PyramidVolume << " " 785 << (IsAngstroem ? "angstrom" : "atomiclength") << "^3." << endl; 786 volume += PyramidVolume; 787 } 788 *out << Verbose(0) << "RESULT: The summed volume is " << setprecision(10) 789 << volume << " " << (IsAngstroem ? "angstrom" : "atomiclength") << "^3." 790 << endl; 791 792 // 7. translate all points back from CoG 793 *out << Verbose(1) << "Translating system back from Center of Gravity." 794 << endl; 795 CenterOfGravity->Scale(-1); 796 Walker = mol->start; 797 while (Walker->next != mol->end) 798 { 799 Walker = Walker->next; 800 Walker->x.Translate(CenterOfGravity); 801 } 802 803 // 8. Store triangles in tecplot file 804 write_tecplot_file(out, tecplot, TesselStruct, mol, 0); 805 806 // free reference lists 807 if (BoundaryFreeFlag) 808 delete[] (BoundaryPoints); 809 810 return volume; 744 VolumeOfConvexEnvelope(ofstream *out, const char *filename, config *configuration, 745 Boundaries *BoundaryPtr, molecule *mol) 746 { 747 bool IsAngstroem = configuration->GetIsAngstroem(); 748 atom *Walker = NULL; 749 struct Tesselation *TesselStruct = new Tesselation; 750 bool BoundaryFreeFlag = false; 751 Boundaries *BoundaryPoints = BoundaryPtr; 752 double volume = 0.; 753 double PyramidVolume = 0.; 754 double G, h; 755 Vector x, y; 756 double a, b, c; 757 758 //Find_non_convex_border(out, tecplot, *TesselStruct, mol); // Is now called from command line. 759 760 // 1. calculate center of gravity 761 *out << endl; 762 Vector *CenterOfGravity = mol->DetermineCenterOfGravity(out); 763 764 // 2. translate all points into CoG 765 *out << Verbose(1) << "Translating system to Center of Gravity." << endl; 766 Walker = mol->start; 767 while (Walker->next != mol->end) 768 { 769 Walker = Walker->next; 770 Walker->x.Translate(CenterOfGravity); 771 } 772 773 // 3. Find all points on the boundary 774 if (BoundaryPoints == NULL) 775 { 776 BoundaryFreeFlag = true; 777 BoundaryPoints = GetBoundaryPoints(out, mol); 778 } 779 else 780 { 781 *out << Verbose(1) << "Using given boundary points set." << endl; 782 } 783 784 // 4. fill the boundary point list 785 for (int axis = 0; axis < NDIM; axis++) 786 for (Boundaries::iterator runner = BoundaryPoints[axis].begin(); runner 787 != BoundaryPoints[axis].end(); runner++) 788 { 789 TesselStruct->AddPoint(runner->second.second); 790 } 791 792 *out << Verbose(2) << "I found " << TesselStruct->PointsOnBoundaryCount 793 << " points on the convex boundary." << endl; 794 // now we have the whole set of edge points in the BoundaryList 795 796 // listing for debugging 797 // *out << Verbose(1) << "Listing PointsOnBoundary:"; 798 // for(PointMap::iterator runner = PointsOnBoundary.begin(); runner != PointsOnBoundary.end(); runner++) { 799 // *out << " " << *runner->second; 800 // } 801 // *out << endl; 802 803 // 5a. guess starting triangle 804 TesselStruct->GuessStartingTriangle(out); 805 806 // 5b. go through all lines, that are not yet part of two triangles (only of one so far) 807 TesselStruct->TesselateOnBoundary(out, configuration, mol); 808 809 *out << Verbose(2) << "I created " << TesselStruct->TrianglesOnBoundaryCount 810 << " triangles with " << TesselStruct->LinesOnBoundaryCount 811 << " lines and " << TesselStruct->PointsOnBoundaryCount << " points." 812 << endl; 813 814 // 6a. Every triangle forms a pyramid with the center of gravity as its peak, sum up the volumes 815 *out << Verbose(1) 816 << "Calculating the volume of the pyramids formed out of triangles and center of gravity." 817 << endl; 818 for (TriangleMap::iterator runner = TesselStruct->TrianglesOnBoundary.begin(); runner 819 != TesselStruct->TrianglesOnBoundary.end(); runner++) 820 { // go through every triangle, calculate volume of its pyramid with CoG as peak 821 x.CopyVector(&runner->second->endpoints[0]->node->x); 822 x.SubtractVector(&runner->second->endpoints[1]->node->x); 823 y.CopyVector(&runner->second->endpoints[0]->node->x); 824 y.SubtractVector(&runner->second->endpoints[2]->node->x); 825 a = sqrt(runner->second->endpoints[0]->node->x.DistanceSquared( 826 &runner->second->endpoints[1]->node->x)); 827 b = sqrt(runner->second->endpoints[0]->node->x.DistanceSquared( 828 &runner->second->endpoints[2]->node->x)); 829 c = sqrt(runner->second->endpoints[2]->node->x.DistanceSquared( 830 &runner->second->endpoints[1]->node->x)); 831 G = sqrt(((a + b + c) * (a + b + c) - 2 * (a * a + b * b + c * c)) / 16.); // area of tesselated triangle 832 x.MakeNormalVector(&runner->second->endpoints[0]->node->x, 833 &runner->second->endpoints[1]->node->x, 834 &runner->second->endpoints[2]->node->x); 835 x.Scale(runner->second->endpoints[1]->node->x.Projection(&x)); 836 h = x.Norm(); // distance of CoG to triangle 837 PyramidVolume = (1. / 3.) * G * h; // this formula holds for _all_ pyramids (independent of n-edge base or (not) centered peak) 838 *out << Verbose(2) << "Area of triangle is " << G << " " 839 << (IsAngstroem ? "angstrom" : "atomiclength") << "^2, height is " 840 << h << " and the volume is " << PyramidVolume << " " 841 << (IsAngstroem ? "angstrom" : "atomiclength") << "^3." << endl; 842 volume += PyramidVolume; 843 } 844 *out << Verbose(0) << "RESULT: The summed volume is " << setprecision(10) 845 << volume << " " << (IsAngstroem ? "angstrom" : "atomiclength") << "^3." 846 << endl; 847 848 // 7. translate all points back from CoG 849 *out << Verbose(1) << "Translating system back from Center of Gravity." 850 << endl; 851 CenterOfGravity->Scale(-1); 852 Walker = mol->start; 853 while (Walker->next != mol->end) 854 { 855 Walker = Walker->next; 856 Walker->x.Translate(CenterOfGravity); 857 } 858 859 // 8. Store triangles in tecplot file 860 string OutputName(filename); 861 OutputName.append(TecplotSuffix); 862 ofstream *tecplot = new ofstream(OutputName.c_str()); 863 write_tecplot_file(out, tecplot, TesselStruct, mol, 0); 864 tecplot->close(); 865 delete(tecplot); 866 867 // free reference lists 868 if (BoundaryFreeFlag) 869 delete[] (BoundaryPoints); 870 871 return volume; 811 872 } 812 873 ; … … 822 883 void 823 884 PrepareClustersinWater(ofstream *out, config *configuration, molecule *mol, 824 825 { 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 885 double ClusterVolume, double celldensity) 886 { 887 // transform to PAS 888 mol->PrincipalAxisSystem(out, true); 889 890 // some preparations beforehand 891 bool IsAngstroem = configuration->GetIsAngstroem(); 892 Boundaries *BoundaryPoints = GetBoundaryPoints(out, mol); 893 double clustervolume; 894 if (ClusterVolume == 0) 895 clustervolume = VolumeOfConvexEnvelope(out, NULL, configuration, 896 BoundaryPoints, mol); 897 else 898 clustervolume = ClusterVolume; 899 double *GreatestDiameter = GetDiametersOfCluster(out, BoundaryPoints, mol, 900 IsAngstroem); 901 Vector BoxLengths; 902 int repetition[NDIM] = 903 { 1, 1, 1 }; 904 int TotalNoClusters = 1; 905 for (int i = 0; i < NDIM; i++) 906 TotalNoClusters *= repetition[i]; 907 908 // sum up the atomic masses 909 double totalmass = 0.; 910 atom *Walker = mol->start; 911 while (Walker->next != mol->end) 912 { 913 Walker = Walker->next; 914 totalmass += Walker->type->mass; 915 } 916 *out << Verbose(0) << "RESULT: The summed mass is " << setprecision(10) 917 << totalmass << " atomicmassunit." << endl; 918 919 *out << Verbose(0) << "RESULT: The average density is " << setprecision(10) 920 << totalmass / clustervolume << " atomicmassunit/" 921 << (IsAngstroem ? "angstrom" : "atomiclength") << "^3." << endl; 922 923 // solve cubic polynomial 924 *out << Verbose(1) << "Solving equidistant suspension in water problem ..." 925 << endl; 926 double cellvolume; 927 if (IsAngstroem) 928 cellvolume = (TotalNoClusters * totalmass / SOLVENTDENSITY_A - (totalmass 929 / clustervolume)) / (celldensity - 1); 930 else 931 cellvolume = (TotalNoClusters * totalmass / SOLVENTDENSITY_a0 - (totalmass 932 / clustervolume)) / (celldensity - 1); 933 *out << Verbose(1) << "Cellvolume needed for a density of " << celldensity 934 << " g/cm^3 is " << cellvolume << " " << (IsAngstroem ? "angstrom" 935 : "atomiclength") << "^3." << endl; 936 937 double minimumvolume = TotalNoClusters * (GreatestDiameter[0] 938 * GreatestDiameter[1] * GreatestDiameter[2]); 939 *out << Verbose(1) 940 << "Minimum volume of the convex envelope contained in a rectangular box is " 941 << minimumvolume << " atomicmassunit/" << (IsAngstroem ? "angstrom" 942 : "atomiclength") << "^3." << endl; 943 if (minimumvolume > cellvolume) 944 { 945 cerr << Verbose(0) 946 << "ERROR: the containing box already has a greater volume than the envisaged cell volume!" 947 << endl; 948 cout << Verbose(0) 949 << "Setting Box dimensions to minimum possible, the greatest diameters." 950 << endl; 951 for (int i = 0; i < NDIM; i++) 952 BoxLengths.x[i] = GreatestDiameter[i]; 953 mol->CenterEdge(out, &BoxLengths); 954 } 955 else 956 { 957 BoxLengths.x[0] = (repetition[0] * GreatestDiameter[0] + repetition[1] 958 * GreatestDiameter[1] + repetition[2] * GreatestDiameter[2]); 959 BoxLengths.x[1] = (repetition[0] * repetition[1] * GreatestDiameter[0] 960 * GreatestDiameter[1] + repetition[0] * repetition[2] 961 * GreatestDiameter[0] * GreatestDiameter[2] + repetition[1] 962 * repetition[2] * GreatestDiameter[1] * GreatestDiameter[2]); 963 BoxLengths.x[2] = minimumvolume - cellvolume; 964 double x0 = 0., x1 = 0., x2 = 0.; 965 if (gsl_poly_solve_cubic(BoxLengths.x[0], BoxLengths.x[1], 966 BoxLengths.x[2], &x0, &x1, &x2) == 1) // either 1 or 3 on return 967 *out << Verbose(0) << "RESULT: The resulting spacing is: " << x0 968 << " ." << endl; 969 else 970 { 971 *out << Verbose(0) << "RESULT: The resulting spacings are: " << x0 972 << " and " << x1 << " and " << x2 << " ." << endl; 973 x0 = x2; // sorted in ascending order 974 } 975 976 cellvolume = 1; 977 for (int i = 0; i < NDIM; i++) 978 { 979 BoxLengths.x[i] = repetition[i] * (x0 + GreatestDiameter[i]); 980 cellvolume *= BoxLengths.x[i]; 981 } 982 983 // set new box dimensions 984 *out << Verbose(0) << "Translating to box with these boundaries." << endl; 985 mol->CenterInBox((ofstream *) &cout, &BoxLengths); 986 } 987 // update Box of atoms by boundary 988 mol->SetBoxDimension(&BoxLengths); 989 *out << Verbose(0) << "RESULT: The resulting cell dimensions are: " 990 << BoxLengths.x[0] << " and " << BoxLengths.x[1] << " and " 991 << BoxLengths.x[2] << " with total volume of " << cellvolume << " " 992 << (IsAngstroem ? "angstrom" : "atomiclength") << "^3." << endl; 932 993 } 933 994 ; … … 939 1000 Tesselation::Tesselation() 940 1001 { 941 942 943 944 1002 PointsOnBoundaryCount = 0; 1003 LinesOnBoundaryCount = 0; 1004 TrianglesOnBoundaryCount = 0; 1005 TriangleFilesWritten = 0; 945 1006 } 946 1007 ; … … 951 1012 Tesselation::~Tesselation() 952 1013 { 953 cout << Verbose(1) << "Free'ing TesselStruct ... " << endl; 954 for (TriangleMap::iterator runner = TrianglesOnBoundary.begin(); runner 955 != TrianglesOnBoundary.end(); runner++) 956 { 957 delete (runner->second); 958 } 1014 cout << Verbose(1) << "Free'ing TesselStruct ... " << endl; 1015 for (TriangleMap::iterator runner = TrianglesOnBoundary.begin(); runner != TrianglesOnBoundary.end(); runner++) { 1016 if (runner->second != NULL) { 1017 delete (runner->second); 1018 runner->second = NULL; 1019 } else 1020 cerr << "ERROR: The triangle " << runner->first << " has already been free'd." << endl; 1021 } 959 1022 } 960 1023 ; … … 968 1031 Tesselation::GuessStartingTriangle(ofstream *out) 969 1032 { 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 tmp = A->second->node->x.Distance(&B->second->node->x);990 991 tmp = A->second->node->x.Distance(&C->second->node->x);992 993 tmp = B->second->node->x.Distance(&C->second->node->x);994 995 996 997 998 999 1000 //// listing distances1001 //*out << Verbose(1) << "Listing DistanceMMap:";1002 //for(DistanceMultiMap::iterator runner = DistanceMMap.begin(); runner != DistanceMMap.end(); runner++) {1003 //*out << " " << runner->first << "(" << *runner->second.first->second << ", " << *runner->second.second->second << ")";1004 //}1005 //*out << endl;1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 tmp = checker->second->node->x.Distance(&A->second->node->x);1062 1063 if ((tmp < A->second->node->x.Distance(1064 1065 < A->second->node->x.Distance(1066 1067 1068 tmp = checker->second->node->x.Distance(1069 1070 if ((tmp < baseline->second.first->second->node->x.Distance(1071 1072 < baseline->second.first->second->node->x.Distance(1073 1074 1075 tmp = checker->second->node->x.Distance(1076 1077 if ((tmp < baseline->second.second->second->node->x.Distance(1078 1079 < baseline->second.second->second->node->x.Distance(1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1033 // 4b. create a starting triangle 1034 // 4b1. create all distances 1035 DistanceMultiMap DistanceMMap; 1036 double distance, tmp; 1037 Vector PlaneVector, TrialVector; 1038 PointMap::iterator A, B, C; // three nodes of the first triangle 1039 A = PointsOnBoundary.begin(); // the first may be chosen arbitrarily 1040 1041 // with A chosen, take each pair B,C and sort 1042 if (A != PointsOnBoundary.end()) 1043 { 1044 B = A; 1045 B++; 1046 for (; B != PointsOnBoundary.end(); B++) 1047 { 1048 C = B; 1049 C++; 1050 for (; C != PointsOnBoundary.end(); C++) 1051 { 1052 tmp = A->second->node->x.DistanceSquared(&B->second->node->x); 1053 distance = tmp * tmp; 1054 tmp = A->second->node->x.DistanceSquared(&C->second->node->x); 1055 distance += tmp * tmp; 1056 tmp = B->second->node->x.DistanceSquared(&C->second->node->x); 1057 distance += tmp * tmp; 1058 DistanceMMap.insert(DistanceMultiMapPair(distance, pair< 1059 PointMap::iterator, PointMap::iterator> (B, C))); 1060 } 1061 } 1062 } 1063 // // listing distances 1064 // *out << Verbose(1) << "Listing DistanceMMap:"; 1065 // for(DistanceMultiMap::iterator runner = DistanceMMap.begin(); runner != DistanceMMap.end(); runner++) { 1066 // *out << " " << runner->first << "(" << *runner->second.first->second << ", " << *runner->second.second->second << ")"; 1067 // } 1068 // *out << endl; 1069 // 4b2. pick three baselines forming a triangle 1070 // 1. we take from the smallest sum of squared distance as the base line BC (with peak A) onward as the triangle candidate 1071 DistanceMultiMap::iterator baseline = DistanceMMap.begin(); 1072 for (; baseline != DistanceMMap.end(); baseline++) 1073 { 1074 // we take from the smallest sum of squared distance as the base line BC (with peak A) onward as the triangle candidate 1075 // 2. next, we have to check whether all points reside on only one side of the triangle 1076 // 3. construct plane vector 1077 PlaneVector.MakeNormalVector(&A->second->node->x, 1078 &baseline->second.first->second->node->x, 1079 &baseline->second.second->second->node->x); 1080 *out << Verbose(2) << "Plane vector of candidate triangle is "; 1081 PlaneVector.Output(out); 1082 *out << endl; 1083 // 4. loop over all points 1084 double sign = 0.; 1085 PointMap::iterator checker = PointsOnBoundary.begin(); 1086 for (; checker != PointsOnBoundary.end(); checker++) 1087 { 1088 // (neglecting A,B,C) 1089 if ((checker == A) || (checker == baseline->second.first) || (checker 1090 == baseline->second.second)) 1091 continue; 1092 // 4a. project onto plane vector 1093 TrialVector.CopyVector(&checker->second->node->x); 1094 TrialVector.SubtractVector(&A->second->node->x); 1095 distance = TrialVector.Projection(&PlaneVector); 1096 if (fabs(distance) < 1e-4) // we need to have a small epsilon around 0 which is still ok 1097 continue; 1098 *out << Verbose(3) << "Projection of " << checker->second->node->Name 1099 << " yields distance of " << distance << "." << endl; 1100 tmp = distance / fabs(distance); 1101 // 4b. Any have different sign to than before? (i.e. would lie outside convex hull with this starting triangle) 1102 if ((sign != 0) && (tmp != sign)) 1103 { 1104 // 4c. If so, break 4. loop and continue with next candidate in 1. loop 1105 *out << Verbose(2) << "Current candidates: " 1106 << A->second->node->Name << "," 1107 << baseline->second.first->second->node->Name << "," 1108 << baseline->second.second->second->node->Name << " leave " 1109 << checker->second->node->Name << " outside the convex hull." 1110 << endl; 1111 break; 1112 } 1113 else 1114 { // note the sign for later 1115 *out << Verbose(2) << "Current candidates: " 1116 << A->second->node->Name << "," 1117 << baseline->second.first->second->node->Name << "," 1118 << baseline->second.second->second->node->Name << " leave " 1119 << checker->second->node->Name << " inside the convex hull." 1120 << endl; 1121 sign = tmp; 1122 } 1123 // 4d. Check whether the point is inside the triangle (check distance to each node 1124 tmp = checker->second->node->x.DistanceSquared(&A->second->node->x); 1125 int innerpoint = 0; 1126 if ((tmp < A->second->node->x.DistanceSquared( 1127 &baseline->second.first->second->node->x)) && (tmp 1128 < A->second->node->x.DistanceSquared( 1129 &baseline->second.second->second->node->x))) 1130 innerpoint++; 1131 tmp = checker->second->node->x.DistanceSquared( 1132 &baseline->second.first->second->node->x); 1133 if ((tmp < baseline->second.first->second->node->x.DistanceSquared( 1134 &A->second->node->x)) && (tmp 1135 < baseline->second.first->second->node->x.DistanceSquared( 1136 &baseline->second.second->second->node->x))) 1137 innerpoint++; 1138 tmp = checker->second->node->x.DistanceSquared( 1139 &baseline->second.second->second->node->x); 1140 if ((tmp < baseline->second.second->second->node->x.DistanceSquared( 1141 &baseline->second.first->second->node->x)) && (tmp 1142 < baseline->second.second->second->node->x.DistanceSquared( 1143 &A->second->node->x))) 1144 innerpoint++; 1145 // 4e. If so, break 4. loop and continue with next candidate in 1. loop 1146 if (innerpoint == 3) 1147 break; 1148 } 1149 // 5. come this far, all on same side? Then break 1. loop and construct triangle 1150 if (checker == PointsOnBoundary.end()) 1151 { 1152 *out << "Looks like we have a candidate!" << endl; 1153 break; 1154 } 1155 } 1156 if (baseline != DistanceMMap.end()) 1157 { 1158 BPS[0] = baseline->second.first->second; 1159 BPS[1] = baseline->second.second->second; 1160 BLS[0] = new class BoundaryLineSet(BPS, LinesOnBoundaryCount); 1161 BPS[0] = A->second; 1162 BPS[1] = baseline->second.second->second; 1163 BLS[1] = new class BoundaryLineSet(BPS, LinesOnBoundaryCount); 1164 BPS[0] = baseline->second.first->second; 1165 BPS[1] = A->second; 1166 BLS[2] = new class BoundaryLineSet(BPS, LinesOnBoundaryCount); 1167 1168 // 4b3. insert created triangle 1169 BTS = new class BoundaryTriangleSet(BLS, TrianglesOnBoundaryCount); 1170 TrianglesOnBoundary.insert(TrianglePair(TrianglesOnBoundaryCount, BTS)); 1171 TrianglesOnBoundaryCount++; 1172 for (int i = 0; i < NDIM; i++) 1173 { 1174 LinesOnBoundary.insert(LinePair(LinesOnBoundaryCount, BTS->lines[i])); 1175 LinesOnBoundaryCount++; 1176 } 1177 1178 *out << Verbose(1) << "Starting triangle is " << *BTS << "." << endl; 1179 } 1180 else 1181 { 1182 *out << Verbose(1) << "No starting triangle found." << endl; 1183 exit(255); 1184 } 1122 1185 } 1123 1186 ; … … 1128 1191 * -# if the lines contains to only one triangle 1129 1192 * -# We search all points in the boundary 1130 * 1131 * 1132 * 1133 * 1193 * -# if the triangle with the baseline and the current point has the smallest of angles (comparison between normal vectors 1194 * -# if the triangle is in forward direction of the baseline (at most 90 degrees angle between vector orthogonal to 1195 * baseline in triangle plane pointing out of the triangle and normal vector of new triangle) 1196 * -# then we have a new triangle, whose baselines we again add (or increase their TriangleCount) 1134 1197 * \param *out output stream for debugging 1135 1198 * \param *configuration for IsAngstroem … … 1138 1201 void 1139 1202 Tesselation::TesselateOnBoundary(ofstream *out, config *configuration, 1140 1141 { 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 //if (LineChecker[0] != baseline->second->endpoints[0]->lines.end())1229 //*out << Verbose(4) << *(baseline->second->endpoints[0]) << " has line " << *(LineChecker[0]->second) << " to " << *(target->second) << " as endpoint with " << LineChecker[0]->second->TrianglesCount << " triangles." << endl;1230 //else1231 //*out << Verbose(4) << *(baseline->second->endpoints[0]) << " has no line to " << *(target->second) << " as endpoint." << endl;1232 //if (LineChecker[1] != baseline->second->endpoints[1]->lines.end())1233 //*out << Verbose(4) << *(baseline->second->endpoints[1]) << " has line " << *(LineChecker[1]->second) << " to " << *(target->second) << " as endpoint with " << LineChecker[1]->second->TrianglesCount << " triangles." << endl;1234 //else1235 //*out << Verbose(4) << *(baseline->second->endpoints[1]) << " has no line to " << *(target->second) << " as endpoint." << endl;1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1203 molecule *mol) 1204 { 1205 bool flag; 1206 PointMap::iterator winner; 1207 class BoundaryPointSet *peak = NULL; 1208 double SmallestAngle, TempAngle; 1209 Vector NormalVector, VirtualNormalVector, CenterVector, TempVector, 1210 PropagationVector; 1211 LineMap::iterator LineChecker[2]; 1212 do 1213 { 1214 flag = false; 1215 for (LineMap::iterator baseline = LinesOnBoundary.begin(); baseline 1216 != LinesOnBoundary.end(); baseline++) 1217 if (baseline->second->TrianglesCount == 1) 1218 { 1219 *out << Verbose(2) << "Current baseline is between " 1220 << *(baseline->second) << "." << endl; 1221 // 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) 1222 SmallestAngle = M_PI; 1223 BTS = baseline->second->triangles.begin()->second; // there is only one triangle so far 1224 // get peak point with respect to this base line's only triangle 1225 for (int i = 0; i < 3; i++) 1226 if ((BTS->endpoints[i] != baseline->second->endpoints[0]) 1227 && (BTS->endpoints[i] != baseline->second->endpoints[1])) 1228 peak = BTS->endpoints[i]; 1229 *out << Verbose(3) << " and has peak " << *peak << "." << endl; 1230 // normal vector of triangle 1231 BTS->GetNormalVector(NormalVector); 1232 *out << Verbose(4) << "NormalVector of base triangle is "; 1233 NormalVector.Output(out); 1234 *out << endl; 1235 // offset to center of triangle 1236 CenterVector.Zero(); 1237 for (int i = 0; i < 3; i++) 1238 CenterVector.AddVector(&BTS->endpoints[i]->node->x); 1239 CenterVector.Scale(1. / 3.); 1240 *out << Verbose(4) << "CenterVector of base triangle is "; 1241 CenterVector.Output(out); 1242 *out << endl; 1243 // vector in propagation direction (out of triangle) 1244 // project center vector onto triangle plane (points from intersection plane-NormalVector to plane-CenterVector intersection) 1245 TempVector.CopyVector(&baseline->second->endpoints[0]->node->x); 1246 TempVector.SubtractVector(&baseline->second->endpoints[1]->node->x); 1247 PropagationVector.MakeNormalVector(&TempVector, &NormalVector); 1248 TempVector.CopyVector(&CenterVector); 1249 TempVector.SubtractVector(&baseline->second->endpoints[0]->node->x); // TempVector is vector on triangle plane pointing from one baseline egde towards center! 1250 //*out << Verbose(2) << "Projection of propagation onto temp: " << PropagationVector.Projection(&TempVector) << "." << endl; 1251 if (PropagationVector.Projection(&TempVector) > 0) // make sure normal propagation vector points outward from baseline 1252 PropagationVector.Scale(-1.); 1253 *out << Verbose(4) << "PropagationVector of base triangle is "; 1254 PropagationVector.Output(out); 1255 *out << endl; 1256 winner = PointsOnBoundary.end(); 1257 for (PointMap::iterator target = PointsOnBoundary.begin(); target 1258 != PointsOnBoundary.end(); target++) 1259 if ((target->second != baseline->second->endpoints[0]) 1260 && (target->second != baseline->second->endpoints[1])) 1261 { // don't take the same endpoints 1262 *out << Verbose(3) << "Target point is " << *(target->second) 1263 << ":"; 1264 bool continueflag = true; 1265 1266 VirtualNormalVector.CopyVector( 1267 &baseline->second->endpoints[0]->node->x); 1268 VirtualNormalVector.AddVector( 1269 &baseline->second->endpoints[0]->node->x); 1270 VirtualNormalVector.Scale(-1. / 2.); // points now to center of base line 1271 VirtualNormalVector.AddVector(&target->second->node->x); // points from center of base line to target 1272 TempAngle = VirtualNormalVector.Angle(&PropagationVector); 1273 continueflag = continueflag && (TempAngle < (M_PI/2.)); // no bends bigger than Pi/2 (90 degrees) 1274 if (!continueflag) 1275 { 1276 *out << Verbose(4) 1277 << "Angle between propagation direction and base line to " 1278 << *(target->second) << " is " << TempAngle 1279 << ", bad direction!" << endl; 1280 continue; 1281 } 1282 else 1283 *out << Verbose(4) 1284 << "Angle between propagation direction and base line to " 1285 << *(target->second) << " is " << TempAngle 1286 << ", good direction!" << endl; 1287 LineChecker[0] = baseline->second->endpoints[0]->lines.find( 1288 target->first); 1289 LineChecker[1] = baseline->second->endpoints[1]->lines.find( 1290 target->first); 1291 // if (LineChecker[0] != baseline->second->endpoints[0]->lines.end()) 1292 // *out << Verbose(4) << *(baseline->second->endpoints[0]) << " has line " << *(LineChecker[0]->second) << " to " << *(target->second) << " as endpoint with " << LineChecker[0]->second->TrianglesCount << " triangles." << endl; 1293 // else 1294 // *out << Verbose(4) << *(baseline->second->endpoints[0]) << " has no line to " << *(target->second) << " as endpoint." << endl; 1295 // if (LineChecker[1] != baseline->second->endpoints[1]->lines.end()) 1296 // *out << Verbose(4) << *(baseline->second->endpoints[1]) << " has line " << *(LineChecker[1]->second) << " to " << *(target->second) << " as endpoint with " << LineChecker[1]->second->TrianglesCount << " triangles." << endl; 1297 // else 1298 // *out << Verbose(4) << *(baseline->second->endpoints[1]) << " has no line to " << *(target->second) << " as endpoint." << endl; 1299 // check first endpoint (if any connecting line goes to target or at least not more than 1) 1300 continueflag = continueflag && (((LineChecker[0] 1301 == baseline->second->endpoints[0]->lines.end()) 1302 || (LineChecker[0]->second->TrianglesCount == 1))); 1303 if (!continueflag) 1304 { 1305 *out << Verbose(4) << *(baseline->second->endpoints[0]) 1306 << " has line " << *(LineChecker[0]->second) 1307 << " to " << *(target->second) 1308 << " as endpoint with " 1309 << LineChecker[0]->second->TrianglesCount 1310 << " triangles." << endl; 1311 continue; 1312 } 1313 // check second endpoint (if any connecting line goes to target or at least not more than 1) 1314 continueflag = continueflag && (((LineChecker[1] 1315 == baseline->second->endpoints[1]->lines.end()) 1316 || (LineChecker[1]->second->TrianglesCount == 1))); 1317 if (!continueflag) 1318 { 1319 *out << Verbose(4) << *(baseline->second->endpoints[1]) 1320 << " has line " << *(LineChecker[1]->second) 1321 << " to " << *(target->second) 1322 << " as endpoint with " 1323 << LineChecker[1]->second->TrianglesCount 1324 << " triangles." << endl; 1325 continue; 1326 } 1327 // check whether the envisaged triangle does not already exist (if both lines exist and have same endpoint) 1328 continueflag = continueflag && (!(((LineChecker[0] 1329 != baseline->second->endpoints[0]->lines.end()) 1330 && (LineChecker[1] 1331 != baseline->second->endpoints[1]->lines.end()) 1332 && (GetCommonEndpoint(LineChecker[0]->second, 1333 LineChecker[1]->second) == peak)))); 1334 if (!continueflag) 1335 { 1336 *out << Verbose(4) << "Current target is peak!" << endl; 1337 continue; 1338 } 1339 // in case NOT both were found 1340 if (continueflag) 1341 { // create virtually this triangle, get its normal vector, calculate angle 1342 flag = true; 1343 VirtualNormalVector.MakeNormalVector( 1344 &baseline->second->endpoints[0]->node->x, 1345 &baseline->second->endpoints[1]->node->x, 1346 &target->second->node->x); 1347 // make it always point inward 1348 if (baseline->second->endpoints[0]->node->x.Projection( 1349 &VirtualNormalVector) > 0) 1350 VirtualNormalVector.Scale(-1.); 1351 // calculate angle 1352 TempAngle = NormalVector.Angle(&VirtualNormalVector); 1353 *out << Verbose(4) << "NormalVector is "; 1354 VirtualNormalVector.Output(out); 1355 *out << " and the angle is " << TempAngle << "." << endl; 1356 if (SmallestAngle > TempAngle) 1357 { // set to new possible winner 1358 SmallestAngle = TempAngle; 1359 winner = target; 1360 } 1361 } 1362 } 1363 // 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 1364 if (winner != PointsOnBoundary.end()) 1365 { 1366 *out << Verbose(2) << "Winning target point is " 1367 << *(winner->second) << " with angle " << SmallestAngle 1368 << "." << endl; 1369 // create the lins of not yet present 1370 BLS[0] = baseline->second; 1371 // 5c. add lines to the line set if those were new (not yet part of a triangle), delete lines that belong to two triangles) 1372 LineChecker[0] = baseline->second->endpoints[0]->lines.find( 1373 winner->first); 1374 LineChecker[1] = baseline->second->endpoints[1]->lines.find( 1375 winner->first); 1376 if (LineChecker[0] 1377 == baseline->second->endpoints[0]->lines.end()) 1378 { // create 1379 BPS[0] = baseline->second->endpoints[0]; 1380 BPS[1] = winner->second; 1381 BLS[1] = new class BoundaryLineSet(BPS, 1382 LinesOnBoundaryCount); 1383 LinesOnBoundary.insert(LinePair(LinesOnBoundaryCount, 1384 BLS[1])); 1385 LinesOnBoundaryCount++; 1386 } 1387 else 1388 BLS[1] = LineChecker[0]->second; 1389 if (LineChecker[1] 1390 == baseline->second->endpoints[1]->lines.end()) 1391 { // create 1392 BPS[0] = baseline->second->endpoints[1]; 1393 BPS[1] = winner->second; 1394 BLS[2] = new class BoundaryLineSet(BPS, 1395 LinesOnBoundaryCount); 1396 LinesOnBoundary.insert(LinePair(LinesOnBoundaryCount, 1397 BLS[2])); 1398 LinesOnBoundaryCount++; 1399 } 1400 else 1401 BLS[2] = LineChecker[1]->second; 1402 BTS = new class BoundaryTriangleSet(BLS, 1403 TrianglesOnBoundaryCount); 1404 TrianglesOnBoundary.insert(TrianglePair( 1405 TrianglesOnBoundaryCount, BTS)); 1406 TrianglesOnBoundaryCount++; 1407 } 1408 else 1409 { 1410 *out << Verbose(1) 1411 << "I could not determine a winner for this baseline " 1412 << *(baseline->second) << "." << endl; 1413 } 1414 1415 // 5d. If the set of lines is not yet empty, go to 5. and continue 1416 } 1417 else 1418 *out << Verbose(2) << "Baseline candidate " << *(baseline->second) 1419 << " has a triangle count of " 1420 << baseline->second->TrianglesCount << "." << endl; 1421 } 1422 while (flag); 1360 1423 1361 1424 } … … 1368 1431 Tesselation::AddPoint(atom *Walker) 1369 1432 { 1370 1371 1372 1373 1374 1433 PointTestPair InsertUnique; 1434 BPS[0] = new class BoundaryPointSet(Walker); 1435 InsertUnique = PointsOnBoundary.insert(PointPair(Walker->nr, BPS[0])); 1436 if (InsertUnique.second) // if new point was not present before, increase counter 1437 PointsOnBoundaryCount++; 1375 1438 } 1376 1439 ; … … 1384 1447 Tesselation::AddTrianglePoint(atom* Candidate, int n) 1385 1448 { 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1449 PointTestPair InsertUnique; 1450 TPS[n] = new class BoundaryPointSet(Candidate); 1451 InsertUnique = PointsOnBoundary.insert(PointPair(Candidate->nr, TPS[n])); 1452 if (InsertUnique.second) // if new point was not present before, increase counter 1453 { 1454 PointsOnBoundaryCount++; 1455 } 1456 else 1457 { 1458 delete TPS[n]; 1459 cout << Verbose(2) << "Atom " << *((InsertUnique.first)->second->node) 1460 << " gibt's schon in der PointMap." << endl; 1461 TPS[n] = (InsertUnique.first)->second; 1462 } 1400 1463 } 1401 1464 ; … … 1410 1473 void 1411 1474 Tesselation::AddTriangleLine(class BoundaryPointSet *a, 1412 1413 { 1414 1415 1416 if ((a->lines.find(b->node->nr))->first == b->node->nr)1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1475 class BoundaryPointSet *b, int n) 1476 { 1477 LineMap::iterator LineWalker; 1478 //cout << "Manually checking endpoints for line." << endl; 1479 if ((a->lines.find(b->node->nr)) != a->lines.end()) // ->first == b->node->nr) 1480 //If a line is there, how do I recognize that beyond a shadow of a doubt? 1481 { 1482 //cout << Verbose(2) << "Line exists already, retrieving it from LinesOnBoundarySet" << endl; 1483 1484 LineWalker = LinesOnBoundary.end(); 1485 LineWalker--; 1486 1487 while (LineWalker->second->endpoints[0]->node->nr != min(a->node->nr, 1488 b->node->nr) or LineWalker->second->endpoints[1]->node->nr != max( 1489 a->node->nr, b->node->nr)) 1490 { 1491 //cout << Verbose(1) << "Looking for line which already exists"<< endl; 1492 LineWalker--; 1493 } 1494 BPS[0] = LineWalker->second->endpoints[0]; 1495 BPS[1] = LineWalker->second->endpoints[1]; 1496 BLS[n] = LineWalker->second; 1497 1498 } 1499 else 1500 { 1501 cout << Verbose(2) 1502 << "Adding line which has not been used before between " 1503 << *(a->node) << " and " << *(b->node) << "." << endl; 1504 BPS[0] = a; 1505 BPS[1] = b; 1506 BLS[n] = new class BoundaryLineSet(BPS, LinesOnBoundaryCount); 1507 1508 LinesOnBoundary.insert(LinePair(LinesOnBoundaryCount, BLS[n])); 1509 LinesOnBoundaryCount++; 1510 1511 } 1449 1512 } 1450 1513 ; … … 1457 1520 { 1458 1521 1459 cout << Verbose(1) << "Adding triangle to its lines" << endl; 1460 int i = 0; 1461 TrianglesOnBoundary.insert(TrianglePair(TrianglesOnBoundaryCount, BTS)); 1462 TrianglesOnBoundaryCount++; 1463 1464 /* 1465 * this is apparently done when constructing triangle 1466 1467 for (i=0; i<3; i++) 1468 { 1469 BLS[i]->AddTriangle(BTS); 1470 } 1471 */ 1472 } 1473 ; 1522 cout << Verbose(1) << "Adding triangle to its lines" << endl; 1523 int i = 0; 1524 TrianglesOnBoundary.insert(TrianglePair(TrianglesOnBoundaryCount, BTS)); 1525 TrianglesOnBoundaryCount++; 1526 1527 /* 1528 * this is apparently done when constructing triangle 1529 1530 for (i=0; i<3; i++) 1531 { 1532 BLS[i]->AddTriangle(BTS); 1533 } 1534 */ 1535 } 1536 ; 1537 1538 1539 double det_get(gsl_matrix *A, int inPlace) { 1540 /* 1541 inPlace = 1 => A is replaced with the LU decomposed copy. 1542 inPlace = 0 => A is retained, and a copy is used for LU. 1543 */ 1544 1545 double det; 1546 int signum; 1547 gsl_permutation *p = gsl_permutation_alloc(A->size1); 1548 gsl_matrix *tmpA; 1549 1550 if (inPlace) 1551 tmpA = A; 1552 else { 1553 gsl_matrix *tmpA = gsl_matrix_alloc(A->size1, A->size2); 1554 gsl_matrix_memcpy(tmpA , A); 1555 } 1556 1557 1558 gsl_linalg_LU_decomp(tmpA , p , &signum); 1559 det = gsl_linalg_LU_det(tmpA , signum); 1560 gsl_permutation_free(p); 1561 if (! inPlace) 1562 gsl_matrix_free(tmpA); 1563 1564 return det; 1565 }; 1566 1567 void get_sphere(Vector *center, Vector &a, Vector &b, Vector &c, double RADIUS) 1568 { 1569 gsl_matrix *A = gsl_matrix_calloc(3,3); 1570 double m11, m12, m13, m14; 1571 1572 for(int i=0;i<3;i++) { 1573 gsl_matrix_set(A, i, 0, a.x[i]); 1574 gsl_matrix_set(A, i, 1, b.x[i]); 1575 gsl_matrix_set(A, i, 2, c.x[i]); 1576 } 1577 m11 = det_get(A, 1); 1578 1579 for(int i=0;i<3;i++) { 1580 gsl_matrix_set(A, i, 0, a.x[i]*a.x[i] + b.x[i]*b.x[i] + c.x[i]*c.x[i]); 1581 gsl_matrix_set(A, i, 1, b.x[i]); 1582 gsl_matrix_set(A, i, 2, c.x[i]); 1583 } 1584 m12 = det_get(A, 1); 1585 1586 for(int i=0;i<3;i++) { 1587 gsl_matrix_set(A, i, 0, a.x[i]*a.x[i] + b.x[i]*b.x[i] + c.x[i]*c.x[i]); 1588 gsl_matrix_set(A, i, 1, a.x[i]); 1589 gsl_matrix_set(A, i, 2, c.x[i]); 1590 } 1591 m13 = det_get(A, 1); 1592 1593 for(int i=0;i<3;i++) { 1594 gsl_matrix_set(A, i, 0, a.x[i]*a.x[i] + b.x[i]*b.x[i] + c.x[i]*c.x[i]); 1595 gsl_matrix_set(A, i, 1, a.x[i]); 1596 gsl_matrix_set(A, i, 2, b.x[i]); 1597 } 1598 m14 = det_get(A, 1); 1599 1600 if (fabs(m11) < MYEPSILON) 1601 cerr << "ERROR: three points are colinear." << endl; 1602 1603 center->x[0] = 0.5 * m12/ m11; 1604 center->x[1] = -0.5 * m13/ m11; 1605 center->x[2] = 0.5 * m14/ m11; 1606 1607 if (fabs(a.Distance(center) - RADIUS) > MYEPSILON) 1608 cerr << "ERROR: The given center is further way by " << fabs(a.Distance(center) - RADIUS) << " from a than RADIUS." << endl; 1609 1610 gsl_matrix_free(A); 1611 }; 1612 1613 1474 1614 1475 1615 /** … … 1489 1629 * @param Umkreisradius double radius of circumscribing circle 1490 1630 */ 1491 1492 void Get_center_of_sphere(Vector* Center, Vector a, Vector b, Vector c, Vector* Direction, Vector* AlternativeDirection, 1493 double HalfplaneIndicator, double AlternativeIndicator, double alpha, double beta, double gamma, double RADIUS, double Umkreisradius) 1494 { 1495 Vector TempNormal, helper; 1496 double Restradius; 1497 1498 *Center = a * sin(2.*alpha) + b * sin(2.*beta) + c * sin(2.*gamma) ; 1499 Center->Scale(1./(sin(2.*alpha) + sin(2.*beta) + sin(2.*gamma))); 1500 // Here we calculated center of circumscribing circle, using barycentric coordinates 1501 1502 TempNormal.CopyVector(&a); 1503 TempNormal.SubtractVector(&b); 1504 helper.CopyVector(&a); 1505 helper.SubtractVector(&c); 1506 TempNormal.VectorProduct(&helper); 1507 if (fabs(HalfplaneIndicator) < MYEPSILON) 1508 { 1509 if ((TempNormal.ScalarProduct(AlternativeDirection) <0 and AlternativeIndicator >0) or (TempNormal.ScalarProduct(AlternativeDirection) >0 and AlternativeIndicator <0)) 1510 { 1511 TempNormal.Scale(-1); 1512 } 1513 } 1514 else 1515 { 1516 if (TempNormal.ScalarProduct(Direction)<0 && HalfplaneIndicator >0 || TempNormal.ScalarProduct(Direction)>0 && HalfplaneIndicator<0) 1517 { 1518 TempNormal.Scale(-1); 1519 } 1520 } 1521 1522 TempNormal.Normalize(); 1523 Restradius = sqrt(RADIUS*RADIUS - Umkreisradius*Umkreisradius); 1524 TempNormal.Scale(Restradius); 1525 1526 Center->AddVector(&TempNormal); 1527 } 1528 ; 1529 1631 void Get_center_of_sphere(Vector* Center, Vector a, Vector b, Vector c, Vector *NewUmkreismittelpunkt, Vector* Direction, Vector* AlternativeDirection, 1632 double HalfplaneIndicator, double AlternativeIndicator, double alpha, double beta, double gamma, double RADIUS, double Umkreisradius) 1633 { 1634 Vector TempNormal, helper; 1635 double Restradius; 1636 Vector OtherCenter; 1637 cout << Verbose(3) << "Begin of Get_center_of_sphere.\n"; 1638 Center->Zero(); 1639 helper.CopyVector(&a); 1640 helper.Scale(sin(2.*alpha)); 1641 Center->AddVector(&helper); 1642 helper.CopyVector(&b); 1643 helper.Scale(sin(2.*beta)); 1644 Center->AddVector(&helper); 1645 helper.CopyVector(&c); 1646 helper.Scale(sin(2.*gamma)); 1647 Center->AddVector(&helper); 1648 //*Center = a * sin(2.*alpha) + b * sin(2.*beta) + c * sin(2.*gamma) ; 1649 Center->Scale(1./(sin(2.*alpha) + sin(2.*beta) + sin(2.*gamma))); 1650 NewUmkreismittelpunkt->CopyVector(Center); 1651 cout << Verbose(4) << "Center of new circumference is " << *NewUmkreismittelpunkt << ".\n"; 1652 // Here we calculated center of circumscribing circle, using barycentric coordinates 1653 cout << Verbose(4) << "Center of circumference is " << *Center << " in direction " << *Direction << ".\n"; 1654 1655 TempNormal.CopyVector(&a); 1656 TempNormal.SubtractVector(&b); 1657 helper.CopyVector(&a); 1658 helper.SubtractVector(&c); 1659 TempNormal.VectorProduct(&helper); 1660 if (fabs(HalfplaneIndicator) < MYEPSILON) 1661 { 1662 if ((TempNormal.ScalarProduct(AlternativeDirection) <0 and AlternativeIndicator >0) or (TempNormal.ScalarProduct(AlternativeDirection) >0 and AlternativeIndicator <0)) 1663 { 1664 TempNormal.Scale(-1); 1665 } 1666 } 1667 else 1668 { 1669 if (TempNormal.ScalarProduct(Direction)<0 && HalfplaneIndicator >0 || TempNormal.ScalarProduct(Direction)>0 && HalfplaneIndicator<0) 1670 { 1671 TempNormal.Scale(-1); 1672 } 1673 } 1674 1675 TempNormal.Normalize(); 1676 Restradius = sqrt(RADIUS*RADIUS - Umkreisradius*Umkreisradius); 1677 cout << Verbose(4) << "Height of center of circumference to center of sphere is " << Restradius << ".\n"; 1678 TempNormal.Scale(Restradius); 1679 cout << Verbose(4) << "Shift vector to sphere of circumference is " << TempNormal << ".\n"; 1680 1681 Center->AddVector(&TempNormal); 1682 cout << Verbose(0) << "Center of sphere of circumference is " << *Center << ".\n"; 1683 get_sphere(&OtherCenter, a, b, c, RADIUS); 1684 cout << Verbose(0) << "OtherCenter of sphere of circumference is " << OtherCenter << ".\n"; 1685 cout << Verbose(3) << "End of Get_center_of_sphere.\n"; 1686 }; 1530 1687 1531 1688 /** This recursive function finds a third point, to form a triangle with two given ones. 1532 1689 * Two atoms are fixed, a candidate is supplied, additionally two vectors for direction distinction, a Storage area to \ 1533 * 1534 * 1535 * 1536 * 1537 * 1538 * 1690 * supply results to the calling function, the radius of the sphere which the triangle shall support and the molecule \ 1691 * upon which we operate. 1692 * If the candidate is more fitting to support the sphere than the already stored atom is, then we write its general \ 1693 * direction and angle into Storage. 1694 * We the determine the recursive level we have reached and if this is not on the threshold yet, call this function again, \ 1695 * with all neighbours of the candidate. 1539 1696 * @param a first point 1540 1697 * @param b second point … … 1552 1709 * @param mol molecule structure with atoms and bonds 1553 1710 */ 1554 1555 void Find_next_suitable_point_via_Angle_of_Sphere(atom* a, atom* b, atom* c, atom* Candidate, atom* Parent, 1556 int RecursionLevel, Vector *Chord, Vector *direction1, Vector *OldNormal, Vector ReferencePoint, 1557 atom*& Opt_Candidate, double *Storage, const double RADIUS, molecule* mol) 1558 { 1559 //cout << "ReferencePoint is " << ReferencePoint.x[0] << " "<< ReferencePoint.x[1] << " "<< ReferencePoint.x[2] << " "<< endl; 1560 /* OldNormal is normal vector on the old triangle 1561 * direction1 is normal on the triangle line, from which we come, as well as on OldNormal. 1562 * Chord points from b to a!!! 1563 */ 1564 Vector dif_a; //Vector from a to candidate 1565 Vector dif_b; //Vector from b to candidate 1566 Vector AngleCheck; 1567 Vector TempNormal, Umkreismittelpunkt; 1568 Vector Mittelpunkt; 1569 1570 double CurrentEpsilon = 0.1; 1571 double alpha, beta, gamma, SideA, SideB, SideC, sign, Umkreisradius, Restradius, Distance; 1572 double BallAngle, AlternativeSign; 1573 atom *Walker; // variable atom point 1574 1575 1576 dif_a.CopyVector(&(a->x)); 1577 dif_a.SubtractVector(&(Candidate->x)); 1578 dif_b.CopyVector(&(b->x)); 1579 dif_b.SubtractVector(&(Candidate->x)); 1580 AngleCheck.CopyVector(&(Candidate->x)); 1581 AngleCheck.SubtractVector(&(a->x)); 1582 AngleCheck.ProjectOntoPlane(Chord); 1583 1584 SideA = dif_b.Norm(); 1585 SideB = dif_a.Norm(); 1586 SideC = Chord->Norm(); 1587 //Chord->Scale(-1); 1588 1589 alpha = Chord->Angle(&dif_a); 1590 beta = M_PI - Chord->Angle(&dif_b); 1591 gamma = dif_a.Angle(&dif_b); 1592 1593 1594 if (a != Candidate and b != Candidate and c != Candidate) 1595 { 1596 1597 Umkreisradius = SideA / 2.0 / sin(alpha); 1598 //cout << Umkreisradius << endl; 1599 //cout << SideB / 2.0 / sin(beta) << endl; 1600 //cout << SideC / 2.0 / sin(gamma) << endl; 1601 1602 if (Umkreisradius < RADIUS) //Checking whether ball will at least rest on points. 1603 { 1604 cout << Verbose(1) << "Candidate is "<< *Candidate << endl; 1605 sign = AngleCheck.ScalarProduct(direction1); 1606 if (fabs(sign)<MYEPSILON) 1607 { 1608 if (AngleCheck.ScalarProduct(OldNormal)<0) 1609 { 1610 sign =0; 1611 AlternativeSign=1; 1612 } 1613 else 1614 { 1615 sign =0; 1616 AlternativeSign=-1; 1617 } 1618 } 1619 else 1620 { 1621 sign /= fabs(sign); 1622 } 1623 1624 1625 1626 Get_center_of_sphere(&Mittelpunkt, (a->x), (b->x), (Candidate->x), OldNormal, direction1, sign, AlternativeSign, alpha, beta, gamma, RADIUS, Umkreisradius); 1627 1628 AngleCheck.CopyVector(&ReferencePoint); 1629 AngleCheck.Scale(-1); 1630 //cout << "AngleCheck is " << AngleCheck.x[0] << " "<< AngleCheck.x[1] << " "<< AngleCheck.x[2] << " "<< endl; 1631 AngleCheck.AddVector(&Mittelpunkt); 1632 //cout << "AngleCheck is " << AngleCheck.x[0] << " "<< AngleCheck.x[1] << " "<< AngleCheck.x[2] << " "<< endl; 1633 1634 BallAngle = AngleCheck.Angle(OldNormal); 1635 1636 //cout << "direction1 is " << direction1->x[0] <<" "<< direction1->x[1] <<" "<< direction1->x[2] <<" " << endl; 1637 //cout << "AngleCheck is " << AngleCheck.x[0] << " "<< AngleCheck.x[1] << " "<< AngleCheck.x[2] << " "<< endl; 1638 1639 cout << Verbose(1) << "BallAngle is " << BallAngle << " Sign is " << sign << endl; 1640 1641 if (AngleCheck.ScalarProduct(direction1) >=0) 1642 { 1643 if (Storage[0]< -1.5) // first Candidate at all 1644 { 1645 1646 cout << "Next better candidate is " << *Candidate << " with "; 1647 Opt_Candidate = Candidate; 1648 Storage[0] = sign; 1649 Storage[1] = AlternativeSign; 1650 Storage[2] = BallAngle; 1651 cout << "Angle is " << Storage[2] << ", Halbraum ist " 1652 << Storage[0] << endl; 1653 1654 1655 } 1656 else 1657 { 1658 if ( Storage[2] > BallAngle) 1659 { 1660 cout << "Next better candidate is " << *Candidate << " with "; 1661 Opt_Candidate = Candidate; 1662 Storage[0] = sign; 1663 Storage[1] = AlternativeSign; 1664 Storage[2] = BallAngle; 1665 cout << "Angle is " << Storage[2] << ", Halbraum ist " 1666 << Storage[0] << endl; 1667 } 1668 else 1669 { 1670 //if (DEBUG) 1671 cout << "Looses to better candidate" << endl; 1672 1673 } 1674 } 1675 } 1676 else 1677 { 1678 //if (DEBUG) 1679 cout << "Refused due to bad direction of ball centre." << endl; 1680 } 1681 } 1682 else 1683 { 1684 //if (DEBUG) 1685 cout << "Doesn't satisfy requirements for circumscribing circle" << endl; 1686 } 1687 } 1688 else 1689 { 1690 //if (DEBUG) 1691 cout << "identisch mit Ursprungslinie" << endl; 1692 1693 } 1694 1695 1696 1697 if (RecursionLevel < 9) // Seven is the recursion level threshold. 1698 { 1699 for (int i = 0; i < mol->NumberOfBondsPerAtom[Candidate->nr]; i++) // go through all bond 1700 { 1701 Walker = mol->ListOfBondsPerAtom[Candidate->nr][i]->GetOtherAtom( 1702 Candidate); 1703 if (Walker == Parent) 1704 { // don't go back the same bond 1705 continue; 1706 } 1707 else 1708 { 1709 Find_next_suitable_point_via_Angle_of_Sphere(a, b, c, Walker, Candidate, RecursionLevel 1710 + 1, Chord, direction1, OldNormal, ReferencePoint, Opt_Candidate, Storage, RADIUS, 1711 mol); //call function again 1712 } 1713 } 1714 } 1715 } 1716 ; 1717 1718 1719 /** This recursive function finds a third point, to form a triangle with two given ones. 1720 * Two atoms are fixed, a candidate is supplied, additionally two vectors for direction distinction, a Storage area to \ 1721 * supply results to the calling function, the radius of the sphere which the triangle shall support and the molecule \ 1722 * upon which we operate. 1723 * If the candidate is more fitting to support the sphere than the already stored atom is, then we write its general \ 1724 * direction and angle into Storage. 1725 * We the determine the recursive level we have reached and if this is not on the threshold yet, call this function again, \ 1726 * with all neighbours of the candidate. 1727 * @param a first point 1728 * @param b second point 1729 * @param Candidate base point along whose bonds to start looking from 1730 * @param Parent point to avoid during search as its wrong direction 1731 * @param RecursionLevel contains current recursion depth 1732 * @param Chord baseline vector of first and second point 1733 * @param d1 second in plane vector (along with \a Chord) of the triangle the baseline belongs to 1734 * @param OldNormal normal of the triangle which the baseline belongs to 1735 * @param Opt_Candidate candidate reference to return 1736 * @param Opt_Mittelpunkt Centerpoint of ball, when resting on Opt_Candidate 1737 * @param Storage array containing two angles of current Opt_Candidate 1738 * @param RADIUS radius of ball 1739 * @param mol molecule structure with atoms and bonds 1740 */ 1741 1742 void Find_next_suitable_point(atom* a, atom* b, atom* Candidate, atom* Parent, 1743 int RecursionLevel, Vector *Chord, Vector *d1, Vector *OldNormal, 1744 atom*& Opt_Candidate, Vector *Opt_Mittelpunkt, double *Storage, const double RADIUS, molecule* mol) 1745 { 1746 /* OldNormal is normal vector on the old triangle 1747 * d1 is normal on the triangle line, from which we come, as well as on OldNormal. 1748 * Chord points from b to a!!! 1749 */ 1750 Vector dif_a; //Vector from a to candidate 1751 Vector dif_b; //Vector from b to candidate 1752 Vector AngleCheck, AngleCheckReference, DirectionCheckPoint; 1753 Vector TempNormal, Umkreismittelpunkt, Mittelpunkt; 1754 1755 double CurrentEpsilon = 0.1; 1756 double alpha, beta, gamma, SideA, SideB, SideC, sign, Umkreisradius, Restradius, Distance; 1757 double BallAngle; 1758 atom *Walker; // variable atom point 1759 1760 1761 dif_a.CopyVector(&(a->x)); 1762 dif_a.SubtractVector(&(Candidate->x)); 1763 dif_b.CopyVector(&(b->x)); 1764 dif_b.SubtractVector(&(Candidate->x)); 1765 DirectionCheckPoint.CopyVector(&dif_a); 1766 DirectionCheckPoint.Scale(-1); 1767 DirectionCheckPoint.ProjectOntoPlane(Chord); 1768 1769 SideA = dif_b.Norm(); 1770 SideB = dif_a.Norm(); 1771 SideC = Chord->Norm(); 1772 //Chord->Scale(-1); 1773 1774 alpha = Chord->Angle(&dif_a); 1775 beta = M_PI - Chord->Angle(&dif_b); 1776 gamma = dif_a.Angle(&dif_b); 1777 1778 1779 if (DEBUG) 1780 { 1781 cout << "Atom number" << Candidate->nr << endl; 1782 Candidate->x.Output((ofstream *) &cout); 1783 cout << "number of bonds " << mol->NumberOfBondsPerAtom[Candidate->nr] 1784 << endl; 1785 } 1786 1787 if (a != Candidate and b != Candidate) 1788 { 1789 // alpha = dif_a.Angle(&dif_b) / 2.; 1790 // SideA = Chord->Norm() / 2.;// (Chord->Norm()/2.) / sin(0.5*alpha); 1791 // SideB = dif_a.Norm(); 1792 // centerline = SideA * SideA + SideB * SideB - 2. * SideA * SideB * cos( 1793 // alpha); // note this is squared of center line length 1794 // centerline = (Chord->Norm()/2.) / sin(0.5*alpha); 1795 // Those are remains from Freddie. Needed? 1796 1797 1798 1799 Umkreisradius = SideA / 2.0 / sin(alpha); 1800 //cout << Umkreisradius << endl; 1801 //cout << SideB / 2.0 / sin(beta) << endl; 1802 //cout << SideC / 2.0 / sin(gamma) << endl; 1803 1804 if (Umkreisradius < RADIUS && DirectionCheckPoint.ScalarProduct(&(Candidate->x))>0) //Checking whether ball will at least rest o points. 1805 { 1806 1807 // intermediate calculations to aquire centre of sphere, called Mittelpunkt: 1808 1809 Umkreismittelpunkt = (a->x) * sin(2.*alpha) + b->x * sin(2.*beta) + (Candidate->x) * sin(2.*gamma) ; 1810 Umkreismittelpunkt.Scale(1/(sin(2*alpha) + sin(2*beta) + sin(2*gamma))); 1811 1812 TempNormal.CopyVector(&dif_a); 1813 TempNormal.VectorProduct(&dif_b); 1814 if (TempNormal.ScalarProduct(OldNormal)<0 && sign>0 || TempNormal.ScalarProduct(OldNormal)>0 && sign<0) 1815 { 1816 TempNormal.Scale(-1); 1817 } 1818 TempNormal.Normalize(); 1819 Restradius = sqrt(RADIUS*RADIUS - Umkreisradius*Umkreisradius); 1820 TempNormal.Scale(Restradius); 1821 1822 Mittelpunkt.CopyVector(&Umkreismittelpunkt); 1823 Mittelpunkt.AddVector(&TempNormal); //this is center of sphere supported by a, b and Candidate 1824 1825 AngleCheck.CopyVector(Chord); 1826 AngleCheck.Scale(-0.5); 1827 AngleCheck.SubtractVector(&(b->x)); 1828 AngleCheckReference.CopyVector(&AngleCheck); 1829 AngleCheckReference.AddVector(Opt_Mittelpunkt); 1830 AngleCheck.AddVector(&Mittelpunkt); 1831 1832 BallAngle = AngleCheck.Angle(&AngleCheckReference); 1833 1834 d1->ProjectOntoPlane(&AngleCheckReference); 1835 sign = AngleCheck.ScalarProduct(d1); 1836 sign /= fabs(sign); // +1 if in direction of triangle plane, -1 if in other direction... 1837 1838 1839 if (Storage[0]< -1.5) // first Candidate at all 1840 { 1841 1842 cout << "Next better candidate is " << *Candidate << " with "; 1843 Opt_Candidate = Candidate; 1844 Storage[0] = sign; 1845 Storage[1] = BallAngle; 1846 Opt_Mittelpunkt->CopyVector(&Mittelpunkt); 1847 cout << "Angle is " << Storage[1] << ", Halbraum ist " 1848 << Storage[0] << endl; 1849 1850 1851 } 1852 else 1853 { 1854 /* 1855 * removed due to change in criterium, now checking angle of ball to old normal. 1856 //We will now check for non interference, that is if the new candidate would have the Opt_Candidate 1857 //within the ball. 1858 1859 Distance = Opt_Candidate->x.Distance(&Mittelpunkt); 1860 //cout << "Opt_Candidate " << Opt_Candidate << " has distance " << Distance << " to Center of Candidate " << endl; 1861 1862 1863 if (Distance >RADIUS) // We have no interference and may now check whether the new point is better. 1864 */ 1865 { 1866 //cout << "Atom " << Candidate << " has distance " << Candidate->x.Distance(Opt_Mittelpunkt) << " to Center of Candidate " << endl; 1867 1868 if (((Storage[0] < 0 && fabs(sign - Storage[0]) > CurrentEpsilon))) //This will give absolute preference to those in "right-hand" quadrants 1869 //(Candidate->x.Distance(Opt_Mittelpunkt) < RADIUS)) //and those where Candidate would be within old Sphere. 1870 { 1871 cout << "Next better candidate is " << *Candidate << " with "; 1872 Opt_Candidate = Candidate; 1873 Storage[0] = sign; 1874 Storage[1] = BallAngle; 1875 Opt_Mittelpunkt->CopyVector(&Mittelpunkt); 1876 cout << "Angle is " << Storage[1] << ", Halbraum ist " 1877 << Storage[0] << endl; 1878 1879 1880 } 1881 else 1882 { 1883 if ((fabs(sign - Storage[0]) < CurrentEpsilon && sign > 0 1884 && Storage[1] > BallAngle) || 1885 (fabs(sign - Storage[0]) < CurrentEpsilon && sign < 0 1886 && Storage[1] < BallAngle)) 1887 //Depending on quadrant we prefer higher or lower atom with respect to Triangle normal first. 1888 { 1889 cout << "Next better candidate is " << *Candidate << " with "; 1890 Opt_Candidate = Candidate; 1891 Storage[0] = sign; 1892 Storage[1] = BallAngle; 1893 Opt_Mittelpunkt->CopyVector(&Mittelpunkt); 1894 cout << "Angle is " << Storage[1] << ", Halbraum ist " 1895 << Storage[0] << endl; 1896 } 1897 1898 } 1899 } 1900 /* 1901 * This is for checking point-angle and presence of Candidates in Ball, currently we are checking the ball Angle. 1902 * 1903 else 1904 { 1905 if (sign>0 && BallAngle>0 && Storage[0]<0) 1906 { 1907 cout << "Next better candidate is " << *Candidate << " with "; 1908 Opt_Candidate = Candidate; 1909 Storage[0] = sign; 1910 Storage[1] = BallAngle; 1911 Opt_Mittelpunkt->CopyVector(&Mittelpunkt); 1912 cout << "Angle is " << Storage[1] << ", Halbraum ist " 1913 << Storage[0] << endl; 1914 1915 //Debugging purposes only 1916 cout << "Umkreismittelpunkt has coordinates" << Umkreismittelpunkt.x[0] << " "<< Umkreismittelpunkt.x[1] <<" "<<Umkreismittelpunkt.x[2] << endl; 1917 cout << "Candidate has coordinates" << Candidate->x.x[0]<< " " << Candidate->x.x[1] << " " << Candidate->x.x[2] << endl; 1918 cout << "a has coordinates" << a->x.x[0]<< " " << a->x.x[1] << " " << a->x.x[2] << endl; 1919 cout << "b has coordinates" << b->x.x[0]<< " " << b->x.x[1] << " " << b->x.x[2] << endl; 1920 cout << "Mittelpunkt has coordinates" << Mittelpunkt.x[0] << " " << Mittelpunkt.x[1]<< " " <<Mittelpunkt.x[2] << endl; 1921 cout << "Umkreisradius ist " << Umkreisradius << endl; 1922 cout << "Restradius ist " << Restradius << endl; 1923 cout << "TempNormal has coordinates " << TempNormal.x[0] << " " << TempNormal.x[1] << " " << TempNormal.x[2] << " " << endl; 1924 cout << "OldNormal has coordinates " << OldNormal->x[0] << " " << OldNormal->x[1] << " " << OldNormal->x[2] << " " << endl; 1925 cout << "Dist a to UmkreisMittelpunkt " << a->x.Distance(&Umkreismittelpunkt) << endl; 1926 cout << "Dist b to UmkreisMittelpunkt " << b->x.Distance(&Umkreismittelpunkt) << endl; 1927 cout << "Dist Candidate to UmkreisMittelpunkt " << Candidate->x.Distance(&Umkreismittelpunkt) << endl; 1928 cout << "Dist a to Mittelpunkt " << a->x.Distance(&Mittelpunkt) << endl; 1929 cout << "Dist b to Mittelpunkt " << b->x.Distance(&Mittelpunkt) << endl; 1930 cout << "Dist Candidate to Mittelpunkt " << Candidate->x.Distance(&Mittelpunkt) << endl; 1931 1932 1933 1934 } 1935 else 1936 { 1937 if (DEBUG) 1938 cout << "Looses to better candidate" << endl; 1939 } 1940 } 1941 */ 1942 } 1943 } 1944 else 1945 { 1946 if (DEBUG) 1947 { 1948 cout << "Doesn't satisfy requirements for circumscribing circle" << endl; 1949 } 1950 } 1951 } 1952 1953 else 1954 { 1955 if (DEBUG) 1956 cout << "identisch mit Ursprungslinie" << endl; 1957 } 1958 1959 if (RecursionLevel < 9) // Five is the recursion level threshold. 1960 { 1961 for (int i = 0; i < mol->NumberOfBondsPerAtom[Candidate->nr]; i++) // go through all bond 1962 { 1963 Walker = mol->ListOfBondsPerAtom[Candidate->nr][i]->GetOtherAtom( 1964 Candidate); 1965 if (Walker == Parent) 1966 { // don't go back the same bond 1967 continue; 1968 } 1969 else 1970 { 1971 Find_next_suitable_point(a, b, Walker, Candidate, RecursionLevel 1972 + 1, Chord, d1, OldNormal, Opt_Candidate, Opt_Mittelpunkt, Storage, RADIUS, 1973 mol); //call function again 1974 1975 } 1976 } 1977 } 1978 } 1979 ; 1711 void Tesselation::Find_next_suitable_point_via_Angle_of_Sphere(atom* a, atom* b, atom* c, atom* Candidate, atom* Parent, 1712 int RecursionLevel, Vector *Chord, Vector *direction1, Vector *OldNormal, Vector ReferencePoint, 1713 atom*& Opt_Candidate, double *Storage, const double RADIUS, molecule* mol) 1714 { 1715 cout << Verbose(2) << "Begin of Find_next_suitable_point_via_Angle_of_Sphere, recursion level " << RecursionLevel << ".\n"; 1716 cout << Verbose(3) << "Candidate is "<< *Candidate << endl; 1717 cout << Verbose(4) << "Baseline vector is " << *Chord << "." << endl; 1718 cout << Verbose(4) << "ReferencePoint is " << ReferencePoint << "." << endl; 1719 cout << Verbose(4) << "Normal of base triangle is " << *OldNormal << "." << endl; 1720 cout << Verbose(4) << "Search direction is " << *direction1 << "." << endl; 1721 /* OldNormal is normal vector on the old triangle 1722 * direction1 is normal on the triangle line, from which we come, as well as on OldNormal. 1723 * Chord points from b to a!!! 1724 */ 1725 Vector dif_a; //Vector from a to candidate 1726 Vector dif_b; //Vector from b to candidate 1727 Vector AngleCheck; 1728 Vector TempNormal, Umkreismittelpunkt; 1729 Vector Mittelpunkt; 1730 1731 double CurrentEpsilon = 0.1; 1732 double alpha, beta, gamma, SideA, SideB, SideC, sign, Umkreisradius, Restradius, Distance; 1733 double BallAngle, AlternativeSign; 1734 atom *Walker; // variable atom point 1735 1736 Vector NewUmkreismittelpunkt; 1737 1738 if (a != Candidate and b != Candidate and c != Candidate) { 1739 cout << Verbose(3) << "We have a unique candidate!" << endl; 1740 dif_a.CopyVector(&(a->x)); 1741 dif_a.SubtractVector(&(Candidate->x)); 1742 dif_b.CopyVector(&(b->x)); 1743 dif_b.SubtractVector(&(Candidate->x)); 1744 AngleCheck.CopyVector(&(Candidate->x)); 1745 AngleCheck.SubtractVector(&(a->x)); 1746 AngleCheck.ProjectOntoPlane(Chord); 1747 1748 SideA = dif_b.Norm(); 1749 SideB = dif_a.Norm(); 1750 SideC = Chord->Norm(); 1751 //Chord->Scale(-1); 1752 1753 alpha = Chord->Angle(&dif_a); 1754 beta = M_PI - Chord->Angle(&dif_b); 1755 gamma = dif_a.Angle(&dif_b); 1756 1757 cout << Verbose(2) << "Base triangle has sides " << dif_a << ", " << dif_b << ", " << *Chord << " with angles " << alpha/M_PI*180. << ", " << beta/M_PI*180. << ", " << gamma/M_PI*180. << "." << endl; 1758 1759 if (fabs(M_PI - alpha - beta - gamma) > MYEPSILON) { 1760 cerr << Verbose(0) << "WARNING: sum of angles for base triangle " << (alpha + beta + gamma)/M_PI*180. << " != 180.\n"; 1761 cout << Verbose(1) << "Base triangle has sides " << dif_a << ", " << dif_b << ", " << *Chord << " with angles " << alpha/M_PI*180. << ", " << beta/M_PI*180. << ", " << gamma/M_PI*180. << "." << endl; 1762 } 1763 1764 if ((M_PI*179./180. > alpha) && (M_PI*179./180. > beta) && (M_PI*179./180. > gamma)) { 1765 Umkreisradius = SideA / 2.0 / sin(alpha); 1766 //cout << Umkreisradius << endl; 1767 //cout << SideB / 2.0 / sin(beta) << endl; 1768 //cout << SideC / 2.0 / sin(gamma) << endl; 1769 1770 if (Umkreisradius < RADIUS) { //Checking whether ball will at least rest on points. 1771 cout << Verbose(3) << "Circle of circumference would fit: " << Umkreisradius << " < " << RADIUS << "." << endl; 1772 cout << Verbose(2) << "Candidate is "<< *Candidate << endl; 1773 sign = AngleCheck.ScalarProduct(direction1); 1774 if (fabs(sign)<MYEPSILON) { 1775 if (AngleCheck.ScalarProduct(OldNormal)<0) { 1776 sign =0; 1777 AlternativeSign=1; 1778 } else { 1779 sign =0; 1780 AlternativeSign=-1; 1781 } 1782 } else { 1783 sign /= fabs(sign); 1784 } 1785 if (sign >= 0) { 1786 cout << Verbose(3) << "Candidate is in search direction: " << sign << "." << endl; 1787 Get_center_of_sphere(&Mittelpunkt, (a->x), (b->x), (Candidate->x), &NewUmkreismittelpunkt, OldNormal, direction1, sign, AlternativeSign, alpha, beta, gamma, RADIUS, Umkreisradius); 1788 Mittelpunkt.SubtractVector(&ReferencePoint); 1789 cout << Verbose(3) << "Reference vector to sphere's center is " << Mittelpunkt << "." << endl; 1790 BallAngle = Mittelpunkt.Angle(OldNormal); 1791 cout << Verbose(3) << "Angle between normal of base triangle and center of ball sphere is :" << BallAngle << "." << endl; 1792 1793 //cout << "direction1 is " << *direction1 << "." << endl; 1794 //cout << "Mittelpunkt is " << Mittelpunkt << "."<< endl; 1795 //cout << Verbose(3) << "BallAngle is " << BallAngle << " Sign is " << sign << endl; 1796 1797 NewUmkreismittelpunkt.SubtractVector(&ReferencePoint); 1798 1799 if ((Mittelpunkt.ScalarProduct(direction1) >=0) || (fabs(NewUmkreismittelpunkt.Norm()) < MYEPSILON)) { 1800 if (Storage[0]< -1.5) { // first Candidate at all 1801 if (1) {//if (CheckPresenceOfTriangle((ofstream *)&cout,a,b,Candidate)) { 1802 cout << Verbose(2) << "First good candidate is " << *Candidate << " with "; 1803 Opt_Candidate = Candidate; 1804 Storage[0] = sign; 1805 Storage[1] = AlternativeSign; 1806 Storage[2] = BallAngle; 1807 cout << " angle " << Storage[2] << " and Up/Down " << Storage[0] << endl; 1808 } else 1809 cout << "Candidate " << *Candidate << " does not belong to a valid triangle." << endl; 1810 } else { 1811 if ( Storage[2] > BallAngle) { 1812 if (1) { //if (CheckPresenceOfTriangle((ofstream *)&cout,a,b,Candidate)) { 1813 cout << Verbose(2) << "Next better candidate is " << *Candidate << " with "; 1814 Opt_Candidate = Candidate; 1815 Storage[0] = sign; 1816 Storage[1] = AlternativeSign; 1817 Storage[2] = BallAngle; 1818 cout << " angle " << Storage[2] << " and Up/Down " << Storage[0] << endl; 1819 } else 1820 cout << "Candidate " << *Candidate << " does not belong to a valid triangle." << endl; 1821 } else { 1822 if (DEBUG) { 1823 cout << Verbose(3) << *Candidate << " looses against better candidate " << *Opt_Candidate << "." << endl; 1824 } 1825 } 1826 } 1827 } else { 1828 if (DEBUG) { 1829 cout << Verbose(3) << *Candidate << " refused due to Up/Down sign which is " << sign << endl; 1830 } 1831 } 1832 } else { 1833 if (DEBUG) { 1834 cout << Verbose(3) << *Candidate << " is not in search direction." << endl; 1835 } 1836 } 1837 } else { 1838 if (DEBUG) { 1839 cout << Verbose(3) << *Candidate << " would have circumference of " << Umkreisradius << " bigger than ball's radius " << RADIUS << "." << endl; 1840 } 1841 } 1842 } else { 1843 if (DEBUG) { 1844 cout << Verbose(0) << "Triangle consisting of " << *Candidate << ", " << *a << " and " << *b << " has an angle >150!" << endl; 1845 } 1846 } 1847 } else { 1848 if (DEBUG) { 1849 cout << Verbose(3) << *Candidate << " is either " << *a << " or " << *b << "." << endl; 1850 } 1851 } 1852 1853 if (RecursionLevel < 5) { // Seven is the recursion level threshold. 1854 for (int i = 0; i < mol->NumberOfBondsPerAtom[Candidate->nr]; i++) { // go through all bond 1855 Walker = mol->ListOfBondsPerAtom[Candidate->nr][i]->GetOtherAtom(Candidate); 1856 if (Walker == Parent) { // don't go back the same bond 1857 continue; 1858 } else { 1859 Find_next_suitable_point_via_Angle_of_Sphere(a, b, c, Walker, Candidate, RecursionLevel+1, Chord, direction1, OldNormal, ReferencePoint, Opt_Candidate, Storage, RADIUS, mol); //call function again 1860 } 1861 } 1862 } 1863 cout << Verbose(2) << "End of Find_next_suitable_point_via_Angle_of_Sphere, recursion level " << RecursionLevel << ".\n"; 1864 } 1865 ; 1866 1867 1868 /** Constructs the center of the circumcircle defined by three points \a *a, \a *b and \a *c. 1869 * \param *Center new center on return 1870 * \param *a first point 1871 * \param *b second point 1872 * \param *c third point 1873 */ 1874 void GetCenterofCircumcircle(Vector *Center, Vector *a, Vector *b, Vector *c) 1875 { 1876 Vector helper; 1877 double alpha, beta, gamma; 1878 Vector SideA, SideB, SideC; 1879 SideA.CopyVector(b); 1880 SideA.SubtractVector(c); 1881 SideB.CopyVector(c); 1882 SideB.SubtractVector(a); 1883 SideC.CopyVector(a); 1884 SideC.SubtractVector(b); 1885 alpha = M_PI - SideB.Angle(&SideC); 1886 beta = M_PI - SideC.Angle(&SideA); 1887 gamma = M_PI - SideA.Angle(&SideB); 1888 cout << Verbose(3) << "INFO: alpha = " << alpha/M_PI*180. << ", beta = " << beta/M_PI*180. << ", gamma = " << gamma/M_PI*180. << "." << endl; 1889 if (fabs(M_PI - alpha - beta - gamma) > HULLEPSILON) 1890 cerr << "Sum of angles " << (alpha+beta+gamma)/M_PI*180. << " > 180 degrees by " << fabs(M_PI - alpha - beta - gamma)/M_PI*180. << "!" << endl; 1891 1892 Center->Zero(); 1893 helper.CopyVector(a); 1894 helper.Scale(sin(2.*alpha)); 1895 Center->AddVector(&helper); 1896 helper.CopyVector(b); 1897 helper.Scale(sin(2.*beta)); 1898 Center->AddVector(&helper); 1899 helper.CopyVector(c); 1900 helper.Scale(sin(2.*gamma)); 1901 Center->AddVector(&helper); 1902 Center->Scale(1./(sin(2.*alpha) + sin(2.*beta) + sin(2.*gamma))); 1903 }; 1904 1905 /** Returns the parameter "path length" for a given \a NewSphereCenter relative to \a OldSphereCenter on a circle on the plane \a CirclePlaneNormal with center \a CircleCenter and radius \a CircleRadius. 1906 * Test whether the \a NewSphereCenter is really on the given plane and in distance \a CircleRadius from \a CircleCenter. 1907 * It calculates the angle, making it unique on [0,2.*M_PI) by comparing to SearchDirection. 1908 * Also the new center is invalid if it the same as the old one and does not lie right above (\a NormalVector) the base line (\a CircleCenter). 1909 * \param CircleCenter Center of the parameter circle 1910 * \param CirclePlaneNormal normal vector to plane of the parameter circle 1911 * \param CircleRadius radius of the parameter circle 1912 * \param NewSphereCenter new center of a circumcircle 1913 * \param OldSphereCenter old center of a circumcircle, defining the zero "path length" on the parameter circle 1914 * \param NormalVector normal vector 1915 * \param SearchDirection search direction to make angle unique on return. 1916 * \return Angle between \a NewSphereCenter and \a OldSphereCenter relative to \a CircleCenter, 2.*M_PI if one test fails 1917 */ 1918 double GetPathLengthonCircumCircle(Vector &CircleCenter, Vector &CirclePlaneNormal, double CircleRadius, Vector &NewSphereCenter, Vector &OldSphereCenter, Vector &NormalVector, Vector &SearchDirection) 1919 { 1920 Vector helper; 1921 double radius, alpha; 1922 1923 helper.CopyVector(&NewSphereCenter); 1924 // test whether new center is on the parameter circle's plane 1925 if (fabs(helper.ScalarProduct(&CirclePlaneNormal)) > HULLEPSILON) { 1926 cerr << "ERROR: Something's very wrong here: NewSphereCenter is not on the band's plane as desired by " <<fabs(helper.ScalarProduct(&CirclePlaneNormal)) << "!" << endl; 1927 helper.ProjectOntoPlane(&CirclePlaneNormal); 1928 } 1929 radius = helper.ScalarProduct(&helper); 1930 // test whether the new center vector has length of CircleRadius 1931 if (fabs(radius - CircleRadius) > HULLEPSILON) 1932 cerr << Verbose(1) << "ERROR: The projected center of the new sphere has radius " << radius << " instead of " << CircleRadius << "." << endl; 1933 alpha = helper.Angle(&OldSphereCenter); 1934 // make the angle unique by checking the halfplanes/search direction 1935 if (helper.ScalarProduct(&SearchDirection) < -HULLEPSILON) // acos is not unique on [0, 2.*M_PI), hence extra check to decide between two half intervals 1936 alpha = 2.*M_PI - alpha; 1937 cout << Verbose(2) << "INFO: RelativeNewSphereCenter is " << helper << ", RelativeOldSphereCenter is " << OldSphereCenter << " and resulting angle is " << alpha << "." << endl; 1938 radius = helper.Distance(&OldSphereCenter); 1939 helper.ProjectOntoPlane(&NormalVector); 1940 // check whether new center is somewhat away or at least right over the current baseline to prevent intersecting triangles 1941 if ((radius > HULLEPSILON) || (helper.Norm() < HULLEPSILON)) { 1942 cout << Verbose(2) << "INFO: Distance between old and new center is " << radius << " and between new center and baseline center is " << helper.Norm() << "." << endl; 1943 return alpha; 1944 } else { 1945 cout << Verbose(1) << "ERROR: NewSphereCenter " << helper << " is too close to OldSphereCenter" << OldSphereCenter << "." << endl; 1946 return 2.*M_PI; 1947 } 1948 }; 1949 1950 1951 /** This recursive function finds a third point, to form a triangle with two given ones. 1952 * The idea is as follows: A sphere with fixed radius is (almost) uniquely defined in space by three points 1953 * that sit on its boundary. Hence, when two points are given and we look for the (next) third point, then 1954 * the center of the sphere is still fixed up to a single parameter. The band of possible values 1955 * describes a circle in 3D-space. The old center of the sphere for the current base triangle gives 1956 * us the "null" on this circle, the new center of the candidate point will be some way along this 1957 * circle. The shorter the way the better is the candidate. Note that the direction is clearly given 1958 * by the normal vector of the base triangle that always points outwards by construction. 1959 * Hence, we construct a Center of this circle which sits right in the middle of the current base line. 1960 * We construct the normal vector that defines the plane this circle lies in, it is just in the 1961 * direction of the baseline. And finally, we need the radius of the circle, which is given by the rest 1962 * with respect to the length of the baseline and the sphere's fixed \a RADIUS. 1963 * Note that there is one difficulty: The circumcircle is uniquely defined, but for the circumsphere's center 1964 * there are two possibilities which becomes clear from the construction as seen below. Hence, we must check 1965 * both. 1966 * Note also that the acos() function is not unique on [0, 2.*M_PI). Hence, we need an additional check 1967 * to decide for one of the two possible angles. Therefore we need a SearchDirection and to make this check 1968 * sensible we need OldSphereCenter to be orthogonal to it. Either we construct SearchDirection orthogonal 1969 * right away, or -- what we do here -- we rotate the relative sphere centers such that this orthogonality 1970 * holds. Then, the normalized projection onto the SearchDirection is either +1 or -1 and thus states whether 1971 * the angle is uniquely in either (0,M_PI] or [M_PI, 2.*M_PI). 1972 * @param BaseTriangle BoundaryTriangleSet of the current base triangle with all three points 1973 * @param BaseLine BoundaryLineSet of BaseTriangle with the current base line 1974 * @param OptCandidate candidate reference on return 1975 * @param OptCandidateCenter candidate's sphere center on return 1976 * @param ShortestAngle the current path length on this circle band for the current Opt_Candidate 1977 * @param RADIUS radius of sphere 1978 * @param *LC LinkedCell structure with neighbouring atoms 1979 */ 1980 // void Find_next_suitable_point(class BoundaryTriangleSet *BaseTriangle, class BoundaryLineSet *BaseLine, atom*& OptCandidate, Vector *OptCandidateCenter, double *ShortestAngle, const double RADIUS, LinkedCell *LC) 1981 // { 1982 // atom *Walker = NULL; 1983 // Vector CircleCenter; // center of the circle, i.e. of the band of sphere's centers 1984 // Vector CirclePlaneNormal; // normal vector defining the plane this circle lives in 1985 // Vector OldSphereCenter; // center of the sphere defined by the three points of BaseTriangle 1986 // Vector NewSphereCenter; // center of the sphere defined by the two points of BaseLine and the one of Candidate, first possibility 1987 // Vector OtherNewSphereCenter; // center of the sphere defined by the two points of BaseLine and the one of Candidate, second possibility 1988 // Vector NewNormalVector; // normal vector of the Candidate's triangle 1989 // Vector SearchDirection; // vector that points out of BaseTriangle and is orthonormal to its NormalVector (i.e. the desired direction for the best Candidate) 1990 // Vector helper; 1991 // LinkedAtoms *List = NULL; 1992 // double CircleRadius; // radius of this circle 1993 // double radius; 1994 // double alpha, Otheralpha; // angles (i.e. parameter for the circle). 1995 // double Nullalpha; // angle between OldSphereCenter and NormalVector of base triangle 1996 // int N[NDIM], Nlower[NDIM], Nupper[NDIM]; 1997 // atom *Candidate = NULL; 1998 // 1999 // cout << Verbose(1) << "Begin of Find_next_suitable_point" << endl; 2000 // 2001 // cout << Verbose(2) << "INFO: NormalVector of BaseTriangle is " << BaseTriangle->NormalVector << "." << endl; 2002 // 2003 // // construct center of circle 2004 // CircleCenter.CopyVector(&(BaseLine->endpoints[0]->node->x)); 2005 // CircleCenter.AddVector(&BaseLine->endpoints[1]->node->x); 2006 // CircleCenter.Scale(0.5); 2007 // 2008 // // construct normal vector of circle 2009 // CirclePlaneNormal.CopyVector(&BaseLine->endpoints[0]->node->x); 2010 // CirclePlaneNormal.SubtractVector(&BaseLine->endpoints[1]->node->x); 2011 // 2012 // // calculate squared radius of circle 2013 // radius = CirclePlaneNormal.ScalarProduct(&CirclePlaneNormal); 2014 // if (radius/4. < RADIUS*RADIUS) { 2015 // CircleRadius = RADIUS*RADIUS - radius/4.; 2016 // CirclePlaneNormal.Normalize(); 2017 // cout << Verbose(2) << "INFO: CircleCenter is at " << CircleCenter << ", CirclePlaneNormal is " << CirclePlaneNormal << " with circle radius " << sqrt(CircleRadius) << "." << endl; 2018 // 2019 // // construct old center 2020 // GetCenterofCircumcircle(&OldSphereCenter, &(BaseTriangle->endpoints[0]->node->x), &(BaseTriangle->endpoints[1]->node->x), &(BaseTriangle->endpoints[2]->node->x)); 2021 // helper.CopyVector(&BaseTriangle->NormalVector); // normal vector ensures that this is correct center of the two possible ones 2022 // radius = BaseLine->endpoints[0]->node->x.DistanceSquared(&OldSphereCenter); 2023 // helper.Scale(sqrt(RADIUS*RADIUS - radius)); 2024 // OldSphereCenter.AddVector(&helper); 2025 // OldSphereCenter.SubtractVector(&CircleCenter); 2026 // cout << Verbose(2) << "INFO: OldSphereCenter is at " << OldSphereCenter << "." << endl; 2027 // 2028 // // test whether old center is on the band's plane 2029 // if (fabs(OldSphereCenter.ScalarProduct(&CirclePlaneNormal)) > HULLEPSILON) { 2030 // cerr << "ERROR: Something's very wrong here: OldSphereCenter is not on the band's plane as desired by " << fabs(OldSphereCenter.ScalarProduct(&CirclePlaneNormal)) << "!" << endl; 2031 // OldSphereCenter.ProjectOntoPlane(&CirclePlaneNormal); 2032 // } 2033 // radius = OldSphereCenter.ScalarProduct(&OldSphereCenter); 2034 // if (fabs(radius - CircleRadius) < HULLEPSILON) { 2035 // 2036 // // construct SearchDirection 2037 // SearchDirection.MakeNormalVector(&BaseTriangle->NormalVector, &CirclePlaneNormal); 2038 // helper.CopyVector(&BaseLine->endpoints[0]->node->x); 2039 // for(int i=0;i<3;i++) // just take next different endpoint 2040 // if ((BaseTriangle->endpoints[i]->node != BaseLine->endpoints[0]->node) && (BaseTriangle->endpoints[i]->node != BaseLine->endpoints[1]->node)) { 2041 // helper.SubtractVector(&BaseTriangle->endpoints[i]->node->x); 2042 // } 2043 // if (helper.ScalarProduct(&SearchDirection) < -HULLEPSILON) // ohoh, SearchDirection points inwards! 2044 // SearchDirection.Scale(-1.); 2045 // SearchDirection.ProjectOntoPlane(&OldSphereCenter); 2046 // SearchDirection.Normalize(); 2047 // cout << Verbose(2) << "INFO: SearchDirection is " << SearchDirection << "." << endl; 2048 // if (fabs(OldSphereCenter.ScalarProduct(&SearchDirection)) > HULLEPSILON) { // rotated the wrong way! 2049 // cerr << "ERROR: SearchDirection and RelativeOldSphereCenter are still not orthogonal!" << endl; 2050 // } 2051 // 2052 // if (LC->SetIndexToVector(&CircleCenter)) { // get cell for the starting atom 2053 // for(int i=0;i<NDIM;i++) // store indices of this cell 2054 // N[i] = LC->n[i]; 2055 // cout << Verbose(2) << "INFO: Center cell is " << N[0] << ", " << N[1] << ", " << N[2] << " with No. " << LC->index << "." << endl; 2056 // } else { 2057 // cerr << "ERROR: Vector " << CircleCenter << " is outside of LinkedCell's bounding box." << endl; 2058 // return; 2059 // } 2060 // // then go through the current and all neighbouring cells and check the contained atoms for possible candidates 2061 // cout << Verbose(2) << "LC Intervals:"; 2062 // for (int i=0;i<NDIM;i++) { 2063 // Nlower[i] = ((N[i]-1) >= 0) ? N[i]-1 : 0; 2064 // Nupper[i] = ((N[i]+1) < LC->N[i]) ? N[i]+1 : LC->N[i]-1; 2065 // cout << " [" << Nlower[i] << "," << Nupper[i] << "] "; 2066 // } 2067 // cout << endl; 2068 // for (LC->n[0] = Nlower[0]; LC->n[0] <= Nupper[0]; LC->n[0]++) 2069 // for (LC->n[1] = Nlower[1]; LC->n[1] <= Nupper[1]; LC->n[1]++) 2070 // for (LC->n[2] = Nlower[2]; LC->n[2] <= Nupper[2]; LC->n[2]++) { 2071 // List = LC->GetCurrentCell(); 2072 // cout << Verbose(2) << "Current cell is " << LC->n[0] << ", " << LC->n[1] << ", " << LC->n[2] << " with No. " << LC->index << "." << endl; 2073 // if (List != NULL) { 2074 // for (LinkedAtoms::iterator Runner = List->begin(); Runner != List->end(); Runner++) { 2075 // Candidate = (*Runner); 2076 // 2077 // // check for three unique points 2078 // if ((Candidate != BaseTriangle->endpoints[0]->node) && (Candidate != BaseTriangle->endpoints[1]->node) && (Candidate != BaseTriangle->endpoints[2]->node)) { 2079 // cout << Verbose(1) << "INFO: Current Candidate is " << *Candidate << " at " << Candidate->x << "." << endl; 2080 // 2081 // // construct both new centers 2082 // GetCenterofCircumcircle(&NewSphereCenter, &(BaseLine->endpoints[0]->node->x), &(BaseLine->endpoints[1]->node->x), &(Candidate->x)); 2083 // OtherNewSphereCenter.CopyVector(&NewSphereCenter); 2084 // 2085 // if ((NewNormalVector.MakeNormalVector(&(BaseLine->endpoints[0]->node->x), &(BaseLine->endpoints[1]->node->x), &(Candidate->x))) && (fabs(NewNormalVector.ScalarProduct(&NewNormalVector)) > HULLEPSILON)) { 2086 // helper.CopyVector(&NewNormalVector); 2087 // cout << Verbose(2) << "INFO: NewNormalVector is " << NewNormalVector << "." << endl; 2088 // radius = BaseLine->endpoints[0]->node->x.DistanceSquared(&NewSphereCenter); 2089 // if (radius < RADIUS*RADIUS) { 2090 // helper.Scale(sqrt(RADIUS*RADIUS - radius)); 2091 // cout << Verbose(3) << "INFO: Distance of NewCircleCenter to NewSphereCenter is " << helper.Norm() << "." << endl; 2092 // NewSphereCenter.AddVector(&helper); 2093 // NewSphereCenter.SubtractVector(&CircleCenter); 2094 // cout << Verbose(2) << "INFO: NewSphereCenter is at " << NewSphereCenter << "." << endl; 2095 // 2096 // helper.Scale(-1.); // OtherNewSphereCenter is created by the same vector just in the other direction 2097 // OtherNewSphereCenter.AddVector(&helper); 2098 // OtherNewSphereCenter.SubtractVector(&CircleCenter); 2099 // cout << Verbose(2) << "INFO: OtherNewSphereCenter is at " << OtherNewSphereCenter << "." << endl; 2100 // 2101 // // check both possible centers 2102 // alpha = GetPathLengthonCircumCircle(CircleCenter, CirclePlaneNormal, CircleRadius, NewSphereCenter, OldSphereCenter, BaseTriangle->NormalVector, SearchDirection); 2103 // Otheralpha = GetPathLengthonCircumCircle(CircleCenter, CirclePlaneNormal, CircleRadius, OtherNewSphereCenter, OldSphereCenter, BaseTriangle->NormalVector, SearchDirection); 2104 // alpha = min(alpha, Otheralpha); 2105 // if (*ShortestAngle > alpha) { 2106 // OptCandidate = Candidate; 2107 // *ShortestAngle = alpha; 2108 // if (alpha != Otheralpha) 2109 // OptCandidateCenter->CopyVector(&NewSphereCenter); 2110 // else 2111 // OptCandidateCenter->CopyVector(&OtherNewSphereCenter); 2112 // cout << Verbose(1) << "We have found a better candidate: " << *OptCandidate << " with " << alpha << " and circumsphere's center at " << *OptCandidateCenter << "." << endl; 2113 // } else { 2114 // if (OptCandidate != NULL) 2115 // cout << Verbose(1) << "REJECT: Old candidate: " << *OptCandidate << " is better than " << alpha << " with " << *ShortestAngle << "." << endl; 2116 // else 2117 // cout << Verbose(2) << "REJECT: Candidate " << *Candidate << " with " << alpha << " was rejected." << endl; 2118 // } 2119 // 2120 // } else { 2121 // cout << Verbose(1) << "REJECT: NewSphereCenter " << NewSphereCenter << " is too far away: " << radius << "." << endl; 2122 // } 2123 // } else { 2124 // cout << Verbose(1) << "REJECT: Three points from " << *BaseLine << " and Candidate " << *Candidate << " are linear-dependent." << endl; 2125 // } 2126 // } else { 2127 // cout << Verbose(1) << "REJECT: Base triangle " << *BaseTriangle << " contains Candidate " << *Candidate << "." << endl; 2128 // } 2129 // } 2130 // } 2131 // } 2132 // } else { 2133 // cerr << Verbose(1) << "ERROR: The projected center of the old sphere has radius " << radius << " instead of " << CircleRadius << "." << endl; 2134 // } 2135 // } else { 2136 // cout << Verbose(1) << "Circumcircle for base line " << *BaseLine << " and base triangle " << *BaseTriangle << " is too big!" << endl; 2137 // } 2138 // 2139 // cout << Verbose(1) << "End of Find_next_suitable_point" << endl; 2140 // }; 2141 2142 2143 /** Checks whether the triangle consisting of the three atoms is already present. 2144 * Searches for the points in Tesselation::PointsOnBoundary and checks their 2145 * lines. If any of the three edges already has two triangles attached, false is 2146 * returned. 2147 * \param *out output stream for debugging 2148 * \param *Candidates endpoints of the triangle candidate 2149 * \return false - triangle invalid due to edge criteria, true - triangle may be added. 2150 */ 2151 bool Tesselation::CheckPresenceOfTriangle(ofstream *out, atom *Candidates[3]) { 2152 LineMap::iterator FindLine; 2153 PointMap::iterator FindPoint; 2154 bool Present[3]; 2155 2156 *out << Verbose(2) << "Begin of CheckPresenceOfTriangle" << endl; 2157 for (int i=0;i<3;i++) { // check through all endpoints 2158 FindPoint = PointsOnBoundary.find(Candidates[i]->nr); 2159 if (FindPoint != PointsOnBoundary.end()) 2160 TPS[i] = FindPoint->second; 2161 else 2162 TPS[i] = NULL; 2163 } 2164 2165 // check lines 2166 for (int i=0;i<3;i++) 2167 if (TPS[i] != NULL) 2168 for (int j=i;j<3;j++) 2169 if (TPS[j] != NULL) { 2170 FindLine = TPS[i]->lines.find(TPS[j]->node->nr); 2171 if ((FindLine != TPS[i]->lines.end()) && (FindLine->second->TrianglesCount > 1)) { 2172 *out << "WARNING: Line " << *FindLine->second << " already present with " << FindLine->second->TrianglesCount << " triangles attached." << endl; 2173 *out << Verbose(2) << "End of CheckPresenceOfTriangle" << endl; 2174 return false; 2175 } 2176 } 2177 *out << Verbose(2) << "End of CheckPresenceOfTriangle" << endl; 2178 return true; 2179 }; 2180 2181 /** This recursive function finds a third point, to form a triangle with two given ones. 2182 * Note that this function is for the starting triangle. 2183 * The idea is as follows: A sphere with fixed radius is (almost) uniquely defined in space by three points 2184 * that sit on its boundary. Hence, when two points are given and we look for the (next) third point, then 2185 * the center of the sphere is still fixed up to a single parameter. The band of possible values 2186 * describes a circle in 3D-space. The old center of the sphere for the current base triangle gives 2187 * us the "null" on this circle, the new center of the candidate point will be some way along this 2188 * circle. The shorter the way the better is the candidate. Note that the direction is clearly given 2189 * by the normal vector of the base triangle that always points outwards by construction. 2190 * Hence, we construct a Center of this circle which sits right in the middle of the current base line. 2191 * We construct the normal vector that defines the plane this circle lies in, it is just in the 2192 * direction of the baseline. And finally, we need the radius of the circle, which is given by the rest 2193 * with respect to the length of the baseline and the sphere's fixed \a RADIUS. 2194 * Note that there is one difficulty: The circumcircle is uniquely defined, but for the circumsphere's center 2195 * there are two possibilities which becomes clear from the construction as seen below. Hence, we must check 2196 * both. 2197 * Note also that the acos() function is not unique on [0, 2.*M_PI). Hence, we need an additional check 2198 * to decide for one of the two possible angles. Therefore we need a SearchDirection and to make this check 2199 * sensible we need OldSphereCenter to be orthogonal to it. Either we construct SearchDirection orthogonal 2200 * right away, or -- what we do here -- we rotate the relative sphere centers such that this orthogonality 2201 * holds. Then, the normalized projection onto the SearchDirection is either +1 or -1 and thus states whether 2202 * the angle is uniquely in either (0,M_PI] or [M_PI, 2.*M_PI). 2203 * @param NormalVector normal direction of the base triangle (here the unit axis vector, \sa Find_starting_triangle()) 2204 * @param SearchDirection general direction where to search for the next point, relative to center of BaseLine 2205 * @param OldSphereCenter center of sphere for base triangle, relative to center of BaseLine, giving null angle for the parameter circle 2206 * @param BaseLine BoundaryLineSet with the current base line 2207 * @param ThirdNode third atom to avoid in search 2208 * @param OptCandidate candidate reference on return 2209 * @param OptCandidateCenter candidate's sphere center on return 2210 * @param ShortestAngle the current path length on this circle band for the current Opt_Candidate 2211 * @param RADIUS radius of sphere 2212 * @param *LC LinkedCell structure with neighbouring atoms 2213 */ 2214 void Find_third_point_for_Tesselation(Vector NormalVector, Vector SearchDirection, Vector OldSphereCenter, class BoundaryLineSet *BaseLine, atom *ThirdNode, atom*& OptCandidate, Vector *OptCandidateCenter, double *ShortestAngle, const double RADIUS, LinkedCell *LC) 2215 { 2216 atom *Walker = NULL; 2217 Vector CircleCenter; // center of the circle, i.e. of the band of sphere's centers 2218 Vector CirclePlaneNormal; // normal vector defining the plane this circle lives in 2219 Vector NewSphereCenter; // center of the sphere defined by the two points of BaseLine and the one of Candidate, first possibility 2220 Vector OtherNewSphereCenter; // center of the sphere defined by the two points of BaseLine and the one of Candidate, second possibility 2221 Vector NewNormalVector; // normal vector of the Candidate's triangle 2222 Vector helper; 2223 LinkedAtoms *List = NULL; 2224 double CircleRadius; // radius of this circle 2225 double radius; 2226 double alpha, Otheralpha; // angles (i.e. parameter for the circle). 2227 double Nullalpha; // angle between OldSphereCenter and NormalVector of base triangle 2228 int N[NDIM], Nlower[NDIM], Nupper[NDIM]; 2229 atom *Candidate = NULL; 2230 2231 cout << Verbose(1) << "Begin of Find_third_point_for_Tesselation" << endl; 2232 2233 cout << Verbose(2) << "INFO: NormalVector of BaseTriangle is " << NormalVector << "." << endl; 2234 2235 // construct center of circle 2236 CircleCenter.CopyVector(&(BaseLine->endpoints[0]->node->x)); 2237 CircleCenter.AddVector(&BaseLine->endpoints[1]->node->x); 2238 CircleCenter.Scale(0.5); 2239 2240 // construct normal vector of circle 2241 CirclePlaneNormal.CopyVector(&BaseLine->endpoints[0]->node->x); 2242 CirclePlaneNormal.SubtractVector(&BaseLine->endpoints[1]->node->x); 2243 2244 // calculate squared radius of circle 2245 radius = CirclePlaneNormal.ScalarProduct(&CirclePlaneNormal); 2246 if (radius/4. < RADIUS*RADIUS) { 2247 CircleRadius = RADIUS*RADIUS - radius/4.; 2248 CirclePlaneNormal.Normalize(); 2249 cout << Verbose(2) << "INFO: CircleCenter is at " << CircleCenter << ", CirclePlaneNormal is " << CirclePlaneNormal << " with circle radius " << sqrt(CircleRadius) << "." << endl; 2250 2251 // test whether old center is on the band's plane 2252 if (fabs(OldSphereCenter.ScalarProduct(&CirclePlaneNormal)) > HULLEPSILON) { 2253 cerr << "ERROR: Something's very wrong here: OldSphereCenter is not on the band's plane as desired by " << fabs(OldSphereCenter.ScalarProduct(&CirclePlaneNormal)) << "!" << endl; 2254 OldSphereCenter.ProjectOntoPlane(&CirclePlaneNormal); 2255 } 2256 radius = OldSphereCenter.ScalarProduct(&OldSphereCenter); 2257 if (fabs(radius - CircleRadius) < HULLEPSILON) { 2258 2259 // check SearchDirection 2260 cout << Verbose(2) << "INFO: SearchDirection is " << SearchDirection << "." << endl; 2261 if (fabs(OldSphereCenter.ScalarProduct(&SearchDirection)) > HULLEPSILON) { // rotated the wrong way! 2262 cerr << "ERROR: SearchDirection and RelativeOldSphereCenter are not orthogonal!" << endl; 2263 } 2264 // get cell for the starting atom 2265 if (LC->SetIndexToVector(&CircleCenter)) { 2266 for(int i=0;i<NDIM;i++) // store indices of this cell 2267 N[i] = LC->n[i]; 2268 cout << Verbose(2) << "INFO: Center cell is " << N[0] << ", " << N[1] << ", " << N[2] << " with No. " << LC->index << "." << endl; 2269 } else { 2270 cerr << "ERROR: Vector " << CircleCenter << " is outside of LinkedCell's bounding box." << endl; 2271 return; 2272 } 2273 // then go through the current and all neighbouring cells and check the contained atoms for possible candidates 2274 cout << Verbose(2) << "LC Intervals:"; 2275 for (int i=0;i<NDIM;i++) { 2276 Nlower[i] = ((N[i]-1) >= 0) ? N[i]-1 : 0; 2277 Nupper[i] = ((N[i]+1) < LC->N[i]) ? N[i]+1 : LC->N[i]-1; 2278 cout << " [" << Nlower[i] << "," << Nupper[i] << "] "; 2279 } 2280 cout << endl; 2281 for (LC->n[0] = Nlower[0]; LC->n[0] <= Nupper[0]; LC->n[0]++) 2282 for (LC->n[1] = Nlower[1]; LC->n[1] <= Nupper[1]; LC->n[1]++) 2283 for (LC->n[2] = Nlower[2]; LC->n[2] <= Nupper[2]; LC->n[2]++) { 2284 List = LC->GetCurrentCell(); 2285 //cout << Verbose(2) << "Current cell is " << LC->n[0] << ", " << LC->n[1] << ", " << LC->n[2] << " with No. " << LC->index << "." << endl; 2286 if (List != NULL) { 2287 for (LinkedAtoms::iterator Runner = List->begin(); Runner != List->end(); Runner++) { 2288 Candidate = (*Runner); 2289 2290 // check for three unique points 2291 if ((Candidate != BaseLine->endpoints[0]->node) && (Candidate != BaseLine->endpoints[1]->node) && (Candidate != ThirdNode)) { 2292 cout << Verbose(1) << "INFO: Current Candidate is " << *Candidate << " at " << Candidate->x << "." << endl; 2293 2294 // construct both new centers 2295 GetCenterofCircumcircle(&NewSphereCenter, &(BaseLine->endpoints[0]->node->x), &(BaseLine->endpoints[1]->node->x), &(Candidate->x)); 2296 OtherNewSphereCenter.CopyVector(&NewSphereCenter); 2297 2298 if ((NewNormalVector.MakeNormalVector(&(BaseLine->endpoints[0]->node->x), &(BaseLine->endpoints[1]->node->x), &(Candidate->x))) && (fabs(NewNormalVector.ScalarProduct(&NewNormalVector)) > HULLEPSILON)) { 2299 helper.CopyVector(&NewNormalVector); 2300 cout << Verbose(2) << "INFO: NewNormalVector is " << NewNormalVector << "." << endl; 2301 radius = BaseLine->endpoints[0]->node->x.DistanceSquared(&NewSphereCenter); 2302 if (radius < RADIUS*RADIUS) { 2303 helper.Scale(sqrt(RADIUS*RADIUS - radius)); 2304 cout << Verbose(3) << "INFO: Distance of NewCircleCenter to NewSphereCenter is " << helper.Norm() << "." << endl; 2305 NewSphereCenter.AddVector(&helper); 2306 NewSphereCenter.SubtractVector(&CircleCenter); 2307 cout << Verbose(2) << "INFO: NewSphereCenter is at " << NewSphereCenter << "." << endl; 2308 2309 helper.Scale(-1.); // OtherNewSphereCenter is created by the same vector just in the other direction 2310 OtherNewSphereCenter.AddVector(&helper); 2311 OtherNewSphereCenter.SubtractVector(&CircleCenter); 2312 cout << Verbose(2) << "INFO: OtherNewSphereCenter is at " << OtherNewSphereCenter << "." << endl; 2313 2314 // check both possible centers 2315 alpha = GetPathLengthonCircumCircle(CircleCenter, CirclePlaneNormal, CircleRadius, NewSphereCenter, OldSphereCenter, NormalVector, SearchDirection); 2316 Otheralpha = GetPathLengthonCircumCircle(CircleCenter, CirclePlaneNormal, CircleRadius, OtherNewSphereCenter, OldSphereCenter, NormalVector, SearchDirection); 2317 alpha = min(alpha, Otheralpha); 2318 if (*ShortestAngle > alpha) { 2319 OptCandidate = Candidate; 2320 *ShortestAngle = alpha; 2321 if (alpha != Otheralpha) 2322 OptCandidateCenter->CopyVector(&NewSphereCenter); 2323 else 2324 OptCandidateCenter->CopyVector(&OtherNewSphereCenter); 2325 cout << Verbose(1) << "ACCEPT: We have found a better candidate: " << *OptCandidate << " with " << alpha << " and circumsphere's center at " << *OptCandidateCenter << "." << endl; 2326 } else { 2327 if (OptCandidate != NULL) 2328 cout << Verbose(1) << "REJECT: Old candidate: " << *OptCandidate << " is better than " << alpha << " with " << *ShortestAngle << "." << endl; 2329 else 2330 cout << Verbose(2) << "REJECT: Candidate " << *Candidate << " with " << alpha << " was rejected." << endl; 2331 } 2332 2333 } else { 2334 cout << Verbose(1) << "REJECT: NewSphereCenter " << NewSphereCenter << " is too far away: " << radius << "." << endl; 2335 } 2336 } else { 2337 cout << Verbose(1) << "REJECT: Three points from " << *BaseLine << " and Candidate " << *Candidate << " are linear-dependent." << endl; 2338 } 2339 } else { 2340 if (ThirdNode != NULL) 2341 cout << Verbose(1) << "REJECT: Base triangle " << *BaseLine << " and " << *ThirdNode << " contains Candidate " << *Candidate << "." << endl; 2342 else 2343 cout << Verbose(1) << "REJECT: Base triangle " << *BaseLine << " contains Candidate " << *Candidate << "." << endl; 2344 } 2345 } 2346 } 2347 } 2348 } else { 2349 cerr << Verbose(1) << "ERROR: The projected center of the old sphere has radius " << radius << " instead of " << CircleRadius << "." << endl; 2350 } 2351 } else { 2352 if (ThirdNode != NULL) 2353 cout << Verbose(1) << "Circumcircle for base line " << *BaseLine << " and third node " << *ThirdNode << " is too big!" << endl; 2354 else 2355 cout << Verbose(1) << "Circumcircle for base line " << *BaseLine << " is too big!" << endl; 2356 } 2357 2358 cout << Verbose(1) << "End of Find_third_point_for_Tesselation" << endl; 2359 }; 2360 2361 /** Finds the second point of starting triangle. 2362 * \param *a first atom 2363 * \param *Candidate pointer to candidate atom on return 2364 * \param Oben vector indicating the outside 2365 * \param Opt_Candidate reference to recommended candidate on return 2366 * \param Storage[3] array storing angles and other candidate information 2367 * \param RADIUS radius of virtual sphere 2368 * \param *LC LinkedCell structure with neighbouring atoms 2369 */ 2370 void Find_second_point_for_Tesselation(atom* a, atom* Candidate, Vector Oben, atom*& Opt_Candidate, double Storage[3], double RADIUS, LinkedCell *LC) 2371 { 2372 cout << Verbose(2) << "Begin of Find_second_point_for_Tesselation" << endl; 2373 int i; 2374 Vector AngleCheck; 2375 atom* Walker; 2376 double norm = -1., angle; 2377 LinkedAtoms *List = NULL; 2378 int N[NDIM], Nlower[NDIM], Nupper[NDIM]; 2379 2380 if (LC->SetIndexToAtom(a)) { // get cell for the starting atom 2381 for(int i=0;i<NDIM;i++) // store indices of this cell 2382 N[i] = LC->n[i]; 2383 } else { 2384 cerr << "ERROR: Atom " << *a << " is not found in cell " << LC->index << "." << endl; 2385 return; 2386 } 2387 // then go through the current and all neighbouring cells and check the contained atoms for possible candidates 2388 cout << Verbose(2) << "LC Intervals:"; 2389 for (int i=0;i<NDIM;i++) { 2390 Nlower[i] = ((N[i]-1) >= 0) ? N[i]-1 : 0; 2391 Nupper[i] = ((N[i]+1) < LC->N[i]) ? N[i]+1 : LC->N[i]-1; 2392 cout << " [" << Nlower[i] << "," << Nupper[i] << "] "; 2393 } 2394 cout << endl; 2395 for (LC->n[0] = Nlower[0]; LC->n[0] <= Nupper[0]; LC->n[0]++) 2396 for (LC->n[1] = Nlower[1]; LC->n[1] <= Nupper[1]; LC->n[1]++) 2397 for (LC->n[2] = Nlower[2]; LC->n[2] <= Nupper[2]; LC->n[2]++) { 2398 List = LC->GetCurrentCell(); 2399 //cout << Verbose(2) << "Current cell is " << LC->n[0] << ", " << LC->n[1] << ", " << LC->n[2] << " with No. " << LC->index << "." << endl; 2400 if (List != NULL) { 2401 for (LinkedAtoms::iterator Runner = List->begin(); Runner != List->end(); Runner++) { 2402 Candidate = (*Runner); 2403 // check if we only have one unique point yet ... 2404 if (a != Candidate) { 2405 cout << Verbose(3) << "Current candidate is " << *Candidate << ": "; 2406 AngleCheck.CopyVector(&(Candidate->x)); 2407 AngleCheck.SubtractVector(&(a->x)); 2408 norm = AngleCheck.Norm(); 2409 // second point shall have smallest angle with respect to Oben vector 2410 if (norm < RADIUS) { 2411 angle = AngleCheck.Angle(&Oben); 2412 if (angle < Storage[0]) { 2413 //cout << Verbose(1) << "Old values of Storage: %lf %lf \n", Storage[0], Storage[1]); 2414 cout << "Is a better candidate with distance " << norm << " and " << angle << ".\n"; 2415 Opt_Candidate = Candidate; 2416 Storage[0] = AngleCheck.Angle(&Oben); 2417 //cout << Verbose(1) << "Changing something in Storage: %lf %lf. \n", Storage[0], Storage[2]); 2418 } else { 2419 cout << "Looses with angle " << angle << " to a better candidate " << *Opt_Candidate << endl; 2420 } 2421 } else { 2422 cout << "Refused due to Radius " << norm << endl; 2423 } 2424 } 2425 } 2426 } 2427 } 2428 cout << Verbose(2) << "End of Find_second_point_for_Tesselation" << endl; 2429 }; 2430 2431 /** Finds the starting triangle for find_non_convex_border(). 2432 * Looks at the outermost atom per axis, then Find_second_point_for_Tesselation() 2433 * for the second and Find_next_suitable_point_via_Angle_of_Sphere() for the third 2434 * point are called. 2435 * \param RADIUS radius of virtual rolling sphere 2436 * \param *LC LinkedCell structure with neighbouring atoms 2437 */ 2438 void Tesselation::Find_starting_triangle(ofstream *out, molecule *mol, const double RADIUS, LinkedCell *LC) 2439 { 2440 cout << Verbose(1) << "Begin of Find_starting_triangle\n"; 2441 int i = 0; 2442 LinkedAtoms *List = NULL; 2443 atom* Walker; 2444 atom* FirstPoint; 2445 atom* SecondPoint; 2446 atom* MaxAtom[NDIM]; 2447 double max_coordinate[NDIM]; 2448 Vector Oben; 2449 Vector helper; 2450 Vector Chord; 2451 Vector SearchDirection; 2452 Vector OptCandidateCenter; 2453 2454 Oben.Zero(); 2455 2456 for (i = 0; i < 3; i++) { 2457 MaxAtom[i] = NULL; 2458 max_coordinate[i] = -1; 2459 } 2460 2461 // 1. searching topmost atom with respect to each axis 2462 for (int i=0;i<NDIM;i++) { // each axis 2463 LC->n[i] = LC->N[i]-1; // current axis is topmost cell 2464 for (LC->n[(i+1)%NDIM]=0;LC->n[(i+1)%NDIM]<LC->N[(i+1)%NDIM];LC->n[(i+1)%NDIM]++) 2465 for (LC->n[(i+2)%NDIM]=0;LC->n[(i+2)%NDIM]<LC->N[(i+2)%NDIM];LC->n[(i+2)%NDIM]++) { 2466 List = LC->GetCurrentCell(); 2467 //cout << Verbose(2) << "Current cell is " << LC->n[0] << ", " << LC->n[1] << ", " << LC->n[2] << " with No. " << LC->index << "." << endl; 2468 if (List != NULL) { 2469 for (LinkedAtoms::iterator Runner = List->begin();Runner != List->end();Runner++) { 2470 cout << Verbose(2) << "Current atom is " << *(*Runner) << "." << endl; 2471 if ((*Runner)->x.x[i] > max_coordinate[i]) { 2472 max_coordinate[i] = (*Runner)->x.x[i]; 2473 MaxAtom[i] = (*Runner); 2474 } 2475 } 2476 } else { 2477 cerr << "ERROR: The current cell " << LC->n[0] << "," << LC->n[1] << "," << LC->n[2] << " is invalid!" << endl; 2478 } 2479 } 2480 } 2481 2482 cout << Verbose(2) << "Found maximum coordinates: "; 2483 for (int i=0;i<NDIM;i++) 2484 cout << i << ": " << *MaxAtom[i] << "\t"; 2485 cout << endl; 2486 const int k = 1; // arbitrary choice 2487 Oben.x[k] = 1.; 2488 FirstPoint = MaxAtom[k]; 2489 cout << Verbose(1) << "Coordinates of start atom " << *FirstPoint << " at " << FirstPoint->x << "." << endl; 2490 2491 // add first point 2492 AddTrianglePoint(FirstPoint, 0); 2493 2494 double ShortestAngle; 2495 atom* Opt_Candidate = NULL; 2496 ShortestAngle = 999999.; // This will contain the angle, which will be always positive (when looking for second point), when looking for third point this will be the quadrant. 2497 2498 Find_second_point_for_Tesselation(FirstPoint, NULL, Oben, Opt_Candidate, &ShortestAngle, RADIUS, LC); // we give same point as next candidate as its bonds are looked into in find_second_... 2499 SecondPoint = Opt_Candidate; 2500 cout << Verbose(1) << "Found second point is " << *SecondPoint << " at " << SecondPoint->x << ".\n"; 2501 2502 // add second point and first baseline 2503 AddTrianglePoint(SecondPoint, 1); 2504 AddTriangleLine(TPS[0], TPS[1], 0); 2505 2506 helper.CopyVector(&(FirstPoint->x)); 2507 helper.SubtractVector(&(SecondPoint->x)); 2508 helper.Normalize(); 2509 Oben.ProjectOntoPlane(&helper); 2510 Oben.Normalize(); 2511 helper.VectorProduct(&Oben); 2512 ShortestAngle = 2.*M_PI; // This will indicate the quadrant. 2513 2514 Chord.CopyVector(&(FirstPoint->x)); // bring into calling function 2515 Chord.SubtractVector(&(SecondPoint->x)); 2516 double radius = Chord.ScalarProduct(&Chord); 2517 double CircleRadius = sqrt(RADIUS*RADIUS - radius/4.); 2518 helper.CopyVector(&Oben); 2519 helper.Scale(CircleRadius); 2520 // Now, oben and helper are two orthonormalized vectors in the plane defined by Chord (not normalized) 2521 2522 cout << Verbose(2) << "Looking for third point candidates \n"; 2523 // look in one direction of baseline for initial candidate 2524 Opt_Candidate = NULL; 2525 SearchDirection.MakeNormalVector(&Chord, &Oben); // whether we look "left" first or "right" first is not important ... 2526 2527 cout << Verbose(1) << "Looking for third point candidates ...\n"; 2528 Find_third_point_for_Tesselation(Oben, SearchDirection, helper, BLS[0], NULL, Opt_Candidate, &OptCandidateCenter, &ShortestAngle, RADIUS, LC); 2529 cout << Verbose(1) << "Third Point is " << *Opt_Candidate << endl; 2530 2531 // add third point 2532 AddTrianglePoint(Opt_Candidate, 2); 2533 2534 // FOUND Starting Triangle: FirstPoint, SecondPoint, Opt_Candidate 2535 2536 // Finally, we only have to add the found further lines 2537 AddTriangleLine(TPS[1], TPS[2], 1); 2538 AddTriangleLine(TPS[0], TPS[2], 2); 2539 // ... and triangles to the Maps of the Tesselation class 2540 BTS = new class BoundaryTriangleSet(BLS, TrianglesOnBoundaryCount); 2541 AddTriangleToLines(); 2542 // ... and calculate its normal vector (with correct orientation) 2543 OptCandidateCenter.Scale(-1.); 2544 cout << Verbose(2) << "Oben is currently " << OptCandidateCenter << "." << endl; 2545 BTS->GetNormalVector(OptCandidateCenter); 2546 cout << Verbose(0) << "==> The found starting triangle consists of " << *FirstPoint << ", " << *SecondPoint << " and " << *Opt_Candidate << " with normal vector " << BTS->NormalVector << ".\n"; 2547 cout << Verbose(2) << "Projection is " << BTS->NormalVector.Projection(&Oben) << "." << endl; 2548 cout << Verbose(1) << "End of Find_starting_triangle\n"; 2549 }; 1980 2550 1981 2551 /** This function finds a triangle to a line, adjacent to an existing one. 1982 * @param out 1983 * @param mol molecule structure with all atoms and bonds2552 * @param out output stream for debugging 2553 * @param *mol molecule with Atom's and Bond's 1984 2554 * @param Line current baseline to search from 1985 2555 * @param T current triangle which \a Line is edge of 1986 2556 * @param RADIUS radius of the rolling ball 1987 2557 * @param N number of found triangles 2558 * @param *filename filename base for intermediate envelopes 2559 * @param *LC LinkedCell structure with neighbouring atoms 1988 2560 */ 1989 void Tesselation::Find_next_suitable_triangle(ofstream *out, 1990 molecule* mol, BoundaryLineSet &Line, BoundaryTriangleSet &T, 1991 const double& RADIUS, int N, const char *tempbasename) 1992 { 1993 cout << Verbose(1) << "Looking for next suitable triangle \n"; 1994 Vector direction1; 1995 Vector helper; 1996 Vector Chord; 1997 ofstream *tempstream = NULL; 1998 char NumberName[255]; 1999 double tmp; 2000 //atom* Walker; 2001 atom* OldThirdPoint; 2002 2003 double Storage[3]; 2004 Storage[0] = -2.; // This direction is either +1 or -1 one, so any result will take precedence over initial values 2005 Storage[1] = -2.; // This is also lower then any value produced by an eligible atom, which are all positive 2006 Storage[2] = 9999999.; 2007 atom* Opt_Candidate = NULL; 2008 Vector Opt_Mittelpunkt; 2009 2010 cout << Verbose(1) << "Constructing helpful vectors ... " << endl; 2011 helper.CopyVector(&(Line.endpoints[0]->node->x)); 2012 for (int i = 0; i < 3; i++) 2013 { 2014 if (T.endpoints[i]->node->nr != Line.endpoints[0]->node->nr 2015 && T.endpoints[i]->node->nr != Line.endpoints[1]->node->nr) 2016 { 2017 OldThirdPoint = T.endpoints[i]->node; 2018 helper.SubtractVector(&T.endpoints[i]->node->x); 2019 break; 2020 } 2021 } 2022 2023 direction1.CopyVector(&Line.endpoints[0]->node->x); 2024 direction1.SubtractVector(&Line.endpoints[1]->node->x); 2025 direction1.VectorProduct(&(T.NormalVector)); 2026 2027 if (direction1.ScalarProduct(&helper) < 0) 2028 { 2029 direction1.Scale(-1); 2030 } 2031 2032 Chord.CopyVector(&(Line.endpoints[0]->node->x)); // bring into calling function 2033 Chord.SubtractVector(&(Line.endpoints[1]->node->x)); 2034 2035 2036 Vector Umkreismittelpunkt, a, b, c; 2037 double alpha, beta, gamma; 2038 a.CopyVector(&(T.endpoints[0]->node->x)); 2039 b.CopyVector(&(T.endpoints[1]->node->x)); 2040 c.CopyVector(&(T.endpoints[2]->node->x)); 2041 a.SubtractVector(&(T.endpoints[1]->node->x)); 2042 b.SubtractVector(&(T.endpoints[2]->node->x)); 2043 c.SubtractVector(&(T.endpoints[0]->node->x)); 2044 2045 alpha = M_PI - a.Angle(&c); 2046 beta = M_PI - b.Angle(&a); 2047 gamma = M_PI - c.Angle(&b); 2048 2049 Umkreismittelpunkt = (T.endpoints[0]->node->x) * sin(2.*alpha) + T.endpoints[1]->node->x * sin(2.*beta) + (T.endpoints[2]->node->x) * sin(2.*gamma) ; 2050 //cout << "UmkreisMittelpunkt is " << Umkreismittelpunkt.x[0] << " "<< Umkreismittelpunkt.x[1] << " "<< Umkreismittelpunkt.x[2] << " "<< endl; 2051 Umkreismittelpunkt.Scale(1/(sin(2*alpha) + sin(2*beta) + sin(2*gamma))); 2052 cout << "UmkreisMittelpunkt is " << Umkreismittelpunkt.x[0] << " "<< Umkreismittelpunkt.x[1] << " "<< Umkreismittelpunkt.x[2] << " "<< endl; 2053 cout << " We look over line " << Line << " in direction " << direction1.x[0] << " " << direction1.x[1] << " " << direction1.x[2] << " " << endl; 2054 cout << " Old Normal is " << (T.NormalVector.x)[0] << " " << T.NormalVector.x[1] << " " << (T.NormalVector.x)[2] << " " << endl; 2055 2056 2057 cout << Verbose(1) << "Looking for third point candidates for triangle ... " << endl; 2058 2059 Find_next_suitable_point_via_Angle_of_Sphere(Line.endpoints[0]->node, Line.endpoints[1]->node, OldThirdPoint, 2060 Line.endpoints[0]->node, Line.endpoints[1]->node, 0, &Chord, &direction1, 2061 &(T.NormalVector), Umkreismittelpunkt, Opt_Candidate, Storage, RADIUS, mol); 2062 Find_next_suitable_point_via_Angle_of_Sphere(Line.endpoints[0]->node, Line.endpoints[1]->node, OldThirdPoint, 2063 Line.endpoints[1]->node, Line.endpoints[0]->node, 0, &Chord, &direction1, 2064 &(T.NormalVector), Umkreismittelpunkt, Opt_Candidate, Storage, RADIUS, mol); 2065 2066 2067 cout << "Letzter Winkel bei " << TrianglesOnBoundaryCount << " Winkel ist " << Storage[2] << endl; 2068 2069 if ((TrianglesOnBoundaryCount % 10) == 0) { 2070 sprintf(NumberName, "-%d", TriangleFilesWritten); 2071 if (DoTecplotOutput) { 2072 string NameofTempFile(tempbasename); 2073 NameofTempFile.append(NumberName); 2074 NameofTempFile.append(TecplotSuffix); 2075 cout << Verbose(1) << "Writing temporary non convex hull to file " << NameofTempFile << ".\n"; 2076 tempstream = new ofstream(NameofTempFile.c_str(), ios::trunc); 2077 write_tecplot_file(out, tempstream, this, mol, TriangleFilesWritten); 2078 tempstream->close(); 2079 tempstream->flush(); 2080 delete(tempstream); 2081 } 2082 if (DoRaster3DOutput) { 2083 string NameofTempFile(tempbasename); 2084 NameofTempFile.append(NumberName); 2085 NameofTempFile.append(Raster3DSuffix); 2086 cout << Verbose(1) << "Writing temporary non convex hull to file " << NameofTempFile << ".\n"; 2087 tempstream = new ofstream(NameofTempFile.c_str(), ios::trunc); 2088 write_raster3d_file(out, tempstream, this, mol); 2089 tempstream->close(); 2090 tempstream->flush(); 2091 delete(tempstream); 2092 } 2093 if (DoTecplotOutput || DoRaster3DOutput) 2094 TriangleFilesWritten++; 2095 } 2096 2097 // Konstruiere nun neues Dreieck am Ende der Liste der Dreiecke 2098 2099 cout << " Optimal candidate is " << *Opt_Candidate << endl; 2100 2101 AddTrianglePoint(Opt_Candidate, 0); 2102 AddTrianglePoint(Line.endpoints[0]->node, 1); 2103 AddTrianglePoint(Line.endpoints[1]->node, 2); 2104 2105 AddTriangleLine(TPS[0], TPS[1], 0); 2106 AddTriangleLine(TPS[0], TPS[2], 1); 2107 AddTriangleLine(TPS[1], TPS[2], 2); 2108 2109 BTS = new class BoundaryTriangleSet(BLS, TrianglesOnBoundaryCount); 2110 AddTriangleToLines(); 2111 cout << "New triangle with " << *BTS << endl; 2112 cout << "We have "<< TrianglesOnBoundaryCount << endl; 2113 cout << Verbose(1) << "Constructing normal vector for this triangle ... " << endl; 2114 2115 BTS->GetNormalVector(BTS->NormalVector); 2116 2117 if ((BTS->NormalVector.ScalarProduct(&(T.NormalVector)) < 0 && Storage[0] > 0) || 2118 (BTS->NormalVector.ScalarProduct(&(T.NormalVector)) > 0 && Storage[0] < 0) || 2119 (fabs(Storage[0]) < MYEPSILON && Storage[1]*BTS->NormalVector.ScalarProduct(&direction1) < 0) ) 2120 2121 { 2122 BTS->NormalVector.Scale(-1); 2123 }; 2124 2125 } 2126 ; 2127 2128 void Find_second_point_for_Tesselation(atom* a, atom* Candidate, atom* Parent, 2129 int RecursionLevel, Vector Oben, atom*& Opt_Candidate, double Storage[3], 2130 molecule* mol, double RADIUS) 2131 { 2132 cout << Verbose(1) 2133 << "Looking for second point of starting triangle, recursive level " 2134 << RecursionLevel << endl;; 2135 int i; 2136 Vector AngleCheck; 2137 atom* Walker; 2138 double norm = -1.; 2139 2140 // check if we only have one unique point yet ... 2141 if (a != Candidate) 2142 { 2143 AngleCheck.CopyVector(&(Candidate->x)); 2144 AngleCheck.SubtractVector(&(a->x)); 2145 norm = AngleCheck.Norm(); 2146 // second point shall have smallest angle with respect to Oben vector 2147 if (norm < RADIUS) 2148 { 2149 if (AngleCheck.Angle(&Oben) < Storage[0]) 2150 { 2151 //cout << Verbose(1) << "Old values of Storage: %lf %lf \n", Storage[0], Storage[2]); 2152 cout << "Next better candidate is " << *Candidate 2153 << " with distance " << norm << ".\n"; 2154 Opt_Candidate = Candidate; 2155 Storage[0] = AngleCheck.Angle(&Oben); 2156 //cout << Verbose(1) << "Changing something in Storage: %lf %lf. \n", Storage[0], Storage[2]); 2157 } 2158 else 2159 { 2160 cout << Verbose(1) << "Supposedly looses to a better candidate " 2161 << *Opt_Candidate << endl; 2162 } 2163 } 2164 else 2165 { 2166 cout << Verbose(1) << *Candidate << " refused due to Radius " << norm 2167 << endl; 2168 } 2169 } 2170 2171 // if not recursed to deeply, look at all its bonds 2172 if (RecursionLevel < 7) 2173 { 2174 for (i = 0; i < mol->NumberOfBondsPerAtom[Candidate->nr]; i++) 2175 { 2176 Walker = mol->ListOfBondsPerAtom[Candidate->nr][i]->GetOtherAtom( 2177 Candidate); 2178 if (Walker == Parent) // don't go back along the bond we came from 2179 continue; 2180 else 2181 Find_second_point_for_Tesselation(a, Walker, Candidate, 2182 RecursionLevel + 1, Oben, Opt_Candidate, Storage, mol, RADIUS); 2183 }; 2184 }; 2185 } 2186 ; 2187 2188 void Tesselation::Find_starting_triangle(molecule* mol, const double RADIUS) 2189 { 2190 cout << Verbose(1) << "Looking for starting triangle \n"; 2191 int i = 0; 2192 atom* Walker; 2193 atom* FirstPoint; 2194 atom* SecondPoint; 2195 atom* max_index[3]; 2196 double max_coordinate[3]; 2197 Vector Oben; 2198 Vector helper; 2199 Vector Chord; 2200 Vector CenterOfFirstLine; 2201 2202 Oben.Zero(); 2203 2204 for (i = 0; i < 3; i++) 2205 { 2206 max_index[i] = NULL; 2207 max_coordinate[i] = -1; 2208 } 2209 cout << Verbose(1) << "Molecule mol is there and has " << mol->AtomCount 2210 << " Atoms \n"; 2211 2212 // 1. searching topmost atom with respect to each axis 2213 Walker = mol->start; 2214 while (Walker->next != mol->end) 2215 { 2216 Walker = Walker->next; 2217 for (i = 0; i < 3; i++) 2218 { 2219 if (Walker->x.x[i] > max_coordinate[i]) 2220 { 2221 max_coordinate[i] = Walker->x.x[i]; 2222 max_index[i] = Walker; 2223 } 2224 } 2225 } 2226 2227 cout << Verbose(1) << "Found maximum coordinates. " << endl; 2228 //Koennen dies fuer alle Richtungen, legen hier erstmal Richtung auf k=0 2229 const int k = 1; 2230 Oben.x[k] = 1.; 2231 FirstPoint = max_index[k]; 2232 2233 cout << Verbose(1) << "Coordinates of start atom " << *FirstPoint << ": " 2234 << FirstPoint->x.x[0] << endl; 2235 double Storage[3]; 2236 atom* Opt_Candidate = NULL; 2237 Storage[0] = 999999.; // This will contain the angle, which will be always positive (when looking for second point), when looking for third point this will be the quadrant. 2238 Storage[1] = 999999.; // This will be an angle looking for the third point. 2239 Storage[2] = 999999.; 2240 cout << Verbose(1) << "Number of Bonds: " 2241 << mol->NumberOfBondsPerAtom[FirstPoint->nr] << endl; 2242 2243 Find_second_point_for_Tesselation(FirstPoint, FirstPoint, FirstPoint, 0, 2244 Oben, Opt_Candidate, Storage, mol, RADIUS); // we give same point as next candidate as its bonds are looked into in find_second_... 2245 SecondPoint = Opt_Candidate; 2246 cout << Verbose(1) << "Found second point is " << *SecondPoint << ".\n"; 2247 2248 helper.CopyVector(&(FirstPoint->x)); 2249 helper.SubtractVector(&(SecondPoint->x)); 2250 helper.Normalize(); 2251 Oben.ProjectOntoPlane(&helper); 2252 Oben.Normalize(); 2253 helper.VectorProduct(&Oben); 2254 Storage[0] = -2.; // This will indicate the quadrant. 2255 Storage[1] = 9999999.; // This will be an angle looking for the third point. 2256 Storage[2] = 9999999.; 2257 2258 Chord.CopyVector(&(FirstPoint->x)); // bring into calling function 2259 Chord.SubtractVector(&(SecondPoint->x)); 2260 // Now, oben and helper are two orthonormalized vectors in the plane defined by Chord (not normalized) 2261 2262 cout << Verbose(1) << "Looking for third point candidates \n"; 2263 cout << Verbose(1) << " In direction " << helper.x[0] << " " << helper.x[1] << " " << helper.x[2] << " " << endl; 2264 // look in one direction of baseline for initial candidate 2265 Opt_Candidate = NULL; 2266 CenterOfFirstLine.CopyVector(&Chord); 2267 CenterOfFirstLine.Scale(0.5); 2268 CenterOfFirstLine.AddVector(&(SecondPoint->x)); 2269 2270 Find_next_suitable_point_via_Angle_of_Sphere(FirstPoint, SecondPoint, SecondPoint, SecondPoint, FirstPoint, 0, 2271 &Chord, &helper, &Oben, CenterOfFirstLine, Opt_Candidate, Storage, RADIUS, mol); 2272 // look in other direction of baseline for possible better candidate 2273 Find_next_suitable_point_via_Angle_of_Sphere(FirstPoint, SecondPoint, SecondPoint, FirstPoint, SecondPoint, 0, 2274 &Chord, &helper, &Oben, CenterOfFirstLine, Opt_Candidate, Storage, RADIUS, mol); 2275 cout << Verbose(1) << "Third Point is " << *Opt_Candidate << endl; 2276 2277 // FOUND Starting Triangle: FirstPoint, SecondPoint, Opt_Candidate 2278 2279 cout << Verbose(1) << "The found starting triangle consists of " 2280 << *FirstPoint << ", " << *SecondPoint << " and " << *Opt_Candidate 2281 << "." << endl; 2282 2283 // Finally, we only have to add the found points 2284 AddTrianglePoint(FirstPoint, 0); 2285 AddTrianglePoint(SecondPoint, 1); 2286 AddTrianglePoint(Opt_Candidate, 2); 2287 // ... and respective lines 2288 AddTriangleLine(TPS[0], TPS[1], 0); 2289 AddTriangleLine(TPS[1], TPS[2], 1); 2290 AddTriangleLine(TPS[0], TPS[2], 2); 2291 // ... and triangles to the Maps of the Tesselation class 2292 BTS = new class BoundaryTriangleSet(BLS, TrianglesOnBoundaryCount); 2293 AddTriangleToLines(); 2294 // ... and calculate its normal vector (with correct orientation) 2295 Oben.Scale(-1.); 2296 BTS->GetNormalVector(Oben); 2297 } 2298 ; 2299 2300 void Find_non_convex_border(ofstream *out, const char *filename, molecule* mol) 2301 { 2302 int N = 0; 2303 struct Tesselation *Tess = new Tesselation; 2304 cout << Verbose(1) << "Entering search for non convex hull. " << endl; 2305 cout << flush; 2306 const double RADIUS = 6.; 2307 LineMap::iterator baseline; 2308 cout << Verbose(0) << "Begin of Find_non_convex_border\n"; 2309 bool flag = false; // marks whether we went once through all baselines without finding any without two triangles 2310 2311 if ((mol->first->next == mol->last) || (mol->last->previous == mol->first)) 2312 mol->CreateAdjacencyList((ofstream *)&cout, 1.6, true); 2313 2314 Tess->Find_starting_triangle(mol, RADIUS); 2315 2316 baseline = Tess->LinesOnBoundary.begin(); 2317 while (baseline != Tess->LinesOnBoundary.end()) 2318 { 2319 if (baseline->second->TrianglesCount == 1) 2320 { 2321 cout << Verbose(1) << "Begin of Tesselation ... " << endl; 2322 Tess->Find_next_suitable_triangle(out, mol, 2323 *(baseline->second), 2324 *(((baseline->second->triangles.begin()))->second), RADIUS, N, filename); //the line is there, so there is a triangle, but only one. 2325 flag = true; 2326 cout << Verbose(1) << "End of Tesselation ... " << endl; 2327 } 2328 else 2329 { 2330 cout << Verbose(1) << "There is a line with " 2331 << baseline->second->TrianglesCount << " triangles adjacent" 2332 << endl; 2333 } 2334 N++; 2335 baseline++; 2336 } 2337 cout << Verbose(1) << "Writing final tecplot file\n"; 2338 if (DoTecplotOutput) { 2339 string Name(filename); 2340 Name.append(TecplotSuffix); 2341 ofstream tecplot(Name.c_str(), ios::trunc); 2342 write_tecplot_file(out, &tecplot, Tess, mol, -1); 2343 tecplot.close(); 2344 } 2345 if (DoRaster3DOutput) { 2346 string Name(filename); 2347 Name.append(Raster3DSuffix); 2348 ofstream raster(Name.c_str(), ios::trunc); 2349 write_raster3d_file(out, &raster, Tess, mol); 2350 raster.close(); 2351 } 2352 } 2353 ; 2561 bool Tesselation::Find_next_suitable_triangle(ofstream *out, 2562 molecule *mol, BoundaryLineSet &Line, BoundaryTriangleSet &T, 2563 const double& RADIUS, int N, const char *tempbasename, LinkedCell *LC) 2564 { 2565 cout << Verbose(1) << "Begin of Find_next_suitable_triangle\n"; 2566 ofstream *tempstream = NULL; 2567 char NumberName[255]; 2568 double tmp; 2569 2570 atom* Opt_Candidate = NULL; 2571 Vector OptCandidateCenter; 2572 2573 Vector CircleCenter; 2574 Vector CirclePlaneNormal; 2575 Vector OldSphereCenter; 2576 Vector SearchDirection; 2577 Vector helper; 2578 atom *ThirdNode = NULL; 2579 double ShortestAngle = 2.*M_PI; // This will indicate the quadrant. 2580 double radius, CircleRadius; 2581 2582 cout << Verbose(1) << "Current baseline is " << Line << " of triangle " << T << "." << endl; 2583 for (int i=0;i<3;i++) 2584 if ((T.endpoints[i]->node != Line.endpoints[0]->node) && (T.endpoints[i]->node != Line.endpoints[1]->node)) 2585 ThirdNode = T.endpoints[i]->node; 2586 2587 // construct center of circle 2588 CircleCenter.CopyVector(&Line.endpoints[0]->node->x); 2589 CircleCenter.AddVector(&Line.endpoints[1]->node->x); 2590 CircleCenter.Scale(0.5); 2591 2592 // construct normal vector of circle 2593 CirclePlaneNormal.CopyVector(&Line.endpoints[0]->node->x); 2594 CirclePlaneNormal.SubtractVector(&Line.endpoints[1]->node->x); 2595 2596 // calculate squared radius of circle 2597 radius = CirclePlaneNormal.ScalarProduct(&CirclePlaneNormal); 2598 if (radius/4. < RADIUS*RADIUS) { 2599 CircleRadius = RADIUS*RADIUS - radius/4.; 2600 CirclePlaneNormal.Normalize(); 2601 cout << Verbose(2) << "INFO: CircleCenter is at " << CircleCenter << ", CirclePlaneNormal is " << CirclePlaneNormal << " with circle radius " << sqrt(CircleRadius) << "." << endl; 2602 2603 // construct old center 2604 GetCenterofCircumcircle(&OldSphereCenter, &(T.endpoints[0]->node->x), &(T.endpoints[1]->node->x), &(T.endpoints[2]->node->x)); 2605 helper.CopyVector(&T.NormalVector); // normal vector ensures that this is correct center of the two possible ones 2606 radius = Line.endpoints[0]->node->x.DistanceSquared(&OldSphereCenter); 2607 helper.Scale(sqrt(RADIUS*RADIUS - radius)); 2608 OldSphereCenter.AddVector(&helper); 2609 OldSphereCenter.SubtractVector(&CircleCenter); 2610 cout << Verbose(2) << "INFO: OldSphereCenter is at " << OldSphereCenter << "." << endl; 2611 2612 // construct SearchDirection 2613 SearchDirection.MakeNormalVector(&T.NormalVector, &CirclePlaneNormal); 2614 helper.CopyVector(&Line.endpoints[0]->node->x); 2615 helper.SubtractVector(&ThirdNode->x); 2616 if (helper.ScalarProduct(&SearchDirection) < -HULLEPSILON) // ohoh, SearchDirection points inwards! 2617 SearchDirection.Scale(-1.); 2618 SearchDirection.ProjectOntoPlane(&OldSphereCenter); 2619 SearchDirection.Normalize(); 2620 cout << Verbose(2) << "INFO: SearchDirection is " << SearchDirection << "." << endl; 2621 if (fabs(OldSphereCenter.ScalarProduct(&SearchDirection)) > HULLEPSILON) { // rotated the wrong way! 2622 cerr << "ERROR: SearchDirection and RelativeOldSphereCenter are still not orthogonal!" << endl; 2623 } 2624 2625 // add third point 2626 cout << Verbose(1) << "Looking for third point candidates for triangle ... " << endl; 2627 Find_third_point_for_Tesselation(T.NormalVector, SearchDirection, OldSphereCenter, &Line, ThirdNode, Opt_Candidate, &OptCandidateCenter, &ShortestAngle, RADIUS, LC); 2628 2629 } else { 2630 cout << Verbose(1) << "Circumcircle for base line " << Line << " and base triangle " << T << " is too big!" << endl; 2631 } 2632 2633 if (Opt_Candidate == NULL) { 2634 cerr << "WARNING: Could not find a suitable candidate." << endl; 2635 return false; 2636 } 2637 cout << Verbose(1) << " Optimal candidate is " << *Opt_Candidate << " with circumsphere's center at " << OptCandidateCenter << "." << endl; 2638 2639 // check whether all edges of the new triangle still have space for one more triangle (i.e. TriangleCount <2) 2640 atom *AtomCandidates[3]; 2641 AtomCandidates[0] = Opt_Candidate; 2642 AtomCandidates[1] = Line.endpoints[0]->node; 2643 AtomCandidates[2] = Line.endpoints[1]->node; 2644 bool flag = CheckPresenceOfTriangle(out, AtomCandidates); 2645 2646 if (flag) { // if so, add 2647 AddTrianglePoint(Opt_Candidate, 0); 2648 AddTrianglePoint(Line.endpoints[0]->node, 1); 2649 AddTrianglePoint(Line.endpoints[1]->node, 2); 2650 2651 AddTriangleLine(TPS[0], TPS[1], 0); 2652 AddTriangleLine(TPS[0], TPS[2], 1); 2653 AddTriangleLine(TPS[1], TPS[2], 2); 2654 2655 BTS = new class BoundaryTriangleSet(BLS, TrianglesOnBoundaryCount); 2656 AddTriangleToLines(); 2657 2658 OptCandidateCenter.Scale(-1.); 2659 BTS->GetNormalVector(OptCandidateCenter); 2660 OptCandidateCenter.Scale(-1.); 2661 2662 cout << "--> New triangle with " << *BTS << " and normal vector " << BTS->NormalVector << " for this triangle ... " << endl; 2663 cout << Verbose(1) << "We have "<< TrianglesOnBoundaryCount << " for line " << Line << "." << endl; 2664 } else { // else, yell and do nothing 2665 cout << Verbose(1) << "This triangle consisting of "; 2666 cout << *Opt_Candidate << ", "; 2667 cout << *Line.endpoints[0]->node << " and "; 2668 cout << *Line.endpoints[1]->node << " "; 2669 cout << "is invalid!" << endl; 2670 return false; 2671 } 2672 2673 if (flag && (DoSingleStepOutput && (TrianglesOnBoundaryCount % 10 == 0))) { // if we have a new triangle and want to output each new triangle configuration 2674 sprintf(NumberName, "-%04d-%s_%s_%s", TriangleFilesWritten, BTS->endpoints[0]->node->Name, BTS->endpoints[1]->node->Name, BTS->endpoints[2]->node->Name); 2675 if (DoTecplotOutput) { 2676 string NameofTempFile(tempbasename); 2677 NameofTempFile.append(NumberName); 2678 for(size_t npos = NameofTempFile.find_first_of(' '); npos != -1; npos = NameofTempFile.find(' ', npos)) 2679 NameofTempFile.erase(npos, 1); 2680 NameofTempFile.append(TecplotSuffix); 2681 cout << Verbose(1) << "Writing temporary non convex hull to file " << NameofTempFile << ".\n"; 2682 tempstream = new ofstream(NameofTempFile.c_str(), ios::trunc); 2683 write_tecplot_file(out, tempstream, this, mol, TriangleFilesWritten); 2684 tempstream->close(); 2685 tempstream->flush(); 2686 delete(tempstream); 2687 } 2688 2689 if (DoRaster3DOutput) { 2690 string NameofTempFile(tempbasename); 2691 NameofTempFile.append(NumberName); 2692 for(size_t npos = NameofTempFile.find_first_of(' '); npos != -1; npos = NameofTempFile.find(' ', npos)) 2693 NameofTempFile.erase(npos, 1); 2694 NameofTempFile.append(Raster3DSuffix); 2695 cout << Verbose(1) << "Writing temporary non convex hull to file " << NameofTempFile << ".\n"; 2696 tempstream = new ofstream(NameofTempFile.c_str(), ios::trunc); 2697 write_raster3d_file(out, tempstream, this, mol); 2698 // include the current position of the virtual sphere in the temporary raster3d file 2699 // make the circumsphere's center absolute again 2700 helper.CopyVector(&Line.endpoints[0]->node->x); 2701 helper.AddVector(&Line.endpoints[1]->node->x); 2702 helper.Scale(0.5); 2703 OptCandidateCenter.AddVector(&helper); 2704 Vector *center = mol->DetermineCenterOfAll(out); 2705 OptCandidateCenter.AddVector(center); 2706 delete(center); 2707 // and add to file plus translucency object 2708 *tempstream << "# current virtual sphere\n"; 2709 *tempstream << "8\n 25.0 0.6 -1.0 -1.0 -1.0 0.2 0 0 0 0\n"; 2710 *tempstream << "2\n " << OptCandidateCenter.x[0] << " " << OptCandidateCenter.x[1] << " " << OptCandidateCenter.x[2] << "\t" << RADIUS << "\t1 0 0\n"; 2711 *tempstream << "9\n terminating special property\n"; 2712 tempstream->close(); 2713 tempstream->flush(); 2714 delete(tempstream); 2715 } 2716 if (DoTecplotOutput || DoRaster3DOutput) 2717 TriangleFilesWritten++; 2718 } 2719 2720 cout << Verbose(1) << "End of Find_next_suitable_triangle\n"; 2721 return true; 2722 }; 2723 2724 /** Tesselates the non convex boundary by rolling a virtual sphere along the surface of the molecule. 2725 * \param *out output stream for debugging 2726 * \param *mol molecule structure with Atom's and Bond's 2727 * \param *Tess Tesselation filled with points, lines and triangles on boundary on return 2728 * \param *LCList linked cell list of all atoms 2729 * \param *filename filename prefix for output of vertex data 2730 * \para RADIUS radius of the virtual sphere 2731 */ 2732 void Find_non_convex_border(ofstream *out, molecule* mol, class Tesselation *Tess, class LinkedCell *LCList, const char *filename, const double RADIUS) 2733 { 2734 int N = 0; 2735 bool freeTess = false; 2736 *out << Verbose(1) << "Entering search for non convex hull. " << endl; 2737 if (Tess == NULL) { 2738 *out << Verbose(1) << "Allocating Tesselation struct ..." << endl; 2739 Tess = new Tesselation; 2740 freeTess = true; 2741 } 2742 bool freeLC = false; 2743 LineMap::iterator baseline; 2744 *out << Verbose(0) << "Begin of Find_non_convex_border\n"; 2745 bool flag = false; // marks whether we went once through all baselines without finding any without two triangles 2746 bool failflag = false; 2747 2748 if (LCList == NULL) { 2749 LCList = new LinkedCell(mol, 2.*RADIUS); 2750 freeLC = true; 2751 } 2752 2753 Tess->Find_starting_triangle(out, mol, RADIUS, LCList); 2754 2755 baseline = Tess->LinesOnBoundary.begin(); 2756 while ((baseline != Tess->LinesOnBoundary.end()) || (flag)) { 2757 if (baseline->second->TrianglesCount == 1) { 2758 failflag = Tess->Find_next_suitable_triangle(out, mol, *(baseline->second), *(((baseline->second->triangles.begin()))->second), RADIUS, N, filename, LCList); //the line is there, so there is a triangle, but only one. 2759 flag = flag || failflag; 2760 if (!failflag) 2761 cerr << "WARNING: Find_next_suitable_triangle failed." << endl; 2762 } else { 2763 cout << Verbose(1) << "Line " << *baseline->second << " has " << baseline->second->TrianglesCount << " triangles adjacent" << endl; 2764 } 2765 N++; 2766 baseline++; 2767 if ((baseline == Tess->LinesOnBoundary.end()) && (flag)) { 2768 baseline = Tess->LinesOnBoundary.begin(); // restart if we reach end due to newly inserted lines 2769 flag = false; 2770 } 2771 } 2772 if (1) { //failflag) { 2773 *out << Verbose(1) << "Writing final tecplot file\n"; 2774 if (DoTecplotOutput) { 2775 string OutputName(filename); 2776 OutputName.append(TecplotSuffix); 2777 ofstream *tecplot = new ofstream(OutputName.c_str()); 2778 write_tecplot_file(out, tecplot, Tess, mol, -1); 2779 tecplot->close(); 2780 delete(tecplot); 2781 } 2782 if (DoRaster3DOutput) { 2783 string OutputName(filename); 2784 OutputName.append(Raster3DSuffix); 2785 ofstream *raster = new ofstream(OutputName.c_str()); 2786 write_raster3d_file(out, raster, Tess, mol); 2787 raster->close(); 2788 delete(raster); 2789 } 2790 } else { 2791 cerr << "ERROR: Could definately not find all necessary triangles!" << endl; 2792 } 2793 if (freeTess) 2794 delete(Tess); 2795 if (freeLC) 2796 delete(LCList); 2797 *out << Verbose(0) << "End of Find_non_convex_border\n"; 2798 }; 2799 -
Property mode
changed from
Note:
See TracChangeset
for help on using the changeset viewer.