Changeset 6ac7ee for src/boundary.cpp
- Timestamp:
- Feb 9, 2009, 5:24:10 PM (17 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, Candidate_v1.7.0, 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
-
src/boundary.cpp (modified) (33 diffs, 1 prop)
Legend:
- Unmodified
- Added
- Removed
-
src/boundary.cpp
-
Property mode
changed from
100644to100755
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 LinesCount = 0;15 Nr = -1;17 LinesCount = 0; 18 Nr = -1; 16 19 } 17 20 ; … … 19 22 BoundaryPointSet::BoundaryPointSet(atom *Walker) 20 23 { 21 node = Walker;22 LinesCount = 0;23 Nr = Walker->nr;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 ost << "[" << a.Nr << "|" << a.node->Name << "]";55 return ost;58 ost << "[" << a.Nr << "|" << a.node->Name << "]"; 59 return ost; 56 60 } 57 61 ; … … 61 65 BoundaryLineSet::BoundaryLineSet() 62 66 { 63 for (int i = 0; i < 2; i++)64 endpoints[i] = NULL;65 TrianglesCount = 0;66 Nr = -1;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 // set number73 Nr = number;74 // set endpoints in ascending order75 SetEndpointsOrdered(endpoints, Point[0], Point[1]);76 // add this line to the hash maps of both endpoints77 Point[0]->AddLine(this); //Taken out, to check whether we can avoid unwanted double adding.78 Point[1]->AddLine(this); //79 // clear triangles list80 TrianglesCount = 0;81 cout << Verbose(5) << "New Line with endpoints " << *this << "." << endl;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 cout << Verbose(6) << "Add " << triangle->Nr << " to line " << *this << "."111 << endl;112 triangles.insert(TrianglePair(TrianglesCount, triangle));113 TrianglesCount++;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 ost << "[" << a.Nr << "|" << a.endpoints[0]->node->Name << ","121 << a.endpoints[1]->node->Name << "]";122 return ost;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 for (int i = 0; i < 3; i++)132 {133 endpoints[i] = NULL;134 lines[i] = NULL;135 }136 Nr = -1;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 int number)142 { 143 // set number144 Nr = number;145 // set lines146 cout << Verbose(5) << "New triangle " << Nr << ":" << endl;147 for (int i = 0; i < 3; i++)148 {149 lines[i] = line[i];150 lines[i]->AddTriangle(this);151 }152 // get ascending order of endpoints153 map<int, class BoundaryPointSet *> OrderMap;154 for (int i = 0; i < 3; i++)155 // for all three lines156 for (int j = 0; j < 2; j++)157 { // for both endpoints158 OrderMap.insert(pair<int, class BoundaryPointSet *> (159 line[i]->endpoints[j]->Nr, line[i]->endpoints[j]));160 // and we don't care whether insertion fails161 }162 // set endpoints163 int Counter = 0;164 cout << Verbose(6) << " with end points ";165 for (map<int, class BoundaryPointSet *>::iterator runner = OrderMap.begin(); runner166 != OrderMap.end(); runner++)167 {168 endpoints[Counter] = runner->second;169 cout << " " << *endpoints[Counter];170 Counter++;171 }172 if (Counter < 3)173 {174 cerr << "ERROR! We have a triangle with only two distinct endpoints!"175 << endl;176 //exit(1);177 }178 cout << "." << endl;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 // get normal vector207 NormalVector.MakeNormalVector(&endpoints[0]->node->x, &endpoints[1]->node->x,208 &endpoints[2]->node->x);209 210 // make it always point inward (any offset vector onto plane projected onto normal vector suffices)211 if (endpoints[0]->node->x.Projection(&OtherVector) > 0)212 NormalVector.Scale(-1.);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 ost << "[" << a.Nr << "|" << a.endpoints[0]->node->Name << ","220 << a.endpoints[1]->node->Name << "," << a.endpoints[2]->node->Name << "]";221 return ost;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 class BoundaryLineSet * lines[2] =236 { line1, line2 };237 class BoundaryPointSet *node = NULL;238 map<int, class BoundaryPointSet *> OrderMap;239 pair<map<int, class BoundaryPointSet *>::iterator, bool> OrderTest;240 for (int i = 0; i < 2; i++)241 // for both lines242 for (int j = 0; j < 2; j++)243 { // for both endpoints244 OrderTest = OrderMap.insert(pair<int, class BoundaryPointSet *> (245 lines[i]->endpoints[j]->Nr, lines[i]->endpoints[j]));246 if (!OrderTest.second)247 { // if insertion fails, we have common endpoint248 node = OrderTest.first->second;249 cout << Verbose(5) << "Common endpoint of lines " << *line1250 << " and " << *line2 << " is: " << *node << "." << endl;251 j = 2;252 i = 2;253 break;254 }255 }256 return node;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 atom *Walker = NULL;271 PointMap PointsOnBoundary;272 LineMap LinesOnBoundary;273 TriangleMap TrianglesOnBoundary;274 275 *out << Verbose(1) << "Finding all boundary points." << endl;276 Boundaries *BoundaryPoints = new Boundaries[NDIM]; // first is alpha, second is (r, nr)277 BoundariesTestPair BoundaryTestPair;278 Vector AxisVector, AngleReferenceVector, AngleReferenceNormalVector;279 double radius, angle;280 // 3a. Go through every axis281 for (int axis = 0; axis < NDIM; axis++)282 {283 AxisVector.Zero();284 AngleReferenceVector.Zero();285 AngleReferenceNormalVector.Zero();286 AxisVector.x[axis] = 1.;287 AngleReferenceVector.x[(axis + 1) % NDIM] = 1.;288 AngleReferenceNormalVector.x[(axis + 2) % NDIM] = 1.;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 // 3b. construct set of all points, transformed into cylindrical system and with left and right neighbours298 Walker = mol->start;299 while (Walker->next != mol->end)300 {301 Walker = Walker->next;302 Vector ProjectedVector;303 ProjectedVector.CopyVector(&Walker->x);304 ProjectedVector.ProjectOntoPlane(&AxisVector);305 // correct for negative side306 //if (Projection(y) < 0)307 //angle = 2.*M_PI - angle;308 radius = ProjectedVector.Norm();309 if (fabs(radius) > MYEPSILON)310 angle = ProjectedVector.Angle(&AngleReferenceVector);311 else312 angle = 0.; // otherwise it's a vector in Axis Direction and unimportant for boundary issues313 314 //*out << "Checking sign in quadrant : " << ProjectedVector.Projection(&AngleReferenceNormalVector) << "." << endl;315 if (ProjectedVector.Projection(&AngleReferenceNormalVector) > 0)316 {317 angle = 2. * M_PI - angle;318 }319 //*out << Verbose(2) << "Inserting " << *Walker << ": (r, alpha) = (" << radius << "," << angle << "): ";320 //ProjectedVector.Output(out);321 //*out << endl;322 BoundaryTestPair = BoundaryPoints[axis].insert(BoundariesPair(angle,323 DistancePair (radius, Walker)));324 if (BoundaryTestPair.second)325 { // successfully inserted326 }327 else328 { // same point exists, check first r, then distance of original vectors to center of gravity329 *out << Verbose(2)330 << "Encountered two vectors whose projection onto axis "331 << axis << " is equal: " << endl;332 *out << Verbose(2) << "Present vector: ";333 BoundaryTestPair.first->second.second->x.Output(out);334 *out << endl;335 *out << Verbose(2) << "New vector: ";336 Walker->x.Output(out);337 *out << endl;338 double tmp = ProjectedVector.Norm();339 if (tmp > BoundaryTestPair.first->second.first)340 {341 BoundaryTestPair.first->second.first = tmp;342 BoundaryTestPair.first->second.second = Walker;343 *out << Verbose(2) << "Keeping new vector." << endl;344 }345 else if (tmp == BoundaryTestPair.first->second.first)346 {347 if (BoundaryTestPair.first->second.second->x.ScalarProduct(348 &BoundaryTestPair.first->second.second->x)349 < Walker->x.ScalarProduct(&Walker->x))350 { // Norm() does a sqrt, which makes it a lot slower351 BoundaryTestPair.first->second.second = Walker;352 *out << Verbose(2) << "Keeping new vector." << endl;353 }354 else355 {356 *out << Verbose(2) << "Keeping present vector." << endl;357 }358 }359 else360 {361 *out << Verbose(2) << "Keeping present vector." << endl;362 }363 }364 }365 // printing all inserted for debugging366 //{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 // 3c. throw out points whose distance is less than the mean of left and right neighbours379 bool flag = false;380 do381 { // do as long as we still throw one out per round382 *out << Verbose(1)383 << "Looking for candidates to kick out by convex condition ... "384 << endl;385 flag = false;386 Boundaries::iterator left = BoundaryPoints[axis].end();387 Boundaries::iterator right = BoundaryPoints[axis].end();388 for (Boundaries::iterator runner = BoundaryPoints[axis].begin(); runner389 != BoundaryPoints[axis].end(); runner++)390 {391 // set neighbours correctly392 if (runner == BoundaryPoints[axis].begin())393 {394 left = BoundaryPoints[axis].end();395 }396 else397 {398 left = runner;399 }400 left--;401 right = runner;402 right++;403 if (right == BoundaryPoints[axis].end())404 {405 right = BoundaryPoints[axis].begin();406 }407 // check distance408 409 // construct the vector of each side of the triangle on the projected plane (defined by normal vector AxisVector)410 {411 Vector SideA, SideB, SideC, SideH;412 SideA.CopyVector(&left->second.second->x);413 SideA.ProjectOntoPlane(&AxisVector);414 //*out << "SideA: ";415 //SideA.Output(out);416 //*out << endl;417 418 SideB.CopyVector(&right->second.second->x);419 SideB.ProjectOntoPlane(&AxisVector);420 //*out << "SideB: ";421 //SideB.Output(out);422 //*out << endl;423 424 SideC.CopyVector(&left->second.second->x);425 SideC.SubtractVector(&right->second.second->x);426 SideC.ProjectOntoPlane(&AxisVector);427 //*out << "SideC: ";428 //SideC.Output(out);429 //*out << endl;430 431 SideH.CopyVector(&runner->second.second->x);432 SideH.ProjectOntoPlane(&AxisVector);433 //*out << "SideH: ";434 //SideH.Output(out);435 //*out << endl;436 437 // calculate each length438 double a = SideA.Norm();439 //double b = SideB.Norm();440 //double c = SideC.Norm();441 double h = SideH.Norm();442 // calculate the angles443 double alpha = SideA.Angle(&SideH);444 double beta = SideA.Angle(&SideC);445 double gamma = SideB.Angle(&SideH);446 double delta = SideC.Angle(&SideH);447 double MinDistance = a * sin(beta) / (sin(delta)) * (((alpha448 < M_PI / 2.) || (gamma < M_PI / 2.)) ? 1. : -1.);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 //*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;451 if ((fabs(h / fabs(h) - MinDistance / fabs(MinDistance))452 < MYEPSILON) && (h < MinDistance))453 {454 // throw out point455 //*out << Verbose(1) << "Throwing out " << *runner->second.second << "." << endl;456 BoundaryPoints[axis].erase(runner);457 flag = true;458 }459 }460 }461 }462 while (flag);463 }464 return BoundaryPoints;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 bool IsAngstroem)479 { 480 // get points on boundary of NULL was given as parameter481 bool BoundaryFreeFlag = false;482 Boundaries *BoundaryPoints = BoundaryPtr;483 if (BoundaryPoints == NULL)484 {485 BoundaryFreeFlag = true;486 BoundaryPoints = GetBoundaryPoints(out, mol);487 }488 else489 {490 *out << Verbose(1) << "Using given boundary points set." << endl;491 }492 // determine biggest "diameter" of cluster for each axis493 Boundaries::iterator Neighbour, OtherNeighbour;494 double *GreatestDiameter = new double[NDIM];495 for (int i = 0; i < NDIM; i++)496 GreatestDiameter[i] = 0.;497 double OldComponent, tmp, w1, w2;498 Vector DistanceVector, OtherVector;499 int component, Othercomponent;500 for (int axis = 0; axis < NDIM; axis++)501 { // regard each projected plane502 //*out << Verbose(1) << "Current axis is " << axis << "." << endl;503 for (int j = 0; j < 2; j++)504 { // and for both axis on the current plane505 component = (axis + j + 1) % NDIM;506 Othercomponent = (axis + 1 + ((j + 1) & 1)) % NDIM;507 //*out << Verbose(1) << "Current component is " << component << ", Othercomponent is " << Othercomponent << "." << endl;508 for (Boundaries::iterator runner = BoundaryPoints[axis].begin(); runner509 != BoundaryPoints[axis].end(); runner++)510 {511 //*out << Verbose(2) << "Current runner is " << *(runner->second.second) << "." << endl;512 // seek for the neighbours pair where the Othercomponent sign flips513 Neighbour = runner;514 Neighbour++;515 if (Neighbour == BoundaryPoints[axis].end()) // make it wrap around516 Neighbour = BoundaryPoints[axis].begin();517 DistanceVector.CopyVector(&runner->second.second->x);518 DistanceVector.SubtractVector(&Neighbour->second.second->x);519 do520 { // seek for neighbour pair where it flips521 OldComponent = DistanceVector.x[Othercomponent];522 Neighbour++;523 if (Neighbour == BoundaryPoints[axis].end()) // make it wrap around524 Neighbour = BoundaryPoints[axis].begin();525 DistanceVector.CopyVector(&runner->second.second->x);526 DistanceVector.SubtractVector(&Neighbour->second.second->x);527 //*out << Verbose(3) << "OldComponent is " << OldComponent << ", new one is " << DistanceVector.x[Othercomponent] << "." << endl;528 }529 while ((runner != Neighbour) && (fabs(OldComponent / fabs(530 OldComponent) - DistanceVector.x[Othercomponent] / fabs(531 DistanceVector.x[Othercomponent])) < MYEPSILON)); // as long as sign does not flip532 if (runner != Neighbour)533 {534 OtherNeighbour = Neighbour;535 if (OtherNeighbour == BoundaryPoints[axis].begin()) // make it wrap around536 OtherNeighbour = BoundaryPoints[axis].end();537 OtherNeighbour--;538 //*out << Verbose(2) << "The pair, where the sign of OtherComponent flips, is: " << *(Neighbour->second.second) << " and " << *(OtherNeighbour->second.second) << "." << endl;539 // now we have found the pair: Neighbour and OtherNeighbour540 OtherVector.CopyVector(&runner->second.second->x);541 OtherVector.SubtractVector(&OtherNeighbour->second.second->x);542 //*out << Verbose(2) << "Distances to Neighbour and OtherNeighbour are " << DistanceVector.x[component] << " and " << OtherVector.x[component] << "." << endl;543 //*out << Verbose(2) << "OtherComponents to Neighbour and OtherNeighbour are " << DistanceVector.x[Othercomponent] << " and " << OtherVector.x[Othercomponent] << "." << endl;544 // do linear interpolation between points (is exact) to extract exact intersection between Neighbour and OtherNeighbour545 w1 = fabs(OtherVector.x[Othercomponent]);546 w2 = fabs(DistanceVector.x[Othercomponent]);547 tmp = fabs((w1 * DistanceVector.x[component] + w2548 * OtherVector.x[component]) / (w1 + w2));549 // mark if it has greater diameter550 //*out << Verbose(2) << "Comparing current greatest " << GreatestDiameter[component] << " to new " << tmp << "." << endl;551 GreatestDiameter[component] = (GreatestDiameter[component]552 > tmp) ? GreatestDiameter[component] : tmp;553 } //else554 //*out << Verbose(2) << "Saw no sign flip, probably top or bottom node." << endl;555 }556 }557 }558 *out << Verbose(0) << "RESULT: The biggest diameters are "559 << GreatestDiameter[0] << " and " << GreatestDiameter[1] << " and "560 << GreatestDiameter[2] << " " << (IsAngstroem ? "angstrom"561 : "atomiclength") << "." << endl;562 563 // free reference lists564 if (BoundaryFreeFlag)565 delete[] (BoundaryPoints);566 567 return GreatestDiameter;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 class Tesselation *TesselStruct, class molecule *mol, int N)634 { 635 if (tecplot != NULL)636 {637 *tecplot << "TITLE = \"3D CONVEX SHELL\"" << endl;638 *tecplot << "VARIABLES = \"X\" \"Y\" \"Z\"" << endl;639 *tecplot << "ZONE T=\"TRIANGLES" << N << "\", N="640 << TesselStruct->PointsOnBoundaryCount << ", E="641 << TesselStruct->TrianglesOnBoundaryCount642 << ", DATAPACKING=POINT, ZONETYPE=FETRIANGLE" << endl;643 int *LookupList = new int[mol->AtomCount];644 for (int i = 0; i < mol->AtomCount; i++)645 LookupList[i] = -1;646 647 // print atom coordinates648 *out << Verbose(2) << "The following triangles were created:";649 int Counter = 1;650 atom *Walker = NULL;651 for (PointMap::iterator target = TesselStruct->PointsOnBoundary.begin(); target652 != TesselStruct->PointsOnBoundary.end(); target++)653 {654 Walker = target->second->node;655 LookupList[Walker->nr] = Counter++;656 *tecplot << Walker->x.x[0] << " " << Walker->x.x[1] << " "657 << Walker->x.x[2] << " " << endl;658 }659 *tecplot << endl;660 // print connectivity661 for (TriangleMap::iterator runner =662 TesselStruct->TrianglesOnBoundary.begin(); runner663 != TesselStruct->TrianglesOnBoundary.end(); runner++)664 {665 *out << " " << runner->second->endpoints[0]->node->Name << "<->"666 << runner->second->endpoints[1]->node->Name << "<->"667 << runner->second->endpoints[2]->node->Name;668 *tecplot << LookupList[runner->second->endpoints[0]->node->nr] << " "669 << LookupList[runner->second->endpoints[1]->node->nr] << " "670 << LookupList[runner->second->endpoints[2]->node->nr] << endl;671 }672 delete[] (LookupList);673 *out << endl;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 double ClusterVolume, double celldensity)825 { 826 // transform to PAS827 mol->PrincipalAxisSystem(out, true);828 829 // some preparations beforehand830 bool IsAngstroem = configuration->GetIsAngstroem();831 Boundaries *BoundaryPoints = GetBoundaryPoints(out, mol);832 double clustervolume;833 if (ClusterVolume == 0)834 clustervolume = VolumeOfConvexEnvelope(out, NULL, configuration,835 BoundaryPoints, mol);836 else837 clustervolume = ClusterVolume;838 double *GreatestDiameter = GetDiametersOfCluster(out, BoundaryPoints, mol,839 IsAngstroem);840 Vector BoxLengths;841 int repetition[NDIM] =842 { 1, 1, 1 };843 int TotalNoClusters = 1;844 for (int i = 0; i < NDIM; i++)845 TotalNoClusters *= repetition[i];846 847 // sum up the atomic masses848 double totalmass = 0.;849 atom *Walker = mol->start;850 while (Walker->next != mol->end)851 {852 Walker = Walker->next;853 totalmass += Walker->type->mass;854 }855 *out << Verbose(0) << "RESULT: The summed mass is " << setprecision(10)856 << totalmass << " atomicmassunit." << endl;857 858 *out << Verbose(0) << "RESULT: The average density is " << setprecision(10)859 << totalmass / clustervolume << " atomicmassunit/"860 << (IsAngstroem ? "angstrom" : "atomiclength") << "^3." << endl;861 862 // solve cubic polynomial863 *out << Verbose(1) << "Solving equidistant suspension in water problem ..."864 << endl;865 double cellvolume;866 if (IsAngstroem)867 cellvolume = (TotalNoClusters * totalmass / SOLVENTDENSITY_A - (totalmass868 / clustervolume)) / (celldensity - 1);869 else870 cellvolume = (TotalNoClusters * totalmass / SOLVENTDENSITY_a0 - (totalmass871 / clustervolume)) / (celldensity - 1);872 *out << Verbose(1) << "Cellvolume needed for a density of " << celldensity873 << " g/cm^3 is " << cellvolume << " " << (IsAngstroem ? "angstrom"874 : "atomiclength") << "^3." << endl;875 876 double minimumvolume = TotalNoClusters * (GreatestDiameter[0]877 * GreatestDiameter[1] * GreatestDiameter[2]);878 *out << Verbose(1)879 << "Minimum volume of the convex envelope contained in a rectangular box is "880 << minimumvolume << " atomicmassunit/" << (IsAngstroem ? "angstrom"881 : "atomiclength") << "^3." << endl;882 if (minimumvolume > cellvolume)883 {884 cerr << Verbose(0)885 << "ERROR: the containing box already has a greater volume than the envisaged cell volume!"886 << endl;887 cout << Verbose(0)888 << "Setting Box dimensions to minimum possible, the greatest diameters."889 << endl;890 for (int i = 0; i < NDIM; i++)891 BoxLengths.x[i] = GreatestDiameter[i];892 mol->CenterEdge(out, &BoxLengths);893 }894 else895 {896 BoxLengths.x[0] = (repetition[0] * GreatestDiameter[0] + repetition[1]897 * GreatestDiameter[1] + repetition[2] * GreatestDiameter[2]);898 BoxLengths.x[1] = (repetition[0] * repetition[1] * GreatestDiameter[0]899 * GreatestDiameter[1] + repetition[0] * repetition[2]900 * GreatestDiameter[0] * GreatestDiameter[2] + repetition[1]901 * repetition[2] * GreatestDiameter[1] * GreatestDiameter[2]);902 BoxLengths.x[2] = minimumvolume - cellvolume;903 double x0 = 0., x1 = 0., x2 = 0.;904 if (gsl_poly_solve_cubic(BoxLengths.x[0], BoxLengths.x[1],905 BoxLengths.x[2], &x0, &x1, &x2) == 1) // either 1 or 3 on return906 *out << Verbose(0) << "RESULT: The resulting spacing is: " << x0907 << " ." << endl;908 else909 {910 *out << Verbose(0) << "RESULT: The resulting spacings are: " << x0911 << " and " << x1 << " and " << x2 << " ." << endl;912 x0 = x2; // sorted in ascending order913 }914 915 cellvolume = 1;916 for (int i = 0; i < NDIM; i++)917 {918 BoxLengths.x[i] = repetition[i] * (x0 + GreatestDiameter[i]);919 cellvolume *= BoxLengths.x[i];920 }921 922 // set new box dimensions923 *out << Verbose(0) << "Translating to box with these boundaries." << endl;924 mol->CenterInBox((ofstream *) &cout, &BoxLengths);925 }926 // update Box of atoms by boundary927 mol->SetBoxDimension(&BoxLengths);928 *out << Verbose(0) << "RESULT: The resulting cell dimensions are: "929 << BoxLengths.x[0] << " and " << BoxLengths.x[1] << " and "930 << BoxLengths.x[2] << " with total volume of " << cellvolume << " "931 << (IsAngstroem ? "angstrom" : "atomiclength") << "^3." << endl;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 PointsOnBoundaryCount = 0;942 LinesOnBoundaryCount = 0;943 TrianglesOnBoundaryCount = 0;944 TriangleFilesWritten = 0;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 // 4b. create a starting triangle971 // 4b1. create all distances972 DistanceMultiMap DistanceMMap;973 double distance, tmp;974 Vector PlaneVector, TrialVector;975 PointMap::iterator A, B, C; // three nodes of the first triangle976 A = PointsOnBoundary.begin(); // the first may be chosen arbitrarily977 978 // with A chosen, take each pair B,C and sort979 if (A != PointsOnBoundary.end())980 {981 B = A;982 B++;983 for (; B != PointsOnBoundary.end(); B++)984 {985 C = B;986 C++;987 for (; C != PointsOnBoundary.end(); C++)988 {989 tmp = A->second->node->x.Distance(&B->second->node->x);990 distance = tmp * tmp;991 tmp = A->second->node->x.Distance(&C->second->node->x);992 distance += tmp * tmp;993 tmp = B->second->node->x.Distance(&C->second->node->x);994 distance += tmp * tmp;995 DistanceMMap.insert(DistanceMultiMapPair(distance, pair<996 PointMap::iterator, PointMap::iterator> (B, C)));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 // 4b2. pick three baselines forming a triangle1007 // 1. we take from the smallest sum of squared distance as the base line BC (with peak A) onward as the triangle candidate1008 DistanceMultiMap::iterator baseline = DistanceMMap.begin();1009 for (; baseline != DistanceMMap.end(); baseline++)1010 {1011 // we take from the smallest sum of squared distance as the base line BC (with peak A) onward as the triangle candidate1012 // 2. next, we have to check whether all points reside on only one side of the triangle1013 // 3. construct plane vector1014 PlaneVector.MakeNormalVector(&A->second->node->x,1015 &baseline->second.first->second->node->x,1016 &baseline->second.second->second->node->x);1017 *out << Verbose(2) << "Plane vector of candidate triangle is ";1018 PlaneVector.Output(out);1019 *out << endl;1020 // 4. loop over all points1021 double sign = 0.;1022 PointMap::iterator checker = PointsOnBoundary.begin();1023 for (; checker != PointsOnBoundary.end(); checker++)1024 {1025 // (neglecting A,B,C)1026 if ((checker == A) || (checker == baseline->second.first) || (checker1027 == baseline->second.second))1028 continue;1029 // 4a. project onto plane vector1030 TrialVector.CopyVector(&checker->second->node->x);1031 TrialVector.SubtractVector(&A->second->node->x);1032 distance = TrialVector.Projection(&PlaneVector);1033 if (fabs(distance) < 1e-4) // we need to have a small epsilon around 0 which is still ok1034 continue;1035 *out << Verbose(3) << "Projection of " << checker->second->node->Name1036 << " yields distance of " << distance << "." << endl;1037 tmp = distance / fabs(distance);1038 // 4b. Any have different sign to than before? (i.e. would lie outside convex hull with this starting triangle)1039 if ((sign != 0) && (tmp != sign))1040 {1041 // 4c. If so, break 4. loop and continue with next candidate in 1. loop1042 *out << Verbose(2) << "Current candidates: "1043 << A->second->node->Name << ","1044 << baseline->second.first->second->node->Name << ","1045 << baseline->second.second->second->node->Name << " leave "1046 << checker->second->node->Name << " outside the convex hull."1047 << endl;1048 break;1049 }1050 else1051 { // note the sign for later1052 *out << Verbose(2) << "Current candidates: "1053 << A->second->node->Name << ","1054 << baseline->second.first->second->node->Name << ","1055 << baseline->second.second->second->node->Name << " leave "1056 << checker->second->node->Name << " inside the convex hull."1057 << endl;1058 sign = tmp;1059 }1060 // 4d. Check whether the point is inside the triangle (check distance to each node1061 tmp = checker->second->node->x.Distance(&A->second->node->x);1062 int innerpoint = 0;1063 if ((tmp < A->second->node->x.Distance(1064 &baseline->second.first->second->node->x)) && (tmp1065 < A->second->node->x.Distance(1066 &baseline->second.second->second->node->x)))1067 innerpoint++;1068 tmp = checker->second->node->x.Distance(1069 &baseline->second.first->second->node->x);1070 if ((tmp < baseline->second.first->second->node->x.Distance(1071 &A->second->node->x)) && (tmp1072 < baseline->second.first->second->node->x.Distance(1073 &baseline->second.second->second->node->x)))1074 innerpoint++;1075 tmp = checker->second->node->x.Distance(1076 &baseline->second.second->second->node->x);1077 if ((tmp < baseline->second.second->second->node->x.Distance(1078 &baseline->second.first->second->node->x)) && (tmp1079 < baseline->second.second->second->node->x.Distance(1080 &A->second->node->x)))1081 innerpoint++;1082 // 4e. If so, break 4. loop and continue with next candidate in 1. loop1083 if (innerpoint == 3)1084 break;1085 }1086 // 5. come this far, all on same side? Then break 1. loop and construct triangle1087 if (checker == PointsOnBoundary.end())1088 {1089 *out << "Looks like we have a candidate!" << endl;1090 break;1091 }1092 }1093 if (baseline != DistanceMMap.end())1094 {1095 BPS[0] = baseline->second.first->second;1096 BPS[1] = baseline->second.second->second;1097 BLS[0] = new class BoundaryLineSet(BPS, LinesOnBoundaryCount);1098 BPS[0] = A->second;1099 BPS[1] = baseline->second.second->second;1100 BLS[1] = new class BoundaryLineSet(BPS, LinesOnBoundaryCount);1101 BPS[0] = baseline->second.first->second;1102 BPS[1] = A->second;1103 BLS[2] = new class BoundaryLineSet(BPS, LinesOnBoundaryCount);1104 1105 // 4b3. insert created triangle1106 BTS = new class BoundaryTriangleSet(BLS, TrianglesOnBoundaryCount);1107 TrianglesOnBoundary.insert(TrianglePair(TrianglesOnBoundaryCount, BTS));1108 TrianglesOnBoundaryCount++;1109 for (int i = 0; i < NDIM; i++)1110 {1111 LinesOnBoundary.insert(LinePair(LinesOnBoundaryCount, BTS->lines[i]));1112 LinesOnBoundaryCount++;1113 }1114 1115 *out << Verbose(1) << "Starting triangle is " << *BTS << "." << endl;1116 }1117 else1118 {1119 *out << Verbose(1) << "No starting triangle found." << endl;1120 exit(255);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 * -# if the triangle with the baseline and the current point has the smallest of angles (comparison between normal vectors1131 * -# if the triangle is in forward direction of the baseline (at most 90 degrees angle between vector orthogonal to1132 * baseline in triangle plane pointing out of the triangle and normal vector of new triangle)1133 * -# then we have a new triangle, whose baselines we again add (or increase their TriangleCount)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 molecule *mol)1141 { 1142 bool flag;1143 PointMap::iterator winner;1144 class BoundaryPointSet *peak = NULL;1145 double SmallestAngle, TempAngle;1146 Vector NormalVector, VirtualNormalVector, CenterVector, TempVector,1147 PropagationVector;1148 LineMap::iterator LineChecker[2];1149 do1150 {1151 flag = false;1152 for (LineMap::iterator baseline = LinesOnBoundary.begin(); baseline1153 != LinesOnBoundary.end(); baseline++)1154 if (baseline->second->TrianglesCount == 1)1155 {1156 *out << Verbose(2) << "Current baseline is between "1157 << *(baseline->second) << "." << endl;1158 // 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)1159 SmallestAngle = M_PI;1160 BTS = baseline->second->triangles.begin()->second; // there is only one triangle so far1161 // get peak point with respect to this base line's only triangle1162 for (int i = 0; i < 3; i++)1163 if ((BTS->endpoints[i] != baseline->second->endpoints[0])1164 && (BTS->endpoints[i] != baseline->second->endpoints[1]))1165 peak = BTS->endpoints[i];1166 *out << Verbose(3) << " and has peak " << *peak << "." << endl;1167 // normal vector of triangle1168 BTS->GetNormalVector(NormalVector);1169 *out << Verbose(4) << "NormalVector of base triangle is ";1170 NormalVector.Output(out);1171 *out << endl;1172 // offset to center of triangle1173 CenterVector.Zero();1174 for (int i = 0; i < 3; i++)1175 CenterVector.AddVector(&BTS->endpoints[i]->node->x);1176 CenterVector.Scale(1. / 3.);1177 *out << Verbose(4) << "CenterVector of base triangle is ";1178 CenterVector.Output(out);1179 *out << endl;1180 // vector in propagation direction (out of triangle)1181 // project center vector onto triangle plane (points from intersection plane-NormalVector to plane-CenterVector intersection)1182 TempVector.CopyVector(&baseline->second->endpoints[0]->node->x);1183 TempVector.SubtractVector(&baseline->second->endpoints[1]->node->x);1184 PropagationVector.MakeNormalVector(&TempVector, &NormalVector);1185 TempVector.CopyVector(&CenterVector);1186 TempVector.SubtractVector(&baseline->second->endpoints[0]->node->x); // TempVector is vector on triangle plane pointing from one baseline egde towards center!1187 //*out << Verbose(2) << "Projection of propagation onto temp: " << PropagationVector.Projection(&TempVector) << "." << endl;1188 if (PropagationVector.Projection(&TempVector) > 0) // make sure normal propagation vector points outward from baseline1189 PropagationVector.Scale(-1.);1190 *out << Verbose(4) << "PropagationVector of base triangle is ";1191 PropagationVector.Output(out);1192 *out << endl;1193 winner = PointsOnBoundary.end();1194 for (PointMap::iterator target = PointsOnBoundary.begin(); target1195 != PointsOnBoundary.end(); target++)1196 if ((target->second != baseline->second->endpoints[0])1197 && (target->second != baseline->second->endpoints[1]))1198 { // don't take the same endpoints1199 *out << Verbose(3) << "Target point is " << *(target->second)1200 << ":";1201 bool continueflag = true;1202 1203 VirtualNormalVector.CopyVector(1204 &baseline->second->endpoints[0]->node->x);1205 VirtualNormalVector.AddVector(1206 &baseline->second->endpoints[0]->node->x);1207 VirtualNormalVector.Scale(-1. / 2.); // points now to center of base line1208 VirtualNormalVector.AddVector(&target->second->node->x); // points from center of base line to target1209 TempAngle = VirtualNormalVector.Angle(&PropagationVector);1210 continueflag = continueflag && (TempAngle < (M_PI/2.)); // no bends bigger than Pi/2 (90 degrees)1211 if (!continueflag)1212 {1213 *out << Verbose(4)1214 << "Angle between propagation direction and base line to "1215 << *(target->second) << " is " << TempAngle1216 << ", bad direction!" << endl;1217 continue;1218 }1219 else1220 *out << Verbose(4)1221 << "Angle between propagation direction and base line to "1222 << *(target->second) << " is " << TempAngle1223 << ", good direction!" << endl;1224 LineChecker[0] = baseline->second->endpoints[0]->lines.find(1225 target->first);1226 LineChecker[1] = baseline->second->endpoints[1]->lines.find(1227 target->first);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 // check first endpoint (if any connecting line goes to target or at least not more than 1)1237 continueflag = continueflag && (((LineChecker[0]1238 == baseline->second->endpoints[0]->lines.end())1239 || (LineChecker[0]->second->TrianglesCount == 1)));1240 if (!continueflag)1241 {1242 *out << Verbose(4) << *(baseline->second->endpoints[0])1243 << " has line " << *(LineChecker[0]->second)1244 << " to " << *(target->second)1245 << " as endpoint with "1246 << LineChecker[0]->second->TrianglesCount1247 << " triangles." << endl;1248 continue;1249 }1250 // check second endpoint (if any connecting line goes to target or at least not more than 1)1251 continueflag = continueflag && (((LineChecker[1]1252 == baseline->second->endpoints[1]->lines.end())1253 || (LineChecker[1]->second->TrianglesCount == 1)));1254 if (!continueflag)1255 {1256 *out << Verbose(4) << *(baseline->second->endpoints[1])1257 << " has line " << *(LineChecker[1]->second)1258 << " to " << *(target->second)1259 << " as endpoint with "1260 << LineChecker[1]->second->TrianglesCount1261 << " triangles." << endl;1262 continue;1263 }1264 // check whether the envisaged triangle does not already exist (if both lines exist and have same endpoint)1265 continueflag = continueflag && (!(((LineChecker[0]1266 != baseline->second->endpoints[0]->lines.end())1267 && (LineChecker[1]1268 != baseline->second->endpoints[1]->lines.end())1269 && (GetCommonEndpoint(LineChecker[0]->second,1270 LineChecker[1]->second) == peak))));1271 if (!continueflag)1272 {1273 *out << Verbose(4) << "Current target is peak!" << endl;1274 continue;1275 }1276 // in case NOT both were found1277 if (continueflag)1278 { // create virtually this triangle, get its normal vector, calculate angle1279 flag = true;1280 VirtualNormalVector.MakeNormalVector(1281 &baseline->second->endpoints[0]->node->x,1282 &baseline->second->endpoints[1]->node->x,1283 &target->second->node->x);1284 // make it always point inward1285 if (baseline->second->endpoints[0]->node->x.Projection(1286 &VirtualNormalVector) > 0)1287 VirtualNormalVector.Scale(-1.);1288 // calculate angle1289 TempAngle = NormalVector.Angle(&VirtualNormalVector);1290 *out << Verbose(4) << "NormalVector is ";1291 VirtualNormalVector.Output(out);1292 *out << " and the angle is " << TempAngle << "." << endl;1293 if (SmallestAngle > TempAngle)1294 { // set to new possible winner1295 SmallestAngle = TempAngle;1296 winner = target;1297 }1298 }1299 }1300 // 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 triangle1301 if (winner != PointsOnBoundary.end())1302 {1303 *out << Verbose(2) << "Winning target point is "1304 << *(winner->second) << " with angle " << SmallestAngle1305 << "." << endl;1306 // create the lins of not yet present1307 BLS[0] = baseline->second;1308 // 5c. add lines to the line set if those were new (not yet part of a triangle), delete lines that belong to two triangles)1309 LineChecker[0] = baseline->second->endpoints[0]->lines.find(1310 winner->first);1311 LineChecker[1] = baseline->second->endpoints[1]->lines.find(1312 winner->first);1313 if (LineChecker[0]1314 == baseline->second->endpoints[0]->lines.end())1315 { // create1316 BPS[0] = baseline->second->endpoints[0];1317 BPS[1] = winner->second;1318 BLS[1] = new class BoundaryLineSet(BPS,1319 LinesOnBoundaryCount);1320 LinesOnBoundary.insert(LinePair(LinesOnBoundaryCount,1321 BLS[1]));1322 LinesOnBoundaryCount++;1323 }1324 else1325 BLS[1] = LineChecker[0]->second;1326 if (LineChecker[1]1327 == baseline->second->endpoints[1]->lines.end())1328 { // create1329 BPS[0] = baseline->second->endpoints[1];1330 BPS[1] = winner->second;1331 BLS[2] = new class BoundaryLineSet(BPS,1332 LinesOnBoundaryCount);1333 LinesOnBoundary.insert(LinePair(LinesOnBoundaryCount,1334 BLS[2]));1335 LinesOnBoundaryCount++;1336 }1337 else1338 BLS[2] = LineChecker[1]->second;1339 BTS = new class BoundaryTriangleSet(BLS,1340 TrianglesOnBoundaryCount);1341 TrianglesOnBoundary.insert(TrianglePair(1342 TrianglesOnBoundaryCount, BTS));1343 TrianglesOnBoundaryCount++;1344 }1345 else1346 {1347 *out << Verbose(1)1348 << "I could not determine a winner for this baseline "1349 << *(baseline->second) << "." << endl;1350 }1351 1352 // 5d. If the set of lines is not yet empty, go to 5. and continue1353 }1354 else1355 *out << Verbose(2) << "Baseline candidate " << *(baseline->second)1356 << " has a triangle count of "1357 << baseline->second->TrianglesCount << "." << endl;1358 }1359 while (flag);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 PointTestPair InsertUnique;1371 BPS[0] = new class BoundaryPointSet(Walker);1372 InsertUnique = PointsOnBoundary.insert(PointPair(Walker->nr, BPS[0]));1373 if (InsertUnique.second) // if new point was not present before, increase counter1374 PointsOnBoundaryCount++;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 PointTestPair InsertUnique;1387 TPS[n] = new class BoundaryPointSet(Candidate);1388 InsertUnique = PointsOnBoundary.insert(PointPair(Candidate->nr, TPS[n]));1389 if (InsertUnique.second) // if new point was not present before, increase counter1390 {1391 PointsOnBoundaryCount++;1392 }1393 else1394 {1395 delete TPS[n];1396 cout << Verbose(2) << "Atom " << *((InsertUnique.first)->second->node)1397 << " gibt's schon in der PointMap." << endl;1398 TPS[n] = (InsertUnique.first)->second;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 class BoundaryPointSet *b, int n)1413 { 1414 LineMap::iterator LineWalker;1415 //cout << "Manually checking endpoints for line." << endl;1416 if ((a->lines.find(b->node->nr))->first == b->node->nr)1417 //If a line is there, how do I recognize that beyond a shadow of a doubt?1418 {1419 //cout << Verbose(2) << "Line exists already, retrieving it from LinesOnBoundarySet" << endl;1420 1421 LineWalker = LinesOnBoundary.end();1422 LineWalker--;1423 1424 while (LineWalker->second->endpoints[0]->node->nr != min(a->node->nr,1425 b->node->nr) or LineWalker->second->endpoints[1]->node->nr != max(1426 a->node->nr, b->node->nr))1427 {1428 //cout << Verbose(1) << "Looking for line which already exists"<< endl;1429 LineWalker--;1430 }1431 BPS[0] = LineWalker->second->endpoints[0];1432 BPS[1] = LineWalker->second->endpoints[1];1433 BLS[n] = LineWalker->second;1434 1435 }1436 else1437 {1438 cout << Verbose(2)1439 << "Adding line which has not been used before between "1440 << *(a->node) << " and " << *(b->node) << "." << endl;1441 BPS[0] = a;1442 BPS[1] = b;1443 BLS[n] = new class BoundaryLineSet(BPS, LinesOnBoundaryCount);1444 1445 LinesOnBoundary.insert(LinePair(LinesOnBoundaryCount, BLS[n]));1446 LinesOnBoundaryCount++;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 * supply results to the calling function, the radius of the sphere which the triangle shall support and the molecule \1534 * upon which we operate.1535 * If the candidate is more fitting to support the sphere than the already stored atom is, then we write its general \1536 * direction and angle into Storage.1537 * We the determine the recursive level we have reached and if this is not on the threshold yet, call this function again, \1538 * with all neighbours of the candidate.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 output stream for debugging1983 * @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.
